| author | |
| committer | |
| log | 135a335ce12a33666e44cb13e0be4bb893877565 |
| tree | 23b10bed3d36e3fb244c6a2e5d5765d8b7a71fb5 |
| parent | b01c5a95c468650f143e0ae96f6c3865852fdcda |
| parent | f43711e5fbbedafa1c28c933fdca0949427c77cd |
84 files changed, 11186 insertions(+), 2859 deletions(-)
.travis.yml+3-1| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | sudo: required | |
| 2 | services: | |
| 3 | - docker | |
| 1 | 4 | os: |
| 2 | 5 | - linux |
| 3 | 6 | - osx |
| 4 | 7 | dist: trusty |
| 5 | 8 | osx_image: xcode8.3 |
| 6 | sudo: required | |
| 7 | 9 | language: cpp |
| 8 | 10 | before_install: |
| 9 | 11 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi |
CMakeLists.txt+33-9| ... | ... | @@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE) |
| 5 | 5 | "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) |
| 6 | 6 | endif() |
| 7 | 7 | |
| 8 | if(NOT CMAKE_INSTALL_PREFIX) | |
| 9 | set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE STRING | |
| 10 | "Directory to install zig to" FORCE) | |
| 11 | endif() | |
| 12 | ||
| 8 | 13 | project(zig C CXX) |
| 9 | 14 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) |
| 10 | 15 | |
| ... | ... | @@ -30,11 +35,7 @@ if(GIT_EXE) |
| 30 | 35 | endif() |
| 31 | 36 | message("Configuring zig version ${ZIG_VERSION}") |
| 32 | 37 | |
| 33 | set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found") | |
| 34 | set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found") | |
| 35 | set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory") | |
| 36 | set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target") | |
| 37 | set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target") | |
| 38 | set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") | |
| 38 | 39 | |
| 39 | 40 | string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}") |
| 40 | 41 | string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}") |
| ... | ... | @@ -49,6 +50,22 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead |
| 49 | 50 | find_package(llvm) |
| 50 | 51 | find_package(clang) |
| 51 | 52 | |
| 53 | if(NOT MSVC) | |
| 54 | find_library(LIBXML2 NAMES xml2 libxml2) | |
| 55 | if(${LIBXML2} STREQUAL "LIBXML2-NOTFOUND") | |
| 56 | message(FATAL_ERROR "Could not find libxml2") | |
| 57 | else() | |
| 58 | message("${LIBXML2} found") | |
| 59 | endif() | |
| 60 | ||
| 61 | find_library(ZLIB NAMES z zlib libz) | |
| 62 | if(${ZLIB} STREQUAL "ZLIB-NOTFOUND") | |
| 63 | message(FATAL_ERROR "Could not find zlib") | |
| 64 | else() | |
| 65 | message("${ZLIB} found") | |
| 66 | endif() | |
| 67 | endif() | |
| 68 | ||
| 52 | 69 | set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp") |
| 53 | 70 | |
| 54 | 71 | if(ZIG_FORCE_EXTERNAL_LLD) |
| ... | ... | @@ -413,18 +430,24 @@ set(ZIG_STD_FILES |
| 413 | 430 | "crypto/sha2.zig" |
| 414 | 431 | "crypto/sha3.zig" |
| 415 | 432 | "crypto/blake2.zig" |
| 433 | "crypto/hmac.zig" | |
| 416 | 434 | "cstr.zig" |
| 417 | 435 | "debug/failing_allocator.zig" |
| 418 | 436 | "debug/index.zig" |
| 419 | 437 | "dwarf.zig" |
| 420 | 438 | "elf.zig" |
| 421 | 439 | "empty.zig" |
| 422 | "endian.zig" | |
| 440 | "event.zig" | |
| 423 | 441 | "fmt/errol/enum3.zig" |
| 424 | 442 | "fmt/errol/index.zig" |
| 425 | 443 | "fmt/errol/lookup.zig" |
| 426 | 444 | "fmt/index.zig" |
| 427 | 445 | "hash_map.zig" |
| 446 | "hash/index.zig" | |
| 447 | "hash/adler.zig" | |
| 448 | "hash/crc.zig" | |
| 449 | "hash/fnv.zig" | |
| 450 | "hash/siphash.zig" | |
| 428 | 451 | "heap.zig" |
| 429 | 452 | "index.zig" |
| 430 | 453 | "io.zig" |
| ... | ... | @@ -485,7 +508,6 @@ set(ZIG_STD_FILES |
| 485 | 508 | "os/get_user_id.zig" |
| 486 | 509 | "os/index.zig" |
| 487 | 510 | "os/linux/errno.zig" |
| 488 | "os/linux/i386.zig" | |
| 489 | 511 | "os/linux/index.zig" |
| 490 | 512 | "os/linux/x86_64.zig" |
| 491 | 513 | "os/path.zig" |
| ... | ... | @@ -493,7 +515,7 @@ set(ZIG_STD_FILES |
| 493 | 515 | "os/windows/index.zig" |
| 494 | 516 | "os/windows/util.zig" |
| 495 | 517 | "os/zen.zig" |
| 496 | "rand.zig" | |
| 518 | "rand/index.zig" | |
| 497 | 519 | "sort.zig" |
| 498 | 520 | "special/bootstrap.zig" |
| 499 | 521 | "special/bootstrap_lib.zig" |
| ... | ... | @@ -682,6 +704,8 @@ if(MINGW) |
| 682 | 704 | set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++") |
| 683 | 705 | elseif(MSVC) |
| 684 | 706 | set(EXE_LDFLAGS "/STACK:16777216") |
| 707 | elseif(ZIG_STATIC) | |
| 708 | set(EXE_LDFLAGS "-static") | |
| 685 | 709 | else() |
| 686 | 710 | set(EXE_LDFLAGS " ") |
| 687 | 711 | endif() |
| ... | ... | @@ -710,7 +734,7 @@ target_link_libraries(zig LINK_PUBLIC |
| 710 | 734 | ${CMAKE_THREAD_LIBS_INIT} |
| 711 | 735 | ) |
| 712 | 736 | if(NOT MSVC) |
| 713 | target_link_libraries(zig LINK_PUBLIC xml2) | |
| 737 | target_link_libraries(zig LINK_PUBLIC ${LIBXML2}) | |
| 714 | 738 | endif() |
| 715 | 739 | if(ZIG_DIA_GUIDS_LIB) |
| 716 | 740 | target_link_libraries(zig LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) |
README.md+4-10| ... | ... | @@ -138,31 +138,25 @@ libc. Create demo games using Zig. |
| 138 | 138 | |
| 139 | 139 | ##### POSIX |
| 140 | 140 | |
| 141 | If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`, | |
| 142 | `ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to | |
| 143 | (example below). | |
| 144 | ||
| 145 | 141 | ``` |
| 146 | 142 | mkdir build |
| 147 | 143 | cd build |
| 148 | cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o)) | |
| 144 | cmake .. | |
| 149 | 145 | make |
| 150 | 146 | make install |
| 151 | ./zig build --build-file ../build.zig test | |
| 147 | bin/zig build --build-file ../build.zig test | |
| 152 | 148 | ``` |
| 153 | 149 | |
| 154 | 150 | ##### MacOS |
| 155 | 151 | |
| 156 | `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused. | |
| 157 | ||
| 158 | 152 | ``` |
| 159 | 153 | brew install cmake llvm@6 |
| 160 | 154 | brew outdated llvm@6 || brew upgrade llvm@6 |
| 161 | 155 | mkdir build |
| 162 | 156 | cd build |
| 163 | cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@6/ -DCMAKE_INSTALL_PREFIX=$(pwd) | |
| 157 | cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@6/ | |
| 164 | 158 | make install |
| 165 | ./zig build --build-file ../build.zig test | |
| 159 | bin/zig build --build-file ../build.zig test | |
| 166 | 160 | ``` |
| 167 | 161 | |
| 168 | 162 | ##### Windows |
build.zig+13| ... | ... | @@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void { |
| 45 | 45 | |
| 46 | 46 | var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); |
| 47 | 47 | exe.setBuildMode(mode); |
| 48 | ||
| 49 | // This is for finding /lib/libz.a on alpine linux. | |
| 50 | // TODO turn this into -Dextra-lib-path=/lib option | |
| 51 | exe.addLibPath("/lib"); | |
| 52 | ||
| 48 | 53 | exe.addIncludeDir("src"); |
| 49 | 54 | exe.addIncludeDir(cmake_binary_dir); |
| 50 | 55 | addCppLib(b, exe, cmake_binary_dir, "zig_cpp"); |
| ... | ... | @@ -64,6 +69,14 @@ pub fn build(b: &Builder) !void { |
| 64 | 69 | if (exe.target.getOs() == builtin.Os.linux) { |
| 65 | 70 | const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"}); |
| 66 | 71 | const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next(); |
| 72 | if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) { | |
| 73 | warn( | |
| 74 | \\Unable to determine path to libstdc++.a | |
| 75 | \\On Fedora, install libstdc++-static and try again. | |
| 76 | \\ | |
| 77 | ); | |
| 78 | return error.RequiredLibraryNotFound; | |
| 79 | } | |
| 67 | 80 | exe.addObjectFile(libstdcxx_path); |
| 68 | 81 | |
| 69 | 82 | exe.linkSystemLibrary("pthread"); |
ci/appveyor/build_script.bat+1-3| ... | ... | @@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_ |
| 20 | 20 | |
| 21 | 21 | mkdir %ZIGBUILDDIR% |
| 22 | 22 | cd %ZIGBUILDDIR% |
| 23 | cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release "-DZIG_LIBC_INCLUDE_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt" "-DZIG_LIBC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\bin\x64\ucrt" "-DZIG_LIBC_STATIC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64" || exit /b | |
| 23 | cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b | |
| 24 | 24 | msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b |
| 25 | 25 | |
| 26 | 26 | bin\zig.exe build --build-file ..\build.zig test || exit /b |
| 27 | ||
| 28 | @echo "MSVC build succeeded" |
ci/travis_linux_install+1-1| ... | ... | @@ -4,4 +4,4 @@ set -x |
| 4 | 4 | |
| 5 | 5 | sudo apt-get remove -y llvm-* |
| 6 | 6 | sudo rm -rf /usr/local/* |
| 7 | sudo apt-get install -y clang-6.0 libclang-6.0 libclang-6.0-dev llvm-6.0 llvm-6.0-dev liblld-6.0 liblld-6.0-dev cmake wine1.6-amd64 | |
| 7 | sudo apt-get install -y clang-6.0 libclang-6.0 libclang-6.0-dev llvm-6.0 llvm-6.0-dev liblld-6.0 liblld-6.0-dev cmake wine1.6-amd64 s3cmd |
ci/travis_linux_script+11-20| ... | ... | @@ -8,25 +8,16 @@ export CXX=clang++-6.0 |
| 8 | 8 | echo $PATH |
| 9 | 9 | mkdir build |
| 10 | 10 | cd build |
| 11 | cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $($CC -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | $CC -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $($CC -print-file-name=crtbegin.o)) | |
| 12 | make VERBOSE=1 | |
| 13 | make install | |
| 11 | cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) | |
| 12 | make -j2 install | |
| 14 | 13 | ./zig build --build-file ../build.zig test |
| 15 | 14 | |
| 16 | ./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc | |
| 17 | wine zig-cache/test.exe | |
| 18 | ||
| 19 | ./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-fast | |
| 20 | wine zig-cache/test.exe | |
| 21 | ||
| 22 | ./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-safe | |
| 23 | wine zig-cache/test.exe | |
| 24 | ||
| 25 | ./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc | |
| 26 | wine64 zig-cache/test.exe | |
| 27 | ||
| 28 | #./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-fast | |
| 29 | #wine64 test.exe | |
| 30 | # | |
| 31 | #./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-safe | |
| 32 | #wine64 test.exe | |
| 15 | if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then | |
| 16 | mkdir $TRAVIS_BUILD_DIR/artifacts | |
| 17 | docker run -it --mount type=bind,source="$TRAVIS_BUILD_DIR/artifacts",target=/z ziglang/static-base:llvm6-1 -j2 $TRAVIS_COMMIT | |
| 18 | echo "access_key = $AWS_ACCESS_KEY_ID" >> ~/.s3cfg | |
| 19 | echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg | |
| 20 | s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/ | |
| 21 | touch empty | |
| 22 | s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts) | |
| 23 | fi |
cmake/Findclang.cmake+3-1| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | # CLANG_FOUND |
| 6 | 6 | # CLANG_INCLUDE_DIRS |
| 7 | 7 | # CLANG_LIBRARIES |
| 8 | # CLANG_LIBDIRS | |
| 8 | 9 | |
| 9 | 10 | if(MSVC) |
| 10 | 11 | find_package(CLANG REQUIRED CONFIG) |
| ... | ... | @@ -34,6 +35,7 @@ else() |
| 34 | 35 | string(TOUPPER ${_libname_} _prettylibname_) |
| 35 | 36 | find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_} |
| 36 | 37 | PATHS |
| 38 | ${CLANG_LIBDIRS} | |
| 37 | 39 | /usr/lib/llvm/6/lib |
| 38 | 40 | /usr/lib/llvm-6.0/lib |
| 39 | 41 | /mingw64/lib |
| ... | ... | @@ -60,4 +62,4 @@ endif() |
| 60 | 62 | include(FindPackageHandleStandardArgs) |
| 61 | 63 | find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS) |
| 62 | 64 | |
| 63 | mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES) | |
| 65 | mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES CLANG_LIBDIRS) |
cmake/Findllvm.cmake+2-2| ... | ... | @@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE |
| 15 | 15 | "c:/msys64/mingw64/bin" |
| 16 | 16 | "C:/Libraries/llvm-6.0.0/bin") |
| 17 | 17 | |
| 18 | if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug")) | |
| 18 | if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug") OR ZIG_STATIC) | |
| 19 | 19 | execute_process( |
| 20 | 20 | COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static |
| 21 | 21 | OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES |
| ... | ... | @@ -66,7 +66,7 @@ if(NOT LLVM_LIBRARIES) |
| 66 | 66 | endif() |
| 67 | 67 | |
| 68 | 68 | link_directories("${CMAKE_PREFIX_PATH}/lib") |
| 69 | ||
| 69 | link_directories("${LLVM_LIBDIRS}") | |
| 70 | 70 | |
| 71 | 71 | include(FindPackageHandleStandardArgs) |
| 72 | 72 | find_package_handle_standard_args(LLVM DEFAULT_MSG LLVM_LIBRARIES LLVM_INCLUDE_DIRS) |
doc/docgen.zig+1-1| ... | ... | @@ -55,7 +55,7 @@ pub fn main() !void { |
| 55 | 55 | // TODO issue #709 |
| 56 | 56 | // disabled to pass CI tests, but obviously we want to implement this |
| 57 | 57 | // and then remove this workaround |
| 58 | if (builtin.os == builtin.Os.linux) { | |
| 58 | if (builtin.os != builtin.Os.windows) { | |
| 59 | 59 | os.deleteTree(allocator, tmp_dir_name) catch {}; |
| 60 | 60 | } |
| 61 | 61 | } |
doc/langref.html.in+55-20| ... | ... | @@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C }; |
| 1947 | 1947 | export fn entry(foo: Foo) void { } |
| 1948 | 1948 | {#code_end#} |
| 1949 | 1949 | {#header_close#} |
| 1950 | <p>TODO packed enum</p> | |
| 1951 | {#see_also|@memberName|@memberCount|@tagName#} | |
| 1950 | {#header_open|packed enum#} | |
| 1951 | <p>By default, the size of enums is not guaranteed.</p> | |
| 1952 | <p><code>packed enum</code> causes the size of the enum to be the same as the size of the integer tag type | |
| 1953 | of the enum:</p> | |
| 1954 | {#code_begin|test#} | |
| 1955 | const std = @import("std"); | |
| 1956 | ||
| 1957 | test "packed enum" { | |
| 1958 | const Number = packed enum(u8) { | |
| 1959 | One, | |
| 1960 | Two, | |
| 1961 | Three, | |
| 1962 | }; | |
| 1963 | std.debug.assert(@sizeOf(Number) == @sizeOf(u8)); | |
| 1964 | } | |
| 1965 | {#code_end#} | |
| 1966 | {#header_close#} | |
| 1967 | {#see_also|@memberName|@memberCount|@tagName|@sizeOf#} | |
| 1952 | 1968 | {#header_close#} |
| 1953 | 1969 | {#header_open|union#} |
| 1954 | 1970 | {#code_begin|test|union#} |
| ... | ... | @@ -2017,7 +2033,27 @@ test "union variant switch" { |
| 2017 | 2033 | assert(mem.eql(u8, what_is_it, "this is a number")); |
| 2018 | 2034 | } |
| 2019 | 2035 | |
| 2020 | // TODO union methods | |
| 2036 | // Unions can have methods just like structs and enums: | |
| 2037 | ||
| 2038 | const Variant = union(enum) { | |
| 2039 | Int: i32, | |
| 2040 | Bool: bool, | |
| 2041 | ||
| 2042 | fn truthy(self: &const Variant) bool { | |
| 2043 | return switch (*self) { | |
| 2044 | Variant.Int => |x_int| x_int != 0, | |
| 2045 | Variant.Bool => |x_bool| x_bool, | |
| 2046 | }; | |
| 2047 | } | |
| 2048 | }; | |
| 2049 | ||
| 2050 | test "union method" { | |
| 2051 | var v1 = Variant { .Int = 1 }; | |
| 2052 | var v2 = Variant { .Bool = false }; | |
| 2053 | ||
| 2054 | assert(v1.truthy()); | |
| 2055 | assert(!v2.truthy()); | |
| 2056 | } | |
| 2021 | 2057 | |
| 2022 | 2058 | |
| 2023 | 2059 | const Small = union { |
| ... | ... | @@ -2864,18 +2900,18 @@ const err = (error {FileNotFound}).FileNotFound; |
| 2864 | 2900 | assert to make sure the error value is in fact in the destination error set. |
| 2865 | 2901 | </p> |
| 2866 | 2902 | <p> |
| 2867 | The global error set should generally be avoided when possible, because it prevents | |
| 2868 | the compiler from knowing what errors are possible at compile-time. Knowing | |
| 2869 | the error set at compile-time is better for generated documentationt and for | |
| 2870 | helpful error messages such as forgetting a possible error value in a {#link|switch#}. | |
| 2903 | The global error set should generally be avoided because it prevents the | |
| 2904 | compiler from knowing what errors are possible at compile-time. Knowing | |
| 2905 | the error set at compile-time is better for generated documentation and | |
| 2906 | helpful error messages, such as forgetting a possible error value in a {#link|switch#}. | |
| 2871 | 2907 | </p> |
| 2872 | 2908 | {#header_close#} |
| 2873 | 2909 | {#header_close#} |
| 2874 | 2910 | {#header_open|Error Union Type#} |
| 2875 | 2911 | <p> |
| 2876 | Most of the time you will not find yourself using an error set type. Instead, | |
| 2877 | likely you will be using the error union type. This is when you take an error set | |
| 2878 | and a normal type, and create an error union with the <code>!</code> binary operator. | |
| 2912 | An error set type and normal type can be combined with the <code>!</code> | |
| 2913 | binary operator to form an error union type. You are likely to use an | |
| 2914 | error union type more often than an error set type by itself. | |
| 2879 | 2915 | </p> |
| 2880 | 2916 | <p> |
| 2881 | 2917 | Here is a function to parse a string into a 64-bit integer: |
| ... | ... | @@ -5733,13 +5769,13 @@ VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("alig |
| 5733 | 5769 | |
| 5734 | 5770 | ContainerMember = (ContainerField | FnDef | GlobalVarDecl) |
| 5735 | 5771 | |
| 5736 | ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression "," | |
| 5772 | ContainerField = Symbol option(":" PrefixOpExpression) option("=" PrefixOpExpression) "," | |
| 5737 | 5773 | |
| 5738 | 5774 | UseDecl = "use" Expression ";" |
| 5739 | 5775 | |
| 5740 | 5776 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" |
| 5741 | 5777 | |
| 5742 | FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var") | |
| 5778 | FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("&lt;" Expression "&gt;"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var") | |
| 5743 | 5779 | |
| 5744 | 5780 | FnDef = option("inline" | "export") FnProto Block |
| 5745 | 5781 | |
| ... | ... | @@ -5751,9 +5787,7 @@ Block = option(Symbol ":") "{" many(Statement) "}" |
| 5751 | 5787 | |
| 5752 | 5788 | Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" |
| 5753 | 5789 | |
| 5754 | TypeExpr = ErrorSetExpr | |
| 5755 | ||
| 5756 | ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression | |
| 5790 | TypeExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression | |
| 5757 | 5791 | |
| 5758 | 5792 | BlockOrExpression = Block | Expression |
| 5759 | 5793 | |
| ... | ... | @@ -5833,7 +5867,7 @@ BinaryAndExpression = BitShiftExpression "&amp;" BinaryAndExpression | BitShiftE |
| 5833 | 5867 | |
| 5834 | 5868 | BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression |
| 5835 | 5869 | |
| 5836 | BitShiftOperator = "&lt;&lt;" | "&gt;&gt;" | "&lt;&lt;" | |
| 5870 | BitShiftOperator = "&lt;&lt;" | "&gt;&gt;" | |
| 5837 | 5871 | |
| 5838 | 5872 | AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression |
| 5839 | 5873 | |
| ... | ... | @@ -5845,9 +5879,9 @@ CurlySuffixExpression = TypeExpr option(ContainerInitExpression) |
| 5845 | 5879 | |
| 5846 | 5880 | MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" |
| 5847 | 5881 | |
| 5848 | PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression | |
| 5882 | PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression | |
| 5849 | 5883 | |
| 5850 | SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 5884 | SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 5851 | 5885 | |
| 5852 | 5886 | FieldAccessExpression = "." Symbol |
| 5853 | 5887 | |
| ... | ... | @@ -5865,7 +5899,9 @@ StructLiteralField = "." Symbol "=" Expression |
| 5865 | 5899 | |
| 5866 | 5900 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" |
| 5867 | 5901 | |
| 5868 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | |
| 5902 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType | |
| 5903 | ||
| 5904 | PromiseType = "promise" option("-&gt;" TypeExpr) | |
| 5869 | 5905 | |
| 5870 | 5906 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr |
| 5871 | 5907 | |
| ... | ... | @@ -6033,4 +6069,3 @@ hljs.registerLanguage("zig", function(t) { |
| 6033 | 6069 | </script> |
| 6034 | 6070 | </body> |
| 6035 | 6071 | </html> |
| 6036 |
example/guess_number/main.zig+11-11| ... | ... | @@ -2,7 +2,6 @@ const builtin = @import("builtin"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | const io = std.io; |
| 4 | 4 | const fmt = std.fmt; |
| 5 | const Rand = std.rand.Rand; | |
| 6 | 5 | const os = std.os; |
| 7 | 6 | |
| 8 | 7 | pub fn main() !void { |
| ... | ... | @@ -10,30 +9,31 @@ pub fn main() !void { |
| 10 | 9 | var stdout_file_stream = io.FileOutStream.init(&stdout_file); |
| 11 | 10 | const stdout = &stdout_file_stream.stream; |
| 12 | 11 | |
| 13 | var stdin_file = try io.getStdIn(); | |
| 14 | ||
| 15 | 12 | try stdout.print("Welcome to the Guess Number Game in Zig.\n"); |
| 16 | 13 | |
| 17 | var seed_bytes: [@sizeOf(usize)]u8 = undefined; | |
| 14 | var seed_bytes: [@sizeOf(u64)]u8 = undefined; | |
| 18 | 15 | os.getRandomBytes(seed_bytes[0..]) catch |err| { |
| 19 | 16 | std.debug.warn("unable to seed random number generator: {}", err); |
| 20 | 17 | return err; |
| 21 | 18 | }; |
| 22 | const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big); | |
| 23 | var rand = Rand.init(seed); | |
| 19 | const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); | |
| 20 | var prng = std.rand.DefaultPrng.init(seed); | |
| 24 | 21 | |
| 25 | const answer = rand.range(u8, 0, 100) + 1; | |
| 22 | const answer = prng.random.range(u8, 0, 100) + 1; | |
| 26 | 23 | |
| 27 | 24 | while (true) { |
| 28 | 25 | try stdout.print("\nGuess a number between 1 and 100: "); |
| 29 | 26 | var line_buf : [20]u8 = undefined; |
| 30 | 27 | |
| 31 | const line_len = stdin_file.read(line_buf[0..]) catch |err| { | |
| 32 | try stdout.print("Unable to read from stdin: {}\n", @errorName(err)); | |
| 33 | return err; | |
| 28 | const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) { | |
| 29 | error.InputTooLong => { | |
| 30 | try stdout.print("Input too long.\n"); | |
| 31 | continue; | |
| 32 | }, | |
| 33 | error.EndOfFile, error.StdInUnavailable => return err, | |
| 34 | 34 | }; |
| 35 | 35 | |
| 36 | const guess = fmt.parseUnsigned(u8, line_buf[0..line_len - 1], 10) catch { | |
| 36 | const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch { | |
| 37 | 37 | try stdout.print("Invalid number.\n"); |
| 38 | 38 | continue; |
| 39 | 39 | }; |
src-self-hosted/main.zig+160| ... | ... | @@ -41,6 +41,10 @@ pub fn main() !void { |
| 41 | 41 | const args = try os.argsAlloc(allocator); |
| 42 | 42 | defer os.argsFree(allocator, args); |
| 43 | 43 | |
| 44 | if (args.len >= 2 and mem.eql(u8, args[1], "build")) { | |
| 45 | return buildMain(allocator, args[2..]); | |
| 46 | } | |
| 47 | ||
| 44 | 48 | if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) { |
| 45 | 49 | return fmtMain(allocator, args[2..]); |
| 46 | 50 | } |
| ... | ... | @@ -560,6 +564,161 @@ fn printZen() !void { |
| 560 | 564 | ); |
| 561 | 565 | } |
| 562 | 566 | |
| 567 | fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void { | |
| 568 | var build_file: [] const u8 = "build.zig"; | |
| 569 | var cache_dir: ?[] const u8 = null; | |
| 570 | var zig_install_prefix: ?[] const u8 = null; | |
| 571 | var asked_for_help = false; | |
| 572 | var asked_for_init = false; | |
| 573 | ||
| 574 | var args = ArrayList([] const u8).init(allocator); | |
| 575 | defer args.deinit(); | |
| 576 | ||
| 577 | var zig_exe_path = try os.selfExePath(allocator); | |
| 578 | defer allocator.free(zig_exe_path); | |
| 579 | ||
| 580 | try args.append(""); // Placeholder for zig-cache/build | |
| 581 | try args.append(""); // Placeholder for zig_exe_path | |
| 582 | try args.append(""); // Placeholder for build_file_dirname | |
| 583 | try args.append(""); // Placeholder for full_cache_dir | |
| 584 | ||
| 585 | var i: usize = 0; | |
| 586 | while (i < argv.len) : (i += 1) { | |
| 587 | var arg = argv[i]; | |
| 588 | if (mem.eql(u8, arg, "--help")) { | |
| 589 | asked_for_help = true; | |
| 590 | try args.append(argv[i]); | |
| 591 | } else if (mem.eql(u8, arg, "--init")) { | |
| 592 | asked_for_init = true; | |
| 593 | try args.append(argv[i]); | |
| 594 | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) { | |
| 595 | build_file = argv[i + 1]; | |
| 596 | i += 1; | |
| 597 | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) { | |
| 598 | cache_dir = argv[i + 1]; | |
| 599 | i += 1; | |
| 600 | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) { | |
| 601 | try args.append(arg); | |
| 602 | i += 1; | |
| 603 | zig_install_prefix = argv[i]; | |
| 604 | try args.append(argv[i]); | |
| 605 | } else { | |
| 606 | try args.append(arg); | |
| 607 | } | |
| 608 | } | |
| 609 | ||
| 610 | const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix); | |
| 611 | defer allocator.free(zig_lib_dir); | |
| 612 | ||
| 613 | const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std"); | |
| 614 | defer allocator.free(zig_std_dir); | |
| 615 | ||
| 616 | const special_dir = try os.path.join(allocator, zig_std_dir, "special"); | |
| 617 | defer allocator.free(special_dir); | |
| 618 | ||
| 619 | const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig"); | |
| 620 | defer allocator.free(build_runner_path); | |
| 621 | ||
| 622 | // g = codegen_create(build_runner_path, ...) | |
| 623 | // codegen_set_out_name(g, "build") | |
| 624 | ||
| 625 | const build_file_abs = try os.path.resolve(allocator, ".", build_file); | |
| 626 | defer allocator.free(build_file_abs); | |
| 627 | ||
| 628 | const build_file_basename = os.path.basename(build_file_abs); | |
| 629 | const build_file_dirname = os.path.dirname(build_file_abs); | |
| 630 | ||
| 631 | var full_cache_dir: []u8 = undefined; | |
| 632 | if (cache_dir == null) { | |
| 633 | full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache"); | |
| 634 | } else { | |
| 635 | full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir); | |
| 636 | } | |
| 637 | defer allocator.free(full_cache_dir); | |
| 638 | ||
| 639 | const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build"); | |
| 640 | defer allocator.free(path_to_build_exe); | |
| 641 | // codegen_set_cache_dir(g, full_cache_dir) | |
| 642 | ||
| 643 | args.items[0] = path_to_build_exe; | |
| 644 | args.items[1] = zig_exe_path; | |
| 645 | args.items[2] = build_file_dirname; | |
| 646 | args.items[3] = full_cache_dir; | |
| 647 | ||
| 648 | var build_file_exists: bool = undefined; | |
| 649 | if (os.File.openRead(allocator, build_file_abs)) |*file| { | |
| 650 | file.close(); | |
| 651 | build_file_exists = true; | |
| 652 | } else |_| { | |
| 653 | build_file_exists = false; | |
| 654 | } | |
| 655 | ||
| 656 | if (!build_file_exists and asked_for_help) { | |
| 657 | // TODO(bnoordhuis) Print help message from std/special/build_runner.zig | |
| 658 | return; | |
| 659 | } | |
| 660 | ||
| 661 | if (!build_file_exists and asked_for_init) { | |
| 662 | const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig"); | |
| 663 | defer allocator.free(build_template_path); | |
| 664 | ||
| 665 | var srcfile = try os.File.openRead(allocator, build_template_path); | |
| 666 | defer srcfile.close(); | |
| 667 | ||
| 668 | var dstfile = try os.File.openWrite(allocator, build_file_abs); | |
| 669 | defer dstfile.close(); | |
| 670 | ||
| 671 | while (true) { | |
| 672 | var buffer: [4096]u8 = undefined; | |
| 673 | const n = try srcfile.read(buffer[0..]); | |
| 674 | if (n == 0) break; | |
| 675 | try dstfile.write(buffer[0..n]); | |
| 676 | } | |
| 677 | ||
| 678 | return; | |
| 679 | } | |
| 680 | ||
| 681 | if (!build_file_exists) { | |
| 682 | warn( | |
| 683 | \\No 'build.zig' file found. | |
| 684 | \\Initialize a 'build.zig' template file with `zig build --init`, | |
| 685 | \\or build an executable directly with `zig build-exe $FILENAME.zig`. | |
| 686 | \\See: `zig build --help` or `zig help` for more options. | |
| 687 | \\ | |
| 688 | ); | |
| 689 | os.exit(1); | |
| 690 | } | |
| 691 | ||
| 692 | // codegen_build(g) | |
| 693 | // codegen_link(g, path_to_build_exe) | |
| 694 | // codegen_destroy(g) | |
| 695 | ||
| 696 | var proc = try os.ChildProcess.init(args.toSliceConst(), allocator); | |
| 697 | defer proc.deinit(); | |
| 698 | ||
| 699 | var term = try proc.spawnAndWait(); | |
| 700 | switch (term) { | |
| 701 | os.ChildProcess.Term.Exited => |status| { | |
| 702 | if (status != 0) { | |
| 703 | warn("{} exited with status {}\n", args.at(0), status); | |
| 704 | os.exit(1); | |
| 705 | } | |
| 706 | }, | |
| 707 | os.ChildProcess.Term.Signal => |signal| { | |
| 708 | warn("{} killed by signal {}\n", args.at(0), signal); | |
| 709 | os.exit(1); | |
| 710 | }, | |
| 711 | os.ChildProcess.Term.Stopped => |signal| { | |
| 712 | warn("{} stopped by signal {}\n", args.at(0), signal); | |
| 713 | os.exit(1); | |
| 714 | }, | |
| 715 | os.ChildProcess.Term.Unknown => |status| { | |
| 716 | warn("{} encountered unknown failure {}\n", args.at(0), status); | |
| 717 | os.exit(1); | |
| 718 | }, | |
| 719 | } | |
| 720 | } | |
| 721 | ||
| 563 | 722 | fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { |
| 564 | 723 | for (file_paths) |file_path| { |
| 565 | 724 | var file = try os.File.openRead(allocator, file_path); |
| ... | ... | @@ -582,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { |
| 582 | 741 | defer baf.destroy(); |
| 583 | 742 | |
| 584 | 743 | try parser.renderSource(baf.stream(), tree.root_node); |
| 744 | try baf.finish(); | |
| 585 | 745 | } |
| 586 | 746 | } |
| 587 | 747 |
src/all_types.hpp+71-14| ... | ... | @@ -359,7 +359,6 @@ enum NodeType { |
| 359 | 359 | NodeTypeRoot, |
| 360 | 360 | NodeTypeFnProto, |
| 361 | 361 | NodeTypeFnDef, |
| 362 | NodeTypeFnDecl, | |
| 363 | 362 | NodeTypeParamDecl, |
| 364 | 363 | NodeTypeBlock, |
| 365 | 364 | NodeTypeGroupedExpr, |
| ... | ... | @@ -409,6 +408,7 @@ enum NodeType { |
| 409 | 408 | NodeTypeResume, |
| 410 | 409 | NodeTypeAwaitExpr, |
| 411 | 410 | NodeTypeSuspend, |
| 411 | NodeTypePromiseType, | |
| 412 | 412 | }; |
| 413 | 413 | |
| 414 | 414 | struct AstNodeRoot { |
| ... | ... | @@ -452,10 +452,6 @@ struct AstNodeFnDef { |
| 452 | 452 | AstNode *body; |
| 453 | 453 | }; |
| 454 | 454 | |
| 455 | struct AstNodeFnDecl { | |
| 456 | AstNode *fn_proto; | |
| 457 | }; | |
| 458 | ||
| 459 | 455 | struct AstNodeParamDecl { |
| 460 | 456 | Buf *name; |
| 461 | 457 | AstNode *type; |
| ... | ... | @@ -712,10 +708,6 @@ struct AstNodeSwitchRange { |
| 712 | 708 | AstNode *end; |
| 713 | 709 | }; |
| 714 | 710 | |
| 715 | struct AstNodeLabel { | |
| 716 | Buf *name; | |
| 717 | }; | |
| 718 | ||
| 719 | 711 | struct AstNodeCompTime { |
| 720 | 712 | AstNode *expr; |
| 721 | 713 | }; |
| ... | ... | @@ -879,6 +871,10 @@ struct AstNodeSuspend { |
| 879 | 871 | AstNode *promise_symbol; |
| 880 | 872 | }; |
| 881 | 873 | |
| 874 | struct AstNodePromiseType { | |
| 875 | AstNode *payload_type; // can be NULL | |
| 876 | }; | |
| 877 | ||
| 882 | 878 | struct AstNode { |
| 883 | 879 | enum NodeType type; |
| 884 | 880 | size_t line; |
| ... | ... | @@ -887,7 +883,6 @@ struct AstNode { |
| 887 | 883 | union { |
| 888 | 884 | AstNodeRoot root; |
| 889 | 885 | AstNodeFnDef fn_def; |
| 890 | AstNodeFnDecl fn_decl; | |
| 891 | 886 | AstNodeFnProto fn_proto; |
| 892 | 887 | AstNodeParamDecl param_decl; |
| 893 | 888 | AstNodeBlock block; |
| ... | ... | @@ -912,7 +907,6 @@ struct AstNode { |
| 912 | 907 | AstNodeSwitchExpr switch_expr; |
| 913 | 908 | AstNodeSwitchProng switch_prong; |
| 914 | 909 | AstNodeSwitchRange switch_range; |
| 915 | AstNodeLabel label; | |
| 916 | 910 | AstNodeCompTime comptime_expr; |
| 917 | 911 | AstNodeAsmExpr asm_expr; |
| 918 | 912 | AstNodeFieldAccessExpr field_access_expr; |
| ... | ... | @@ -939,6 +933,7 @@ struct AstNode { |
| 939 | 933 | AstNodeResumeExpr resume_expr; |
| 940 | 934 | AstNodeAwaitExpr await_expr; |
| 941 | 935 | AstNodeSuspend suspend; |
| 936 | AstNodePromiseType promise_type; | |
| 942 | 937 | } data; |
| 943 | 938 | }; |
| 944 | 939 | |
| ... | ... | @@ -1251,7 +1246,10 @@ struct FnTableEntry { |
| 1251 | 1246 | ScopeBlock *def_scope; // parent is child_scope |
| 1252 | 1247 | Buf symbol_name; |
| 1253 | 1248 | TypeTableEntry *type_entry; // function type |
| 1254 | TypeTableEntry *implicit_return_type; | |
| 1249 | // in the case of normal functions this is the implicit return type | |
| 1250 | // in the case of async functions this is the implicit return type according to the | |
| 1251 | // zig source code, not according to zig ir | |
| 1252 | TypeTableEntry *src_implicit_return_type; | |
| 1255 | 1253 | bool is_test; |
| 1256 | 1254 | FnInline fn_inline; |
| 1257 | 1255 | FnAnalState anal_state; |
| ... | ... | @@ -1612,7 +1610,8 @@ struct CodeGen { |
| 1612 | 1610 | FnTableEntry *panic_fn; |
| 1613 | 1611 | LLVMValueRef cur_ret_ptr; |
| 1614 | 1612 | LLVMValueRef cur_fn_val; |
| 1615 | LLVMValueRef cur_err_ret_trace_val; | |
| 1613 | LLVMValueRef cur_err_ret_trace_val_arg; | |
| 1614 | LLVMValueRef cur_err_ret_trace_val_stack; | |
| 1616 | 1615 | bool c_want_stdint; |
| 1617 | 1616 | bool c_want_stdbool; |
| 1618 | 1617 | AstNode *root_export_decl; |
| ... | ... | @@ -1646,6 +1645,8 @@ struct CodeGen { |
| 1646 | 1645 | LLVMValueRef coro_save_fn_val; |
| 1647 | 1646 | LLVMValueRef coro_promise_fn_val; |
| 1648 | 1647 | LLVMValueRef coro_alloc_helper_fn_val; |
| 1648 | LLVMValueRef merge_err_ret_traces_fn_val; | |
| 1649 | LLVMValueRef add_error_return_trace_addr_fn_val; | |
| 1649 | 1650 | bool error_during_imports; |
| 1650 | 1651 | |
| 1651 | 1652 | const char **clang_argv; |
| ... | ... | @@ -1751,6 +1752,7 @@ enum ScopeId { |
| 1751 | 1752 | ScopeIdLoop, |
| 1752 | 1753 | ScopeIdFnDef, |
| 1753 | 1754 | ScopeIdCompTime, |
| 1755 | ScopeIdCoroPrelude, | |
| 1754 | 1756 | }; |
| 1755 | 1757 | |
| 1756 | 1758 | struct Scope { |
| ... | ... | @@ -1858,6 +1860,12 @@ struct ScopeFnDef { |
| 1858 | 1860 | FnTableEntry *fn_entry; |
| 1859 | 1861 | }; |
| 1860 | 1862 | |
| 1863 | // This scope is created to indicate that the code in the scope | |
| 1864 | // is auto-generated coroutine prelude stuff. | |
| 1865 | struct ScopeCoroPrelude { | |
| 1866 | Scope base; | |
| 1867 | }; | |
| 1868 | ||
| 1861 | 1869 | // synchronized with code in define_builtin_compile_vars |
| 1862 | 1870 | enum AtomicOrder { |
| 1863 | 1871 | AtomicOrderUnordered, |
| ... | ... | @@ -1944,6 +1952,7 @@ enum IrInstructionId { |
| 1944 | 1952 | IrInstructionIdSetRuntimeSafety, |
| 1945 | 1953 | IrInstructionIdSetFloatMode, |
| 1946 | 1954 | IrInstructionIdArrayType, |
| 1955 | IrInstructionIdPromiseType, | |
| 1947 | 1956 | IrInstructionIdSliceType, |
| 1948 | 1957 | IrInstructionIdAsm, |
| 1949 | 1958 | IrInstructionIdSizeOf, |
| ... | ... | @@ -2034,6 +2043,10 @@ enum IrInstructionId { |
| 2034 | 2043 | IrInstructionIdAtomicRmw, |
| 2035 | 2044 | IrInstructionIdPromiseResultType, |
| 2036 | 2045 | IrInstructionIdAwaitBookkeeping, |
| 2046 | IrInstructionIdSaveErrRetAddr, | |
| 2047 | IrInstructionIdAddImplicitReturnType, | |
| 2048 | IrInstructionIdMergeErrRetTraces, | |
| 2049 | IrInstructionIdMarkErrRetTracePtr, | |
| 2037 | 2050 | }; |
| 2038 | 2051 | |
| 2039 | 2052 | struct IrInstruction { |
| ... | ... | @@ -2360,6 +2373,12 @@ struct IrInstructionArrayType { |
| 2360 | 2373 | IrInstruction *child_type; |
| 2361 | 2374 | }; |
| 2362 | 2375 | |
| 2376 | struct IrInstructionPromiseType { | |
| 2377 | IrInstruction base; | |
| 2378 | ||
| 2379 | IrInstruction *payload_type; | |
| 2380 | }; | |
| 2381 | ||
| 2363 | 2382 | struct IrInstructionSliceType { |
| 2364 | 2383 | IrInstruction base; |
| 2365 | 2384 | |
| ... | ... | @@ -2673,6 +2692,7 @@ struct IrInstructionFnProto { |
| 2673 | 2692 | IrInstruction **param_types; |
| 2674 | 2693 | IrInstruction *align_value; |
| 2675 | 2694 | IrInstruction *return_type; |
| 2695 | IrInstruction *async_allocator_type_value; | |
| 2676 | 2696 | bool is_var_args; |
| 2677 | 2697 | }; |
| 2678 | 2698 | |
| ... | ... | @@ -2865,6 +2885,11 @@ struct IrInstructionExport { |
| 2865 | 2885 | |
| 2866 | 2886 | struct IrInstructionErrorReturnTrace { |
| 2867 | 2887 | IrInstruction base; |
| 2888 | ||
| 2889 | enum Nullable { | |
| 2890 | Null, | |
| 2891 | NonNull, | |
| 2892 | } nullable; | |
| 2868 | 2893 | }; |
| 2869 | 2894 | |
| 2870 | 2895 | struct IrInstructionErrorUnion { |
| ... | ... | @@ -2987,6 +3012,30 @@ struct IrInstructionAwaitBookkeeping { |
| 2987 | 3012 | IrInstruction *promise_result_type; |
| 2988 | 3013 | }; |
| 2989 | 3014 | |
| 3015 | struct IrInstructionSaveErrRetAddr { | |
| 3016 | IrInstruction base; | |
| 3017 | }; | |
| 3018 | ||
| 3019 | struct IrInstructionAddImplicitReturnType { | |
| 3020 | IrInstruction base; | |
| 3021 | ||
| 3022 | IrInstruction *value; | |
| 3023 | }; | |
| 3024 | ||
| 3025 | struct IrInstructionMergeErrRetTraces { | |
| 3026 | IrInstruction base; | |
| 3027 | ||
| 3028 | IrInstruction *coro_promise_ptr; | |
| 3029 | IrInstruction *src_err_ret_trace_ptr; | |
| 3030 | IrInstruction *dest_err_ret_trace_ptr; | |
| 3031 | }; | |
| 3032 | ||
| 3033 | struct IrInstructionMarkErrRetTracePtr { | |
| 3034 | IrInstruction base; | |
| 3035 | ||
| 3036 | IrInstruction *err_ret_trace_ptr; | |
| 3037 | }; | |
| 3038 | ||
| 2990 | 3039 | static const size_t slice_ptr_index = 0; |
| 2991 | 3040 | static const size_t slice_len_index = 1; |
| 2992 | 3041 | |
| ... | ... | @@ -2996,10 +3045,18 @@ static const size_t maybe_null_index = 1; |
| 2996 | 3045 | static const size_t err_union_err_index = 0; |
| 2997 | 3046 | static const size_t err_union_payload_index = 1; |
| 2998 | 3047 | |
| 3048 | // TODO call graph analysis to find out what this number needs to be for every function | |
| 3049 | static const size_t stack_trace_ptr_count = 30; | |
| 3050 | ||
| 3051 | // these belong to the async function | |
| 3052 | #define RETURN_ADDRESSES_FIELD_NAME "return_addresses" | |
| 3053 | #define ERR_RET_TRACE_FIELD_NAME "err_ret_trace" | |
| 3054 | #define RESULT_FIELD_NAME "result" | |
| 2999 | 3055 | #define ASYNC_ALLOC_FIELD_NAME "allocFn" |
| 3000 | 3056 | #define ASYNC_FREE_FIELD_NAME "freeFn" |
| 3001 | 3057 | #define AWAITER_HANDLE_FIELD_NAME "awaiter_handle" |
| 3002 | #define RESULT_FIELD_NAME "result" | |
| 3058 | // these point to data belonging to the awaiter | |
| 3059 | #define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr" | |
| 3003 | 3060 | #define RESULT_PTR_FIELD_NAME "result_ptr" |
| 3004 | 3061 | |
| 3005 | 3062 |
src/analyze.cpp+148-21| ... | ... | @@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) { |
| 170 | 170 | return &scope->base; |
| 171 | 171 | } |
| 172 | 172 | |
| 173 | Scope *create_coro_prelude_scope(AstNode *node, Scope *parent) { | |
| 174 | ScopeCoroPrelude *scope = allocate<ScopeCoroPrelude>(1); | |
| 175 | init_scope(&scope->base, ScopeIdCoroPrelude, node, parent); | |
| 176 | return &scope->base; | |
| 177 | } | |
| 178 | ||
| 173 | 179 | ImportTableEntry *get_scope_import(Scope *scope) { |
| 174 | 180 | while (scope) { |
| 175 | 181 | if (scope->id == ScopeIdDecls) { |
| ... | ... | @@ -462,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) |
| 462 | 468 | |
| 463 | 469 | TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise); |
| 464 | 470 | TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false); |
| 465 | const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME}; | |
| 466 | TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type}; | |
| 471 | ||
| 472 | ZigList<const char *> field_names = {}; | |
| 473 | field_names.append(AWAITER_HANDLE_FIELD_NAME); | |
| 474 | field_names.append(RESULT_FIELD_NAME); | |
| 475 | field_names.append(RESULT_PTR_FIELD_NAME); | |
| 476 | if (g->have_err_ret_tracing) { | |
| 477 | field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME); | |
| 478 | field_names.append(ERR_RET_TRACE_FIELD_NAME); | |
| 479 | field_names.append(RETURN_ADDRESSES_FIELD_NAME); | |
| 480 | } | |
| 481 | ||
| 482 | ZigList<TypeTableEntry *> field_types = {}; | |
| 483 | field_types.append(awaiter_handle_type); | |
| 484 | field_types.append(return_type); | |
| 485 | field_types.append(result_ptr_type); | |
| 486 | if (g->have_err_ret_tracing) { | |
| 487 | field_types.append(get_ptr_to_stack_trace_type(g)); | |
| 488 | field_types.append(g->stack_trace_type); | |
| 489 | field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count)); | |
| 490 | } | |
| 491 | ||
| 492 | assert(field_names.length == field_types.length); | |
| 467 | 493 | Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name)); |
| 468 | TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3); | |
| 494 | TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length); | |
| 469 | 495 | |
| 470 | 496 | return_type->promise_frame_parent = entry; |
| 471 | 497 | return entry; |
| ... | ... | @@ -985,7 +1011,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 985 | 1011 | // populate the name of the type |
| 986 | 1012 | buf_resize(&fn_type->name, 0); |
| 987 | 1013 | if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) { |
| 988 | buf_appendf(&fn_type->name, "async(%s) ", buf_ptr(&fn_type_id->async_allocator_type->name)); | |
| 1014 | assert(fn_type_id->async_allocator_type != nullptr); | |
| 1015 | buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name)); | |
| 989 | 1016 | } else { |
| 990 | 1017 | const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc); |
| 991 | 1018 | buf_appendf(&fn_type->name, "%s", cc_str); |
| ... | ... | @@ -3209,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3209 | 3236 | break; |
| 3210 | 3237 | case NodeTypeContainerDecl: |
| 3211 | 3238 | case NodeTypeParamDecl: |
| 3212 | case NodeTypeFnDecl: | |
| 3213 | 3239 | case NodeTypeReturnExpr: |
| 3214 | 3240 | case NodeTypeDefer: |
| 3215 | 3241 | case NodeTypeBlock: |
| ... | ... | @@ -3253,6 +3279,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3253 | 3279 | case NodeTypeResume: |
| 3254 | 3280 | case NodeTypeAwaitExpr: |
| 3255 | 3281 | case NodeTypeSuspend: |
| 3282 | case NodeTypePromiseType: | |
| 3256 | 3283 | zig_unreachable(); |
| 3257 | 3284 | } |
| 3258 | 3285 | } |
| ... | ... | @@ -3590,6 +3617,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { |
| 3590 | 3617 | case ScopeIdCImport: |
| 3591 | 3618 | case ScopeIdLoop: |
| 3592 | 3619 | case ScopeIdCompTime: |
| 3620 | case ScopeIdCoroPrelude: | |
| 3593 | 3621 | scope = scope->parent; |
| 3594 | 3622 | continue; |
| 3595 | 3623 | case ScopeIdFnDef: |
| ... | ... | @@ -3864,7 +3892,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3864 | 3892 | |
| 3865 | 3893 | TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, |
| 3866 | 3894 | &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3867 | fn_table_entry->implicit_return_type = block_return_type; | |
| 3895 | fn_table_entry->src_implicit_return_type = block_return_type; | |
| 3868 | 3896 | |
| 3869 | 3897 | if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) { |
| 3870 | 3898 | assert(g->errors.length > 0); |
| ... | ... | @@ -3876,10 +3904,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3876 | 3904 | TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; |
| 3877 | 3905 | if (return_err_set_type->data.error_set.infer_fn != nullptr) { |
| 3878 | 3906 | TypeTableEntry *inferred_err_set_type; |
| 3879 | if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) { | |
| 3880 | inferred_err_set_type = fn_table_entry->implicit_return_type; | |
| 3881 | } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3882 | inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type; | |
| 3907 | if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) { | |
| 3908 | inferred_err_set_type = fn_table_entry->src_implicit_return_type; | |
| 3909 | } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3910 | inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type; | |
| 3883 | 3911 | } else { |
| 3884 | 3912 | add_node_error(g, return_type_node, |
| 3885 | 3913 | buf_sprintf("function with inferred error set must return at least one possible error")); |
| ... | ... | @@ -4276,26 +4304,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) { |
| 4276 | 4304 | return g->win_sdk; |
| 4277 | 4305 | } |
| 4278 | 4306 | |
| 4307 | ||
| 4308 | Buf *get_linux_libc_lib_path(const char *o_file) { | |
| 4309 | const char *cc_exe = getenv("CC"); | |
| 4310 | cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; | |
| 4311 | ZigList<const char *> args = {}; | |
| 4312 | args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file))); | |
| 4313 | Termination term; | |
| 4314 | Buf *out_stderr = buf_alloc(); | |
| 4315 | Buf *out_stdout = buf_alloc(); | |
| 4316 | int err; | |
| 4317 | if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { | |
| 4318 | zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err)); | |
| 4319 | } | |
| 4320 | if (term.how != TerminationIdClean || term.code != 0) { | |
| 4321 | zig_panic("unable to determine libc lib path: executing C compiler command failed"); | |
| 4322 | } | |
| 4323 | if (buf_ends_with_str(out_stdout, "\n")) { | |
| 4324 | buf_resize(out_stdout, buf_len(out_stdout) - 1); | |
| 4325 | } | |
| 4326 | if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) { | |
| 4327 | zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file); | |
| 4328 | } | |
| 4329 | Buf *result = buf_alloc(); | |
| 4330 | os_path_dirname(out_stdout, result); | |
| 4331 | return result; | |
| 4332 | } | |
| 4333 | ||
| 4334 | Buf *get_linux_libc_include_path(void) { | |
| 4335 | const char *cc_exe = getenv("CC"); | |
| 4336 | cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; | |
| 4337 | ZigList<const char *> args = {}; | |
| 4338 | args.append("-E"); | |
| 4339 | args.append("-Wp,-v"); | |
| 4340 | args.append("-xc"); | |
| 4341 | args.append("/dev/null"); | |
| 4342 | Termination term; | |
| 4343 | Buf *out_stderr = buf_alloc(); | |
| 4344 | Buf *out_stdout = buf_alloc(); | |
| 4345 | int err; | |
| 4346 | if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { | |
| 4347 | zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err)); | |
| 4348 | } | |
| 4349 | if (term.how != TerminationIdClean || term.code != 0) { | |
| 4350 | zig_panic("unable to determine libc include path: executing C compiler command failed"); | |
| 4351 | } | |
| 4352 | char *prev_newline = buf_ptr(out_stderr); | |
| 4353 | ZigList<const char *> search_paths = {}; | |
| 4354 | bool found_search_paths = false; | |
| 4355 | for (;;) { | |
| 4356 | char *newline = strchr(prev_newline, '\n'); | |
| 4357 | if (newline == nullptr) { | |
| 4358 | zig_panic("unable to determine libc include path: bad output from C compiler command"); | |
| 4359 | } | |
| 4360 | *newline = 0; | |
| 4361 | if (found_search_paths) { | |
| 4362 | if (strcmp(prev_newline, "End of search list.") == 0) { | |
| 4363 | break; | |
| 4364 | } | |
| 4365 | search_paths.append(prev_newline); | |
| 4366 | } else { | |
| 4367 | if (strcmp(prev_newline, "#include <...> search starts here:") == 0) { | |
| 4368 | found_search_paths = true; | |
| 4369 | } | |
| 4370 | } | |
| 4371 | prev_newline = newline + 1; | |
| 4372 | } | |
| 4373 | if (search_paths.length == 0) { | |
| 4374 | zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are"); | |
| 4375 | } | |
| 4376 | for (size_t i = 0; i < search_paths.length; i += 1) { | |
| 4377 | // search in reverse order | |
| 4378 | const char *search_path = search_paths.items[search_paths.length - i - 1]; | |
| 4379 | // cut off spaces | |
| 4380 | while (*search_path == ' ') { | |
| 4381 | search_path += 1; | |
| 4382 | } | |
| 4383 | Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path); | |
| 4384 | bool exists; | |
| 4385 | if ((err = os_file_exists(stdlib_path, &exists))) { | |
| 4386 | exists = false; | |
| 4387 | } | |
| 4388 | if (exists) { | |
| 4389 | return buf_create_from_str(search_path); | |
| 4390 | } | |
| 4391 | } | |
| 4392 | zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths"); | |
| 4393 | } | |
| 4394 | ||
| 4279 | 4395 | void find_libc_include_path(CodeGen *g) { |
| 4280 | if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) { | |
| 4281 | ZigWindowsSDK *sdk = get_windows_sdk(g); | |
| 4396 | if (g->libc_include_dir == nullptr) { | |
| 4282 | 4397 | |
| 4283 | 4398 | if (g->zig_target.os == OsWindows) { |
| 4399 | ZigWindowsSDK *sdk = get_windows_sdk(g); | |
| 4400 | g->libc_include_dir = buf_alloc(); | |
| 4284 | 4401 | if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) { |
| 4285 | 4402 | zig_panic("Unable to determine libc include path."); |
| 4286 | 4403 | } |
| 4404 | } else if (g->zig_target.os == OsLinux) { | |
| 4405 | g->libc_include_dir = get_linux_libc_include_path(); | |
| 4406 | } else if (g->zig_target.os == OsMacOSX) { | |
| 4407 | g->libc_include_dir = buf_create_from_str("/usr/include"); | |
| 4408 | } else { | |
| 4409 | // TODO find libc at runtime for other operating systems | |
| 4410 | zig_panic("Unable to determine libc include path."); | |
| 4287 | 4411 | } |
| 4288 | 4412 | } |
| 4289 | ||
| 4290 | // TODO find libc at runtime for other operating systems | |
| 4291 | if(!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) { | |
| 4292 | zig_panic("Unable to determine libc include path."); | |
| 4293 | } | |
| 4413 | assert(buf_len(g->libc_include_dir) != 0); | |
| 4294 | 4414 | } |
| 4295 | 4415 | |
| 4296 | 4416 | void find_libc_lib_path(CodeGen *g) { |
| 4297 | 4417 | // later we can handle this better by reporting an error via the normal mechanism |
| 4298 | if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0 || | |
| 4418 | if (g->libc_lib_dir == nullptr || | |
| 4299 | 4419 | (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr))) |
| 4300 | 4420 | { |
| 4301 | 4421 | if (g->zig_target.os == OsWindows) { |
| ... | ... | @@ -4319,18 +4439,25 @@ void find_libc_lib_path(CodeGen *g) { |
| 4319 | 4439 | g->msvc_lib_dir = vc_lib_dir; |
| 4320 | 4440 | g->libc_lib_dir = ucrt_lib_path; |
| 4321 | 4441 | g->kernel32_lib_dir = kern_lib_path; |
| 4442 | } else if (g->zig_target.os == OsLinux) { | |
| 4443 | g->libc_lib_dir = get_linux_libc_lib_path("crt1.o"); | |
| 4322 | 4444 | } else { |
| 4323 | 4445 | zig_panic("Unable to determine libc lib path."); |
| 4324 | 4446 | } |
| 4447 | } else { | |
| 4448 | assert(buf_len(g->libc_lib_dir) != 0); | |
| 4325 | 4449 | } |
| 4326 | 4450 | |
| 4327 | if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) { | |
| 4451 | if (g->libc_static_lib_dir == nullptr) { | |
| 4328 | 4452 | if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) { |
| 4329 | 4453 | return; |
| 4330 | } | |
| 4331 | else { | |
| 4454 | } else if (g->zig_target.os == OsLinux) { | |
| 4455 | g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o"); | |
| 4456 | } else { | |
| 4332 | 4457 | zig_panic("Unable to determine libc static lib path."); |
| 4333 | 4458 | } |
| 4459 | } else { | |
| 4460 | assert(buf_len(g->libc_static_lib_dir) != 0); | |
| 4334 | 4461 | } |
| 4335 | 4462 | } |
| 4336 | 4463 |
src/analyze.hpp+1| ... | ... | @@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent); |
| 107 | 107 | ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); |
| 108 | 108 | ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); |
| 109 | 109 | Scope *create_comptime_scope(AstNode *node, Scope *parent); |
| 110 | Scope *create_coro_prelude_scope(AstNode *node, Scope *parent); | |
| 110 | 111 | |
| 111 | 112 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 112 | 113 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
src/ast_render.cpp+21-4| ... | ... | @@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) { |
| 148 | 148 | return "Root"; |
| 149 | 149 | case NodeTypeFnDef: |
| 150 | 150 | return "FnDef"; |
| 151 | case NodeTypeFnDecl: | |
| 152 | return "FnDecl"; | |
| 153 | 151 | case NodeTypeFnProto: |
| 154 | 152 | return "FnProto"; |
| 155 | 153 | case NodeTypeParamDecl: |
| ... | ... | @@ -250,6 +248,8 @@ static const char *node_type_str(NodeType node_type) { |
| 250 | 248 | return "AwaitExpr"; |
| 251 | 249 | case NodeTypeSuspend: |
| 252 | 250 | return "Suspend"; |
| 251 | case NodeTypePromiseType: | |
| 252 | return "PromiseType"; | |
| 253 | 253 | } |
| 254 | 254 | zig_unreachable(); |
| 255 | 255 | } |
| ... | ... | @@ -658,6 +658,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 658 | 658 | if (node->data.fn_call_expr.is_builtin) { |
| 659 | 659 | fprintf(ar->f, "@"); |
| 660 | 660 | } |
| 661 | if (node->data.fn_call_expr.is_async) { | |
| 662 | fprintf(ar->f, "async"); | |
| 663 | if (node->data.fn_call_expr.async_allocator != nullptr) { | |
| 664 | fprintf(ar->f, "<"); | |
| 665 | render_node_extra(ar, node->data.fn_call_expr.async_allocator, true); | |
| 666 | fprintf(ar->f, ">"); | |
| 667 | } | |
| 668 | fprintf(ar->f, " "); | |
| 669 | } | |
| 661 | 670 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 662 | 671 | bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); |
| 663 | 672 | render_node_extra(ar, fn_ref_node, grouped); |
| ... | ... | @@ -772,6 +781,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 772 | 781 | render_node_ungrouped(ar, node->data.array_type.child_type); |
| 773 | 782 | break; |
| 774 | 783 | } |
| 784 | case NodeTypePromiseType: | |
| 785 | { | |
| 786 | fprintf(ar->f, "promise"); | |
| 787 | if (node->data.promise_type.payload_type != nullptr) { | |
| 788 | fprintf(ar->f, "->"); | |
| 789 | render_node_grouped(ar, node->data.promise_type.payload_type); | |
| 790 | } | |
| 791 | break; | |
| 792 | } | |
| 775 | 793 | case NodeTypeErrorType: |
| 776 | 794 | fprintf(ar->f, "error"); |
| 777 | 795 | break; |
| ... | ... | @@ -1023,7 +1041,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1023 | 1041 | case NodeTypeUnwrapErrorExpr: |
| 1024 | 1042 | { |
| 1025 | 1043 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); |
| 1026 | fprintf(ar->f, " %%%% "); | |
| 1044 | fprintf(ar->f, " catch "); | |
| 1027 | 1045 | if (node->data.unwrap_err_expr.symbol) { |
| 1028 | 1046 | Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol; |
| 1029 | 1047 | fprintf(ar->f, "|%s| ", buf_ptr(var_name)); |
| ... | ... | @@ -1078,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1078 | 1096 | } |
| 1079 | 1097 | break; |
| 1080 | 1098 | } |
| 1081 | case NodeTypeFnDecl: | |
| 1082 | 1099 | case NodeTypeParamDecl: |
| 1083 | 1100 | case NodeTypeTestDecl: |
| 1084 | 1101 | case NodeTypeStructField: |
src/codegen.cpp+328-96| ... | ... | @@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 112 | 112 | // that's for native compilation |
| 113 | 113 | g->zig_target = *target; |
| 114 | 114 | resolve_target_object_format(&g->zig_target); |
| 115 | g->dynamic_linker = buf_create_from_str(""); | |
| 116 | g->libc_lib_dir = buf_create_from_str(""); | |
| 117 | g->libc_static_lib_dir = buf_create_from_str(""); | |
| 118 | g->libc_include_dir = buf_create_from_str(""); | |
| 115 | g->dynamic_linker = nullptr; | |
| 116 | g->libc_lib_dir = nullptr; | |
| 117 | g->libc_static_lib_dir = nullptr; | |
| 118 | g->libc_include_dir = nullptr; | |
| 119 | 119 | g->msvc_lib_dir = nullptr; |
| 120 | 120 | g->kernel32_lib_dir = nullptr; |
| 121 | 121 | g->each_lib_rpath = false; |
| ... | ... | @@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 123 | 123 | // native compilation, we can rely on the configuration stuff |
| 124 | 124 | g->is_native_target = true; |
| 125 | 125 | get_native_target(&g->zig_target); |
| 126 | g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER); | |
| 127 | g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR); | |
| 128 | g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR); | |
| 129 | g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR); | |
| 126 | g->dynamic_linker = nullptr; // find it at runtime | |
| 127 | g->libc_lib_dir = nullptr; // find it at runtime | |
| 128 | g->libc_static_lib_dir = nullptr; // find it at runtime | |
| 129 | g->libc_include_dir = nullptr; // find it at runtime | |
| 130 | 130 | g->msvc_lib_dir = nullptr; // find it at runtime |
| 131 | 131 | g->kernel32_lib_dir = nullptr; // find it at runtime |
| 132 | ||
| 133 | #ifdef ZIG_EACH_LIB_RPATH | |
| 134 | 132 | g->each_lib_rpath = true; |
| 135 | #endif | |
| 136 | 133 | |
| 137 | 134 | if (g->zig_target.os == OsMacOSX || |
| 138 | 135 | g->zig_target.os == OsIOS) |
| ... | ... | @@ -411,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e |
| 411 | 408 | if (!g->have_err_ret_tracing) { |
| 412 | 409 | return UINT32_MAX; |
| 413 | 410 | } |
| 411 | if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { | |
| 412 | return 0; | |
| 413 | } | |
| 414 | 414 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 415 | 415 | if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) { |
| 416 | 416 | return UINT32_MAX; |
| ... | ... | @@ -653,6 +653,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 653 | 653 | case ScopeIdDeferExpr: |
| 654 | 654 | case ScopeIdLoop: |
| 655 | 655 | case ScopeIdCompTime: |
| 656 | case ScopeIdCoroPrelude: | |
| 656 | 657 | return get_di_scope(g, scope->parent); |
| 657 | 658 | } |
| 658 | 659 | zig_unreachable(); |
| ... | ... | @@ -1116,22 +1117,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) { |
| 1116 | 1117 | return g->return_address_fn_val; |
| 1117 | 1118 | } |
| 1118 | 1119 | |
| 1119 | static LLVMValueRef get_return_err_fn(CodeGen *g) { | |
| 1120 | if (g->return_err_fn != nullptr) | |
| 1121 | return g->return_err_fn; | |
| 1122 | ||
| 1123 | assert(g->err_tag_type != nullptr); | |
| 1120 | static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { | |
| 1121 | if (g->add_error_return_trace_addr_fn_val != nullptr) | |
| 1122 | return g->add_error_return_trace_addr_fn_val; | |
| 1124 | 1123 | |
| 1125 | 1124 | LLVMTypeRef arg_types[] = { |
| 1126 | // error return trace pointer | |
| 1127 | 1125 | get_ptr_to_stack_trace_type(g)->type_ref, |
| 1126 | g->builtin_types.entry_usize->type_ref, | |
| 1128 | 1127 | }; |
| 1129 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); | |
| 1128 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); | |
| 1130 | 1129 | |
| 1131 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); | |
| 1130 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false); | |
| 1132 | 1131 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 1133 | addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address | |
| 1134 | addLLVMFnAttr(fn_val, "cold"); | |
| 1132 | addLLVMFnAttr(fn_val, "alwaysinline"); | |
| 1135 | 1133 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 1136 | 1134 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); |
| 1137 | 1135 | addLLVMFnAttr(fn_val, "nounwind"); |
| ... | ... | @@ -1153,6 +1151,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1153 | 1151 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address; |
| 1154 | 1152 | |
| 1155 | 1153 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); |
| 1154 | LLVMValueRef address_value = LLVMGetParam(fn_val, 1); | |
| 1155 | ||
| 1156 | 1156 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| 1157 | 1157 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, ""); |
| 1158 | 1158 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| ... | ... | @@ -1174,15 +1174,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1174 | 1174 | LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, ""); |
| 1175 | 1175 | LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, ""); |
| 1176 | 1176 | |
| 1177 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | |
| 1178 | LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, ""); | |
| 1179 | LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); | |
| 1180 | ||
| 1181 | LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, ""); | |
| 1182 | 1177 | gen_store_untyped(g, address_value, address_slot, 0, false); |
| 1183 | 1178 | |
| 1184 | 1179 | // stack_trace.index += 1; |
| 1185 | LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); | |
| 1180 | LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); | |
| 1186 | 1181 | gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); |
| 1187 | 1182 | |
| 1188 | 1183 | // return; |
| ... | ... | @@ -1191,6 +1186,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1191 | 1186 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 1192 | 1187 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| 1193 | 1188 | |
| 1189 | g->add_error_return_trace_addr_fn_val = fn_val; | |
| 1190 | return fn_val; | |
| 1191 | } | |
| 1192 | ||
| 1193 | static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { | |
| 1194 | if (g->merge_err_ret_traces_fn_val) | |
| 1195 | return g->merge_err_ret_traces_fn_val; | |
| 1196 | ||
| 1197 | assert(g->stack_trace_type != nullptr); | |
| 1198 | ||
| 1199 | LLVMTypeRef param_types[] = { | |
| 1200 | get_ptr_to_stack_trace_type(g)->type_ref, | |
| 1201 | get_ptr_to_stack_trace_type(g)->type_ref, | |
| 1202 | }; | |
| 1203 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); | |
| 1204 | ||
| 1205 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false); | |
| 1206 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); | |
| 1207 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); | |
| 1208 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | |
| 1209 | addLLVMFnAttr(fn_val, "nounwind"); | |
| 1210 | add_uwtable_attr(g, fn_val); | |
| 1211 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); | |
| 1212 | addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); | |
| 1213 | addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); | |
| 1214 | addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); | |
| 1215 | addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); | |
| 1216 | addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); | |
| 1217 | if (g->build_mode == BuildModeDebug) { | |
| 1218 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); | |
| 1219 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); | |
| 1220 | } | |
| 1221 | ||
| 1222 | // this is above the ZigLLVMClearCurrentDebugLocation | |
| 1223 | LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); | |
| 1224 | ||
| 1225 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); | |
| 1226 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); | |
| 1227 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); | |
| 1228 | LLVMPositionBuilderAtEnd(g->builder, entry_block); | |
| 1229 | ZigLLVMClearCurrentDebugLocation(g->builder); | |
| 1230 | ||
| 1231 | // var frame_index: usize = undefined; | |
| 1232 | // var frames_left: usize = undefined; | |
| 1233 | // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) { | |
| 1234 | // frame_index = 0; | |
| 1235 | // frames_left = src_stack_trace.index; | |
| 1236 | // if (frames_left == 0) return; | |
| 1237 | // } else { | |
| 1238 | // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len; | |
| 1239 | // frames_left = src_stack_trace.instruction_addresses.len; | |
| 1240 | // } | |
| 1241 | // while (true) { | |
| 1242 | // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]); | |
| 1243 | // frames_left -= 1; | |
| 1244 | // if (frames_left == 0) return; | |
| 1245 | // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len; | |
| 1246 | // } | |
| 1247 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); | |
| 1248 | ||
| 1249 | LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index"); | |
| 1250 | LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left"); | |
| 1251 | ||
| 1252 | LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0); | |
| 1253 | LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1); | |
| 1254 | ||
| 1255 | size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | |
| 1256 | size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | |
| 1257 | LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, | |
| 1258 | (unsigned)src_index_field_index, ""); | |
| 1259 | LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, | |
| 1260 | (unsigned)src_addresses_field_index, ""); | |
| 1261 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | |
| 1262 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 1263 | LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, ""); | |
| 1264 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 1265 | LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, ""); | |
| 1266 | LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, ""); | |
| 1267 | LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, ""); | |
| 1268 | LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, ""); | |
| 1269 | LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, ""); | |
| 1270 | LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap"); | |
| 1271 | LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap"); | |
| 1272 | LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop"); | |
| 1273 | LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block); | |
| 1274 | ||
| 1275 | LLVMPositionBuilderAtEnd(g->builder, no_wrap_block); | |
| 1276 | LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref); | |
| 1277 | LLVMBuildStore(g->builder, usize_zero, frame_index_ptr); | |
| 1278 | LLVMBuildStore(g->builder, src_index_val, frames_left_ptr); | |
| 1279 | LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, ""); | |
| 1280 | LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block); | |
| 1281 | ||
| 1282 | LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block); | |
| 1283 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false); | |
| 1284 | LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, ""); | |
| 1285 | LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, ""); | |
| 1286 | LLVMBuildStore(g->builder, mod_len, frame_index_ptr); | |
| 1287 | LLVMBuildStore(g->builder, src_len_val, frames_left_ptr); | |
| 1288 | LLVMBuildBr(g->builder, loop_block); | |
| 1289 | ||
| 1290 | LLVMPositionBuilderAtEnd(g->builder, loop_block); | |
| 1291 | LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, ""); | |
| 1292 | LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, ""); | |
| 1293 | LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, ""); | |
| 1294 | LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val}; | |
| 1295 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); | |
| 1296 | LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, ""); | |
| 1297 | LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, ""); | |
| 1298 | LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, ""); | |
| 1299 | LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue"); | |
| 1300 | LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block); | |
| 1301 | ||
| 1302 | LLVMPositionBuilderAtEnd(g->builder, return_block); | |
| 1303 | LLVMBuildRetVoid(g->builder); | |
| 1304 | ||
| 1305 | LLVMPositionBuilderAtEnd(g->builder, continue_block); | |
| 1306 | LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr); | |
| 1307 | LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, ""); | |
| 1308 | LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, ""); | |
| 1309 | LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, ""); | |
| 1310 | LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr); | |
| 1311 | LLVMBuildBr(g->builder, loop_block); | |
| 1312 | ||
| 1313 | LLVMPositionBuilderAtEnd(g->builder, prev_block); | |
| 1314 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); | |
| 1315 | ||
| 1316 | g->merge_err_ret_traces_fn_val = fn_val; | |
| 1317 | return fn_val; | |
| 1318 | ||
| 1319 | } | |
| 1320 | ||
| 1321 | static LLVMValueRef get_return_err_fn(CodeGen *g) { | |
| 1322 | if (g->return_err_fn != nullptr) | |
| 1323 | return g->return_err_fn; | |
| 1324 | ||
| 1325 | assert(g->err_tag_type != nullptr); | |
| 1326 | ||
| 1327 | LLVMTypeRef arg_types[] = { | |
| 1328 | // error return trace pointer | |
| 1329 | get_ptr_to_stack_trace_type(g)->type_ref, | |
| 1330 | }; | |
| 1331 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); | |
| 1332 | ||
| 1333 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); | |
| 1334 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); | |
| 1335 | addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address | |
| 1336 | addLLVMFnAttr(fn_val, "cold"); | |
| 1337 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); | |
| 1338 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | |
| 1339 | addLLVMFnAttr(fn_val, "nounwind"); | |
| 1340 | add_uwtable_attr(g, fn_val); | |
| 1341 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); | |
| 1342 | if (g->build_mode == BuildModeDebug) { | |
| 1343 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); | |
| 1344 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); | |
| 1345 | } | |
| 1346 | ||
| 1347 | // this is above the ZigLLVMClearCurrentDebugLocation | |
| 1348 | LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); | |
| 1349 | ||
| 1350 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); | |
| 1351 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); | |
| 1352 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); | |
| 1353 | LLVMPositionBuilderAtEnd(g->builder, entry_block); | |
| 1354 | ZigLLVMClearCurrentDebugLocation(g->builder); | |
| 1355 | ||
| 1356 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); | |
| 1357 | ||
| 1358 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref; | |
| 1359 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | |
| 1360 | LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, ""); | |
| 1361 | LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); | |
| 1362 | ||
| 1363 | LLVMValueRef args[] = { err_ret_trace_ptr, return_address }; | |
| 1364 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); | |
| 1365 | LLVMBuildRetVoid(g->builder); | |
| 1366 | ||
| 1367 | LLVMPositionBuilderAtEnd(g->builder, prev_block); | |
| 1368 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); | |
| 1369 | ||
| 1194 | 1370 | g->return_err_fn = fn_val; |
| 1195 | 1371 | return fn_val; |
| 1196 | 1372 | } |
| ... | ... | @@ -1318,9 +1494,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1318 | 1494 | return fn_val; |
| 1319 | 1495 | } |
| 1320 | 1496 | |
| 1321 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | |
| 1497 | static bool is_coro_prelude_scope(Scope *scope) { | |
| 1498 | while (scope != nullptr) { | |
| 1499 | if (scope->id == ScopeIdCoroPrelude) { | |
| 1500 | return true; | |
| 1501 | } else if (scope->id == ScopeIdFnDef) { | |
| 1502 | break; | |
| 1503 | } | |
| 1504 | scope = scope->parent; | |
| 1505 | } | |
| 1506 | return false; | |
| 1507 | } | |
| 1508 | ||
| 1509 | static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) { | |
| 1510 | if (!g->have_err_ret_tracing) { | |
| 1511 | return nullptr; | |
| 1512 | } | |
| 1513 | if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { | |
| 1514 | return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack; | |
| 1515 | } | |
| 1516 | if (g->cur_err_ret_trace_val_stack != nullptr) { | |
| 1517 | return g->cur_err_ret_trace_val_stack; | |
| 1518 | } | |
| 1519 | return g->cur_err_ret_trace_val_arg; | |
| 1520 | } | |
| 1521 | ||
| 1522 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { | |
| 1322 | 1523 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); |
| 1323 | LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val; | |
| 1524 | LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); | |
| 1324 | 1525 | if (err_ret_trace_val == nullptr) { |
| 1325 | 1526 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 1326 | 1527 | err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref); |
| ... | ... | @@ -1607,32 +1808,24 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1607 | 1808 | return instruction->llvm_value; |
| 1608 | 1809 | } |
| 1609 | 1810 | |
| 1811 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, | |
| 1812 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) | |
| 1813 | { | |
| 1814 | assert(g->have_err_ret_tracing); | |
| 1815 | ||
| 1816 | LLVMValueRef return_err_fn = get_return_err_fn(g); | |
| 1817 | LLVMValueRef args[] = { | |
| 1818 | get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope), | |
| 1819 | }; | |
| 1820 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | |
| 1821 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1822 | return call_instruction; | |
| 1823 | } | |
| 1824 | ||
| 1610 | 1825 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { |
| 1611 | 1826 | LLVMValueRef value = ir_llvm_value(g, return_instruction->value); |
| 1612 | 1827 | TypeTableEntry *return_type = return_instruction->value->value.type; |
| 1613 | 1828 | |
| 1614 | if (g->have_err_ret_tracing) { | |
| 1615 | bool is_err_return = false; | |
| 1616 | if (return_type->id == TypeTableEntryIdErrorUnion) { | |
| 1617 | if (return_instruction->value->value.special == ConstValSpecialStatic) { | |
| 1618 | is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr; | |
| 1619 | } else if (return_instruction->value->value.special == ConstValSpecialRuntime) { | |
| 1620 | is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; | |
| 1621 | // TODO: emit a branch to check if the return value is an error | |
| 1622 | } | |
| 1623 | } else if (return_type->id == TypeTableEntryIdErrorSet) { | |
| 1624 | is_err_return = true; | |
| 1625 | } | |
| 1626 | if (is_err_return) { | |
| 1627 | LLVMValueRef return_err_fn = get_return_err_fn(g); | |
| 1628 | LLVMValueRef args[] = { | |
| 1629 | g->cur_err_ret_trace_val, | |
| 1630 | }; | |
| 1631 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | |
| 1632 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1633 | LLVMSetTailCall(call_instruction, true); | |
| 1634 | } | |
| 1635 | } | |
| 1636 | 1829 | if (handle_is_ptr(return_type)) { |
| 1637 | 1830 | if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { |
| 1638 | 1831 | assert(g->cur_ret_ptr); |
| ... | ... | @@ -2732,7 +2925,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2732 | 2925 | gen_param_index += 1; |
| 2733 | 2926 | } |
| 2734 | 2927 | if (prefix_arg_err_ret_stack) { |
| 2735 | gen_param_values[gen_param_index] = g->cur_err_ret_trace_val; | |
| 2928 | gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 2736 | 2929 | gen_param_index += 1; |
| 2737 | 2930 | } |
| 2738 | 2931 | if (instruction->is_async) { |
| ... | ... | @@ -3299,11 +3492,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I |
| 3299 | 3492 | static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, |
| 3300 | 3493 | IrInstructionErrorReturnTrace *instruction) |
| 3301 | 3494 | { |
| 3302 | if (g->cur_err_ret_trace_val == nullptr) { | |
| 3495 | LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 3496 | if (cur_err_ret_trace_val == nullptr) { | |
| 3303 | 3497 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 3304 | 3498 | return LLVMConstNull(ptr_to_stack_trace_type->type_ref); |
| 3305 | 3499 | } |
| 3306 | return g->cur_err_ret_trace_val; | |
| 3500 | return cur_err_ret_trace_val; | |
| 3307 | 3501 | } |
| 3308 | 3502 | |
| 3309 | 3503 | static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) { |
| ... | ... | @@ -3733,7 +3927,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3733 | 3927 | LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); |
| 3734 | 3928 | |
| 3735 | 3929 | LLVMPositionBuilderAtEnd(g->builder, err_block); |
| 3736 | gen_safety_crash_for_err(g, err_val); | |
| 3930 | gen_safety_crash_for_err(g, err_val, instruction->base.scope); | |
| 3737 | 3931 | |
| 3738 | 3932 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3739 | 3933 | } |
| ... | ... | @@ -3925,7 +4119,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec |
| 3925 | 4119 | } |
| 3926 | 4120 | |
| 3927 | 4121 | static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { |
| 3928 | gen_panic(g, ir_llvm_value(g, instruction->msg), g->cur_err_ret_trace_val); | |
| 4122 | gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); | |
| 3929 | 4123 | return nullptr; |
| 3930 | 4124 | } |
| 3931 | 4125 | |
| ... | ... | @@ -4187,6 +4381,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, |
| 4187 | 4381 | return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, ""); |
| 4188 | 4382 | } |
| 4189 | 4383 | |
| 4384 | static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable, | |
| 4385 | IrInstructionMergeErrRetTraces *instruction) | |
| 4386 | { | |
| 4387 | assert(g->have_err_ret_tracing); | |
| 4388 | ||
| 4389 | LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr); | |
| 4390 | LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr); | |
| 4391 | ||
| 4392 | LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; | |
| 4393 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 4394 | return nullptr; | |
| 4395 | } | |
| 4396 | ||
| 4397 | static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable, | |
| 4398 | IrInstructionMarkErrRetTracePtr *instruction) | |
| 4399 | { | |
| 4400 | assert(g->have_err_ret_tracing); | |
| 4401 | g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr); | |
| 4402 | return nullptr; | |
| 4403 | } | |
| 4404 | ||
| 4190 | 4405 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 4191 | 4406 | AstNode *source_node = instruction->source_node; |
| 4192 | 4407 | Scope *scope = instruction->scope; |
| ... | ... | @@ -4212,6 +4427,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4212 | 4427 | case IrInstructionIdSetRuntimeSafety: |
| 4213 | 4428 | case IrInstructionIdSetFloatMode: |
| 4214 | 4429 | case IrInstructionIdArrayType: |
| 4430 | case IrInstructionIdPromiseType: | |
| 4215 | 4431 | case IrInstructionIdSliceType: |
| 4216 | 4432 | case IrInstructionIdSizeOf: |
| 4217 | 4433 | case IrInstructionIdSwitchTarget: |
| ... | ... | @@ -4252,6 +4468,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4252 | 4468 | case IrInstructionIdErrorUnion: |
| 4253 | 4469 | case IrInstructionIdPromiseResultType: |
| 4254 | 4470 | case IrInstructionIdAwaitBookkeeping: |
| 4471 | case IrInstructionIdAddImplicitReturnType: | |
| 4255 | 4472 | zig_unreachable(); |
| 4256 | 4473 | |
| 4257 | 4474 | case IrInstructionIdReturn: |
| ... | ... | @@ -4400,6 +4617,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4400 | 4617 | return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction); |
| 4401 | 4618 | case IrInstructionIdAtomicRmw: |
| 4402 | 4619 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); |
| 4620 | case IrInstructionIdSaveErrRetAddr: | |
| 4621 | return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); | |
| 4622 | case IrInstructionIdMergeErrRetTraces: | |
| 4623 | return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); | |
| 4624 | case IrInstructionIdMarkErrRetTracePtr: | |
| 4625 | return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); | |
| 4403 | 4626 | } |
| 4404 | 4627 | zig_unreachable(); |
| 4405 | 4628 | } |
| ... | ... | @@ -5282,39 +5505,23 @@ static void do_code_gen(CodeGen *g) { |
| 5282 | 5505 | clear_debug_source_node(g); |
| 5283 | 5506 | |
| 5284 | 5507 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); |
| 5285 | if (err_ret_trace_arg_index != UINT32_MAX) { | |
| 5286 | g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 5287 | } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) { | |
| 5288 | // TODO call graph analysis to find out what this number needs to be for every function | |
| 5289 | static const size_t stack_trace_ptr_count = 30; | |
| 5290 | ||
| 5291 | TypeTableEntry *usize = g->builtin_types.entry_usize; | |
| 5292 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); | |
| 5293 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", | |
| 5294 | get_abi_alignment(g, array_type)); | |
| 5295 | g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | |
| 5296 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | |
| 5297 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, ""); | |
| 5298 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); | |
| 5299 | ||
| 5300 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | |
| 5301 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, ""); | |
| 5302 | ||
| 5303 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | |
| 5304 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 5305 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, ""); | |
| 5306 | LLVMValueRef zero = LLVMConstNull(usize->type_ref); | |
| 5307 | LLVMValueRef indices[] = {zero, zero}; | |
| 5308 | LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val, | |
| 5309 | indices, 2, ""); | |
| 5310 | gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, | |
| 5311 | get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false)); | |
| 5508 | bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; | |
| 5509 | if (have_err_ret_trace_arg) { | |
| 5510 | g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 5511 | } else { | |
| 5512 | g->cur_err_ret_trace_val_arg = nullptr; | |
| 5513 | } | |
| 5312 | 5514 | |
| 5313 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 5314 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | |
| 5315 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | |
| 5515 | // error return tracing setup | |
| 5516 | bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 5517 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg; | |
| 5518 | LLVMValueRef err_ret_array_val = nullptr; | |
| 5519 | if (have_err_ret_trace_stack) { | |
| 5520 | TypeTableEntry *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count); | |
| 5521 | err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); | |
| 5522 | g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | |
| 5316 | 5523 | } else { |
| 5317 | g->cur_err_ret_trace_val = nullptr; | |
| 5524 | g->cur_err_ret_trace_val_stack = nullptr; | |
| 5318 | 5525 | } |
| 5319 | 5526 | |
| 5320 | 5527 | // allocate temporary stack data |
| ... | ... | @@ -5407,6 +5614,31 @@ static void do_code_gen(CodeGen *g) { |
| 5407 | 5614 | } |
| 5408 | 5615 | } |
| 5409 | 5616 | |
| 5617 | // finishing error return trace setup. we have to do this after all the allocas. | |
| 5618 | if (have_err_ret_trace_stack) { | |
| 5619 | TypeTableEntry *usize = g->builtin_types.entry_usize; | |
| 5620 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | |
| 5621 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); | |
| 5622 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); | |
| 5623 | ||
| 5624 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | |
| 5625 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); | |
| 5626 | ||
| 5627 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | |
| 5628 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 5629 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, ""); | |
| 5630 | LLVMValueRef zero = LLVMConstNull(usize->type_ref); | |
| 5631 | LLVMValueRef indices[] = {zero, zero}; | |
| 5632 | LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val, | |
| 5633 | indices, 2, ""); | |
| 5634 | TypeTableEntry *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false); | |
| 5635 | gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type); | |
| 5636 | ||
| 5637 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 5638 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | |
| 5639 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | |
| 5640 | } | |
| 5641 | ||
| 5410 | 5642 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; |
| 5411 | 5643 | |
| 5412 | 5644 | // create debug variable declarations for parameters |
| ... | ... | @@ -5914,6 +6146,8 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 5914 | 6146 | os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); |
| 5915 | 6147 | Buf *contents = buf_alloc(); |
| 5916 | 6148 | |
| 6149 | // Modifications to this struct must be coordinated with code that does anything with | |
| 6150 | // g->stack_trace_type. There are hard-coded references to the field indexes. | |
| 5917 | 6151 | buf_append_str(contents, |
| 5918 | 6152 | "pub const StackTrace = struct {\n" |
| 5919 | 6153 | " index: usize,\n" |
| ... | ... | @@ -6178,7 +6412,9 @@ static void init(CodeGen *g) { |
| 6178 | 6412 | g->builder = LLVMCreateBuilder(); |
| 6179 | 6413 | g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true); |
| 6180 | 6414 | |
| 6181 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); | |
| 6415 | // Don't use ZIG_VERSION_STRING here, llvm misparses it when it includes | |
| 6416 | // the git revision. | |
| 6417 | Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH); | |
| 6182 | 6418 | const char *flags = ""; |
| 6183 | 6419 | unsigned runtime_version = 0; |
| 6184 | 6420 | ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name), |
| ... | ... | @@ -6257,7 +6493,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package |
| 6257 | 6493 | zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); |
| 6258 | 6494 | } |
| 6259 | 6495 | Buf *import_code = buf_alloc(); |
| 6260 | if ((err = os_fetch_file_path(abs_full_path, import_code))) { | |
| 6496 | if ((err = os_fetch_file_path(abs_full_path, import_code, false))) { | |
| 6261 | 6497 | zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); |
| 6262 | 6498 | } |
| 6263 | 6499 | |
| ... | ... | @@ -6345,7 +6581,7 @@ static void gen_root_source(CodeGen *g) { |
| 6345 | 6581 | } |
| 6346 | 6582 | |
| 6347 | 6583 | Buf *source_code = buf_alloc(); |
| 6348 | if ((err = os_fetch_file_path(rel_full_path, source_code))) { | |
| 6584 | if ((err = os_fetch_file_path(rel_full_path, source_code, true))) { | |
| 6349 | 6585 | zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err)); |
| 6350 | 6586 | } |
| 6351 | 6587 | |
| ... | ... | @@ -6410,7 +6646,7 @@ static void gen_global_asm(CodeGen *g) { |
| 6410 | 6646 | int err; |
| 6411 | 6647 | for (size_t i = 0; i < g->assembly_files.length; i += 1) { |
| 6412 | 6648 | Buf *asm_file = g->assembly_files.at(i); |
| 6413 | if ((err = os_fetch_file_path(asm_file, &contents))) { | |
| 6649 | if ((err = os_fetch_file_path(asm_file, &contents, false))) { | |
| 6414 | 6650 | zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); |
| 6415 | 6651 | } |
| 6416 | 6652 | buf_append_buf(&g->global_asm, &contents); |
| ... | ... | @@ -6592,6 +6828,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf |
| 6592 | 6828 | } |
| 6593 | 6829 | } |
| 6594 | 6830 | case TypeTableEntryIdStruct: |
| 6831 | case TypeTableEntryIdOpaque: | |
| 6595 | 6832 | { |
| 6596 | 6833 | buf_init_from_str(out_buf, "struct "); |
| 6597 | 6834 | buf_append_buf(out_buf, &type_entry->name); |
| ... | ... | @@ -6609,11 +6846,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf |
| 6609 | 6846 | buf_append_buf(out_buf, &type_entry->name); |
| 6610 | 6847 | return; |
| 6611 | 6848 | } |
| 6612 | case TypeTableEntryIdOpaque: | |
| 6613 | { | |
| 6614 | buf_init_from_buf(out_buf, &type_entry->name); | |
| 6615 | return; | |
| 6616 | } | |
| 6617 | 6849 | case TypeTableEntryIdArray: |
| 6618 | 6850 | { |
| 6619 | 6851 | TypeTableEntryArray *array_data = &type_entry->data.array; |
src/config.h.in-8| ... | ... | @@ -13,14 +13,6 @@ |
| 13 | 13 | #define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ |
| 14 | 14 | #define ZIG_VERSION_STRING "@ZIG_VERSION@" |
| 15 | 15 | |
| 16 | #define ZIG_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" | |
| 17 | #define ZIG_LIBC_INCLUDE_DIR "@ZIG_LIBC_INCLUDE_DIR_ESCAPED@" | |
| 18 | #define ZIG_LIBC_LIB_DIR "@ZIG_LIBC_LIB_DIR_ESCAPED@" | |
| 19 | #define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR_ESCAPED@" | |
| 20 | #define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@" | |
| 21 | ||
| 22 | #cmakedefine ZIG_EACH_LIB_RPATH | |
| 23 | ||
| 24 | 16 | // Only used for running tests before installing. |
| 25 | 17 | #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" |
| 26 | 18 |
src/ir.cpp+381-111| ... | ... | @@ -34,7 +34,7 @@ struct IrAnalyze { |
| 34 | 34 | size_t old_bb_index; |
| 35 | 35 | size_t instruction_index; |
| 36 | 36 | TypeTableEntry *explicit_return_type; |
| 37 | ZigList<IrInstruction *> implicit_return_type_list; | |
| 37 | ZigList<IrInstruction *> src_implicit_return_type_list; | |
| 38 | 38 | IrBasicBlock *const_predecessor_bb; |
| 39 | 39 | }; |
| 40 | 40 | |
| ... | ... | @@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) { |
| 349 | 349 | return IrInstructionIdArrayType; |
| 350 | 350 | } |
| 351 | 351 | |
| 352 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) { | |
| 353 | return IrInstructionIdPromiseType; | |
| 354 | } | |
| 355 | ||
| 352 | 356 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) { |
| 353 | 357 | return IrInstructionIdSliceType; |
| 354 | 358 | } |
| ... | ... | @@ -713,6 +717,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping |
| 713 | 717 | return IrInstructionIdAwaitBookkeeping; |
| 714 | 718 | } |
| 715 | 719 | |
| 720 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) { | |
| 721 | return IrInstructionIdSaveErrRetAddr; | |
| 722 | } | |
| 723 | ||
| 724 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) { | |
| 725 | return IrInstructionIdAddImplicitReturnType; | |
| 726 | } | |
| 727 | ||
| 728 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) { | |
| 729 | return IrInstructionIdMergeErrRetTraces; | |
| 730 | } | |
| 731 | ||
| 732 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) { | |
| 733 | return IrInstructionIdMarkErrRetTracePtr; | |
| 734 | } | |
| 735 | ||
| 716 | 736 | template<typename T> |
| 717 | 737 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 718 | 738 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -944,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast |
| 944 | 964 | return &const_instruction->base; |
| 945 | 965 | } |
| 946 | 966 | |
| 947 | static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 948 | TypeTableEntry *return_type) | |
| 949 | { | |
| 950 | TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type); | |
| 951 | ||
| 952 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); | |
| 953 | const_instruction->base.value.type = struct_type; | |
| 954 | const_instruction->base.value.special = ConstValSpecialStatic; | |
| 955 | const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count); | |
| 956 | const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry; | |
| 957 | const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic; | |
| 958 | const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr; | |
| 959 | const_instruction->base.value.data.x_struct.fields[1].type = return_type; | |
| 960 | const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef; | |
| 961 | const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry; | |
| 962 | const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef; | |
| 963 | return &const_instruction->base; | |
| 964 | } | |
| 965 | ||
| 966 | 967 | static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, |
| 967 | 968 | IrInstruction *op1, IrInstruction *op2, bool safety_check_on) |
| 968 | 969 | { |
| ... | ... | @@ -1461,6 +1462,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode |
| 1461 | 1462 | return &instruction->base; |
| 1462 | 1463 | } |
| 1463 | 1464 | |
| 1465 | static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1466 | IrInstruction *payload_type) | |
| 1467 | { | |
| 1468 | IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node); | |
| 1469 | instruction->payload_type = payload_type; | |
| 1470 | ||
| 1471 | if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block); | |
| 1472 | ||
| 1473 | return &instruction->base; | |
| 1474 | } | |
| 1475 | ||
| 1464 | 1476 | static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1465 | 1477 | IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value) |
| 1466 | 1478 | { |
| ... | ... | @@ -2141,12 +2153,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc |
| 2141 | 2153 | } |
| 2142 | 2154 | |
| 2143 | 2155 | static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2144 | IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, bool is_var_args) | |
| 2156 | IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, | |
| 2157 | IrInstruction *async_allocator_type_value, bool is_var_args) | |
| 2145 | 2158 | { |
| 2146 | 2159 | IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node); |
| 2147 | 2160 | instruction->param_types = param_types; |
| 2148 | 2161 | instruction->align_value = align_value; |
| 2149 | 2162 | instruction->return_type = return_type; |
| 2163 | instruction->async_allocator_type_value = async_allocator_type_value; | |
| 2150 | 2164 | instruction->is_var_args = is_var_args; |
| 2151 | 2165 | |
| 2152 | 2166 | assert(source_node->type == NodeTypeFnProto); |
| ... | ... | @@ -2156,6 +2170,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s |
| 2156 | 2170 | if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block); |
| 2157 | 2171 | } |
| 2158 | 2172 | if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); |
| 2173 | if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block); | |
| 2159 | 2174 | ir_ref_instruction(return_type, irb->current_basic_block); |
| 2160 | 2175 | |
| 2161 | 2176 | return &instruction->base; |
| ... | ... | @@ -2469,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s |
| 2469 | 2484 | return &instruction->base; |
| 2470 | 2485 | } |
| 2471 | 2486 | |
| 2472 | static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) { | |
| 2487 | static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) { | |
| 2473 | 2488 | IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node); |
| 2489 | instruction->nullable = nullable; | |
| 2474 | 2490 | |
| 2475 | 2491 | return &instruction->base; |
| 2476 | 2492 | } |
| ... | ... | @@ -2675,6 +2691,46 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A |
| 2675 | 2691 | return &instruction->base; |
| 2676 | 2692 | } |
| 2677 | 2693 | |
| 2694 | static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) { | |
| 2695 | IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node); | |
| 2696 | return &instruction->base; | |
| 2697 | } | |
| 2698 | ||
| 2699 | static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2700 | IrInstruction *value) | |
| 2701 | { | |
| 2702 | IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node); | |
| 2703 | instruction->value = value; | |
| 2704 | ||
| 2705 | ir_ref_instruction(value, irb->current_basic_block); | |
| 2706 | ||
| 2707 | return &instruction->base; | |
| 2708 | } | |
| 2709 | ||
| 2710 | static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2711 | IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr) | |
| 2712 | { | |
| 2713 | IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node); | |
| 2714 | instruction->coro_promise_ptr = coro_promise_ptr; | |
| 2715 | instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr; | |
| 2716 | instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr; | |
| 2717 | ||
| 2718 | ir_ref_instruction(coro_promise_ptr, irb->current_basic_block); | |
| 2719 | ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block); | |
| 2720 | ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block); | |
| 2721 | ||
| 2722 | return &instruction->base; | |
| 2723 | } | |
| 2724 | ||
| 2725 | static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) { | |
| 2726 | IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node); | |
| 2727 | instruction->err_ret_trace_ptr = err_ret_trace_ptr; | |
| 2728 | ||
| 2729 | ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block); | |
| 2730 | ||
| 2731 | return &instruction->base; | |
| 2732 | } | |
| 2733 | ||
| 2678 | 2734 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2679 | 2735 | results[ReturnKindUnconditional] = 0; |
| 2680 | 2736 | results[ReturnKindError] = 0; |
| ... | ... | @@ -2699,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) { |
| 2699 | 2755 | |
| 2700 | 2756 | static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) { |
| 2701 | 2757 | Scope *scope = inner_scope; |
| 2758 | bool is_noreturn = false; | |
| 2702 | 2759 | while (scope != outer_scope) { |
| 2703 | 2760 | if (!scope) |
| 2704 | return false; | |
| 2761 | return is_noreturn; | |
| 2705 | 2762 | |
| 2706 | 2763 | if (scope->id == ScopeIdDefer) { |
| 2707 | 2764 | AstNode *defer_node = scope->source_node; |
| ... | ... | @@ -2714,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 2714 | 2771 | Scope *defer_expr_scope = defer_node->data.defer.expr_scope; |
| 2715 | 2772 | IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); |
| 2716 | 2773 | if (defer_expr_value != irb->codegen->invalid_instruction) { |
| 2717 | ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value)); | |
| 2774 | if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) { | |
| 2775 | is_noreturn = true; | |
| 2776 | } else { | |
| 2777 | ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value)); | |
| 2778 | } | |
| 2718 | 2779 | } |
| 2719 | 2780 | } |
| 2720 | 2781 | |
| 2721 | 2782 | } |
| 2722 | 2783 | scope = scope->parent; |
| 2723 | 2784 | } |
| 2724 | return true; | |
| 2785 | return is_noreturn; | |
| 2725 | 2786 | } |
| 2726 | 2787 | |
| 2727 | 2788 | static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { |
| ... | ... | @@ -2747,16 +2808,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { |
| 2747 | 2808 | return nullptr; |
| 2748 | 2809 | } |
| 2749 | 2810 | |
| 2811 | static bool exec_is_async(IrExecutable *exec) { | |
| 2812 | FnTableEntry *fn_entry = exec_fn_entry(exec); | |
| 2813 | return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 2814 | } | |
| 2815 | ||
| 2750 | 2816 | static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value, |
| 2751 | 2817 | bool is_generated_code) |
| 2752 | 2818 | { |
| 2753 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); | |
| 2754 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 2819 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value)); | |
| 2820 | ||
| 2821 | bool is_async = exec_is_async(irb->exec); | |
| 2755 | 2822 | if (!is_async) { |
| 2756 | //if (irb->codegen->have_err_ret_tracing) { | |
| 2757 | // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node); | |
| 2758 | // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr); | |
| 2759 | //} | |
| 2760 | 2823 | IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value); |
| 2761 | 2824 | return_inst->is_gen = is_generated_code; |
| 2762 | 2825 | return return_inst; |
| ... | ... | @@ -2778,22 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode |
| 2778 | 2841 | // the above blocks are rendered by ir_gen after the rest of codegen |
| 2779 | 2842 | } |
| 2780 | 2843 | |
| 2781 | //static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) { | |
| 2782 | // if (!irb->codegen->have_err_ret_tracing) | |
| 2783 | // return; | |
| 2784 | // | |
| 2785 | // if (is_async) { | |
| 2786 | // IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr); | |
| 2787 | // IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node); | |
| 2788 | // IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr); | |
| 2789 | // ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize); | |
| 2790 | // return; | |
| 2791 | // } | |
| 2792 | // | |
| 2793 | // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node); | |
| 2794 | // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr); | |
| 2795 | //} | |
| 2796 | ||
| 2797 | 2844 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { |
| 2798 | 2845 | assert(node->type == NodeTypeReturnExpr); |
| 2799 | 2846 | |
| ... | ... | @@ -2839,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2839 | 2886 | |
| 2840 | 2887 | IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); |
| 2841 | 2888 | |
| 2889 | bool should_inline = ir_should_inline(irb->exec, scope); | |
| 2842 | 2890 | IrInstruction *is_comptime; |
| 2843 | if (ir_should_inline(irb->exec, scope)) { | |
| 2891 | if (should_inline) { | |
| 2844 | 2892 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 2845 | 2893 | } else { |
| 2846 | 2894 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); |
| ... | ... | @@ -2853,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2853 | 2901 | if (have_err_defers) { |
| 2854 | 2902 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2855 | 2903 | } |
| 2856 | //ir_gen_save_err_ret_addr(irb, scope, node, is_async); | |
| 2904 | if (irb->codegen->have_err_ret_tracing && !should_inline) { | |
| 2905 | ir_build_save_err_ret_addr(irb, scope, node); | |
| 2906 | } | |
| 2857 | 2907 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 2858 | 2908 | |
| 2859 | 2909 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| ... | ... | @@ -2882,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2882 | 2932 | IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); |
| 2883 | 2933 | IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); |
| 2884 | 2934 | IrInstruction *is_comptime; |
| 2885 | if (ir_should_inline(irb->exec, scope)) { | |
| 2935 | bool should_inline = ir_should_inline(irb->exec, scope); | |
| 2936 | if (should_inline) { | |
| 2886 | 2937 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 2887 | 2938 | } else { |
| 2888 | 2939 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val); |
| ... | ... | @@ -2890,9 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2890 | 2941 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime)); |
| 2891 | 2942 | |
| 2892 | 2943 | ir_set_cursor_at_end_and_append_block(irb, return_block); |
| 2893 | ir_gen_defers_for_block(irb, scope, outer_scope, true); | |
| 2894 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); | |
| 2895 | ir_gen_async_return(irb, scope, node, err_val, false); | |
| 2944 | if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) { | |
| 2945 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); | |
| 2946 | if (irb->codegen->have_err_ret_tracing && !should_inline) { | |
| 2947 | ir_build_save_err_ret_addr(irb, scope, node); | |
| 2948 | } | |
| 2949 | ir_gen_async_return(irb, scope, node, err_val, false); | |
| 2950 | } | |
| 2896 | 2951 | |
| 2897 | 2952 | ir_set_cursor_at_end_and_append_block(irb, continue_block); |
| 2898 | 2953 | IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false); |
| ... | ... | @@ -4185,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4185 | 4240 | } |
| 4186 | 4241 | case BuiltinFnIdErrorReturnTrace: |
| 4187 | 4242 | { |
| 4188 | return ir_build_error_return_trace(irb, scope, node); | |
| 4243 | return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null); | |
| 4189 | 4244 | } |
| 4190 | 4245 | case BuiltinFnIdAtomicRmw: |
| 4191 | 4246 | { |
| ... | ... | @@ -5032,6 +5087,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n |
| 5032 | 5087 | } |
| 5033 | 5088 | } |
| 5034 | 5089 | |
| 5090 | static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 5091 | assert(node->type == NodeTypePromiseType); | |
| 5092 | ||
| 5093 | AstNode *payload_type_node = node->data.promise_type.payload_type; | |
| 5094 | IrInstruction *payload_type_value = nullptr; | |
| 5095 | ||
| 5096 | if (payload_type_node != nullptr) { | |
| 5097 | payload_type_value = ir_gen_node(irb, payload_type_node, scope); | |
| 5098 | if (payload_type_value == irb->codegen->invalid_instruction) | |
| 5099 | return payload_type_value; | |
| 5100 | ||
| 5101 | } | |
| 5102 | ||
| 5103 | return ir_build_promise_type(irb, scope, node, payload_type_value); | |
| 5104 | } | |
| 5105 | ||
| 5035 | 5106 | static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5036 | 5107 | assert(node->type == NodeTypeUndefinedLiteral); |
| 5037 | 5108 | return ir_build_const_undefined(irb, scope, node); |
| ... | ... | @@ -5630,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast |
| 5630 | 5701 | |
| 5631 | 5702 | IrBasicBlock *dest_block = loop_scope->continue_block; |
| 5632 | 5703 | ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false); |
| 5633 | return ir_build_br(irb, continue_scope, node, dest_block, is_comptime); | |
| 5704 | return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); | |
| 5634 | 5705 | } |
| 5635 | 5706 | |
| 5636 | 5707 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | ... | @@ -5989,7 +6060,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5989 | 6060 | return_type = nullptr; |
| 5990 | 6061 | } |
| 5991 | 6062 | |
| 5992 | return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args); | |
| 6063 | IrInstruction *async_allocator_type_value = nullptr; | |
| 6064 | if (node->data.fn_proto.async_allocator_type != nullptr) { | |
| 6065 | async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope); | |
| 6066 | if (async_allocator_type_value == irb->codegen->invalid_instruction) | |
| 6067 | return irb->codegen->invalid_instruction; | |
| 6068 | } | |
| 6069 | ||
| 6070 | return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, | |
| 6071 | async_allocator_type_value, is_var_args); | |
| 5993 | 6072 | } |
| 5994 | 6073 | |
| 5995 | 6074 | static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| ... | ... | @@ -6044,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6044 | 6123 | Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6045 | 6124 | IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name); |
| 6046 | 6125 | |
| 6126 | if (irb->codegen->have_err_ret_tracing) { | |
| 6127 | IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull); | |
| 6128 | Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); | |
| 6129 | IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); | |
| 6130 | ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr); | |
| 6131 | } | |
| 6132 | ||
| 6047 | 6133 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6048 | 6134 | IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, |
| 6049 | 6135 | awaiter_handle_field_name); |
| ... | ... | @@ -6067,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6067 | 6153 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle); |
| 6068 | 6154 | IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend"); |
| 6069 | 6155 | IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend"); |
| 6070 | IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge"); | |
| 6156 | IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend"); | |
| 6071 | 6157 | ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false); |
| 6072 | 6158 | |
| 6073 | 6159 | ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); |
| 6160 | if (irb->codegen->have_err_ret_tracing) { | |
| 6161 | Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); | |
| 6162 | IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name); | |
| 6163 | IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull); | |
| 6164 | ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); | |
| 6165 | } | |
| 6074 | 6166 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6075 | 6167 | IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name); |
| 6076 | 6168 | IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr); |
| ... | ... | @@ -6092,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6092 | 6184 | |
| 6093 | 6185 | ir_set_cursor_at_end_and_append_block(irb, cleanup_block); |
| 6094 | 6186 | ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); |
| 6095 | ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false); | |
| 6187 | ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false)); | |
| 6096 | 6188 | |
| 6097 | 6189 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| 6098 | 6190 | IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr); |
| ... | ... | @@ -6168,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod |
| 6168 | 6260 | |
| 6169 | 6261 | ir_set_cursor_at_end_and_append_block(irb, cleanup_block); |
| 6170 | 6262 | ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); |
| 6171 | ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false); | |
| 6263 | ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false)); | |
| 6172 | 6264 | |
| 6173 | 6265 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| 6174 | 6266 | return ir_build_const_void(irb, parent_scope, node); |
| ... | ... | @@ -6187,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6187 | 6279 | case NodeTypeSwitchRange: |
| 6188 | 6280 | case NodeTypeStructField: |
| 6189 | 6281 | case NodeTypeFnDef: |
| 6190 | case NodeTypeFnDecl: | |
| 6191 | 6282 | case NodeTypeTestDecl: |
| 6192 | 6283 | zig_unreachable(); |
| 6193 | 6284 | case NodeTypeBlock: |
| ... | ... | @@ -6232,6 +6323,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6232 | 6323 | return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); |
| 6233 | 6324 | case NodeTypeArrayType: |
| 6234 | 6325 | return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval); |
| 6326 | case NodeTypePromiseType: | |
| 6327 | return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval); | |
| 6235 | 6328 | case NodeTypeStringLiteral: |
| 6236 | 6329 | return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval); |
| 6237 | 6330 | case NodeTypeUndefinedLiteral: |
| ... | ... | @@ -6324,63 +6417,92 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6324 | 6417 | IrInstruction *coro_id; |
| 6325 | 6418 | IrInstruction *u8_ptr_type; |
| 6326 | 6419 | IrInstruction *const_bool_false; |
| 6420 | IrInstruction *coro_promise_ptr; | |
| 6421 | IrInstruction *err_ret_trace_ptr; | |
| 6327 | 6422 | TypeTableEntry *return_type; |
| 6328 | 6423 | Buf *result_ptr_field_name; |
| 6329 | 6424 | VariableTableEntry *coro_size_var; |
| 6330 | 6425 | if (is_async) { |
| 6331 | 6426 | // create the coro promise |
| 6332 | const_bool_false = ir_build_const_bool(irb, scope, node, false); | |
| 6333 | VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | |
| 6427 | Scope *coro_scope = create_coro_prelude_scope(node, scope); | |
| 6428 | const_bool_false = ir_build_const_bool(irb, coro_scope, node, false); | |
| 6429 | VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6334 | 6430 | |
| 6335 | 6431 | return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; |
| 6336 | IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type); | |
| 6337 | ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init); | |
| 6338 | IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false); | |
| 6339 | ||
| 6340 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | |
| 6341 | IrInstruction *null_value = ir_build_const_null(irb, scope, node); | |
| 6342 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node, | |
| 6432 | IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); | |
| 6433 | TypeTableEntry *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); | |
| 6434 | IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); | |
| 6435 | // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa | |
| 6436 | ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); | |
| 6437 | coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false); | |
| 6438 | ||
| 6439 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6440 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); | |
| 6441 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, | |
| 6343 | 6442 | get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); |
| 6344 | ir_build_var_decl(irb, scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); | |
| 6345 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, scope, node, | |
| 6443 | ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); | |
| 6444 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, | |
| 6346 | 6445 | await_handle_var, false, false); |
| 6347 | 6446 | |
| 6348 | u8_ptr_type = ir_build_const_type(irb, scope, node, | |
| 6447 | u8_ptr_type = ir_build_const_type(irb, coro_scope, node, | |
| 6349 | 6448 | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); |
| 6350 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr); | |
| 6351 | coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr); | |
| 6352 | coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | |
| 6353 | IrInstruction *coro_size = ir_build_coro_size(irb, scope, node); | |
| 6354 | ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size); | |
| 6355 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, | |
| 6449 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); | |
| 6450 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); | |
| 6451 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6452 | IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); | |
| 6453 | ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); | |
| 6454 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, | |
| 6356 | 6455 | ImplicitAllocatorIdArg); |
| 6357 | irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false); | |
| 6358 | ir_build_var_decl(irb, scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); | |
| 6456 | irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); | |
| 6457 | ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); | |
| 6359 | 6458 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); |
| 6360 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name); | |
| 6361 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); | |
| 6362 | IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size); | |
| 6363 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr); | |
| 6364 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); | |
| 6365 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk"); | |
| 6366 | ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); | |
| 6459 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); | |
| 6460 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); | |
| 6461 | IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size); | |
| 6462 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); | |
| 6463 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError"); | |
| 6464 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk"); | |
| 6465 | ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); | |
| 6367 | 6466 | |
| 6368 | 6467 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); |
| 6369 | IrInstruction *undef = ir_build_const_undefined(irb, scope, node); | |
| 6370 | ir_build_return(irb, scope, node, undef); | |
| 6468 | // we can return undefined here, because the caller passes a pointer to the error struct field | |
| 6469 | // in the error union result, and we populate it in case of allocation failure. | |
| 6470 | ir_build_return(irb, coro_scope, node, undef); | |
| 6371 | 6471 | |
| 6372 | 6472 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); |
| 6373 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr); | |
| 6374 | irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr); | |
| 6473 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); | |
| 6474 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); | |
| 6375 | 6475 | |
| 6376 | 6476 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6377 | 6477 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| 6378 | 6478 | awaiter_handle_field_name); |
| 6479 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value); | |
| 6379 | 6480 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6380 | 6481 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); |
| 6381 | 6482 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6382 | 6483 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); |
| 6383 | 6484 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); |
| 6485 | if (irb->codegen->have_err_ret_tracing) { | |
| 6486 | // initialize the error return trace | |
| 6487 | Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME); | |
| 6488 | IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name); | |
| 6489 | ||
| 6490 | Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); | |
| 6491 | err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); | |
| 6492 | ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr); | |
| 6493 | ||
| 6494 | // coordinate with builtin.zig | |
| 6495 | Buf *index_name = buf_create_from_str("index"); | |
| 6496 | IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name); | |
| 6497 | IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); | |
| 6498 | ir_build_store_ptr(irb, scope, node, index_ptr, zero); | |
| 6499 | ||
| 6500 | Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses"); | |
| 6501 | IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name); | |
| 6502 | ||
| 6503 | IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); | |
| 6504 | ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); | |
| 6505 | } | |
| 6384 | 6506 | |
| 6385 | 6507 | |
| 6386 | 6508 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
| ... | ... | @@ -6395,6 +6517,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6395 | 6517 | return false; |
| 6396 | 6518 | |
| 6397 | 6519 | if (!instr_is_unreachable(result)) { |
| 6520 | // no need for save_err_ret_addr because this cannot return error | |
| 6398 | 6521 | ir_gen_async_return(irb, scope, result->source_node, result, true); |
| 6399 | 6522 | } |
| 6400 | 6523 | |
| ... | ... | @@ -6430,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6430 | 6553 | IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); |
| 6431 | 6554 | ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val); |
| 6432 | 6555 | } |
| 6556 | if (irb->codegen->have_err_ret_tracing) { | |
| 6557 | Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); | |
| 6558 | IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); | |
| 6559 | IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); | |
| 6560 | ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); | |
| 6561 | } | |
| 6433 | 6562 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| 6434 | 6563 | |
| 6435 | 6564 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); |
| ... | ... | @@ -10074,13 +10203,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 10074 | 10203 | return result; |
| 10075 | 10204 | } |
| 10076 | 10205 | |
| 10206 | static TypeTableEntry *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira, | |
| 10207 | IrInstructionAddImplicitReturnType *instruction) | |
| 10208 | { | |
| 10209 | IrInstruction *value = instruction->value->other; | |
| 10210 | if (type_is_invalid(value->value.type)) | |
| 10211 | return ir_unreach_error(ira); | |
| 10212 | ||
| 10213 | ira->src_implicit_return_type_list.append(value); | |
| 10214 | ||
| 10215 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 10216 | out_val->type = ira->codegen->builtin_types.entry_void; | |
| 10217 | return out_val->type; | |
| 10218 | } | |
| 10219 | ||
| 10077 | 10220 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, |
| 10078 | 10221 | IrInstructionReturn *return_instruction) |
| 10079 | 10222 | { |
| 10080 | 10223 | IrInstruction *value = return_instruction->value->other; |
| 10081 | 10224 | if (type_is_invalid(value->value.type)) |
| 10082 | 10225 | return ir_unreach_error(ira); |
| 10083 | ira->implicit_return_type_list.append(value); | |
| 10084 | 10226 | |
| 10085 | 10227 | IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); |
| 10086 | 10228 | if (casted_value == ira->codegen->invalid_instruction) |
| ... | ... | @@ -10958,6 +11100,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * |
| 10958 | 11100 | result_type = get_array_type(ira->codegen, child_type, new_len); |
| 10959 | 11101 | |
| 10960 | 11102 | out_array_val = out_val; |
| 11103 | } else if (is_slice(op1_type) || is_slice(op2_type)) { | |
| 11104 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, child_type, true); | |
| 11105 | result_type = get_slice_type(ira->codegen, ptr_type); | |
| 11106 | out_array_val = create_const_vals(1); | |
| 11107 | out_array_val->special = ConstValSpecialStatic; | |
| 11108 | out_array_val->type = get_array_type(ira->codegen, child_type, new_len); | |
| 11109 | ||
| 11110 | out_val->data.x_struct.fields = create_const_vals(2); | |
| 11111 | ||
| 11112 | out_val->data.x_struct.fields[slice_ptr_index].type = ptr_type; | |
| 11113 | out_val->data.x_struct.fields[slice_ptr_index].special = ConstValSpecialStatic; | |
| 11114 | out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.special = ConstPtrSpecialBaseArray; | |
| 11115 | out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.data.base_array.array_val = out_array_val; | |
| 11116 | out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.data.base_array.elem_index = 0; | |
| 11117 | ||
| 11118 | out_val->data.x_struct.fields[slice_len_index].type = ira->codegen->builtin_types.entry_usize; | |
| 11119 | out_val->data.x_struct.fields[slice_len_index].special = ConstValSpecialStatic; | |
| 11120 | bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index].data.x_bigint, new_len); | |
| 10961 | 11121 | } else { |
| 10962 | 11122 | new_len += 1; // null byte |
| 10963 | 11123 | |
| ... | ... | @@ -11453,22 +11613,33 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 11453 | 11613 | return ira->codegen->builtin_types.entry_void; |
| 11454 | 11614 | } |
| 11455 | 11615 | |
| 11616 | static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { | |
| 11617 | FnTableEntry *fn_entry = exec_fn_entry(exec); | |
| 11618 | return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing; | |
| 11619 | } | |
| 11620 | ||
| 11456 | 11621 | static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 11457 | 11622 | IrInstructionErrorReturnTrace *instruction) |
| 11458 | 11623 | { |
| 11459 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 11460 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); | |
| 11461 | TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); | |
| 11462 | if (fn_entry == nullptr || !fn_entry->calls_or_awaits_errorable_fn || !ira->codegen->have_err_ret_tracing) { | |
| 11463 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 11464 | out_val->data.x_maybe = nullptr; | |
| 11624 | if (instruction->nullable == IrInstructionErrorReturnTrace::Null) { | |
| 11625 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); | |
| 11626 | TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); | |
| 11627 | if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { | |
| 11628 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 11629 | out_val->data.x_maybe = nullptr; | |
| 11630 | return nullable_type; | |
| 11631 | } | |
| 11632 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | |
| 11633 | instruction->base.source_node, instruction->nullable); | |
| 11634 | ir_link_new_instruction(new_instruction, &instruction->base); | |
| 11465 | 11635 | return nullable_type; |
| 11636 | } else { | |
| 11637 | assert(ira->codegen->have_err_ret_tracing); | |
| 11638 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | |
| 11639 | instruction->base.source_node, instruction->nullable); | |
| 11640 | ir_link_new_instruction(new_instruction, &instruction->base); | |
| 11641 | return get_ptr_to_stack_trace_type(ira->codegen); | |
| 11466 | 11642 | } |
| 11467 | ||
| 11468 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | |
| 11469 | instruction->base.source_node); | |
| 11470 | ir_link_new_instruction(new_instruction, &instruction->base); | |
| 11471 | return nullable_type; | |
| 11472 | 11643 | } |
| 11473 | 11644 | |
| 11474 | 11645 | static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira, |
| ... | ... | @@ -12950,6 +13121,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 12950 | 13121 | { |
| 12951 | 13122 | if (!is_slice(bare_struct_type)) { |
| 12952 | 13123 | ScopeDecls *container_scope = get_container_scope(bare_struct_type); |
| 13124 | assert(container_scope != nullptr); | |
| 12953 | 13125 | auto entry = container_scope->decl_table.maybe_get(field_name); |
| 12954 | 13126 | Tld *tld = entry ? entry->value : nullptr; |
| 12955 | 13127 | if (tld && tld->id == TldIdFn) { |
| ... | ... | @@ -13999,6 +14171,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 13999 | 14171 | zig_unreachable(); |
| 14000 | 14172 | } |
| 14001 | 14173 | |
| 14174 | static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) { | |
| 14175 | TypeTableEntry *promise_type; | |
| 14176 | ||
| 14177 | if (instruction->payload_type == nullptr) { | |
| 14178 | promise_type = ira->codegen->builtin_types.entry_promise; | |
| 14179 | } else { | |
| 14180 | TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload_type->other); | |
| 14181 | if (type_is_invalid(payload_type)) | |
| 14182 | return ira->codegen->builtin_types.entry_invalid; | |
| 14183 | ||
| 14184 | promise_type = get_promise_type(ira->codegen, payload_type); | |
| 14185 | } | |
| 14186 | ||
| 14187 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14188 | out_val->data.x_type = promise_type; | |
| 14189 | return ira->codegen->builtin_types.entry_type; | |
| 14190 | } | |
| 14191 | ||
| 14002 | 14192 | static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 14003 | 14193 | IrInstructionSizeOf *size_of_instruction) |
| 14004 | 14194 | { |
| ... | ... | @@ -14569,7 +14759,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi |
| 14569 | 14759 | return ira->codegen->builtin_types.entry_namespace; |
| 14570 | 14760 | } |
| 14571 | 14761 | |
| 14572 | if ((err = os_fetch_file_path(abs_full_path, import_code))) { | |
| 14762 | if ((err = os_fetch_file_path(abs_full_path, import_code, true))) { | |
| 14573 | 14763 | if (err == ErrorFileNotFound) { |
| 14574 | 14764 | ir_add_error_node(ira, source_node, |
| 14575 | 14765 | buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); |
| ... | ... | @@ -15430,7 +15620,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr |
| 15430 | 15620 | // load from file system into const expr |
| 15431 | 15621 | Buf *file_contents = buf_alloc(); |
| 15432 | 15622 | int err; |
| 15433 | if ((err = os_fetch_file_path(&file_path, file_contents))) { | |
| 15623 | if ((err = os_fetch_file_path(&file_path, file_contents, false))) { | |
| 15434 | 15624 | if (err == ErrorFileNotFound) { |
| 15435 | 15625 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); |
| 15436 | 15626 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -16561,6 +16751,18 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc |
| 16561 | 16751 | if (type_is_invalid(fn_type_id.return_type)) |
| 16562 | 16752 | return ira->codegen->builtin_types.entry_invalid; |
| 16563 | 16753 | |
| 16754 | if (fn_type_id.cc == CallingConventionAsync) { | |
| 16755 | if (instruction->async_allocator_type_value == nullptr) { | |
| 16756 | ir_add_error(ira, &instruction->base, | |
| 16757 | buf_sprintf("async fn proto missing allocator type")); | |
| 16758 | return ira->codegen->builtin_types.entry_invalid; | |
| 16759 | } | |
| 16760 | IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other; | |
| 16761 | fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value); | |
| 16762 | if (type_is_invalid(fn_type_id.async_allocator_type)) | |
| 16763 | return ira->codegen->builtin_types.entry_invalid; | |
| 16764 | } | |
| 16765 | ||
| 16564 | 16766 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 16565 | 16767 | out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id); |
| 16566 | 16768 | return ira->codegen->builtin_types.entry_type; |
| ... | ... | @@ -16789,18 +16991,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira, |
| 16789 | 16991 | static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) { |
| 16790 | 16992 | IrInstruction *msg = instruction->msg->other; |
| 16791 | 16993 | if (type_is_invalid(msg->value.type)) |
| 16792 | return ira->codegen->builtin_types.entry_invalid; | |
| 16994 | return ir_unreach_error(ira); | |
| 16793 | 16995 | |
| 16794 | 16996 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) { |
| 16795 | 16997 | ir_add_error(ira, &instruction->base, buf_sprintf("encountered @panic at compile-time")); |
| 16796 | return ira->codegen->builtin_types.entry_invalid; | |
| 16998 | return ir_unreach_error(ira); | |
| 16797 | 16999 | } |
| 16798 | 17000 | |
| 16799 | 17001 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); |
| 16800 | 17002 | TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 16801 | 17003 | IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type); |
| 16802 | 17004 | if (type_is_invalid(casted_msg->value.type)) |
| 16803 | return ira->codegen->builtin_types.entry_invalid; | |
| 17005 | return ir_unreach_error(ira); | |
| 16804 | 17006 | |
| 16805 | 17007 | IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope, |
| 16806 | 17008 | instruction->base.source_node, casted_msg); |
| ... | ... | @@ -17757,6 +17959,59 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, |
| 17757 | 17959 | return out_val->type; |
| 17758 | 17960 | } |
| 17759 | 17961 | |
| 17962 | static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira, | |
| 17963 | IrInstructionMergeErrRetTraces *instruction) | |
| 17964 | { | |
| 17965 | IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other; | |
| 17966 | if (type_is_invalid(coro_promise_ptr->value.type)) | |
| 17967 | return ira->codegen->builtin_types.entry_invalid; | |
| 17968 | ||
| 17969 | assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer); | |
| 17970 | TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type; | |
| 17971 | assert(promise_frame_type->id == TypeTableEntryIdStruct); | |
| 17972 | TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry; | |
| 17973 | ||
| 17974 | if (!type_can_fail(promise_result_type)) { | |
| 17975 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 17976 | out_val->type = ira->codegen->builtin_types.entry_void; | |
| 17977 | return out_val->type; | |
| 17978 | } | |
| 17979 | ||
| 17980 | IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other; | |
| 17981 | if (type_is_invalid(src_err_ret_trace_ptr->value.type)) | |
| 17982 | return ira->codegen->builtin_types.entry_invalid; | |
| 17983 | ||
| 17984 | IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other; | |
| 17985 | if (type_is_invalid(dest_err_ret_trace_ptr->value.type)) | |
| 17986 | return ira->codegen->builtin_types.entry_invalid; | |
| 17987 | ||
| 17988 | IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope, | |
| 17989 | instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); | |
| 17990 | ir_link_new_instruction(result, &instruction->base); | |
| 17991 | result->value.type = ira->codegen->builtin_types.entry_void; | |
| 17992 | return result->value.type; | |
| 17993 | } | |
| 17994 | ||
| 17995 | static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) { | |
| 17996 | IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope, | |
| 17997 | instruction->base.source_node); | |
| 17998 | ir_link_new_instruction(result, &instruction->base); | |
| 17999 | result->value.type = ira->codegen->builtin_types.entry_void; | |
| 18000 | return result->value.type; | |
| 18001 | } | |
| 18002 | ||
| 18003 | static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) { | |
| 18004 | IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other; | |
| 18005 | if (type_is_invalid(err_ret_trace_ptr->value.type)) | |
| 18006 | return ira->codegen->builtin_types.entry_invalid; | |
| 18007 | ||
| 18008 | IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope, | |
| 18009 | instruction->base.source_node, err_ret_trace_ptr); | |
| 18010 | ir_link_new_instruction(result, &instruction->base); | |
| 18011 | result->value.type = ira->codegen->builtin_types.entry_void; | |
| 18012 | return result->value.type; | |
| 18013 | } | |
| 18014 | ||
| 17760 | 18015 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 17761 | 18016 | switch (instruction->id) { |
| 17762 | 18017 | case IrInstructionIdInvalid: |
| ... | ... | @@ -17822,6 +18077,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17822 | 18077 | return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction); |
| 17823 | 18078 | case IrInstructionIdArrayType: |
| 17824 | 18079 | return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction); |
| 18080 | case IrInstructionIdPromiseType: | |
| 18081 | return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction); | |
| 17825 | 18082 | case IrInstructionIdSizeOf: |
| 17826 | 18083 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); |
| 17827 | 18084 | case IrInstructionIdTestNonNull: |
| ... | ... | @@ -17994,6 +18251,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17994 | 18251 | return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); |
| 17995 | 18252 | case IrInstructionIdAwaitBookkeeping: |
| 17996 | 18253 | return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction); |
| 18254 | case IrInstructionIdSaveErrRetAddr: | |
| 18255 | return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); | |
| 18256 | case IrInstructionIdAddImplicitReturnType: | |
| 18257 | return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction); | |
| 18258 | case IrInstructionIdMergeErrRetTraces: | |
| 18259 | return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); | |
| 18260 | case IrInstructionIdMarkErrRetTracePtr: | |
| 18261 | return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); | |
| 17997 | 18262 | } |
| 17998 | 18263 | zig_unreachable(); |
| 17999 | 18264 | } |
| ... | ... | @@ -18067,11 +18332,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl |
| 18067 | 18332 | |
| 18068 | 18333 | if (new_exec->invalid) { |
| 18069 | 18334 | return ira->codegen->builtin_types.entry_invalid; |
| 18070 | } else if (ira->implicit_return_type_list.length == 0) { | |
| 18335 | } else if (ira->src_implicit_return_type_list.length == 0) { | |
| 18071 | 18336 | return codegen->builtin_types.entry_unreachable; |
| 18072 | 18337 | } else { |
| 18073 | return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items, | |
| 18074 | ira->implicit_return_type_list.length); | |
| 18338 | return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items, | |
| 18339 | ira->src_implicit_return_type_list.length); | |
| 18075 | 18340 | } |
| 18076 | 18341 | } |
| 18077 | 18342 | |
| ... | ... | @@ -18119,6 +18384,10 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18119 | 18384 | case IrInstructionIdCoroSave: |
| 18120 | 18385 | case IrInstructionIdCoroAllocHelper: |
| 18121 | 18386 | case IrInstructionIdAwaitBookkeeping: |
| 18387 | case IrInstructionIdSaveErrRetAddr: | |
| 18388 | case IrInstructionIdAddImplicitReturnType: | |
| 18389 | case IrInstructionIdMergeErrRetTraces: | |
| 18390 | case IrInstructionIdMarkErrRetTracePtr: | |
| 18122 | 18391 | return true; |
| 18123 | 18392 | |
| 18124 | 18393 | case IrInstructionIdPhi: |
| ... | ... | @@ -18141,6 +18410,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18141 | 18410 | case IrInstructionIdStructFieldPtr: |
| 18142 | 18411 | case IrInstructionIdUnionFieldPtr: |
| 18143 | 18412 | case IrInstructionIdArrayType: |
| 18413 | case IrInstructionIdPromiseType: | |
| 18144 | 18414 | case IrInstructionIdSliceType: |
| 18145 | 18415 | case IrInstructionIdSizeOf: |
| 18146 | 18416 | case IrInstructionIdTestNonNull: |
src/ir_print.cpp+61-3| ... | ... | @@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) { |
| 201 | 201 | if (call_instruction->is_async) { |
| 202 | 202 | fprintf(irp->f, "async"); |
| 203 | 203 | if (call_instruction->async_allocator != nullptr) { |
| 204 | fprintf(irp->f, "("); | |
| 204 | fprintf(irp->f, "<"); | |
| 205 | 205 | ir_print_other_instruction(irp, call_instruction->async_allocator); |
| 206 | fprintf(irp->f, ")"); | |
| 206 | fprintf(irp->f, ">"); | |
| 207 | 207 | } |
| 208 | 208 | fprintf(irp->f, " "); |
| 209 | 209 | } |
| ... | ... | @@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio |
| 404 | 404 | ir_print_other_instruction(irp, instruction->child_type); |
| 405 | 405 | } |
| 406 | 406 | |
| 407 | static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) { | |
| 408 | fprintf(irp->f, "promise"); | |
| 409 | if (instruction->payload_type != nullptr) { | |
| 410 | fprintf(irp->f, "->"); | |
| 411 | ir_print_other_instruction(irp, instruction->payload_type); | |
| 412 | } | |
| 413 | } | |
| 414 | ||
| 407 | 415 | static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) { |
| 408 | 416 | const char *const_kw = instruction->is_const ? "const " : ""; |
| 409 | 417 | fprintf(irp->f, "[]%s", const_kw); |
| ... | ... | @@ -1016,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { |
| 1016 | 1024 | } |
| 1017 | 1025 | |
| 1018 | 1026 | static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { |
| 1019 | fprintf(irp->f, "@errorReturnTrace()"); | |
| 1027 | fprintf(irp->f, "@errorReturnTrace("); | |
| 1028 | switch (instruction->nullable) { | |
| 1029 | case IrInstructionErrorReturnTrace::Null: | |
| 1030 | fprintf(irp->f, "Null"); | |
| 1031 | break; | |
| 1032 | case IrInstructionErrorReturnTrace::NonNull: | |
| 1033 | fprintf(irp->f, "NonNull"); | |
| 1034 | break; | |
| 1035 | } | |
| 1036 | fprintf(irp->f, ")"); | |
| 1020 | 1037 | } |
| 1021 | 1038 | |
| 1022 | 1039 | static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) { |
| ... | ... | @@ -1161,6 +1178,32 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi |
| 1161 | 1178 | fprintf(irp->f, ")"); |
| 1162 | 1179 | } |
| 1163 | 1180 | |
| 1181 | static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) { | |
| 1182 | fprintf(irp->f, "@saveErrRetAddr()"); | |
| 1183 | } | |
| 1184 | ||
| 1185 | static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImplicitReturnType *instruction) { | |
| 1186 | fprintf(irp->f, "@addImplicitReturnType("); | |
| 1187 | ir_print_other_instruction(irp, instruction->value); | |
| 1188 | fprintf(irp->f, ")"); | |
| 1189 | } | |
| 1190 | ||
| 1191 | static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) { | |
| 1192 | fprintf(irp->f, "@mergeErrRetTraces("); | |
| 1193 | ir_print_other_instruction(irp, instruction->coro_promise_ptr); | |
| 1194 | fprintf(irp->f, ","); | |
| 1195 | ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr); | |
| 1196 | fprintf(irp->f, ","); | |
| 1197 | ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr); | |
| 1198 | fprintf(irp->f, ")"); | |
| 1199 | } | |
| 1200 | ||
| 1201 | static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) { | |
| 1202 | fprintf(irp->f, "@markErrRetTracePtr("); | |
| 1203 | ir_print_other_instruction(irp, instruction->err_ret_trace_ptr); | |
| 1204 | fprintf(irp->f, ")"); | |
| 1205 | } | |
| 1206 | ||
| 1164 | 1207 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1165 | 1208 | ir_print_prefix(irp, instruction); |
| 1166 | 1209 | switch (instruction->id) { |
| ... | ... | @@ -1253,6 +1296,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1253 | 1296 | case IrInstructionIdArrayType: |
| 1254 | 1297 | ir_print_array_type(irp, (IrInstructionArrayType *)instruction); |
| 1255 | 1298 | break; |
| 1299 | case IrInstructionIdPromiseType: | |
| 1300 | ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction); | |
| 1301 | break; | |
| 1256 | 1302 | case IrInstructionIdSliceType: |
| 1257 | 1303 | ir_print_slice_type(irp, (IrInstructionSliceType *)instruction); |
| 1258 | 1304 | break; |
| ... | ... | @@ -1532,6 +1578,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1532 | 1578 | case IrInstructionIdAwaitBookkeeping: |
| 1533 | 1579 | ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction); |
| 1534 | 1580 | break; |
| 1581 | case IrInstructionIdSaveErrRetAddr: | |
| 1582 | ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction); | |
| 1583 | break; | |
| 1584 | case IrInstructionIdAddImplicitReturnType: | |
| 1585 | ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction); | |
| 1586 | break; | |
| 1587 | case IrInstructionIdMergeErrRetTraces: | |
| 1588 | ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction); | |
| 1589 | break; | |
| 1590 | case IrInstructionIdMarkErrRetTracePtr: | |
| 1591 | ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); | |
| 1592 | break; | |
| 1535 | 1593 | } |
| 1536 | 1594 | fprintf(irp->f, "\n"); |
| 1537 | 1595 | } |
src/link.cpp+54-7| ... | ... | @@ -164,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) { |
| 164 | 164 | lj->rpath_table.put(rpath, true); |
| 165 | 165 | } |
| 166 | 166 | |
| 167 | static Buf *try_dynamic_linker_path(const char *ld_name) { | |
| 168 | const char *cc_exe = getenv("CC"); | |
| 169 | cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; | |
| 170 | ZigList<const char *> args = {}; | |
| 171 | args.append(buf_ptr(buf_sprintf("-print-file-name=%s", ld_name))); | |
| 172 | Termination term; | |
| 173 | Buf *out_stderr = buf_alloc(); | |
| 174 | Buf *out_stdout = buf_alloc(); | |
| 175 | int err; | |
| 176 | if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { | |
| 177 | return nullptr; | |
| 178 | } | |
| 179 | if (term.how != TerminationIdClean || term.code != 0) { | |
| 180 | return nullptr; | |
| 181 | } | |
| 182 | if (buf_ends_with_str(out_stdout, "\n")) { | |
| 183 | buf_resize(out_stdout, buf_len(out_stdout) - 1); | |
| 184 | } | |
| 185 | if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, ld_name)) { | |
| 186 | return nullptr; | |
| 187 | } | |
| 188 | return out_stdout; | |
| 189 | } | |
| 190 | ||
| 191 | static Buf *get_dynamic_linker_path(CodeGen *g) { | |
| 192 | if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) { | |
| 193 | static const char *ld_names[] = { | |
| 194 | "ld-linux-x86-64.so.2", | |
| 195 | "ld-musl-x86_64.so.1", | |
| 196 | }; | |
| 197 | for (size_t i = 0; i < array_length(ld_names); i += 1) { | |
| 198 | const char *ld_name = ld_names[i]; | |
| 199 | Buf *result = try_dynamic_linker_path(ld_name); | |
| 200 | if (result != nullptr) { | |
| 201 | return result; | |
| 202 | } | |
| 203 | } | |
| 204 | } | |
| 205 | return target_dynamic_linker(&g->zig_target); | |
| 206 | } | |
| 207 | ||
| 167 | 208 | static void construct_linker_job_elf(LinkJob *lj) { |
| 168 | 209 | CodeGen *g = lj->codegen; |
| 169 | 210 | |
| ... | ... | @@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) { |
| 259 | 300 | lj->args.append(buf_ptr(g->libc_static_lib_dir)); |
| 260 | 301 | } |
| 261 | 302 | |
| 262 | if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) { | |
| 263 | lj->args.append("-dynamic-linker"); | |
| 264 | lj->args.append(buf_ptr(g->dynamic_linker)); | |
| 265 | } else { | |
| 266 | lj->args.append("-dynamic-linker"); | |
| 267 | lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target))); | |
| 303 | if (!g->is_static) { | |
| 304 | if (g->dynamic_linker != nullptr) { | |
| 305 | assert(buf_len(g->dynamic_linker) != 0); | |
| 306 | lj->args.append("-dynamic-linker"); | |
| 307 | lj->args.append(buf_ptr(g->dynamic_linker)); | |
| 308 | } else { | |
| 309 | Buf *resolved_dynamic_linker = get_dynamic_linker_path(g); | |
| 310 | lj->args.append("-dynamic-linker"); | |
| 311 | lj->args.append(buf_ptr(resolved_dynamic_linker)); | |
| 312 | } | |
| 268 | 313 | } |
| 269 | 314 | |
| 270 | 315 | if (shared) { |
| ... | ... | @@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) { |
| 423 | 468 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir)))); |
| 424 | 469 | |
| 425 | 470 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir)))); |
| 426 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); | |
| 471 | if (g->libc_static_lib_dir != nullptr) { | |
| 472 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); | |
| 473 | } | |
| 427 | 474 | } |
| 428 | 475 | |
| 429 | 476 | if (lj->link_in_crt) { |
src/main.cpp+52-16| ... | ... | @@ -23,6 +23,7 @@ static int usage(const char *arg0) { |
| 23 | 23 | " build-exe [source] create executable from source or object files\n" |
| 24 | 24 | " build-lib [source] create library from source or object files\n" |
| 25 | 25 | " build-obj [source] create object from source or assembly\n" |
| 26 | " run [source] create executable and run immediately\n" | |
| 26 | 27 | " translate-c [source] convert c code to zig code\n" |
| 27 | 28 | " targets list available compilation targets\n" |
| 28 | 29 | " test [source] create and run a test build\n" |
| ... | ... | @@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) { |
| 195 | 196 | } |
| 196 | 197 | } |
| 197 | 198 | |
| 198 | if (ZIG_INSTALL_PREFIX != nullptr) { | |
| 199 | if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { | |
| 200 | return 0; | |
| 201 | } | |
| 202 | } | |
| 203 | ||
| 204 | ||
| 205 | 199 | return ErrorFileNotFound; |
| 206 | 200 | } |
| 207 | 201 | |
| ... | ... | @@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) { |
| 227 | 221 | enum Cmd { |
| 228 | 222 | CmdInvalid, |
| 229 | 223 | CmdBuild, |
| 224 | CmdRun, | |
| 230 | 225 | CmdTest, |
| 231 | 226 | CmdVersion, |
| 232 | 227 | CmdZen, |
| ... | ... | @@ -336,6 +331,8 @@ int main(int argc, char **argv) { |
| 336 | 331 | CliPkg *cur_pkg = allocate<CliPkg>(1); |
| 337 | 332 | BuildMode build_mode = BuildModeDebug; |
| 338 | 333 | ZigList<const char *> test_exec_args = {0}; |
| 334 | int comptime_args_end = 0; | |
| 335 | int runtime_args_start = argc; | |
| 339 | 336 | |
| 340 | 337 | if (argc >= 2 && strcmp(argv[1], "build") == 0) { |
| 341 | 338 | const char *zig_exe_path = arg0; |
| ... | ... | @@ -452,10 +449,11 @@ int main(int argc, char **argv) { |
| 452 | 449 | |
| 453 | 450 | if ((err = os_copy_file(build_template_path, &build_file_abs))) { |
| 454 | 451 | fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err)); |
| 452 | return EXIT_FAILURE; | |
| 455 | 453 | } else { |
| 456 | 454 | fprintf(stderr, "Wrote build.zig template\n"); |
| 455 | return EXIT_SUCCESS; | |
| 457 | 456 | } |
| 458 | return EXIT_SUCCESS; | |
| 459 | 457 | } |
| 460 | 458 | |
| 461 | 459 | fprintf(stderr, |
| ... | ... | @@ -487,11 +485,15 @@ int main(int argc, char **argv) { |
| 487 | 485 | return (term.how == TerminationIdClean) ? term.code : -1; |
| 488 | 486 | } |
| 489 | 487 | |
| 490 | for (int i = 1; i < argc; i += 1) { | |
| 488 | for (int i = 1; i < argc; i += 1, comptime_args_end += 1) { | |
| 491 | 489 | char *arg = argv[i]; |
| 492 | 490 | |
| 493 | 491 | if (arg[0] == '-') { |
| 494 | if (strcmp(arg, "--release-fast") == 0) { | |
| 492 | if (strcmp(arg, "--") == 0) { | |
| 493 | // ignore -- from both compile and runtime arg sets | |
| 494 | runtime_args_start = i + 1; | |
| 495 | break; | |
| 496 | } else if (strcmp(arg, "--release-fast") == 0) { | |
| 495 | 497 | build_mode = BuildModeFastRelease; |
| 496 | 498 | } else if (strcmp(arg, "--release-safe") == 0) { |
| 497 | 499 | build_mode = BuildModeSafeRelease; |
| ... | ... | @@ -658,6 +660,9 @@ int main(int argc, char **argv) { |
| 658 | 660 | } else if (strcmp(arg, "build-lib") == 0) { |
| 659 | 661 | cmd = CmdBuild; |
| 660 | 662 | out_type = OutTypeLib; |
| 663 | } else if (strcmp(arg, "run") == 0) { | |
| 664 | cmd = CmdRun; | |
| 665 | out_type = OutTypeExe; | |
| 661 | 666 | } else if (strcmp(arg, "version") == 0) { |
| 662 | 667 | cmd = CmdVersion; |
| 663 | 668 | } else if (strcmp(arg, "zen") == 0) { |
| ... | ... | @@ -676,6 +681,7 @@ int main(int argc, char **argv) { |
| 676 | 681 | } else { |
| 677 | 682 | switch (cmd) { |
| 678 | 683 | case CmdBuild: |
| 684 | case CmdRun: | |
| 679 | 685 | case CmdTranslateC: |
| 680 | 686 | case CmdTest: |
| 681 | 687 | if (!in_file) { |
| ... | ... | @@ -730,8 +736,8 @@ int main(int argc, char **argv) { |
| 730 | 736 | } |
| 731 | 737 | } |
| 732 | 738 | |
| 733 | ||
| 734 | 739 | switch (cmd) { |
| 740 | case CmdRun: | |
| 735 | 741 | case CmdBuild: |
| 736 | 742 | case CmdTranslateC: |
| 737 | 743 | case CmdTest: |
| ... | ... | @@ -739,7 +745,7 @@ int main(int argc, char **argv) { |
| 739 | 745 | if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { |
| 740 | 746 | fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); |
| 741 | 747 | return usage(arg0); |
| 742 | } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) { | |
| 748 | } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { | |
| 743 | 749 | fprintf(stderr, "Expected source file argument.\n"); |
| 744 | 750 | return usage(arg0); |
| 745 | 751 | } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { |
| ... | ... | @@ -751,6 +757,10 @@ int main(int argc, char **argv) { |
| 751 | 757 | |
| 752 | 758 | bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); |
| 753 | 759 | |
| 760 | if (cmd == CmdRun) { | |
| 761 | out_name = "run"; | |
| 762 | } | |
| 763 | ||
| 754 | 764 | Buf *in_file_buf = nullptr; |
| 755 | 765 | |
| 756 | 766 | Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") : |
| ... | ... | @@ -775,9 +785,23 @@ int main(int argc, char **argv) { |
| 775 | 785 | Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; |
| 776 | 786 | |
| 777 | 787 | Buf *full_cache_dir = buf_alloc(); |
| 778 | os_path_resolve(buf_create_from_str("."), | |
| 779 | buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir), | |
| 780 | full_cache_dir); | |
| 788 | Buf *run_exec_path = buf_alloc(); | |
| 789 | if (cmd == CmdRun) { | |
| 790 | if (buf_out_name == nullptr) { | |
| 791 | buf_out_name = buf_create_from_str("run"); | |
| 792 | } | |
| 793 | ||
| 794 | Buf *global_cache_dir = buf_alloc(); | |
| 795 | os_get_global_cache_directory(global_cache_dir); | |
| 796 | os_path_join(global_cache_dir, buf_out_name, run_exec_path); | |
| 797 | os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir); | |
| 798 | ||
| 799 | out_file = buf_ptr(run_exec_path); | |
| 800 | } else { | |
| 801 | os_path_resolve(buf_create_from_str("."), | |
| 802 | buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir), | |
| 803 | full_cache_dir); | |
| 804 | } | |
| 781 | 805 | |
| 782 | 806 | Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix); |
| 783 | 807 | |
| ... | ... | @@ -861,7 +885,7 @@ int main(int argc, char **argv) { |
| 861 | 885 | |
| 862 | 886 | add_package(g, cur_pkg, g->root_package); |
| 863 | 887 | |
| 864 | if (cmd == CmdBuild) { | |
| 888 | if (cmd == CmdBuild || cmd == CmdRun) { | |
| 865 | 889 | codegen_set_emit_file_type(g, emit_file_type); |
| 866 | 890 | |
| 867 | 891 | for (size_t i = 0; i < objects.length; i += 1) { |
| ... | ... | @@ -874,6 +898,18 @@ int main(int argc, char **argv) { |
| 874 | 898 | codegen_link(g, out_file); |
| 875 | 899 | if (timing_info) |
| 876 | 900 | codegen_print_timing_report(g, stdout); |
| 901 | ||
| 902 | if (cmd == CmdRun) { | |
| 903 | ZigList<const char*> args = {0}; | |
| 904 | for (int i = runtime_args_start; i < argc; ++i) { | |
| 905 | args.append(argv[i]); | |
| 906 | } | |
| 907 | ||
| 908 | Termination term; | |
| 909 | os_spawn_process(buf_ptr(run_exec_path), args, &term); | |
| 910 | return term.code; | |
| 911 | } | |
| 912 | ||
| 877 | 913 | return EXIT_SUCCESS; |
| 878 | 914 | } else if (cmd == CmdTranslateC) { |
| 879 | 915 | codegen_translate_c(g, in_file_buf); |
src/os.cpp+90-11| ... | ... | @@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t; |
| 45 | 45 | #if defined(__MACH__) |
| 46 | 46 | #include <mach/clock.h> |
| 47 | 47 | #include <mach/mach.h> |
| 48 | #include <mach-o/dyld.h> | |
| 48 | 49 | #endif |
| 49 | 50 | |
| 50 | 51 | #if defined(ZIG_OS_WINDOWS) |
| ... | ... | @@ -57,10 +58,6 @@ static clock_serv_t cclock; |
| 57 | 58 | #include <errno.h> |
| 58 | 59 | #include <time.h> |
| 59 | 60 | |
| 60 | // these implementations are lazy. But who cares, we'll make a robust | |
| 61 | // implementation in the zig standard library and then this code all gets | |
| 62 | // deleted when we self-host. it works for now. | |
| 63 | ||
| 64 | 61 | #if defined(ZIG_OS_POSIX) |
| 65 | 62 | static void populate_termination(Termination *term, int status) { |
| 66 | 63 | if (WIFEXITED(status)) { |
| ... | ... | @@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) { |
| 291 | 288 | return; |
| 292 | 289 | } |
| 293 | 290 | |
| 294 | int os_fetch_file(FILE *f, Buf *out_buf) { | |
| 291 | int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { | |
| 295 | 292 | static const ssize_t buf_size = 0x2000; |
| 296 | 293 | buf_resize(out_buf, buf_size); |
| 297 | 294 | ssize_t actual_buf_len = 0; |
| 295 | ||
| 296 | bool first_read = true; | |
| 297 | ||
| 298 | 298 | for (;;) { |
| 299 | 299 | size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f); |
| 300 | 300 | actual_buf_len += amt_read; |
| 301 | ||
| 302 | if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) { | |
| 303 | size_t i = 0; | |
| 304 | while (true) { | |
| 305 | if (i > buf_len(out_buf)) { | |
| 306 | zig_panic("shebang line exceeded %zd characters", buf_size); | |
| 307 | } | |
| 308 | ||
| 309 | size_t current_pos = i; | |
| 310 | i += 1; | |
| 311 | ||
| 312 | if (out_buf->list.at(current_pos) == '\n') { | |
| 313 | break; | |
| 314 | } | |
| 315 | } | |
| 316 | ||
| 317 | ZigList<char> *list = &out_buf->list; | |
| 318 | memmove(list->items, list->items + i, list->length - i); | |
| 319 | list->length -= i; | |
| 320 | ||
| 321 | actual_buf_len -= i; | |
| 322 | } | |
| 323 | ||
| 301 | 324 | if (amt_read != buf_size) { |
| 302 | 325 | if (feof(f)) { |
| 303 | 326 | buf_resize(out_buf, actual_buf_len); |
| ... | ... | @@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) { |
| 308 | 331 | } |
| 309 | 332 | |
| 310 | 333 | buf_resize(out_buf, actual_buf_len + buf_size); |
| 334 | first_read = false; | |
| 311 | 335 | } |
| 312 | 336 | zig_unreachable(); |
| 313 | 337 | } |
| ... | ... | @@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args, |
| 377 | 401 | |
| 378 | 402 | FILE *stdout_f = fdopen(stdout_pipe[0], "rb"); |
| 379 | 403 | FILE *stderr_f = fdopen(stderr_pipe[0], "rb"); |
| 380 | os_fetch_file(stdout_f, out_stdout); | |
| 381 | os_fetch_file(stderr_f, out_stderr); | |
| 404 | os_fetch_file(stdout_f, out_stdout, false); | |
| 405 | os_fetch_file(stderr_f, out_stderr, false); | |
| 382 | 406 | |
| 383 | 407 | fclose(stdout_f); |
| 384 | 408 | fclose(stderr_f); |
| ... | ... | @@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) { |
| 591 | 615 | } |
| 592 | 616 | } |
| 593 | 617 | |
| 594 | int os_fetch_file_path(Buf *full_path, Buf *out_contents) { | |
| 618 | int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { | |
| 595 | 619 | FILE *f = fopen(buf_ptr(full_path), "rb"); |
| 596 | 620 | if (!f) { |
| 597 | 621 | switch (errno) { |
| ... | ... | @@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| 610 | 634 | return ErrorFileSystem; |
| 611 | 635 | } |
| 612 | 636 | } |
| 613 | int result = os_fetch_file(f, out_contents); | |
| 637 | int result = os_fetch_file(f, out_contents, skip_shebang); | |
| 614 | 638 | fclose(f); |
| 615 | 639 | return result; |
| 616 | 640 | } |
| ... | ... | @@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) { |
| 783 | 807 | #endif |
| 784 | 808 | } |
| 785 | 809 | |
| 810 | #if defined(ZIG_OS_POSIX) | |
| 811 | int os_get_global_cache_directory(Buf *out_tmp_path) { | |
| 812 | const char *tmp_dir = getenv("TMPDIR"); | |
| 813 | if (!tmp_dir) { | |
| 814 | tmp_dir = P_tmpdir; | |
| 815 | } | |
| 816 | ||
| 817 | Buf *tmp_dir_buf = buf_create_from_str(tmp_dir); | |
| 818 | Buf *cache_dirname_buf = buf_create_from_str("zig-cache"); | |
| 819 | ||
| 820 | buf_resize(out_tmp_path, 0); | |
| 821 | os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path); | |
| 822 | ||
| 823 | buf_deinit(tmp_dir_buf); | |
| 824 | buf_deinit(cache_dirname_buf); | |
| 825 | return 0; | |
| 826 | } | |
| 827 | #endif | |
| 828 | ||
| 829 | #if defined(ZIG_OS_WINDOWS) | |
| 830 | int os_get_global_cache_directory(Buf *out_tmp_path) { | |
| 831 | char tmp_dir[MAX_PATH + 1]; | |
| 832 | if (GetTempPath(MAX_PATH, tmp_dir) == 0) { | |
| 833 | zig_panic("GetTempPath failed"); | |
| 834 | } | |
| 835 | ||
| 836 | Buf *tmp_dir_buf = buf_create_from_str(tmp_dir); | |
| 837 | Buf *cache_dirname_buf = buf_create_from_str("zig-cache"); | |
| 838 | ||
| 839 | buf_resize(out_tmp_path, 0); | |
| 840 | os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path); | |
| 841 | ||
| 842 | buf_deinit(tmp_dir_buf); | |
| 843 | buf_deinit(cache_dirname_buf); | |
| 844 | return 0; | |
| 845 | } | |
| 846 | #endif | |
| 847 | ||
| 786 | 848 | int os_delete_file(Buf *path) { |
| 787 | 849 | if (remove(buf_ptr(path))) { |
| 788 | 850 | return ErrorFileSystem; |
| ... | ... | @@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) { |
| 927 | 989 | } |
| 928 | 990 | |
| 929 | 991 | #elif defined(ZIG_OS_DARWIN) |
| 930 | return ErrorFileNotFound; | |
| 992 | uint32_t u32_len = 0; | |
| 993 | int ret1 = _NSGetExecutablePath(nullptr, &u32_len); | |
| 994 | assert(ret1 != 0); | |
| 995 | buf_resize(out_path, u32_len); | |
| 996 | int ret2 = _NSGetExecutablePath(buf_ptr(out_path), &u32_len); | |
| 997 | assert(ret2 == 0); | |
| 998 | return 0; | |
| 931 | 999 | #elif defined(ZIG_OS_LINUX) |
| 932 | return ErrorFileNotFound; | |
| 1000 | buf_resize(out_path, 256); | |
| 1001 | for (;;) { | |
| 1002 | ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path)); | |
| 1003 | if (amt == -1) { | |
| 1004 | return ErrorUnexpected; | |
| 1005 | } | |
| 1006 | if (amt == (ssize_t)buf_len(out_path)) { | |
| 1007 | buf_resize(out_path, buf_len(out_path) * 2); | |
| 1008 | continue; | |
| 1009 | } | |
| 1010 | return 0; | |
| 1011 | } | |
| 933 | 1012 | #endif |
| 934 | 1013 | return ErrorFileNotFound; |
| 935 | 1014 | } |
src/os.hpp+4-2| ... | ... | @@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path); |
| 51 | 51 | void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path); |
| 52 | 52 | bool os_path_is_absolute(Buf *path); |
| 53 | 53 | |
| 54 | int os_get_global_cache_directory(Buf *out_tmp_path); | |
| 55 | ||
| 54 | 56 | int os_make_path(Buf *path); |
| 55 | 57 | int os_make_dir(Buf *path); |
| 56 | 58 | |
| 57 | 59 | void os_write_file(Buf *full_path, Buf *contents); |
| 58 | 60 | int os_copy_file(Buf *src_path, Buf *dest_path); |
| 59 | 61 | |
| 60 | int os_fetch_file(FILE *file, Buf *out_contents); | |
| 61 | int os_fetch_file_path(Buf *full_path, Buf *out_contents); | |
| 62 | int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); | |
| 63 | int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); | |
| 62 | 64 | |
| 63 | 65 | int os_get_cwd(Buf *out_cwd); |
| 64 | 66 |
src/parser.cpp+92-70| ... | ... | @@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 705 | 705 | } |
| 706 | 706 | |
| 707 | 707 | /* |
| 708 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | |
| 708 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType | |
| 709 | 709 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" |
| 710 | 710 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" |
| 711 | 711 | */ |
| ... | ... | @@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 774 | 774 | AstNode *node = ast_create_node(pc, NodeTypeSuspend, token); |
| 775 | 775 | *token_index += 1; |
| 776 | 776 | return node; |
| 777 | } else if (token->id == TokenIdKeywordPromise) { | |
| 778 | AstNode *node = ast_create_node(pc, NodeTypePromiseType, token); | |
| 779 | *token_index += 1; | |
| 780 | Token *arrow_tok = &pc->tokens->at(*token_index); | |
| 781 | if (arrow_tok->id == TokenIdArrow) { | |
| 782 | *token_index += 1; | |
| 783 | node->data.promise_type.payload_type = ast_parse_type_expr(pc, token_index, true); | |
| 784 | } | |
| 785 | return node; | |
| 777 | 786 | } else if (token->id == TokenIdKeywordError) { |
| 778 | 787 | Token *next_token = &pc->tokens->at(*token_index + 1); |
| 779 | 788 | if (next_token->id == TokenIdLBrace) { |
| ... | ... | @@ -955,8 +964,68 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde |
| 955 | 964 | } |
| 956 | 965 | } |
| 957 | 966 | |
| 967 | static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index, Token *fn_token, | |
| 968 | AstNode *async_allocator_type_node, CallingConvention cc, bool is_extern, VisibMod visib_mod) | |
| 969 | { | |
| 970 | AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); | |
| 971 | node->data.fn_proto.visib_mod = visib_mod; | |
| 972 | node->data.fn_proto.cc = cc; | |
| 973 | node->data.fn_proto.is_extern = is_extern; | |
| 974 | node->data.fn_proto.async_allocator_type = async_allocator_type_node; | |
| 975 | ||
| 976 | Token *fn_name = &pc->tokens->at(*token_index); | |
| 977 | ||
| 978 | if (fn_name->id == TokenIdSymbol) { | |
| 979 | *token_index += 1; | |
| 980 | node->data.fn_proto.name = token_buf(fn_name); | |
| 981 | } else { | |
| 982 | node->data.fn_proto.name = nullptr; | |
| 983 | } | |
| 984 | ||
| 985 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | |
| 986 | ||
| 987 | Token *next_token = &pc->tokens->at(*token_index); | |
| 988 | if (next_token->id == TokenIdKeywordAlign) { | |
| 989 | *token_index += 1; | |
| 990 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 991 | ||
| 992 | node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true); | |
| 993 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 994 | next_token = &pc->tokens->at(*token_index); | |
| 995 | } | |
| 996 | if (next_token->id == TokenIdKeywordSection) { | |
| 997 | *token_index += 1; | |
| 998 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 999 | ||
| 1000 | node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true); | |
| 1001 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 1002 | next_token = &pc->tokens->at(*token_index); | |
| 1003 | } | |
| 1004 | if (next_token->id == TokenIdKeywordVar) { | |
| 1005 | node->data.fn_proto.return_var_token = next_token; | |
| 1006 | *token_index += 1; | |
| 1007 | next_token = &pc->tokens->at(*token_index); | |
| 1008 | } else { | |
| 1009 | if (next_token->id == TokenIdKeywordError) { | |
| 1010 | Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1); | |
| 1011 | if (maybe_lbrace_tok->id == TokenIdLBrace) { | |
| 1012 | *token_index += 1; | |
| 1013 | node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token); | |
| 1014 | return node; | |
| 1015 | } | |
| 1016 | } else if (next_token->id == TokenIdBang) { | |
| 1017 | *token_index += 1; | |
| 1018 | node->data.fn_proto.auto_err_set = true; | |
| 1019 | next_token = &pc->tokens->at(*token_index); | |
| 1020 | } | |
| 1021 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true); | |
| 1022 | } | |
| 1023 | ||
| 1024 | return node; | |
| 1025 | } | |
| 1026 | ||
| 958 | 1027 | /* |
| 959 | SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 1028 | SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 960 | 1029 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 961 | 1030 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 962 | 1031 | SliceExpression = "[" Expression ".." option(Expression) "]" |
| ... | ... | @@ -972,19 +1041,25 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 972 | 1041 | |
| 973 | 1042 | AstNode *allocator_expr_node = nullptr; |
| 974 | 1043 | Token *async_lparen_tok = &pc->tokens->at(*token_index); |
| 975 | if (async_lparen_tok->id == TokenIdLParen) { | |
| 1044 | if (async_lparen_tok->id == TokenIdCmpLessThan) { | |
| 976 | 1045 | *token_index += 1; |
| 977 | allocator_expr_node = ast_parse_expression(pc, token_index, true); | |
| 978 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 1046 | allocator_expr_node = ast_parse_prefix_op_expr(pc, token_index, true); | |
| 1047 | ast_eat_token(pc, token_index, TokenIdCmpGreaterThan); | |
| 979 | 1048 | } |
| 980 | 1049 | |
| 981 | AstNode *fn_ref_expr_node = ast_parse_primary_expr(pc, token_index, true); | |
| 982 | Token *lparen_tok = ast_eat_token(pc, token_index, TokenIdLParen); | |
| 983 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, lparen_tok); | |
| 1050 | Token *fncall_token = &pc->tokens->at(*token_index); | |
| 1051 | if (fncall_token->id == TokenIdKeywordFn) { | |
| 1052 | *token_index += 1; | |
| 1053 | return ast_parse_fn_proto_partial(pc, token_index, fncall_token, allocator_expr_node, CallingConventionAsync, | |
| 1054 | false, VisibModPrivate); | |
| 1055 | } | |
| 1056 | AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true); | |
| 1057 | if (node->type != NodeTypeFnCallExpr) { | |
| 1058 | ast_error(pc, fncall_token, "expected function call, found '%s'", token_name(fncall_token->id)); | |
| 1059 | } | |
| 984 | 1060 | node->data.fn_call_expr.is_async = true; |
| 985 | 1061 | node->data.fn_call_expr.async_allocator = allocator_expr_node; |
| 986 | node->data.fn_call_expr.fn_ref_expr = fn_ref_expr_node; | |
| 987 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); | |
| 1062 | assert(node->data.fn_call_expr.fn_ref_expr != nullptr); | |
| 988 | 1063 | |
| 989 | 1064 | primary_expr = node; |
| 990 | 1065 | } else { |
| ... | ... | @@ -2433,9 +2508,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2433 | 2508 | } else if (first_token->id == TokenIdKeywordAsync) { |
| 2434 | 2509 | *token_index += 1; |
| 2435 | 2510 | Token *next_token = &pc->tokens->at(*token_index); |
| 2436 | if (next_token->id == TokenIdLParen) { | |
| 2511 | if (next_token->id == TokenIdCmpLessThan) { | |
| 2512 | *token_index += 1; | |
| 2437 | 2513 | async_allocator_type_node = ast_parse_type_expr(pc, token_index, true); |
| 2438 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2514 | ast_eat_token(pc, token_index, TokenIdCmpGreaterThan); | |
| 2439 | 2515 | } |
| 2440 | 2516 | fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); |
| 2441 | 2517 | cc = CallingConventionAsync; |
| ... | ... | @@ -2469,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2469 | 2545 | return nullptr; |
| 2470 | 2546 | } |
| 2471 | 2547 | |
| 2472 | AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); | |
| 2473 | node->data.fn_proto.visib_mod = visib_mod; | |
| 2474 | node->data.fn_proto.cc = cc; | |
| 2475 | node->data.fn_proto.is_extern = is_extern; | |
| 2476 | node->data.fn_proto.async_allocator_type = async_allocator_type_node; | |
| 2477 | ||
| 2478 | Token *fn_name = &pc->tokens->at(*token_index); | |
| 2479 | ||
| 2480 | if (fn_name->id == TokenIdSymbol) { | |
| 2481 | *token_index += 1; | |
| 2482 | node->data.fn_proto.name = token_buf(fn_name); | |
| 2483 | } else { | |
| 2484 | node->data.fn_proto.name = nullptr; | |
| 2485 | } | |
| 2486 | ||
| 2487 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | |
| 2488 | ||
| 2489 | Token *next_token = &pc->tokens->at(*token_index); | |
| 2490 | if (next_token->id == TokenIdKeywordAlign) { | |
| 2491 | *token_index += 1; | |
| 2492 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 2493 | ||
| 2494 | node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true); | |
| 2495 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2496 | next_token = &pc->tokens->at(*token_index); | |
| 2497 | } | |
| 2498 | if (next_token->id == TokenIdKeywordSection) { | |
| 2499 | *token_index += 1; | |
| 2500 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 2501 | ||
| 2502 | node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true); | |
| 2503 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2504 | next_token = &pc->tokens->at(*token_index); | |
| 2505 | } | |
| 2506 | if (next_token->id == TokenIdKeywordVar) { | |
| 2507 | node->data.fn_proto.return_var_token = next_token; | |
| 2508 | *token_index += 1; | |
| 2509 | next_token = &pc->tokens->at(*token_index); | |
| 2510 | } else { | |
| 2511 | if (next_token->id == TokenIdKeywordError) { | |
| 2512 | Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1); | |
| 2513 | if (maybe_lbrace_tok->id == TokenIdLBrace) { | |
| 2514 | *token_index += 1; | |
| 2515 | node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token); | |
| 2516 | return node; | |
| 2517 | } | |
| 2518 | } else if (next_token->id == TokenIdBang) { | |
| 2519 | *token_index += 1; | |
| 2520 | node->data.fn_proto.auto_err_set = true; | |
| 2521 | next_token = &pc->tokens->at(*token_index); | |
| 2522 | } | |
| 2523 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true); | |
| 2524 | } | |
| 2525 | ||
| 2526 | return node; | |
| 2548 | return ast_parse_fn_proto_partial(pc, token_index, fn_token, async_allocator_type_node, cc, is_extern, visib_mod); | |
| 2527 | 2549 | } |
| 2528 | 2550 | |
| 2529 | 2551 | /* |
| ... | ... | @@ -2901,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2901 | 2923 | visit_field(&node->data.fn_def.fn_proto, visit, context); |
| 2902 | 2924 | visit_field(&node->data.fn_def.body, visit, context); |
| 2903 | 2925 | break; |
| 2904 | case NodeTypeFnDecl: | |
| 2905 | visit_field(&node->data.fn_decl.fn_proto, visit, context); | |
| 2906 | break; | |
| 2907 | 2926 | case NodeTypeParamDecl: |
| 2908 | 2927 | visit_field(&node->data.param_decl.type, visit, context); |
| 2909 | 2928 | break; |
| ... | ... | @@ -3068,6 +3087,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3068 | 3087 | visit_field(&node->data.array_type.child_type, visit, context); |
| 3069 | 3088 | visit_field(&node->data.array_type.align_expr, visit, context); |
| 3070 | 3089 | break; |
| 3090 | case NodeTypePromiseType: | |
| 3091 | visit_field(&node->data.promise_type.payload_type, visit, context); | |
| 3092 | break; | |
| 3071 | 3093 | case NodeTypeErrorType: |
| 3072 | 3094 | // none |
| 3073 | 3095 | break; |
src/parser.hpp-1| ... | ... | @@ -16,7 +16,6 @@ ATTRIBUTE_PRINTF(2, 3) |
| 16 | 16 | void ast_token_error(Token *token, const char *format, ...); |
| 17 | 17 | |
| 18 | 18 | |
| 19 | // This function is provided by generated code, generated by parsergen.cpp | |
| 20 | 19 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color); |
| 21 | 20 | |
| 22 | 21 | void ast_print(AstNode *node, int indent); |
src/target.cpp+4| ... | ... | @@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) { |
| 863 | 863 | env == ZigLLVM_GNUX32) |
| 864 | 864 | { |
| 865 | 865 | return buf_create_from_str("/libx32/ld-linux-x32.so.2"); |
| 866 | } else if (arch == ZigLLVM_x86_64 && | |
| 867 | (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF)) | |
| 868 | { | |
| 869 | return buf_create_from_str("/lib/ld-musl-x86_64.so.1"); | |
| 866 | 870 | } else { |
| 867 | 871 | return buf_create_from_str("/lib64/ld-linux-x86-64.so.2"); |
| 868 | 872 | } |
src/tokenizer.cpp+2| ... | ... | @@ -135,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = { |
| 135 | 135 | {"null", TokenIdKeywordNull}, |
| 136 | 136 | {"or", TokenIdKeywordOr}, |
| 137 | 137 | {"packed", TokenIdKeywordPacked}, |
| 138 | {"promise", TokenIdKeywordPromise}, | |
| 138 | 139 | {"pub", TokenIdKeywordPub}, |
| 139 | 140 | {"resume", TokenIdKeywordResume}, |
| 140 | 141 | {"return", TokenIdKeywordReturn}, |
| ... | ... | @@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) { |
| 1558 | 1559 | case TokenIdKeywordNull: return "null"; |
| 1559 | 1560 | case TokenIdKeywordOr: return "or"; |
| 1560 | 1561 | case TokenIdKeywordPacked: return "packed"; |
| 1562 | case TokenIdKeywordPromise: return "promise"; | |
| 1561 | 1563 | case TokenIdKeywordPub: return "pub"; |
| 1562 | 1564 | case TokenIdKeywordReturn: return "return"; |
| 1563 | 1565 | case TokenIdKeywordSection: return "section"; |
src/tokenizer.hpp+1| ... | ... | @@ -76,6 +76,7 @@ enum TokenId { |
| 76 | 76 | TokenIdKeywordNull, |
| 77 | 77 | TokenIdKeywordOr, |
| 78 | 78 | TokenIdKeywordPacked, |
| 79 | TokenIdKeywordPromise, | |
| 79 | 80 | TokenIdKeywordPub, |
| 80 | 81 | TokenIdKeywordResume, |
| 81 | 82 | TokenIdKeywordReturn, |
std/buf_map.zig+34-17| ... | ... | @@ -1,6 +1,8 @@ |
| 1 | const HashMap = @import("hash_map.zig").HashMap; | |
| 2 | const mem = @import("mem.zig"); | |
| 1 | const std = @import("index.zig"); | |
| 2 | const HashMap = std.HashMap; | |
| 3 | const mem = std.mem; | |
| 3 | 4 | const Allocator = mem.Allocator; |
| 5 | const assert = std.debug.assert; | |
| 4 | 6 | |
| 5 | 7 | /// BufMap copies keys and values before they go into the map, and |
| 6 | 8 | /// frees them when they get removed. |
| ... | ... | @@ -28,18 +30,12 @@ pub const BufMap = struct { |
| 28 | 30 | } |
| 29 | 31 | |
| 30 | 32 | pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void { |
| 31 | if (self.hash_map.get(key)) |entry| { | |
| 32 | const value_copy = try self.copy(value); | |
| 33 | errdefer self.free(value_copy); | |
| 34 | _ = try self.hash_map.put(key, value_copy); | |
| 35 | self.free(entry.value); | |
| 36 | } else { | |
| 37 | const key_copy = try self.copy(key); | |
| 38 | errdefer self.free(key_copy); | |
| 39 | const value_copy = try self.copy(value); | |
| 40 | errdefer self.free(value_copy); | |
| 41 | _ = try self.hash_map.put(key_copy, value_copy); | |
| 42 | } | |
| 33 | self.delete(key); | |
| 34 | const key_copy = try self.copy(key); | |
| 35 | errdefer self.free(key_copy); | |
| 36 | const value_copy = try self.copy(value); | |
| 37 | errdefer self.free(value_copy); | |
| 38 | _ = try self.hash_map.put(key_copy, value_copy); | |
| 43 | 39 | } |
| 44 | 40 | |
| 45 | 41 | pub fn get(self: &BufMap, key: []const u8) ?[]const u8 { |
| ... | ... | @@ -66,8 +62,29 @@ pub const BufMap = struct { |
| 66 | 62 | } |
| 67 | 63 | |
| 68 | 64 | fn copy(self: &BufMap, value: []const u8) ![]const u8 { |
| 69 | const result = try self.hash_map.allocator.alloc(u8, value.len); | |
| 70 | mem.copy(u8, result, value); | |
| 71 | return result; | |
| 65 | return mem.dupe(self.hash_map.allocator, u8, value); | |
| 72 | 66 | } |
| 73 | 67 | }; |
| 68 | ||
| 69 | test "BufMap" { | |
| 70 | var direct_allocator = std.heap.DirectAllocator.init(); | |
| 71 | defer direct_allocator.deinit(); | |
| 72 | ||
| 73 | var bufmap = BufMap.init(&direct_allocator.allocator); | |
| 74 | defer bufmap.deinit(); | |
| 75 | ||
| 76 | try bufmap.set("x", "1"); | |
| 77 | assert(mem.eql(u8, ??bufmap.get("x"), "1")); | |
| 78 | assert(1 == bufmap.count()); | |
| 79 | ||
| 80 | try bufmap.set("x", "2"); | |
| 81 | assert(mem.eql(u8, ??bufmap.get("x"), "2")); | |
| 82 | assert(1 == bufmap.count()); | |
| 83 | ||
| 84 | try bufmap.set("x", "3"); | |
| 85 | assert(mem.eql(u8, ??bufmap.get("x"), "3")); | |
| 86 | assert(1 == bufmap.count()); | |
| 87 | ||
| 88 | bufmap.delete("x"); | |
| 89 | assert(0 == bufmap.count()); | |
| 90 | } |
std/build.zig+11| ... | ... | @@ -1627,6 +1627,7 @@ pub const TestStep = struct { |
| 1627 | 1627 | filter: ?[]const u8, |
| 1628 | 1628 | target: Target, |
| 1629 | 1629 | exec_cmd_args: ?[]const ?[]const u8, |
| 1630 | include_dirs: ArrayList([]const u8), | |
| 1630 | 1631 | |
| 1631 | 1632 | pub fn init(builder: &Builder, root_src: []const u8) TestStep { |
| 1632 | 1633 | const step_name = builder.fmt("test {}", root_src); |
| ... | ... | @@ -1641,6 +1642,7 @@ pub const TestStep = struct { |
| 1641 | 1642 | .link_libs = BufSet.init(builder.allocator), |
| 1642 | 1643 | .target = Target { .Native = {} }, |
| 1643 | 1644 | .exec_cmd_args = null, |
| 1645 | .include_dirs = ArrayList([]const u8).init(builder.allocator), | |
| 1644 | 1646 | }; |
| 1645 | 1647 | } |
| 1646 | 1648 | |
| ... | ... | @@ -1648,6 +1650,10 @@ pub const TestStep = struct { |
| 1648 | 1650 | self.verbose = value; |
| 1649 | 1651 | } |
| 1650 | 1652 | |
| 1653 | pub fn addIncludeDir(self: &TestStep, path: []const u8) void { | |
| 1654 | self.include_dirs.append(path) catch unreachable; | |
| 1655 | } | |
| 1656 | ||
| 1651 | 1657 | pub fn setBuildMode(self: &TestStep, mode: builtin.Mode) void { |
| 1652 | 1658 | self.build_mode = mode; |
| 1653 | 1659 | } |
| ... | ... | @@ -1746,6 +1752,11 @@ pub const TestStep = struct { |
| 1746 | 1752 | } |
| 1747 | 1753 | } |
| 1748 | 1754 | |
| 1755 | for (self.include_dirs.toSliceConst()) |include_path| { | |
| 1756 | try zig_args.append("-isystem"); | |
| 1757 | try zig_args.append(builder.pathFromRoot(include_path)); | |
| 1758 | } | |
| 1759 | ||
| 1749 | 1760 | for (builder.include_paths.toSliceConst()) |include_path| { |
| 1750 | 1761 | try zig_args.append("-isystem"); |
| 1751 | 1762 | try zig_args.append(builder.pathFromRoot(include_path)); |
std/c/darwin.zig+18| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | extern "c" fn __error() &c_int; |
| 2 | 2 | pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int; |
| 3 | 3 | |
| 4 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize; | |
| 4 | 5 | |
| 5 | 6 | pub use @import("../os/darwin_errno.zig"); |
| 6 | 7 | |
| ... | ... | @@ -45,3 +46,20 @@ pub const Sigaction = extern struct { |
| 45 | 46 | sa_mask: sigset_t, |
| 46 | 47 | sa_flags: c_int, |
| 47 | 48 | }; |
| 49 | ||
| 50 | pub const dirent = extern struct { | |
| 51 | d_ino: usize, | |
| 52 | d_seekoff: usize, | |
| 53 | d_reclen: u16, | |
| 54 | d_namlen: u16, | |
| 55 | d_type: u8, | |
| 56 | d_name: u8, // field address is address of first byte of name | |
| 57 | }; | |
| 58 | ||
| 59 | pub const sockaddr = extern struct { | |
| 60 | sa_len: u8, | |
| 61 | sa_family: sa_family_t, | |
| 62 | sa_data: [14]u8, | |
| 63 | }; | |
| 64 | ||
| 65 | pub const sa_family_t = u8; |
std/c/index.zig+1| ... | ... | @@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o |
| 44 | 44 | pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int; |
| 45 | 45 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; |
| 46 | 46 | pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; |
| 47 | pub extern "c" fn rmdir(path: &const u8) c_int; | |
| 47 | 48 | |
| 48 | 49 | pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void; |
| 49 | 50 | pub extern "c" fn malloc(usize) ?&c_void; |
std/crypto/blake2.zig+20-2| ... | ... | @@ -84,7 +84,7 @@ fn Blake2s(comptime out_len: usize) type { return struct { |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | // Full middle blocks. |
| 87 | while (off + 64 < b.len) : (off += 64) { | |
| 87 | while (off + 64 <= b.len) : (off += 64) { | |
| 88 | 88 | d.t += 64; |
| 89 | 89 | d.round(b[off..off + 64], false); |
| 90 | 90 | } |
| ... | ... | @@ -229,6 +229,15 @@ test "blake2s256 streaming" { |
| 229 | 229 | htest.assertEqual(h2, out[0..]); |
| 230 | 230 | } |
| 231 | 231 | |
| 232 | test "blake2s256 aligned final" { | |
| 233 | var block = []u8 {0} ** Blake2s256.block_size; | |
| 234 | var out: [Blake2s256.digest_size]u8 = undefined; | |
| 235 | ||
| 236 | var h = Blake2s256.init(); | |
| 237 | h.update(block); | |
| 238 | h.final(out[0..]); | |
| 239 | } | |
| 240 | ||
| 232 | 241 | |
| 233 | 242 | ///////////////////// |
| 234 | 243 | // Blake2b |
| ... | ... | @@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct { |
| 305 | 314 | } |
| 306 | 315 | |
| 307 | 316 | // Full middle blocks. |
| 308 | while (off + 128 < b.len) : (off += 128) { | |
| 317 | while (off + 128 <= b.len) : (off += 128) { | |
| 309 | 318 | d.t += 128; |
| 310 | 319 | d.round(b[off..off + 128], false); |
| 311 | 320 | } |
| ... | ... | @@ -447,3 +456,12 @@ test "blake2b512 streaming" { |
| 447 | 456 | h.final(out[0..]); |
| 448 | 457 | htest.assertEqual(h2, out[0..]); |
| 449 | 458 | } |
| 459 | ||
| 460 | test "blake2b512 aligned final" { | |
| 461 | var block = []u8 {0} ** Blake2b512.block_size; | |
| 462 | var out: [Blake2b512.digest_size]u8 = undefined; | |
| 463 | ||
| 464 | var h = Blake2b512.init(); | |
| 465 | h.update(block); | |
| 466 | h.final(out[0..]); | |
| 467 | } |
std/crypto/hmac.zig created+81| ... | ... | @@ -0,0 +1,81 @@ |
| 1 | const std = @import("../index.zig"); | |
| 2 | const crypto = std.crypto; | |
| 3 | const debug = std.debug; | |
| 4 | const mem = std.mem; | |
| 5 | ||
| 6 | pub const HmacMd5 = Hmac(crypto.Md5); | |
| 7 | pub const HmacSha1 = Hmac(crypto.Sha1); | |
| 8 | pub const HmacSha256 = Hmac(crypto.Sha256); | |
| 9 | ||
| 10 | pub fn Hmac(comptime H: type) type { | |
| 11 | return struct { | |
| 12 | const digest_size = H.digest_size; | |
| 13 | ||
| 14 | pub fn hash(output: []u8, key: []const u8, message: []const u8) void { | |
| 15 | debug.assert(output.len >= H.digest_size); | |
| 16 | debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption | |
| 17 | var scratch: [H.block_size]u8 = undefined; | |
| 18 | ||
| 19 | // Normalize key length to block size of hash | |
| 20 | if (key.len > H.block_size) { | |
| 21 | H.hash(key, scratch[0..H.digest_size]); | |
| 22 | mem.set(u8, scratch[H.digest_size..H.block_size], 0); | |
| 23 | } else if (key.len < H.block_size) { | |
| 24 | mem.copy(u8, scratch[0..key.len], key); | |
| 25 | mem.set(u8, scratch[key.len..H.block_size], 0); | |
| 26 | } else { | |
| 27 | mem.copy(u8, scratch[0..], key); | |
| 28 | } | |
| 29 | ||
| 30 | var o_key_pad: [H.block_size]u8 = undefined; | |
| 31 | for (o_key_pad) |*b, i| { | |
| 32 | *b = scratch[i] ^ 0x5c; | |
| 33 | } | |
| 34 | ||
| 35 | var i_key_pad: [H.block_size]u8 = undefined; | |
| 36 | for (i_key_pad) |*b, i| { | |
| 37 | *b = scratch[i] ^ 0x36; | |
| 38 | } | |
| 39 | ||
| 40 | // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation | |
| 41 | var hmac = H.init(); | |
| 42 | hmac.update(i_key_pad[0..]); | |
| 43 | hmac.update(message); | |
| 44 | hmac.final(scratch[0..H.digest_size]); | |
| 45 | ||
| 46 | hmac.reset(); | |
| 47 | hmac.update(o_key_pad[0..]); | |
| 48 | hmac.update(scratch[0..H.digest_size]); | |
| 49 | hmac.final(output[0..H.digest_size]); | |
| 50 | } | |
| 51 | }; | |
| 52 | } | |
| 53 | ||
| 54 | const htest = @import("test.zig"); | |
| 55 | ||
| 56 | test "hmac md5" { | |
| 57 | var out: [crypto.Md5.digest_size]u8 = undefined; | |
| 58 | HmacMd5.hash(out[0..], "", ""); | |
| 59 | htest.assertEqual("74e6f7298a9c2d168935f58c001bad88", out[0..]); | |
| 60 | ||
| 61 | HmacMd5.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog"); | |
| 62 | htest.assertEqual("80070713463e7749b90c2dc24911e275", out[0..]); | |
| 63 | } | |
| 64 | ||
| 65 | test "hmac sha1" { | |
| 66 | var out: [crypto.Sha1.digest_size]u8 = undefined; | |
| 67 | HmacSha1.hash(out[0..], "", ""); | |
| 68 | htest.assertEqual("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", out[0..]); | |
| 69 | ||
| 70 | HmacSha1.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog"); | |
| 71 | htest.assertEqual("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", out[0..]); | |
| 72 | } | |
| 73 | ||
| 74 | test "hmac sha256" { | |
| 75 | var out: [crypto.Sha256.digest_size]u8 = undefined; | |
| 76 | HmacSha256.hash(out[0..], "", ""); | |
| 77 | htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]); | |
| 78 | ||
| 79 | HmacSha256.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog"); | |
| 80 | htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]); | |
| 81 | } |
std/crypto/index.zig+6| ... | ... | @@ -19,10 +19,16 @@ pub const Blake2s256 = blake2.Blake2s256; |
| 19 | 19 | pub const Blake2b384 = blake2.Blake2b384; |
| 20 | 20 | pub const Blake2b512 = blake2.Blake2b512; |
| 21 | 21 | |
| 22 | const hmac = @import("hmac.zig"); | |
| 23 | pub const HmacMd5 = hmac.HmacMd5; | |
| 24 | pub const HmacSha1 = hmac.Sha1; | |
| 25 | pub const HmacSha256 = hmac.Sha256; | |
| 26 | ||
| 22 | 27 | test "crypto" { |
| 23 | 28 | _ = @import("md5.zig"); |
| 24 | 29 | _ = @import("sha1.zig"); |
| 25 | 30 | _ = @import("sha2.zig"); |
| 26 | 31 | _ = @import("sha3.zig"); |
| 27 | 32 | _ = @import("blake2.zig"); |
| 33 | _ = @import("hmac.zig"); | |
| 28 | 34 | } |
std/crypto/md5.zig+10-1| ... | ... | @@ -59,7 +59,7 @@ pub const Md5 = struct { |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | // Full middle blocks. |
| 62 | while (off + 64 < b.len) : (off += 64) { | |
| 62 | while (off + 64 <= b.len) : (off += 64) { | |
| 63 | 63 | d.round(b[off..off + 64]); |
| 64 | 64 | } |
| 65 | 65 | |
| ... | ... | @@ -253,3 +253,12 @@ test "md5 streaming" { |
| 253 | 253 | |
| 254 | 254 | htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]); |
| 255 | 255 | } |
| 256 | ||
| 257 | test "md5 aligned final" { | |
| 258 | var block = []u8 {0} ** Md5.block_size; | |
| 259 | var out: [Md5.digest_size]u8 = undefined; | |
| 260 | ||
| 261 | var h = Md5.init(); | |
| 262 | h.update(block); | |
| 263 | h.final(out[0..]); | |
| 264 | } |
std/crypto/sha1.zig+10-1| ... | ... | @@ -60,7 +60,7 @@ pub const Sha1 = struct { |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | // Full middle blocks. |
| 63 | while (off + 64 < b.len) : (off += 64) { | |
| 63 | while (off + 64 <= b.len) : (off += 64) { | |
| 64 | 64 | d.round(b[off..off + 64]); |
| 65 | 65 | } |
| 66 | 66 | |
| ... | ... | @@ -284,3 +284,12 @@ test "sha1 streaming" { |
| 284 | 284 | h.final(out[0..]); |
| 285 | 285 | htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); |
| 286 | 286 | } |
| 287 | ||
| 288 | test "sha1 aligned final" { | |
| 289 | var block = []u8 {0} ** Sha1.block_size; | |
| 290 | var out: [Sha1.digest_size]u8 = undefined; | |
| 291 | ||
| 292 | var h = Sha1.init(); | |
| 293 | h.update(block); | |
| 294 | h.final(out[0..]); | |
| 295 | } |
std/crypto/sha2.zig+20-2| ... | ... | @@ -105,7 +105,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { return struct { |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | // Full middle blocks. |
| 108 | while (off + 64 < b.len) : (off += 64) { | |
| 108 | while (off + 64 <= b.len) : (off += 64) { | |
| 109 | 109 | d.round(b[off..off + 64]); |
| 110 | 110 | } |
| 111 | 111 | |
| ... | ... | @@ -319,6 +319,15 @@ test "sha256 streaming" { |
| 319 | 319 | htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); |
| 320 | 320 | } |
| 321 | 321 | |
| 322 | test "sha256 aligned final" { | |
| 323 | var block = []u8 {0} ** Sha256.block_size; | |
| 324 | var out: [Sha256.digest_size]u8 = undefined; | |
| 325 | ||
| 326 | var h = Sha256.init(); | |
| 327 | h.update(block); | |
| 328 | h.final(out[0..]); | |
| 329 | } | |
| 330 | ||
| 322 | 331 | |
| 323 | 332 | ///////////////////// |
| 324 | 333 | // Sha384 + Sha512 |
| ... | ... | @@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct { |
| 420 | 429 | } |
| 421 | 430 | |
| 422 | 431 | // Full middle blocks. |
| 423 | while (off + 128 < b.len) : (off += 128) { | |
| 432 | while (off + 128 <= b.len) : (off += 128) { | |
| 424 | 433 | d.round(b[off..off + 128]); |
| 425 | 434 | } |
| 426 | 435 | |
| ... | ... | @@ -669,3 +678,12 @@ test "sha512 streaming" { |
| 669 | 678 | h.final(out[0..]); |
| 670 | 679 | htest.assertEqual(h2, out[0..]); |
| 671 | 680 | } |
| 681 | ||
| 682 | test "sha512 aligned final" { | |
| 683 | var block = []u8 {0} ** Sha512.block_size; | |
| 684 | var out: [Sha512.digest_size]u8 = undefined; | |
| 685 | ||
| 686 | var h = Sha512.init(); | |
| 687 | h.update(block); | |
| 688 | h.final(out[0..]); | |
| 689 | } |
std/crypto/sha3.zig+18| ... | ... | @@ -217,6 +217,15 @@ test "sha3-256 streaming" { |
| 217 | 217 | htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | test "sha3-256 aligned final" { | |
| 221 | var block = []u8 {0} ** Sha3_256.block_size; | |
| 222 | var out: [Sha3_256.digest_size]u8 = undefined; | |
| 223 | ||
| 224 | var h = Sha3_256.init(); | |
| 225 | h.update(block); | |
| 226 | h.final(out[0..]); | |
| 227 | } | |
| 228 | ||
| 220 | 229 | test "sha3-384 single" { |
| 221 | 230 | const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"; |
| 222 | 231 | htest.assertEqualHash(Sha3_384, h1 , ""); |
| ... | ... | @@ -278,3 +287,12 @@ test "sha3-512 streaming" { |
| 278 | 287 | h.final(out[0..]); |
| 279 | 288 | htest.assertEqual(h2, out[0..]); |
| 280 | 289 | } |
| 290 | ||
| 291 | test "sha3-512 aligned final" { | |
| 292 | var block = []u8 {0} ** Sha3_512.block_size; | |
| 293 | var out: [Sha3_512.digest_size]u8 = undefined; | |
| 294 | ||
| 295 | var h = Sha3_512.init(); | |
| 296 | h.update(block); | |
| 297 | h.final(out[0..]); | |
| 298 | } |
std/endian.zig deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | const mem = @import("mem.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | ||
| 4 | pub fn swapIfLe(comptime T: type, x: T) T { | |
| 5 | return swapIf(builtin.Endian.Little, T, x); | |
| 6 | } | |
| 7 | ||
| 8 | pub fn swapIfBe(comptime T: type, x: T) T { | |
| 9 | return swapIf(builtin.Endian.Big, T, x); | |
| 10 | } | |
| 11 | ||
| 12 | pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) T { | |
| 13 | return if (builtin.endian == endian) swap(T, x) else x; | |
| 14 | } | |
| 15 | ||
| 16 | pub fn swap(comptime T: type, x: T) T { | |
| 17 | var buf: [@sizeOf(T)]u8 = undefined; | |
| 18 | mem.writeInt(buf[0..], x, builtin.Endian.Little); | |
| 19 | return mem.readInt(buf, T, builtin.Endian.Big); | |
| 20 | } | |
| 21 | ||
| 22 | test "swap" { | |
| 23 | const debug = @import("debug/index.zig"); | |
| 24 | debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE); | |
| 25 | } |
std/event.zig created+235| ... | ... | @@ -0,0 +1,235 @@ |
| 1 | const std = @import("index.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const assert = std.debug.assert; | |
| 4 | const event = this; | |
| 5 | const mem = std.mem; | |
| 6 | const posix = std.os.posix; | |
| 7 | ||
| 8 | pub const TcpServer = struct { | |
| 9 | handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void, | |
| 10 | ||
| 11 | loop: &Loop, | |
| 12 | sockfd: i32, | |
| 13 | accept_coro: ?promise, | |
| 14 | listen_address: std.net.Address, | |
| 15 | ||
| 16 | waiting_for_emfile_node: PromiseNode, | |
| 17 | ||
| 18 | const PromiseNode = std.LinkedList(promise).Node; | |
| 19 | ||
| 20 | pub fn init(loop: &Loop) !TcpServer { | |
| 21 | const sockfd = try std.os.posixSocket(posix.AF_INET, | |
| 22 | posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, | |
| 23 | posix.PROTO_tcp); | |
| 24 | errdefer std.os.close(sockfd); | |
| 25 | ||
| 26 | // TODO can't initialize handler coroutine here because we need well defined copy elision | |
| 27 | return TcpServer { | |
| 28 | .loop = loop, | |
| 29 | .sockfd = sockfd, | |
| 30 | .accept_coro = null, | |
| 31 | .handleRequestFn = undefined, | |
| 32 | .waiting_for_emfile_node = undefined, | |
| 33 | .listen_address = undefined, | |
| 34 | }; | |
| 35 | } | |
| 36 | ||
| 37 | pub fn listen(self: &TcpServer, address: &const std.net.Address, | |
| 38 | handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void | |
| 39 | { | |
| 40 | self.handleRequestFn = handleRequestFn; | |
| 41 | ||
| 42 | try std.os.posixBind(self.sockfd, &address.os_addr); | |
| 43 | try std.os.posixListen(self.sockfd, posix.SOMAXCONN); | |
| 44 | self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd)); | |
| 45 | ||
| 46 | self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self); | |
| 47 | errdefer cancel ??self.accept_coro; | |
| 48 | ||
| 49 | try self.loop.addFd(self.sockfd, ??self.accept_coro); | |
| 50 | errdefer self.loop.removeFd(self.sockfd); | |
| 51 | ||
| 52 | } | |
| 53 | ||
| 54 | pub fn deinit(self: &TcpServer) void { | |
| 55 | self.loop.removeFd(self.sockfd); | |
| 56 | if (self.accept_coro) |accept_coro| cancel accept_coro; | |
| 57 | std.os.close(self.sockfd); | |
| 58 | } | |
| 59 | ||
| 60 | pub async fn handler(self: &TcpServer) void { | |
| 61 | while (true) { | |
| 62 | var accepted_addr: std.net.Address = undefined; | |
| 63 | if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr, | |
| 64 | posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| | |
| 65 | { | |
| 66 | var socket = std.os.File.openHandle(accepted_fd); | |
| 67 | _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) { | |
| 68 | error.OutOfMemory => { | |
| 69 | socket.close(); | |
| 70 | continue; | |
| 71 | }, | |
| 72 | }; | |
| 73 | } else |err| switch (err) { | |
| 74 | error.WouldBlock => { | |
| 75 | suspend; // we will get resumed by epoll_wait in the event loop | |
| 76 | continue; | |
| 77 | }, | |
| 78 | error.ProcessFdQuotaExceeded => { | |
| 79 | errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node); | |
| 80 | suspend |p| { | |
| 81 | self.waiting_for_emfile_node = PromiseNode.init(p); | |
| 82 | std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node); | |
| 83 | } | |
| 84 | continue; | |
| 85 | }, | |
| 86 | error.ConnectionAborted, | |
| 87 | error.FileDescriptorClosed => continue, | |
| 88 | ||
| 89 | error.PageFault => unreachable, | |
| 90 | error.InvalidSyscall => unreachable, | |
| 91 | error.FileDescriptorNotASocket => unreachable, | |
| 92 | error.OperationNotSupported => unreachable, | |
| 93 | ||
| 94 | error.SystemFdQuotaExceeded, | |
| 95 | error.SystemResources, | |
| 96 | error.ProtocolFailure, | |
| 97 | error.BlockedByFirewall, | |
| 98 | error.Unexpected => { | |
| 99 | @panic("TODO handle this error"); | |
| 100 | }, | |
| 101 | } | |
| 102 | } | |
| 103 | } | |
| 104 | }; | |
| 105 | ||
| 106 | pub const Loop = struct { | |
| 107 | allocator: &mem.Allocator, | |
| 108 | epollfd: i32, | |
| 109 | keep_running: bool, | |
| 110 | ||
| 111 | fn init(allocator: &mem.Allocator) !Loop { | |
| 112 | const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC); | |
| 113 | return Loop { | |
| 114 | .keep_running = true, | |
| 115 | .allocator = allocator, | |
| 116 | .epollfd = epollfd, | |
| 117 | }; | |
| 118 | } | |
| 119 | ||
| 120 | pub fn addFd(self: &Loop, fd: i32, prom: promise) !void { | |
| 121 | var ev = std.os.linux.epoll_event { | |
| 122 | .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET, | |
| 123 | .data = std.os.linux.epoll_data { | |
| 124 | .ptr = @ptrToInt(prom), | |
| 125 | }, | |
| 126 | }; | |
| 127 | try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev); | |
| 128 | } | |
| 129 | ||
| 130 | pub fn removeFd(self: &Loop, fd: i32) void { | |
| 131 | std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {}; | |
| 132 | } | |
| 133 | ||
| 134 | async fn waitFd(self: &Loop, fd: i32) !void { | |
| 135 | defer self.removeFd(fd); | |
| 136 | suspend |p| { | |
| 137 | try self.addFd(fd, p); | |
| 138 | } | |
| 139 | } | |
| 140 | ||
| 141 | pub fn stop(self: &Loop) void { | |
| 142 | // TODO make atomic | |
| 143 | self.keep_running = false; | |
| 144 | // TODO activate an fd in the epoll set | |
| 145 | } | |
| 146 | ||
| 147 | pub fn run(self: &Loop) void { | |
| 148 | while (self.keep_running) { | |
| 149 | var events: [16]std.os.linux.epoll_event = undefined; | |
| 150 | const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1); | |
| 151 | for (events[0..count]) |ev| { | |
| 152 | const p = @intToPtr(promise, ev.data.ptr); | |
| 153 | resume p; | |
| 154 | } | |
| 155 | } | |
| 156 | } | |
| 157 | }; | |
| 158 | ||
| 159 | pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File { | |
| 160 | var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733 | |
| 161 | ||
| 162 | const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp); | |
| 163 | errdefer std.os.close(sockfd); | |
| 164 | ||
| 165 | try std.os.posixConnectAsync(sockfd, &address.os_addr); | |
| 166 | try await try async loop.waitFd(sockfd); | |
| 167 | try std.os.posixGetSockOptConnectError(sockfd); | |
| 168 | ||
| 169 | return std.os.File.openHandle(sockfd); | |
| 170 | } | |
| 171 | ||
| 172 | test "listen on a port, send bytes, receive bytes" { | |
| 173 | if (builtin.os != builtin.Os.linux) { | |
| 174 | // TODO build abstractions for other operating systems | |
| 175 | return; | |
| 176 | } | |
| 177 | const MyServer = struct { | |
| 178 | tcp_server: TcpServer, | |
| 179 | ||
| 180 | const Self = this; | |
| 181 | ||
| 182 | async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address, | |
| 183 | _socket: &const std.os.File) void | |
| 184 | { | |
| 185 | const self = @fieldParentPtr(Self, "tcp_server", tcp_server); | |
| 186 | var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733 | |
| 187 | defer socket.close(); | |
| 188 | const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) { | |
| 189 | error.OutOfMemory => @panic("unable to handle connection: out of memory"), | |
| 190 | }; | |
| 191 | (await next_handler) catch |err| { | |
| 192 | std.debug.panic("unable to handle connection: {}\n", err); | |
| 193 | }; | |
| 194 | suspend |p| { cancel p; } | |
| 195 | } | |
| 196 | ||
| 197 | async fn errorableHandler(self: &Self, _addr: &const std.net.Address, | |
| 198 | _socket: &const std.os.File) !void | |
| 199 | { | |
| 200 | const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733 | |
| 201 | var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733 | |
| 202 | ||
| 203 | var adapter = std.io.FileOutStream.init(&socket); | |
| 204 | var stream = &adapter.stream; | |
| 205 | try stream.print("hello from server\n"); | |
| 206 | } | |
| 207 | }; | |
| 208 | ||
| 209 | const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable; | |
| 210 | const addr = std.net.Address.initIp4(ip4addr, 0); | |
| 211 | ||
| 212 | var loop = try Loop.init(std.debug.global_allocator); | |
| 213 | var server = MyServer { | |
| 214 | .tcp_server = try TcpServer.init(&loop), | |
| 215 | }; | |
| 216 | defer server.tcp_server.deinit(); | |
| 217 | try server.tcp_server.listen(addr, MyServer.handler); | |
| 218 | ||
| 219 | const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address); | |
| 220 | defer cancel p; | |
| 221 | loop.run(); | |
| 222 | } | |
| 223 | ||
| 224 | async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void { | |
| 225 | errdefer @panic("test failure"); | |
| 226 | ||
| 227 | var socket_file = try await try async event.connect(loop, address); | |
| 228 | defer socket_file.close(); | |
| 229 | ||
| 230 | var buf: [512]u8 = undefined; | |
| 231 | const amt_read = try socket_file.read(buf[0..]); | |
| 232 | const msg = buf[0..amt_read]; | |
| 233 | assert(mem.eql(u8, msg, "hello from server\n")); | |
| 234 | loop.stop(); | |
| 235 | } |
std/fmt/index.zig+1-1| ... | ... | @@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned |
| 465 | 465 | return x; |
| 466 | 466 | } |
| 467 | 467 | |
| 468 | fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { | |
| 468 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { | |
| 469 | 469 | const value = switch (c) { |
| 470 | 470 | '0' ... '9' => c - '0', |
| 471 | 471 | 'A' ... 'Z' => c - 'A' + 10, |
std/hash/adler.zig created+112| ... | ... | @@ -0,0 +1,112 @@ |
| 1 | // Adler32 checksum. | |
| 2 | // | |
| 3 | // https://tools.ietf.org/html/rfc1950#section-9 | |
| 4 | // https://github.com/madler/zlib/blob/master/adler32.c | |
| 5 | ||
| 6 | const std = @import("../index.zig"); | |
| 7 | const debug = std.debug; | |
| 8 | ||
| 9 | pub const Adler32 = struct { | |
| 10 | const base = 65521; | |
| 11 | const nmax = 5552; | |
| 12 | ||
| 13 | adler: u32, | |
| 14 | ||
| 15 | pub fn init() Adler32 { | |
| 16 | return Adler32 { | |
| 17 | .adler = 1, | |
| 18 | }; | |
| 19 | } | |
| 20 | ||
| 21 | // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer | |
| 22 | // buffer inputs and should be much quicker. | |
| 23 | pub fn update(self: &Adler32, input: []const u8) void { | |
| 24 | var s1 = self.adler & 0xffff; | |
| 25 | var s2 = (self.adler >> 16) & 0xffff; | |
| 26 | ||
| 27 | if (input.len == 1) { | |
| 28 | s1 +%= input[0]; | |
| 29 | if (s1 >= base) { | |
| 30 | s1 -= base; | |
| 31 | } | |
| 32 | s2 +%= s1; | |
| 33 | if (s2 >= base) { | |
| 34 | s2 -= base; | |
| 35 | } | |
| 36 | } | |
| 37 | else if (input.len < 16) { | |
| 38 | for (input) |b| { | |
| 39 | s1 +%= b; | |
| 40 | s2 +%= s1; | |
| 41 | } | |
| 42 | if (s1 >= base) { | |
| 43 | s1 -= base; | |
| 44 | } | |
| 45 | ||
| 46 | s2 %= base; | |
| 47 | } | |
| 48 | else { | |
| 49 | var i: usize = 0; | |
| 50 | while (i + nmax <= input.len) : (i += nmax) { | |
| 51 | const n = nmax / 16; // note: 16 | nmax | |
| 52 | ||
| 53 | var rounds: usize = 0; | |
| 54 | while (rounds < n) : (rounds += 1) { | |
| 55 | comptime var j: usize = 0; | |
| 56 | inline while (j < 16) : (j += 1) { | |
| 57 | s1 +%= input[i + n * j]; | |
| 58 | s2 +%= s1; | |
| 59 | } | |
| 60 | } | |
| 61 | } | |
| 62 | ||
| 63 | if (i < input.len) { | |
| 64 | while (i + 16 <= input.len) : (i += 16) { | |
| 65 | comptime var j: usize = 0; | |
| 66 | inline while (j < 16) : (j += 1) { | |
| 67 | s1 +%= input[i + j]; | |
| 68 | s2 +%= s1; | |
| 69 | } | |
| 70 | } | |
| 71 | while (i < input.len) : (i += 1) { | |
| 72 | s1 +%= input[i]; | |
| 73 | s2 +%= s1; | |
| 74 | } | |
| 75 | ||
| 76 | s1 %= base; | |
| 77 | s2 %= base; | |
| 78 | } | |
| 79 | } | |
| 80 | ||
| 81 | self.adler = s1 | (s2 << 16); | |
| 82 | } | |
| 83 | ||
| 84 | pub fn final(self: &Adler32) u32 { | |
| 85 | return self.adler; | |
| 86 | } | |
| 87 | ||
| 88 | pub fn hash(input: []const u8) u32 { | |
| 89 | var c = Adler32.init(); | |
| 90 | c.update(input); | |
| 91 | return c.final(); | |
| 92 | } | |
| 93 | }; | |
| 94 | ||
| 95 | test "adler32 sanity" { | |
| 96 | debug.assert(Adler32.hash("a") == 0x620062); | |
| 97 | debug.assert(Adler32.hash("example") == 0xbc002ed); | |
| 98 | } | |
| 99 | ||
| 100 | test "adler32 long" { | |
| 101 | const long1 = []u8 {1} ** 1024; | |
| 102 | debug.assert(Adler32.hash(long1[0..]) == 0x06780401); | |
| 103 | ||
| 104 | const long2 = []u8 {1} ** 1025; | |
| 105 | debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402); | |
| 106 | } | |
| 107 | ||
| 108 | test "adler32 very long" { | |
| 109 | const long = []u8 {1} ** 5553; | |
| 110 | debug.assert(Adler32.hash(long[0..]) == 0x707f15b2); | |
| 111 | } | |
| 112 |
std/hash/crc.zig created+180| ... | ... | @@ -0,0 +1,180 @@ |
| 1 | // There are two implementations of CRC32 implemented with the following key characteristics: | |
| 2 | // | |
| 3 | // - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method. | |
| 4 | // | |
| 5 | // - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is | |
| 6 | // still moderately fast just slow relative to the slicing approach. | |
| 7 | ||
| 8 | const std = @import("../index.zig"); | |
| 9 | const debug = std.debug; | |
| 10 | ||
| 11 | pub const Polynomial = struct { | |
| 12 | const IEEE = 0xedb88320; | |
| 13 | const Castagnoli = 0x82f63b78; | |
| 14 | const Koopman = 0xeb31d82e; | |
| 15 | }; | |
| 16 | ||
| 17 | // IEEE is by far the most common CRC and so is aliased by default. | |
| 18 | pub const Crc32 = Crc32WithPoly(Polynomial.IEEE); | |
| 19 | ||
| 20 | // slicing-by-8 crc32 implementation. | |
| 21 | pub fn Crc32WithPoly(comptime poly: u32) type { | |
| 22 | return struct { | |
| 23 | const Self = this; | |
| 24 | const lookup_tables = comptime block: { | |
| 25 | @setEvalBranchQuota(20000); | |
| 26 | var tables: [8][256]u32 = undefined; | |
| 27 | ||
| 28 | for (tables[0]) |*e, i| { | |
| 29 | var crc = u32(i); | |
| 30 | var j: usize = 0; while (j < 8) : (j += 1) { | |
| 31 | if (crc & 1 == 1) { | |
| 32 | crc = (crc >> 1) ^ poly; | |
| 33 | } else { | |
| 34 | crc = (crc >> 1); | |
| 35 | } | |
| 36 | } | |
| 37 | *e = crc; | |
| 38 | } | |
| 39 | ||
| 40 | var i: usize = 0; | |
| 41 | while (i < 256) : (i += 1) { | |
| 42 | var crc = tables[0][i]; | |
| 43 | var j: usize = 1; while (j < 8) : (j += 1) { | |
| 44 | const index = @truncate(u8, crc); | |
| 45 | crc = tables[0][index] ^ (crc >> 8); | |
| 46 | tables[j][i] = crc; | |
| 47 | } | |
| 48 | } | |
| 49 | ||
| 50 | break :block tables; | |
| 51 | }; | |
| 52 | ||
| 53 | crc: u32, | |
| 54 | ||
| 55 | pub fn init() Self { | |
| 56 | return Self { | |
| 57 | .crc = 0xffffffff, | |
| 58 | }; | |
| 59 | } | |
| 60 | ||
| 61 | pub fn update(self: &Self, input: []const u8) void { | |
| 62 | var i: usize = 0; | |
| 63 | while (i + 8 <= input.len) : (i += 8) { | |
| 64 | const p = input[i..i+8]; | |
| 65 | ||
| 66 | // Unrolling this way gives ~50Mb/s increase | |
| 67 | self.crc ^= (u32(p[0]) << 0); | |
| 68 | self.crc ^= (u32(p[1]) << 8); | |
| 69 | self.crc ^= (u32(p[2]) << 16); | |
| 70 | self.crc ^= (u32(p[3]) << 24); | |
| 71 | ||
| 72 | self.crc = | |
| 73 | lookup_tables[0][p[7]] ^ | |
| 74 | lookup_tables[1][p[6]] ^ | |
| 75 | lookup_tables[2][p[5]] ^ | |
| 76 | lookup_tables[3][p[4]] ^ | |
| 77 | lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ | |
| 78 | lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ | |
| 79 | lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ | |
| 80 | lookup_tables[7][@truncate(u8, self.crc >> 0)]; | |
| 81 | } | |
| 82 | ||
| 83 | while (i < input.len) : (i += 1) { | |
| 84 | const index = @truncate(u8, self.crc) ^ input[i]; | |
| 85 | self.crc = (self.crc >> 8) ^ lookup_tables[0][index]; | |
| 86 | } | |
| 87 | } | |
| 88 | ||
| 89 | pub fn final(self: &Self) u32 { | |
| 90 | return ~self.crc; | |
| 91 | } | |
| 92 | ||
| 93 | pub fn hash(input: []const u8) u32 { | |
| 94 | var c = Self.init(); | |
| 95 | c.update(input); | |
| 96 | return c.final(); | |
| 97 | } | |
| 98 | }; | |
| 99 | } | |
| 100 | ||
| 101 | test "crc32 ieee" { | |
| 102 | const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE); | |
| 103 | ||
| 104 | debug.assert(Crc32Ieee.hash("") == 0x00000000); | |
| 105 | debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43); | |
| 106 | debug.assert(Crc32Ieee.hash("abc") == 0x352441c2); | |
| 107 | } | |
| 108 | ||
| 109 | test "crc32 castagnoli" { | |
| 110 | const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli); | |
| 111 | ||
| 112 | debug.assert(Crc32Castagnoli.hash("") == 0x00000000); | |
| 113 | debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330); | |
| 114 | debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7); | |
| 115 | } | |
| 116 | ||
| 117 | // half-byte lookup table implementation. | |
| 118 | pub fn Crc32SmallWithPoly(comptime poly: u32) type { | |
| 119 | return struct { | |
| 120 | const Self = this; | |
| 121 | const lookup_table = comptime block: { | |
| 122 | var table: [16]u32 = undefined; | |
| 123 | ||
| 124 | for (table) |*e, i| { | |
| 125 | var crc = u32(i * 16); | |
| 126 | var j: usize = 0; while (j < 8) : (j += 1) { | |
| 127 | if (crc & 1 == 1) { | |
| 128 | crc = (crc >> 1) ^ poly; | |
| 129 | } else { | |
| 130 | crc = (crc >> 1); | |
| 131 | } | |
| 132 | } | |
| 133 | *e = crc; | |
| 134 | } | |
| 135 | ||
| 136 | break :block table; | |
| 137 | }; | |
| 138 | ||
| 139 | crc: u32, | |
| 140 | ||
| 141 | pub fn init() Self { | |
| 142 | return Self { | |
| 143 | .crc = 0xffffffff, | |
| 144 | }; | |
| 145 | } | |
| 146 | ||
| 147 | pub fn update(self: &Self, input: []const u8) void { | |
| 148 | for (input) |b| { | |
| 149 | self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 0))] ^ (self.crc >> 4); | |
| 150 | self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 4))] ^ (self.crc >> 4); | |
| 151 | } | |
| 152 | } | |
| 153 | ||
| 154 | pub fn final(self: &Self) u32 { | |
| 155 | return ~self.crc; | |
| 156 | } | |
| 157 | ||
| 158 | pub fn hash(input: []const u8) u32 { | |
| 159 | var c = Self.init(); | |
| 160 | c.update(input); | |
| 161 | return c.final(); | |
| 162 | } | |
| 163 | }; | |
| 164 | } | |
| 165 | ||
| 166 | test "small crc32 ieee" { | |
| 167 | const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE); | |
| 168 | ||
| 169 | debug.assert(Crc32Ieee.hash("") == 0x00000000); | |
| 170 | debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43); | |
| 171 | debug.assert(Crc32Ieee.hash("abc") == 0x352441c2); | |
| 172 | } | |
| 173 | ||
| 174 | test "small crc32 castagnoli" { | |
| 175 | const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli); | |
| 176 | ||
| 177 | debug.assert(Crc32Castagnoli.hash("") == 0x00000000); | |
| 178 | debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330); | |
| 179 | debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7); | |
| 180 | } |
std/hash/fnv.zig created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | // FNV1a - Fowler-Noll-Vo hash function | |
| 2 | // | |
| 3 | // FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties. | |
| 4 | // | |
| 5 | // https://tools.ietf.org/html/draft-eastlake-fnv-14 | |
| 6 | ||
| 7 | const std = @import("../index.zig"); | |
| 8 | const debug = std.debug; | |
| 9 | ||
| 10 | pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5); | |
| 11 | pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325); | |
| 12 | pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d); | |
| 13 | ||
| 14 | fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type { | |
| 15 | return struct { | |
| 16 | const Self = this; | |
| 17 | ||
| 18 | value: T, | |
| 19 | ||
| 20 | pub fn init() Self { | |
| 21 | return Self { | |
| 22 | .value = offset, | |
| 23 | }; | |
| 24 | } | |
| 25 | ||
| 26 | pub fn update(self: &Self, input: []const u8) void { | |
| 27 | for (input) |b| { | |
| 28 | self.value ^= b; | |
| 29 | self.value *%= prime; | |
| 30 | } | |
| 31 | } | |
| 32 | ||
| 33 | pub fn final(self: &Self) T { | |
| 34 | return self.value; | |
| 35 | } | |
| 36 | ||
| 37 | pub fn hash(input: []const u8) T { | |
| 38 | var c = Self.init(); | |
| 39 | c.update(input); | |
| 40 | return c.final(); | |
| 41 | } | |
| 42 | }; | |
| 43 | } | |
| 44 | ||
| 45 | test "fnv1a-32" { | |
| 46 | debug.assert(Fnv1a_32.hash("") == 0x811c9dc5); | |
| 47 | debug.assert(Fnv1a_32.hash("a") == 0xe40c292c); | |
| 48 | debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968); | |
| 49 | } | |
| 50 | ||
| 51 | test "fnv1a-64" { | |
| 52 | debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325); | |
| 53 | debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); | |
| 54 | debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); | |
| 55 | } | |
| 56 | ||
| 57 | test "fnv1a-128" { | |
| 58 | debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); | |
| 59 | debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); | |
| 60 | } |
std/hash/index.zig created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | const adler = @import("adler.zig"); | |
| 2 | pub const Adler32 = adler.Adler32; | |
| 3 | ||
| 4 | // pub for polynomials + generic crc32 construction | |
| 5 | pub const crc = @import("crc.zig"); | |
| 6 | pub const Crc32 = crc.Crc32; | |
| 7 | ||
| 8 | const fnv = @import("fnv.zig"); | |
| 9 | pub const Fnv1a_32 = fnv.Fnv1a_32; | |
| 10 | pub const Fnv1a_64 = fnv.Fnv1a_64; | |
| 11 | pub const Fnv1a_128 = fnv.Fnv1a_128; | |
| 12 | ||
| 13 | const siphash = @import("siphash.zig"); | |
| 14 | pub const SipHash64 = siphash.SipHash64; | |
| 15 | pub const SipHash128 = siphash.SipHash128; | |
| 16 | ||
| 17 | test "hash" { | |
| 18 | _ = @import("adler.zig"); | |
| 19 | _ = @import("crc.zig"); | |
| 20 | _ = @import("fnv.zig"); | |
| 21 | _ = @import("siphash.zig"); | |
| 22 | } |
std/hash/siphash.zig created+320| ... | ... | @@ -0,0 +1,320 @@ |
| 1 | // Siphash | |
| 2 | // | |
| 3 | // SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance | |
| 4 | // against hash flooding DoS attacks. | |
| 5 | // | |
| 6 | // https://131002.net/siphash/ | |
| 7 | ||
| 8 | const std = @import("../index.zig"); | |
| 9 | const debug = std.debug; | |
| 10 | const math = std.math; | |
| 11 | const mem = std.mem; | |
| 12 | ||
| 13 | const Endian = @import("builtin").Endian; | |
| 14 | ||
| 15 | pub fn SipHash64(comptime c_rounds: usize, comptime d_rounds: usize) type { | |
| 16 | return SipHash(u64, c_rounds, d_rounds); | |
| 17 | } | |
| 18 | ||
| 19 | pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type { | |
| 20 | return SipHash(u128, c_rounds, d_rounds); | |
| 21 | } | |
| 22 | ||
| 23 | fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type { | |
| 24 | debug.assert(T == u64 or T == u128); | |
| 25 | debug.assert(c_rounds > 0 and d_rounds > 0); | |
| 26 | ||
| 27 | return struct { | |
| 28 | const Self = this; | |
| 29 | const digest_size = 64; | |
| 30 | const block_size = 64; | |
| 31 | ||
| 32 | v0: u64, | |
| 33 | v1: u64, | |
| 34 | v2: u64, | |
| 35 | v3: u64, | |
| 36 | ||
| 37 | // streaming cache | |
| 38 | buf: [8]u8, | |
| 39 | buf_len: usize, | |
| 40 | msg_len: u8, | |
| 41 | ||
| 42 | pub fn init(key: []const u8) Self { | |
| 43 | debug.assert(key.len >= 16); | |
| 44 | ||
| 45 | const k0 = mem.readInt(key[0..8], u64, Endian.Little); | |
| 46 | const k1 = mem.readInt(key[8..16], u64, Endian.Little); | |
| 47 | ||
| 48 | var d = Self { | |
| 49 | .v0 = k0 ^ 0x736f6d6570736575, | |
| 50 | .v1 = k1 ^ 0x646f72616e646f6d, | |
| 51 | .v2 = k0 ^ 0x6c7967656e657261, | |
| 52 | .v3 = k1 ^ 0x7465646279746573, | |
| 53 | ||
| 54 | .buf = undefined, | |
| 55 | .buf_len = 0, | |
| 56 | .msg_len = 0, | |
| 57 | }; | |
| 58 | ||
| 59 | if (T == u128) { | |
| 60 | d.v1 ^= 0xee; | |
| 61 | } | |
| 62 | ||
| 63 | return d; | |
| 64 | } | |
| 65 | ||
| 66 | pub fn update(d: &Self, b: []const u8) void { | |
| 67 | var off: usize = 0; | |
| 68 | ||
| 69 | // Partial from previous. | |
| 70 | if (d.buf_len != 0 and d.buf_len + b.len > 8) { | |
| 71 | off += 8 - d.buf_len; | |
| 72 | mem.copy(u8, d.buf[d.buf_len..], b[0..off]); | |
| 73 | d.round(d.buf[0..]); | |
| 74 | d.buf_len = 0; | |
| 75 | } | |
| 76 | ||
| 77 | // Full middle blocks. | |
| 78 | while (off + 8 <= b.len) : (off += 8) { | |
| 79 | d.round(b[off..off + 8]); | |
| 80 | } | |
| 81 | ||
| 82 | // Remainder for next pass. | |
| 83 | mem.copy(u8, d.buf[d.buf_len..], b[off..]); | |
| 84 | d.buf_len += u8(b[off..].len); | |
| 85 | d.msg_len +%= @truncate(u8, b.len); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn final(d: &Self) T { | |
| 89 | // Padding | |
| 90 | mem.set(u8, d.buf[d.buf_len..], 0); | |
| 91 | d.buf[7] = d.msg_len; | |
| 92 | d.round(d.buf[0..]); | |
| 93 | ||
| 94 | if (T == u128) { | |
| 95 | d.v2 ^= 0xee; | |
| 96 | } else { | |
| 97 | d.v2 ^= 0xff; | |
| 98 | } | |
| 99 | ||
| 100 | comptime var i: usize = 0; | |
| 101 | inline while (i < d_rounds) : (i += 1) { | |
| 102 | @inlineCall(sipRound, d); | |
| 103 | } | |
| 104 | ||
| 105 | const b1 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3; | |
| 106 | if (T == u64) { | |
| 107 | return b1; | |
| 108 | } | |
| 109 | ||
| 110 | d.v1 ^= 0xdd; | |
| 111 | ||
| 112 | comptime var j: usize = 0; | |
| 113 | inline while (j < d_rounds) : (j += 1) { | |
| 114 | @inlineCall(sipRound, d); | |
| 115 | } | |
| 116 | ||
| 117 | const b2 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3; | |
| 118 | return (u128(b2) << 64) | b1; | |
| 119 | } | |
| 120 | ||
| 121 | fn round(d: &Self, b: []const u8) void { | |
| 122 | debug.assert(b.len == 8); | |
| 123 | ||
| 124 | const m = mem.readInt(b[0..], u64, Endian.Little); | |
| 125 | d.v3 ^= m; | |
| 126 | ||
| 127 | comptime var i: usize = 0; | |
| 128 | inline while (i < c_rounds) : (i += 1) { | |
| 129 | @inlineCall(sipRound, d); | |
| 130 | } | |
| 131 | ||
| 132 | d.v0 ^= m; | |
| 133 | } | |
| 134 | ||
| 135 | fn sipRound(d: &Self) void { | |
| 136 | d.v0 +%= d.v1; | |
| 137 | d.v1 = math.rotl(u64, d.v1, u64(13)); | |
| 138 | d.v1 ^= d.v0; | |
| 139 | d.v0 = math.rotl(u64, d.v0, u64(32)); | |
| 140 | d.v2 +%= d.v3; | |
| 141 | d.v3 = math.rotl(u64, d.v3, u64(16)); | |
| 142 | d.v3 ^= d.v2; | |
| 143 | d.v0 +%= d.v3; | |
| 144 | d.v3 = math.rotl(u64, d.v3, u64(21)); | |
| 145 | d.v3 ^= d.v0; | |
| 146 | d.v2 +%= d.v1; | |
| 147 | d.v1 = math.rotl(u64, d.v1, u64(17)); | |
| 148 | d.v1 ^= d.v2; | |
| 149 | d.v2 = math.rotl(u64, d.v2, u64(32)); | |
| 150 | } | |
| 151 | ||
| 152 | pub fn hash(key: []const u8, input: []const u8) T { | |
| 153 | var c = Self.init(key); | |
| 154 | c.update(input); | |
| 155 | return c.final(); | |
| 156 | } | |
| 157 | }; | |
| 158 | } | |
| 159 | ||
| 160 | // Test vectors from reference implementation. | |
| 161 | // https://github.com/veorq/SipHash/blob/master/vectors.h | |
| 162 | const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; | |
| 163 | ||
| 164 | test "siphash64-2-4 sanity" { | |
| 165 | const vectors = [][]const u8 { | |
| 166 | "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // "" | |
| 167 | "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00" | |
| 168 | "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc | |
| 169 | "\x2d\x7e\xfb\xd7\x96\x66\x67\x85", | |
| 170 | "\xb7\x87\x71\x27\xe0\x94\x27\xcf", | |
| 171 | "\x8d\xa6\x99\xcd\x64\x55\x76\x18", | |
| 172 | "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb", | |
| 173 | "\x37\xd1\x01\x8b\xf5\x00\x02\xab", | |
| 174 | "\x62\x24\x93\x9a\x79\xf5\xf5\x93", | |
| 175 | "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e", | |
| 176 | "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a", | |
| 177 | "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4", | |
| 178 | "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75", | |
| 179 | "\x90\x3d\x84\xc0\x27\x56\xea\x14", | |
| 180 | "\xee\xf2\x7a\x8e\x90\xca\x23\xf7", | |
| 181 | "\xe5\x45\xbe\x49\x61\xca\x29\xa1", | |
| 182 | "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f", | |
| 183 | "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69", | |
| 184 | "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b", | |
| 185 | "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb", | |
| 186 | "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe", | |
| 187 | "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0", | |
| 188 | "\x88\x3e\xa3\xe3\x95\x67\x53\x93", | |
| 189 | "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8", | |
| 190 | "\x94\xaf\x49\xf6\xc6\x50\xad\xb8", | |
| 191 | "\xea\xb8\x85\x8a\xde\x92\xe1\xbc", | |
| 192 | "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17", | |
| 193 | "\xad\xcf\x6b\x07\x63\x61\x2e\x2f", | |
| 194 | "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde", | |
| 195 | "\x71\x65\x95\x87\x66\x50\xa2\xa6", | |
| 196 | "\x28\xef\x49\x5c\x53\xa3\x87\xad", | |
| 197 | "\x42\xc3\x41\xd8\xfa\x92\xd8\x32", | |
| 198 | "\xce\x7c\xf2\x72\x2f\x51\x27\x71", | |
| 199 | "\xe3\x78\x59\xf9\x46\x23\xf3\xa7", | |
| 200 | "\x38\x12\x05\xbb\x1a\xb0\xe0\x12", | |
| 201 | "\xae\x97\xa1\x0f\xd4\x34\xe0\x15", | |
| 202 | "\xb4\xa3\x15\x08\xbe\xff\x4d\x31", | |
| 203 | "\x81\x39\x62\x29\xf0\x90\x79\x02", | |
| 204 | "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca", | |
| 205 | "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a", | |
| 206 | "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e", | |
| 207 | "\x92\x59\x58\xfc\xd6\x42\x0c\xad", | |
| 208 | "\xa9\x15\xc2\x9b\xc8\x06\x73\x18", | |
| 209 | "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4", | |
| 210 | "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9", | |
| 211 | "\x87\x57\x75\x19\x04\x8f\x53\xa9", | |
| 212 | "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb", | |
| 213 | "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0", | |
| 214 | "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6", | |
| 215 | "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7", | |
| 216 | "\x72\xfe\x52\x97\x5a\x43\x64\xee", | |
| 217 | "\x5a\x16\x45\xb2\x76\xd5\x92\xa1", | |
| 218 | "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a", | |
| 219 | "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81", | |
| 220 | "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f", | |
| 221 | "\x99\x24\xa4\x3c\xc1\x31\x57\x24", | |
| 222 | "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7", | |
| 223 | "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea", | |
| 224 | "\x13\x50\x79\xa3\x23\x1c\xe6\x60", | |
| 225 | "\x93\x2b\x28\x46\xe4\xd7\x06\x66", | |
| 226 | "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c", | |
| 227 | "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f", | |
| 228 | "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5", | |
| 229 | "\x72\x45\x06\xeb\x4c\x32\x8a\x95", | |
| 230 | }; | |
| 231 | ||
| 232 | const siphash = SipHash64(2, 4); | |
| 233 | ||
| 234 | var buffer: [64]u8 = undefined; | |
| 235 | for (vectors) |vector, i| { | |
| 236 | buffer[i] = u8(i); | |
| 237 | ||
| 238 | const expected = mem.readInt(vector, u64, Endian.Little); | |
| 239 | debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); | |
| 240 | } | |
| 241 | } | |
| 242 | ||
| 243 | test "siphash128-2-4 sanity" { | |
| 244 | const vectors = [][]const u8 { | |
| 245 | "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93", | |
| 246 | "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45", | |
| 247 | "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4", | |
| 248 | "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51", | |
| 249 | "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79", | |
| 250 | "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27", | |
| 251 | "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e", | |
| 252 | "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39", | |
| 253 | "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4", | |
| 254 | "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed", | |
| 255 | "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba", | |
| 256 | "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18", | |
| 257 | "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25", | |
| 258 | "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7", | |
| 259 | "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02", | |
| 260 | "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9", | |
| 261 | "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77", | |
| 262 | "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40", | |
| 263 | "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23", | |
| 264 | "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1", | |
| 265 | "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb", | |
| 266 | "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12", | |
| 267 | "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae", | |
| 268 | "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c", | |
| 269 | "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad", | |
| 270 | "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f", | |
| 271 | "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66", | |
| 272 | "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94", | |
| 273 | "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4", | |
| 274 | "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7", | |
| 275 | "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87", | |
| 276 | "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35", | |
| 277 | "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68", | |
| 278 | "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf", | |
| 279 | "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde", | |
| 280 | "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8", | |
| 281 | "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11", | |
| 282 | "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b", | |
| 283 | "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5", | |
| 284 | "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9", | |
| 285 | "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8", | |
| 286 | "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb", | |
| 287 | "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b", | |
| 288 | "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89", | |
| 289 | "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42", | |
| 290 | "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c", | |
| 291 | "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02", | |
| 292 | "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b", | |
| 293 | "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16", | |
| 294 | "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03", | |
| 295 | "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f", | |
| 296 | "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38", | |
| 297 | "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c", | |
| 298 | "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e", | |
| 299 | "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87", | |
| 300 | "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda", | |
| 301 | "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36", | |
| 302 | "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e", | |
| 303 | "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d", | |
| 304 | "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59", | |
| 305 | "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40", | |
| 306 | "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a", | |
| 307 | "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd", | |
| 308 | "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c", | |
| 309 | }; | |
| 310 | ||
| 311 | const siphash = SipHash128(2, 4); | |
| 312 | ||
| 313 | var buffer: [64]u8 = undefined; | |
| 314 | for (vectors) |vector, i| { | |
| 315 | buffer[i] = u8(i); | |
| 316 | ||
| 317 | const expected = mem.readInt(vector, u128, Endian.Little); | |
| 318 | debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); | |
| 319 | } | |
| 320 | } |
std/hash_map.zig+5-1| ... | ... | @@ -114,6 +114,7 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 114 | 114 | } |
| 115 | 115 | |
| 116 | 116 | pub fn remove(hm: &Self, key: K) ?&Entry { |
| 117 | if (hm.entries.len == 0) return null; | |
| 117 | 118 | hm.incrementModificationCount(); |
| 118 | 119 | const start_index = hm.keyToIndex(key); |
| 119 | 120 | {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) { |
| ... | ... | @@ -236,7 +237,10 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 236 | 237 | } |
| 237 | 238 | |
| 238 | 239 | test "basic hash map usage" { |
| 239 | var map = HashMap(i32, i32, hash_i32, eql_i32).init(debug.global_allocator); | |
| 240 | var direct_allocator = std.heap.DirectAllocator.init(); | |
| 241 | defer direct_allocator.deinit(); | |
| 242 | ||
| 243 | var map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator); | |
| 240 | 244 | defer map.deinit(); |
| 241 | 245 | |
| 242 | 246 | assert((map.put(1, 11) catch unreachable) == null); |
std/index.zig+7-5| ... | ... | @@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig"); |
| 17 | 17 | pub const dwarf = @import("dwarf.zig"); |
| 18 | 18 | pub const elf = @import("elf.zig"); |
| 19 | 19 | pub const empty_import = @import("empty.zig"); |
| 20 | pub const endian = @import("endian.zig"); | |
| 20 | pub const event = @import("event.zig"); | |
| 21 | 21 | pub const fmt = @import("fmt/index.zig"); |
| 22 | pub const hash = @import("hash/index.zig"); | |
| 22 | 23 | pub const heap = @import("heap.zig"); |
| 23 | 24 | pub const io = @import("io.zig"); |
| 24 | 25 | pub const macho = @import("macho.zig"); |
| ... | ... | @@ -26,7 +27,7 @@ pub const math = @import("math/index.zig"); |
| 26 | 27 | pub const mem = @import("mem.zig"); |
| 27 | 28 | pub const net = @import("net.zig"); |
| 28 | 29 | pub const os = @import("os/index.zig"); |
| 29 | pub const rand = @import("rand.zig"); | |
| 30 | pub const rand = @import("rand/index.zig"); | |
| 30 | 31 | pub const sort = @import("sort.zig"); |
| 31 | 32 | pub const unicode = @import("unicode.zig"); |
| 32 | 33 | pub const zig = @import("zig/index.zig"); |
| ... | ... | @@ -49,16 +50,17 @@ test "std" { |
| 49 | 50 | _ = @import("dwarf.zig"); |
| 50 | 51 | _ = @import("elf.zig"); |
| 51 | 52 | _ = @import("empty.zig"); |
| 52 | _ = @import("endian.zig"); | |
| 53 | _ = @import("event.zig"); | |
| 53 | 54 | _ = @import("fmt/index.zig"); |
| 55 | _ = @import("hash/index.zig"); | |
| 54 | 56 | _ = @import("io.zig"); |
| 55 | 57 | _ = @import("macho.zig"); |
| 56 | 58 | _ = @import("math/index.zig"); |
| 57 | 59 | _ = @import("mem.zig"); |
| 58 | _ = @import("heap.zig"); | |
| 59 | 60 | _ = @import("net.zig"); |
| 61 | _ = @import("heap.zig"); | |
| 60 | 62 | _ = @import("os/index.zig"); |
| 61 | _ = @import("rand.zig"); | |
| 63 | _ = @import("rand/index.zig"); | |
| 62 | 64 | _ = @import("sort.zig"); |
| 63 | 65 | _ = @import("unicode.zig"); |
| 64 | 66 | _ = @import("zig/index.zig"); |
std/io.zig+26-4| ... | ... | @@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type { |
| 144 | 144 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents |
| 145 | 145 | /// read from the stream so far are lost. |
| 146 | 146 | pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void { |
| 147 | try buf.resize(0); | |
| 147 | try buffer.resize(0); | |
| 148 | 148 | |
| 149 | 149 | while (true) { |
| 150 | 150 | var byte: u8 = try self.readByte(); |
| ... | ... | @@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type { |
| 153 | 153 | return; |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | if (buf.len() == max_size) { | |
| 156 | if (buffer.len() == max_size) { | |
| 157 | 157 | return error.StreamTooLong; |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | try buf.appendByte(byte); | |
| 160 | try buffer.appendByte(byte); | |
| 161 | 161 | } |
| 162 | 162 | } |
| 163 | 163 | |
| ... | ... | @@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type { |
| 171 | 171 | var buf = Buffer.initNull(allocator); |
| 172 | 172 | defer buf.deinit(); |
| 173 | 173 | |
| 174 | try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); | |
| 174 | try self.readUntilDelimiterBuffer(&buf, delimiter, max_size); | |
| 175 | 175 | return buf.toOwnedSlice(); |
| 176 | 176 | } |
| 177 | 177 | |
| ... | ... | @@ -478,3 +478,25 @@ test "import io tests" { |
| 478 | 478 | } |
| 479 | 479 | } |
| 480 | 480 | |
| 481 | pub fn readLine(buf: []u8) !usize { | |
| 482 | var stdin = getStdIn() catch return error.StdInUnavailable; | |
| 483 | var adapter = FileInStream.init(&stdin); | |
| 484 | var stream = &adapter.stream; | |
| 485 | var index: usize = 0; | |
| 486 | while (true) { | |
| 487 | const byte = stream.readByte() catch return error.EndOfFile; | |
| 488 | switch (byte) { | |
| 489 | '\r' => { | |
| 490 | // trash the following \n | |
| 491 | _ = stream.readByte() catch return error.EndOfFile; | |
| 492 | return index; | |
| 493 | }, | |
| 494 | '\n' => return index, | |
| 495 | else => { | |
| 496 | if (index == buf.len) return error.InputTooLong; | |
| 497 | buf[index] = byte; | |
| 498 | index += 1; | |
| 499 | }, | |
| 500 | } | |
| 501 | } | |
| 502 | } |
std/io_test.zig+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const std = @import("index.zig"); |
| 2 | 2 | const io = std.io; |
| 3 | 3 | const allocator = std.debug.global_allocator; |
| 4 | const Rand = std.rand.Rand; | |
| 4 | const DefaultPrng = std.rand.DefaultPrng; | |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const mem = std.mem; |
| 7 | 7 | const os = std.os; |
| ... | ... | @@ -9,8 +9,8 @@ const builtin = @import("builtin"); |
| 9 | 9 | |
| 10 | 10 | test "write a file, read it, then delete it" { |
| 11 | 11 | var data: [1024]u8 = undefined; |
| 12 | var rng = Rand.init(1234); | |
| 13 | rng.fillBytes(data[0..]); | |
| 12 | var prng = DefaultPrng.init(1234); | |
| 13 | prng.random.bytes(data[0..]); | |
| 14 | 14 | const tmp_file_name = "temp_test_file.txt"; |
| 15 | 15 | { |
| 16 | 16 | var file = try os.File.openWrite(allocator, tmp_file_name); |
std/linked_list.zig+1| ... | ... | @@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | list.len -= 1; |
| 164 | assert(list.len == 0 or (list.first != null and list.last != null)); | |
| 164 | 165 | } |
| 165 | 166 | |
| 166 | 167 | /// Remove and return the last node in the list. |
std/math/atan2.zig+1-1| ... | ... | @@ -22,7 +22,7 @@ const std = @import("../index.zig"); |
| 22 | 22 | const math = std.math; |
| 23 | 23 | const assert = std.debug.assert; |
| 24 | 24 | |
| 25 | fn atan2(comptime T: type, x: T, y: T) T { | |
| 25 | pub fn atan2(comptime T: type, x: T, y: T) T { | |
| 26 | 26 | return switch (T) { |
| 27 | 27 | f32 => atan2_32(x, y), |
| 28 | 28 | f64 => atan2_64(x, y), |
std/math/index.zig+15-2| ... | ... | @@ -515,15 +515,28 @@ test "math.negateCast" { |
| 515 | 515 | |
| 516 | 516 | /// Cast an integer to a different integer type. If the value doesn't fit, |
| 517 | 517 | /// return an error. |
| 518 | pub fn cast(comptime T: type, x: var) !T { | |
| 518 | pub fn cast(comptime T: type, x: var) (error{Overflow}!T) { | |
| 519 | 519 | comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer |
| 520 | if (x > @maxValue(T)) { | |
| 520 | comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Int); // must pass an integer | |
| 521 | if (@maxValue(@typeOf(x)) > @maxValue(T) and x > @maxValue(T)) { | |
| 522 | return error.Overflow; | |
| 523 | } else if (@minValue(@typeOf(x)) < @minValue(T) and x < @minValue(T)) { | |
| 521 | 524 | return error.Overflow; |
| 522 | 525 | } else { |
| 523 | 526 | return T(x); |
| 524 | 527 | } |
| 525 | 528 | } |
| 526 | 529 | |
| 530 | test "math.cast" { | |
| 531 | if (cast(u8, u32(300))) |_| @panic("fail") else |err| assert(err == error.Overflow); | |
| 532 | if (cast(i8, i32(-200))) |_| @panic("fail") else |err| assert(err == error.Overflow); | |
| 533 | if (cast(u8, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow); | |
| 534 | if (cast(u64, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow); | |
| 535 | ||
| 536 | assert((try cast(u8, u32(255))) == u8(255)); | |
| 537 | assert(@typeOf(try cast(u8, u32(255))) == u8); | |
| 538 | } | |
| 539 | ||
| 527 | 540 | pub fn floorPowerOfTwo(comptime T: type, value: T) T { |
| 528 | 541 | var x = value; |
| 529 | 542 |
std/mem.zig+26| ... | ... | @@ -3,6 +3,7 @@ const debug = std.debug; |
| 3 | 3 | const assert = debug.assert; |
| 4 | 4 | const math = std.math; |
| 5 | 5 | const builtin = @import("builtin"); |
| 6 | const mem = this; | |
| 6 | 7 | |
| 7 | 8 | pub const Allocator = struct { |
| 8 | 9 | const Error = error {OutOfMemory}; |
| ... | ... | @@ -550,3 +551,28 @@ test "std.mem.rotate" { |
| 550 | 551 | |
| 551 | 552 | assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 })); |
| 552 | 553 | } |
| 554 | ||
| 555 | // TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by | |
| 556 | // endian-casting the pointer and then dereferencing | |
| 557 | ||
| 558 | pub fn endianSwapIfLe(comptime T: type, x: T) T { | |
| 559 | return endianSwapIf(builtin.Endian.Little, T, x); | |
| 560 | } | |
| 561 | ||
| 562 | pub fn endianSwapIfBe(comptime T: type, x: T) T { | |
| 563 | return endianSwapIf(builtin.Endian.Big, T, x); | |
| 564 | } | |
| 565 | ||
| 566 | pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T { | |
| 567 | return if (builtin.endian == endian) endianSwap(T, x) else x; | |
| 568 | } | |
| 569 | ||
| 570 | pub fn endianSwap(comptime T: type, x: T) T { | |
| 571 | var buf: [@sizeOf(T)]u8 = undefined; | |
| 572 | mem.writeInt(buf[0..], x, builtin.Endian.Little); | |
| 573 | return mem.readInt(buf, T, builtin.Endian.Big); | |
| 574 | } | |
| 575 | ||
| 576 | test "std.mem.endianSwap" { | |
| 577 | assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE); | |
| 578 | } |
std/net.zig+121-162| ... | ... | @@ -1,143 +1,120 @@ |
| 1 | 1 | const std = @import("index.zig"); |
| 2 | const linux = std.os.linux; | |
| 2 | const builtin = @import("builtin"); | |
| 3 | 3 | const assert = std.debug.assert; |
| 4 | const endian = std.endian; | |
| 4 | const net = this; | |
| 5 | const posix = std.os.posix; | |
| 6 | const mem = std.mem; | |
| 5 | 7 | |
| 6 | // TODO don't trust this file, it bit rotted. start over | |
| 7 | ||
| 8 | const Connection = struct { | |
| 9 | socket_fd: i32, | |
| 10 | ||
| 11 | pub fn send(c: Connection, buf: []const u8) !usize { | |
| 12 | const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0); | |
| 13 | const send_err = linux.getErrno(send_ret); | |
| 14 | switch (send_err) { | |
| 15 | 0 => return send_ret, | |
| 16 | linux.EINVAL => unreachable, | |
| 17 | linux.EFAULT => unreachable, | |
| 18 | linux.ECONNRESET => return error.ConnectionReset, | |
| 19 | linux.EINTR => return error.SigInterrupt, | |
| 20 | // TODO there are more possible errors | |
| 21 | else => return error.Unexpected, | |
| 22 | } | |
| 23 | } | |
| 24 | ||
| 25 | pub fn recv(c: Connection, buf: []u8) ![]u8 { | |
| 26 | const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null); | |
| 27 | const recv_err = linux.getErrno(recv_ret); | |
| 28 | switch (recv_err) { | |
| 29 | 0 => return buf[0..recv_ret], | |
| 30 | linux.EINVAL => unreachable, | |
| 31 | linux.EFAULT => unreachable, | |
| 32 | linux.ENOTSOCK => return error.NotSocket, | |
| 33 | linux.EINTR => return error.SigInterrupt, | |
| 34 | linux.ENOMEM => return error.OutOfMemory, | |
| 35 | linux.ECONNREFUSED => return error.ConnectionRefused, | |
| 36 | linux.EBADF => return error.BadFd, | |
| 37 | // TODO more error values | |
| 38 | else => return error.Unexpected, | |
| 39 | } | |
| 40 | } | |
| 41 | ||
| 42 | pub fn close(c: Connection) !void { | |
| 43 | switch (linux.getErrno(linux.close(c.socket_fd))) { | |
| 44 | 0 => return, | |
| 45 | linux.EBADF => unreachable, | |
| 46 | linux.EINTR => return error.SigInterrupt, | |
| 47 | linux.EIO => return error.Io, | |
| 48 | else => return error.Unexpected, | |
| 49 | } | |
| 50 | } | |
| 8 | pub const TmpWinAddr = struct { | |
| 9 | family: u8, | |
| 10 | data: [14]u8, | |
| 51 | 11 | }; |
| 52 | 12 | |
| 53 | const Address = struct { | |
| 54 | family: u16, | |
| 55 | scope_id: u32, | |
| 56 | addr: [16]u8, | |
| 57 | sort_key: i32, | |
| 13 | pub const OsAddress = switch (builtin.os) { | |
| 14 | builtin.Os.windows => TmpWinAddr, | |
| 15 | else => posix.sockaddr, | |
| 58 | 16 | }; |
| 59 | 17 | |
| 60 | pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address { | |
| 61 | if (hostname.len == 0) { | |
| 62 | ||
| 63 | unreachable; // TODO | |
| 18 | pub const Address = struct { | |
| 19 | os_addr: OsAddress, | |
| 20 | ||
| 21 | pub fn initIp4(ip4: u32, port: u16) Address { | |
| 22 | return Address { | |
| 23 | .os_addr = posix.sockaddr { | |
| 24 | .in = posix.sockaddr_in { | |
| 25 | .family = posix.AF_INET, | |
| 26 | .port = std.mem.endianSwapIfLe(u16, port), | |
| 27 | .addr = ip4, | |
| 28 | .zero = []u8{0} ** 8, | |
| 29 | }, | |
| 30 | }, | |
| 31 | }; | |
| 64 | 32 | } |
| 65 | 33 | |
| 66 | unreachable; // TODO | |
| 67 | } | |
| 34 | pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address { | |
| 35 | return Address { | |
| 36 | .family = posix.AF_INET6, | |
| 37 | .os_addr = posix.sockaddr { | |
| 38 | .in6 = posix.sockaddr_in6 { | |
| 39 | .family = posix.AF_INET6, | |
| 40 | .port = std.mem.endianSwapIfLe(u16, port), | |
| 41 | .flowinfo = 0, | |
| 42 | .addr = ip6.addr, | |
| 43 | .scope_id = ip6.scope_id, | |
| 44 | }, | |
| 45 | }, | |
| 46 | }; | |
| 47 | } | |
| 68 | 48 | |
| 69 | pub fn connectAddr(addr: &Address, port: u16) !Connection { | |
| 70 | const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp); | |
| 71 | const socket_err = linux.getErrno(socket_ret); | |
| 72 | if (socket_err > 0) { | |
| 73 | // TODO figure out possible errors from socket() | |
| 74 | return error.Unexpected; | |
| 49 | pub fn initPosix(addr: &const posix.sockaddr) Address { | |
| 50 | return Address { | |
| 51 | .os_addr = *addr, | |
| 52 | }; | |
| 75 | 53 | } |
| 76 | const socket_fd = i32(socket_ret); | |
| 77 | 54 | |
| 78 | const connect_ret = if (addr.family == linux.AF_INET) x: { | |
| 79 | var os_addr: linux.sockaddr_in = undefined; | |
| 80 | os_addr.family = addr.family; | |
| 81 | os_addr.port = endian.swapIfLe(u16, port); | |
| 82 | @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4); | |
| 83 | @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero))); | |
| 84 | break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in)); | |
| 85 | } else if (addr.family == linux.AF_INET6) x: { | |
| 86 | var os_addr: linux.sockaddr_in6 = undefined; | |
| 87 | os_addr.family = addr.family; | |
| 88 | os_addr.port = endian.swapIfLe(u16, port); | |
| 89 | os_addr.flowinfo = 0; | |
| 90 | os_addr.scope_id = addr.scope_id; | |
| 91 | @memcpy(&os_addr.addr[0], &addr.addr[0], 16); | |
| 92 | break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6)); | |
| 93 | } else { | |
| 94 | unreachable; | |
| 95 | }; | |
| 96 | const connect_err = linux.getErrno(connect_ret); | |
| 97 | if (connect_err > 0) { | |
| 98 | switch (connect_err) { | |
| 99 | linux.ETIMEDOUT => return error.TimedOut, | |
| 100 | else => { | |
| 101 | // TODO figure out possible errors from connect() | |
| 102 | return error.Unexpected; | |
| 55 | pub fn format(self: &const Address, out_stream: var) !void { | |
| 56 | switch (self.os_addr.in.family) { | |
| 57 | posix.AF_INET => { | |
| 58 | const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port); | |
| 59 | const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]); | |
| 60 | try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port); | |
| 61 | }, | |
| 62 | posix.AF_INET6 => { | |
| 63 | const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port); | |
| 64 | try out_stream.print("[TODO render ip6 address]:{}", native_endian_port); | |
| 103 | 65 | }, |
| 66 | else => try out_stream.write("(unrecognized address family)"), | |
| 104 | 67 | } |
| 105 | 68 | } |
| 69 | }; | |
| 106 | 70 | |
| 107 | return Connection { | |
| 108 | .socket_fd = socket_fd, | |
| 109 | }; | |
| 110 | } | |
| 111 | ||
| 112 | pub fn connect(hostname: []const u8, port: u16) !Connection { | |
| 113 | var addrs_buf: [1]Address = undefined; | |
| 114 | const addrs_slice = try lookup(hostname, addrs_buf[0..]); | |
| 115 | const main_addr = &addrs_slice[0]; | |
| 116 | ||
| 117 | return connectAddr(main_addr, port); | |
| 118 | } | |
| 71 | pub fn parseIp4(buf: []const u8) !u32 { | |
| 72 | var result: u32 = undefined; | |
| 73 | const out_ptr = ([]u8)((&result)[0..1]); | |
| 119 | 74 | |
| 120 | pub fn parseIpLiteral(buf: []const u8) !Address { | |
| 75 | var x: u8 = 0; | |
| 76 | var index: u8 = 0; | |
| 77 | var saw_any_digits = false; | |
| 78 | for (buf) |c| { | |
| 79 | if (c == '.') { | |
| 80 | if (!saw_any_digits) { | |
| 81 | return error.InvalidCharacter; | |
| 82 | } | |
| 83 | if (index == 3) { | |
| 84 | return error.InvalidEnd; | |
| 85 | } | |
| 86 | out_ptr[index] = x; | |
| 87 | index += 1; | |
| 88 | x = 0; | |
| 89 | saw_any_digits = false; | |
| 90 | } else if (c >= '0' and c <= '9') { | |
| 91 | saw_any_digits = true; | |
| 92 | const digit = c - '0'; | |
| 93 | if (@mulWithOverflow(u8, x, 10, &x)) { | |
| 94 | return error.Overflow; | |
| 95 | } | |
| 96 | if (@addWithOverflow(u8, x, digit, &x)) { | |
| 97 | return error.Overflow; | |
| 98 | } | |
| 99 | } else { | |
| 100 | return error.InvalidCharacter; | |
| 101 | } | |
| 102 | } | |
| 103 | if (index == 3 and saw_any_digits) { | |
| 104 | out_ptr[index] = x; | |
| 105 | return result; | |
| 106 | } | |
| 121 | 107 | |
| 122 | return error.InvalidIpLiteral; | |
| 108 | return error.Incomplete; | |
| 123 | 109 | } |
| 124 | 110 | |
| 125 | fn hexDigit(c: u8) u8 { | |
| 126 | // TODO use switch with range | |
| 127 | if ('0' <= c and c <= '9') { | |
| 128 | return c - '0'; | |
| 129 | } else if ('A' <= c and c <= 'Z') { | |
| 130 | return c - 'A' + 10; | |
| 131 | } else if ('a' <= c and c <= 'z') { | |
| 132 | return c - 'a' + 10; | |
| 133 | } else { | |
| 134 | return @maxValue(u8); | |
| 135 | } | |
| 136 | } | |
| 111 | pub const Ip6Addr = struct { | |
| 112 | scope_id: u32, | |
| 113 | addr: [16]u8, | |
| 114 | }; | |
| 137 | 115 | |
| 138 | fn parseIp6(buf: []const u8) !Address { | |
| 139 | var result: Address = undefined; | |
| 140 | result.family = linux.AF_INET6; | |
| 116 | pub fn parseIp6(buf: []const u8) !Ip6Addr { | |
| 117 | var result: Ip6Addr = undefined; | |
| 141 | 118 | result.scope_id = 0; |
| 142 | 119 | const ip_slice = result.addr[0..]; |
| 143 | 120 | |
| ... | ... | @@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address { |
| 156 | 133 | return error.Overflow; |
| 157 | 134 | } |
| 158 | 135 | } else { |
| 159 | return error.InvalidChar; | |
| 136 | return error.InvalidCharacter; | |
| 160 | 137 | } |
| 161 | 138 | } else if (c == ':') { |
| 162 | 139 | if (!saw_any_digits) { |
| 163 | return error.InvalidChar; | |
| 140 | return error.InvalidCharacter; | |
| 164 | 141 | } |
| 165 | 142 | if (index == 14) { |
| 166 | return error.JunkAtEnd; | |
| 143 | return error.InvalidEnd; | |
| 167 | 144 | } |
| 168 | 145 | ip_slice[index] = @truncate(u8, x >> 8); |
| 169 | 146 | index += 1; |
| ... | ... | @@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address { |
| 174 | 151 | saw_any_digits = false; |
| 175 | 152 | } else if (c == '%') { |
| 176 | 153 | if (!saw_any_digits) { |
| 177 | return error.InvalidChar; | |
| 154 | return error.InvalidCharacter; | |
| 178 | 155 | } |
| 179 | 156 | if (index == 14) { |
| 180 | 157 | ip_slice[index] = @truncate(u8, x >> 8); |
| ... | ... | @@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address { |
| 185 | 162 | scope_id = true; |
| 186 | 163 | saw_any_digits = false; |
| 187 | 164 | } else { |
| 188 | const digit = hexDigit(c); | |
| 189 | if (digit == @maxValue(u8)) { | |
| 190 | return error.InvalidChar; | |
| 191 | } | |
| 165 | const digit = try std.fmt.charToDigit(c, 16); | |
| 192 | 166 | if (@mulWithOverflow(u16, x, 16, &x)) { |
| 193 | 167 | return error.Overflow; |
| 194 | 168 | } |
| ... | ... | @@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address { |
| 216 | 190 | return error.Incomplete; |
| 217 | 191 | } |
| 218 | 192 | |
| 219 | fn parseIp4(buf: []const u8) !u32 { | |
| 220 | var result: u32 = undefined; | |
| 221 | const out_ptr = ([]u8)((&result)[0..1]); | |
| 193 | test "std.net.parseIp4" { | |
| 194 | assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001)); | |
| 222 | 195 | |
| 223 | var x: u8 = 0; | |
| 224 | var index: u8 = 0; | |
| 225 | var saw_any_digits = false; | |
| 226 | for (buf) |c| { | |
| 227 | if (c == '.') { | |
| 228 | if (!saw_any_digits) { | |
| 229 | return error.InvalidChar; | |
| 230 | } | |
| 231 | if (index == 3) { | |
| 232 | return error.JunkAtEnd; | |
| 233 | } | |
| 234 | out_ptr[index] = x; | |
| 235 | index += 1; | |
| 236 | x = 0; | |
| 237 | saw_any_digits = false; | |
| 238 | } else if (c >= '0' and c <= '9') { | |
| 239 | saw_any_digits = true; | |
| 240 | const digit = c - '0'; | |
| 241 | if (@mulWithOverflow(u8, x, 10, &x)) { | |
| 242 | return error.Overflow; | |
| 243 | } | |
| 244 | if (@addWithOverflow(u8, x, digit, &x)) { | |
| 245 | return error.Overflow; | |
| 246 | } | |
| 247 | } else { | |
| 248 | return error.InvalidChar; | |
| 249 | } | |
| 250 | } | |
| 251 | if (index == 3 and saw_any_digits) { | |
| 252 | out_ptr[index] = x; | |
| 253 | return result; | |
| 196 | testParseIp4Fail("256.0.0.1", error.Overflow); | |
| 197 | testParseIp4Fail("x.0.0.1", error.InvalidCharacter); | |
| 198 | testParseIp4Fail("127.0.0.1.1", error.InvalidEnd); | |
| 199 | testParseIp4Fail("127.0.0.", error.Incomplete); | |
| 200 | testParseIp4Fail("100..0.1", error.InvalidCharacter); | |
| 201 | } | |
| 202 | ||
| 203 | fn testParseIp4Fail(buf: []const u8, expected_err: error) void { | |
| 204 | if (parseIp4(buf)) |_| { | |
| 205 | @panic("expected error"); | |
| 206 | } else |e| { | |
| 207 | assert(e == expected_err); | |
| 254 | 208 | } |
| 209 | } | |
| 255 | 210 | |
| 256 | return error.Incomplete; | |
| 211 | test "std.net.parseIp6" { | |
| 212 | const addr = try parseIp6("FF01:0:0:0:0:0:0:FB"); | |
| 213 | assert(addr.addr[0] == 0xff); | |
| 214 | assert(addr.addr[1] == 0x01); | |
| 215 | assert(addr.addr[2] == 0x00); | |
| 257 | 216 | } |
std/os/child_process.zig-35| ... | ... | @@ -13,8 +13,6 @@ const builtin = @import("builtin"); |
| 13 | 13 | const Os = builtin.Os; |
| 14 | 14 | const LinkedList = std.LinkedList; |
| 15 | 15 | |
| 16 | var children_nodes = LinkedList(&ChildProcess).init(); | |
| 17 | ||
| 18 | 16 | const is_windows = builtin.os == Os.windows; |
| 19 | 17 | |
| 20 | 18 | pub const ChildProcess = struct { |
| ... | ... | @@ -296,8 +294,6 @@ pub const ChildProcess = struct { |
| 296 | 294 | } |
| 297 | 295 | |
| 298 | 296 | fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term { |
| 299 | children_nodes.remove(&self.llnode); | |
| 300 | ||
| 301 | 297 | defer { |
| 302 | 298 | os.close(self.err_pipe[0]); |
| 303 | 299 | os.close(self.err_pipe[1]); |
| ... | ... | @@ -427,9 +423,6 @@ pub const ChildProcess = struct { |
| 427 | 423 | self.llnode = LinkedList(&ChildProcess).Node.init(self); |
| 428 | 424 | self.term = null; |
| 429 | 425 | |
| 430 | // TODO make this atomic so it works even with threads | |
| 431 | children_nodes.prepend(&self.llnode); | |
| 432 | ||
| 433 | 426 | if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); } |
| 434 | 427 | if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); } |
| 435 | 428 | if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); } |
| ... | ... | @@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt { |
| 773 | 766 | os.posixRead(fd, bytes[0..]) catch return error.SystemResources; |
| 774 | 767 | return mem.readInt(bytes[0..], ErrInt, builtin.endian); |
| 775 | 768 | } |
| 776 | ||
| 777 | extern fn sigchld_handler(_: i32) void { | |
| 778 | while (true) { | |
| 779 | var status: i32 = undefined; | |
| 780 | const pid_result = posix.waitpid(-1, &status, posix.WNOHANG); | |
| 781 | if (pid_result == 0) { | |
| 782 | return; | |
| 783 | } | |
| 784 | const err = posix.getErrno(pid_result); | |
| 785 | if (err > 0) { | |
| 786 | if (err == posix.ECHILD) { | |
| 787 | return; | |
| 788 | } | |
| 789 | unreachable; | |
| 790 | } | |
| 791 | handleTerm(i32(pid_result), status); | |
| 792 | } | |
| 793 | } | |
| 794 | ||
| 795 | fn handleTerm(pid: i32, status: i32) void { | |
| 796 | var it = children_nodes.first; | |
| 797 | while (it) |node| : (it = node.next) { | |
| 798 | if (node.data.pid == pid) { | |
| 799 | node.data.handleWaitResult(status); | |
| 800 | return; | |
| 801 | } | |
| 802 | } | |
| 803 | } |
std/os/darwin.zig+35| ... | ... | @@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks |
| 56 | 56 | pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only |
| 57 | 57 | pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec |
| 58 | 58 | |
| 59 | pub const O_ACCMODE = 3; | |
| 60 | pub const O_ALERT = 536870912; | |
| 61 | pub const O_ASYNC = 64; | |
| 62 | pub const O_DIRECTORY = 1048576; | |
| 63 | pub const O_DP_GETRAWENCRYPTED = 1; | |
| 64 | pub const O_DP_GETRAWUNENCRYPTED = 2; | |
| 65 | pub const O_DSYNC = 4194304; | |
| 66 | pub const O_FSYNC = O_SYNC; | |
| 67 | pub const O_NOCTTY = 131072; | |
| 68 | pub const O_POPUP = 2147483648; | |
| 69 | pub const O_SYNC = 128; | |
| 70 | ||
| 59 | 71 | pub const SEEK_SET = 0x0; |
| 60 | 72 | pub const SEEK_CUR = 0x1; |
| 61 | 73 | pub const SEEK_END = 0x2; |
| 62 | 74 | |
| 75 | pub const DT_UNKNOWN = 0; | |
| 76 | pub const DT_FIFO = 1; | |
| 77 | pub const DT_CHR = 2; | |
| 78 | pub const DT_DIR = 4; | |
| 79 | pub const DT_BLK = 6; | |
| 80 | pub const DT_REG = 8; | |
| 81 | pub const DT_LNK = 10; | |
| 82 | pub const DT_SOCK = 12; | |
| 83 | pub const DT_WHT = 14; | |
| 84 | ||
| 63 | 85 | pub const SIG_BLOCK = 1; /// block specified signal set |
| 64 | 86 | pub const SIG_UNBLOCK = 2; /// unblock specified signal set |
| 65 | 87 | pub const SIG_SETMASK = 3; /// set specified signal set |
| ... | ... | @@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize { |
| 192 | 214 | return errnoWrap(c.pipe(@ptrCast(&c_int, fds))); |
| 193 | 215 | } |
| 194 | 216 | |
| 217 | ||
| 218 | pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize { | |
| 219 | return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep))); | |
| 220 | } | |
| 221 | ||
| 195 | 222 | pub fn mkdir(path: &const u8, mode: u32) usize { |
| 196 | 223 | return errnoWrap(c.mkdir(path, mode)); |
| 197 | 224 | } |
| ... | ... | @@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize { |
| 204 | 231 | return errnoWrap(c.rename(old, new)); |
| 205 | 232 | } |
| 206 | 233 | |
| 234 | pub fn rmdir(path: &const u8) usize { | |
| 235 | return errnoWrap(c.rmdir(path)); | |
| 236 | } | |
| 237 | ||
| 207 | 238 | pub fn chdir(path: &const u8) usize { |
| 208 | 239 | return errnoWrap(c.chdir(path)); |
| 209 | 240 | } |
| ... | ... | @@ -268,6 +299,10 @@ pub const empty_sigset = sigset_t(0); |
| 268 | 299 | |
| 269 | 300 | pub const timespec = c.timespec; |
| 270 | 301 | pub const Stat = c.Stat; |
| 302 | pub const dirent = c.dirent; | |
| 303 | ||
| 304 | pub const sa_family_t = c.sa_family_t; | |
| 305 | pub const sockaddr = c.sockaddr; | |
| 271 | 306 | |
| 272 | 307 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 273 | 308 | pub const Sigaction = struct { |
std/os/file.zig+1-1| ... | ... | @@ -233,7 +233,7 @@ pub const File = struct { |
| 233 | 233 | Unexpected, |
| 234 | 234 | }; |
| 235 | 235 | |
| 236 | fn mode(self: &File) ModeError!FileMode { | |
| 236 | fn mode(self: &File) ModeError!os.FileMode { | |
| 237 | 237 | if (is_posix) { |
| 238 | 238 | var stat: posix.Stat = undefined; |
| 239 | 239 | const err = posix.getErrno(posix.fstat(self.handle, &stat)); |
std/os/index.zig+605-33| ... | ... | @@ -4,6 +4,19 @@ const Os = builtin.Os; |
| 4 | 4 | const is_windows = builtin.os == Os.windows; |
| 5 | 5 | const os = this; |
| 6 | 6 | |
| 7 | test "std.os" { | |
| 8 | _ = @import("child_process.zig"); | |
| 9 | _ = @import("darwin.zig"); | |
| 10 | _ = @import("darwin_errno.zig"); | |
| 11 | _ = @import("get_user_id.zig"); | |
| 12 | _ = @import("linux/errno.zig"); | |
| 13 | _ = @import("linux/index.zig"); | |
| 14 | _ = @import("linux/x86_64.zig"); | |
| 15 | _ = @import("path.zig"); | |
| 16 | _ = @import("test.zig"); | |
| 17 | _ = @import("windows/index.zig"); | |
| 18 | } | |
| 19 | ||
| 7 | 20 | pub const windows = @import("windows/index.zig"); |
| 8 | 21 | pub const darwin = @import("darwin.zig"); |
| 9 | 22 | pub const linux = @import("linux/index.zig"); |
| ... | ... | @@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) { |
| 14 | 27 | Os.zen => zen, |
| 15 | 28 | else => @compileError("Unsupported OS"), |
| 16 | 29 | }; |
| 30 | pub const net = @import("net.zig"); | |
| 17 | 31 | |
| 18 | 32 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 19 | 33 | pub const path = @import("path.zig"); |
| ... | ... | @@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn { |
| 173 | 187 | } |
| 174 | 188 | } |
| 175 | 189 | |
| 190 | /// When a file descriptor is closed on linux, it pops the first | |
| 191 | /// node from this queue and resumes it. | |
| 192 | /// Async functions which get the EMFILE error code can suspend, | |
| 193 | /// putting their coroutine handle into this list. | |
| 194 | /// TODO make this an atomic linked list | |
| 195 | pub var emfile_promise_queue = std.LinkedList(promise).init(); | |
| 196 | ||
| 176 | 197 | /// Closes the file handle. Keeps trying if it gets interrupted by a signal. |
| 177 | 198 | pub fn close(handle: FileHandle) void { |
| 178 | 199 | if (is_windows) { |
| ... | ... | @@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void { |
| 180 | 201 | } else { |
| 181 | 202 | while (true) { |
| 182 | 203 | const err = posix.getErrno(posix.close(handle)); |
| 183 | if (err == posix.EINTR) { | |
| 184 | continue; | |
| 185 | } else { | |
| 186 | return; | |
| 204 | switch (err) { | |
| 205 | posix.EINTR => continue, | |
| 206 | else => { | |
| 207 | if (emfile_promise_queue.popFirst()) |p| resume p.data; | |
| 208 | return; | |
| 209 | }, | |
| 187 | 210 | } |
| 188 | 211 | } |
| 189 | 212 | } |
| ... | ... | @@ -1050,15 +1073,16 @@ const DeleteTreeError = error { |
| 1050 | 1073 | }; |
| 1051 | 1074 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void { |
| 1052 | 1075 | start_over: while (true) { |
| 1076 | var got_access_denied = false; | |
| 1053 | 1077 | // First, try deleting the item as a file. This way we don't follow sym links. |
| 1054 | 1078 | if (deleteFile(allocator, full_path)) { |
| 1055 | 1079 | return; |
| 1056 | 1080 | } else |err| switch (err) { |
| 1057 | 1081 | error.FileNotFound => return, |
| 1058 | 1082 | error.IsDir => {}, |
| 1083 | error.AccessDenied => got_access_denied = true, | |
| 1059 | 1084 | |
| 1060 | 1085 | error.OutOfMemory, |
| 1061 | error.AccessDenied, | |
| 1062 | 1086 | error.SymLinkLoop, |
| 1063 | 1087 | error.NameTooLong, |
| 1064 | 1088 | error.SystemResources, |
| ... | ... | @@ -1071,7 +1095,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError! |
| 1071 | 1095 | } |
| 1072 | 1096 | { |
| 1073 | 1097 | var dir = Dir.open(allocator, full_path) catch |err| switch (err) { |
| 1074 | error.NotDir => continue :start_over, | |
| 1098 | error.NotDir => { | |
| 1099 | if (got_access_denied) { | |
| 1100 | return error.AccessDenied; | |
| 1101 | } | |
| 1102 | continue :start_over; | |
| 1103 | }, | |
| 1075 | 1104 | |
| 1076 | 1105 | error.OutOfMemory, |
| 1077 | 1106 | error.AccessDenied, |
| ... | ... | @@ -1109,18 +1138,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError! |
| 1109 | 1138 | } |
| 1110 | 1139 | |
| 1111 | 1140 | pub const Dir = struct { |
| 1112 | // See man getdents | |
| 1113 | 1141 | fd: i32, |
| 1142 | darwin_seek: darwin_seek_t, | |
| 1114 | 1143 | allocator: &Allocator, |
| 1115 | 1144 | buf: []u8, |
| 1116 | 1145 | index: usize, |
| 1117 | 1146 | end_index: usize, |
| 1118 | 1147 | |
| 1119 | const LinuxEntry = extern struct { | |
| 1120 | d_ino: usize, | |
| 1121 | d_off: usize, | |
| 1122 | d_reclen: u16, | |
| 1123 | d_name: u8, // field address is the address of first byte of name | |
| 1148 | const darwin_seek_t = switch (builtin.os) { | |
| 1149 | Os.macosx, Os.ios => i64, | |
| 1150 | else => void, | |
| 1124 | 1151 | }; |
| 1125 | 1152 | |
| 1126 | 1153 | pub const Entry = struct { |
| ... | ... | @@ -1135,15 +1162,26 @@ pub const Dir = struct { |
| 1135 | 1162 | SymLink, |
| 1136 | 1163 | File, |
| 1137 | 1164 | UnixDomainSocket, |
| 1165 | Whiteout, | |
| 1138 | 1166 | Unknown, |
| 1139 | 1167 | }; |
| 1140 | 1168 | }; |
| 1141 | 1169 | |
| 1142 | 1170 | pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir { |
| 1143 | const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0); | |
| 1171 | const fd = switch (builtin.os) { | |
| 1172 | Os.windows => @compileError("TODO support Dir.open for windows"), | |
| 1173 | Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0), | |
| 1174 | Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0), | |
| 1175 | else => @compileError("Dir.open is not supported for this platform"), | |
| 1176 | }; | |
| 1177 | const darwin_seek_init = switch (builtin.os) { | |
| 1178 | Os.macosx, Os.ios => 0, | |
| 1179 | else => {}, | |
| 1180 | }; | |
| 1144 | 1181 | return Dir { |
| 1145 | 1182 | .allocator = allocator, |
| 1146 | 1183 | .fd = fd, |
| 1184 | .darwin_seek = darwin_seek_init, | |
| 1147 | 1185 | .index = 0, |
| 1148 | 1186 | .end_index = 0, |
| 1149 | 1187 | .buf = []u8{}, |
| ... | ... | @@ -1158,6 +1196,76 @@ pub const Dir = struct { |
| 1158 | 1196 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 1159 | 1197 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. |
| 1160 | 1198 | pub fn next(self: &Dir) !?Entry { |
| 1199 | switch (builtin.os) { | |
| 1200 | Os.linux => return self.nextLinux(), | |
| 1201 | Os.macosx, Os.ios => return self.nextDarwin(), | |
| 1202 | Os.windows => return self.nextWindows(), | |
| 1203 | else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)), | |
| 1204 | } | |
| 1205 | } | |
| 1206 | ||
| 1207 | fn nextDarwin(self: &Dir) !?Entry { | |
| 1208 | start_over: while (true) { | |
| 1209 | if (self.index >= self.end_index) { | |
| 1210 | if (self.buf.len == 0) { | |
| 1211 | self.buf = try self.allocator.alloc(u8, page_size); | |
| 1212 | } | |
| 1213 | ||
| 1214 | while (true) { | |
| 1215 | const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len, | |
| 1216 | &self.darwin_seek); | |
| 1217 | const err = posix.getErrno(result); | |
| 1218 | if (err > 0) { | |
| 1219 | switch (err) { | |
| 1220 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, | |
| 1221 | posix.EINVAL => { | |
| 1222 | self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2); | |
| 1223 | continue; | |
| 1224 | }, | |
| 1225 | else => return unexpectedErrorPosix(err), | |
| 1226 | } | |
| 1227 | } | |
| 1228 | if (result == 0) | |
| 1229 | return null; | |
| 1230 | self.index = 0; | |
| 1231 | self.end_index = result; | |
| 1232 | break; | |
| 1233 | } | |
| 1234 | } | |
| 1235 | const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]); | |
| 1236 | const next_index = self.index + darwin_entry.d_reclen; | |
| 1237 | self.index = next_index; | |
| 1238 | ||
| 1239 | const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen]; | |
| 1240 | ||
| 1241 | // skip . and .. entries | |
| 1242 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { | |
| 1243 | continue :start_over; | |
| 1244 | } | |
| 1245 | ||
| 1246 | const entry_kind = switch (darwin_entry.d_type) { | |
| 1247 | posix.DT_BLK => Entry.Kind.BlockDevice, | |
| 1248 | posix.DT_CHR => Entry.Kind.CharacterDevice, | |
| 1249 | posix.DT_DIR => Entry.Kind.Directory, | |
| 1250 | posix.DT_FIFO => Entry.Kind.NamedPipe, | |
| 1251 | posix.DT_LNK => Entry.Kind.SymLink, | |
| 1252 | posix.DT_REG => Entry.Kind.File, | |
| 1253 | posix.DT_SOCK => Entry.Kind.UnixDomainSocket, | |
| 1254 | posix.DT_WHT => Entry.Kind.Whiteout, | |
| 1255 | else => Entry.Kind.Unknown, | |
| 1256 | }; | |
| 1257 | return Entry { | |
| 1258 | .name = name, | |
| 1259 | .kind = entry_kind, | |
| 1260 | }; | |
| 1261 | } | |
| 1262 | } | |
| 1263 | ||
| 1264 | fn nextWindows(self: &Dir) !?Entry { | |
| 1265 | @compileError("TODO support Dir.next for windows"); | |
| 1266 | } | |
| 1267 | ||
| 1268 | fn nextLinux(self: &Dir) !?Entry { | |
| 1161 | 1269 | start_over: while (true) { |
| 1162 | 1270 | if (self.index >= self.end_index) { |
| 1163 | 1271 | if (self.buf.len == 0) { |
| ... | ... | @@ -1166,7 +1274,7 @@ pub const Dir = struct { |
| 1166 | 1274 | |
| 1167 | 1275 | while (true) { |
| 1168 | 1276 | const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); |
| 1169 | const err = linux.getErrno(result); | |
| 1277 | const err = posix.getErrno(result); | |
| 1170 | 1278 | if (err > 0) { |
| 1171 | 1279 | switch (err) { |
| 1172 | 1280 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, |
| ... | ... | @@ -1184,7 +1292,7 @@ pub const Dir = struct { |
| 1184 | 1292 | break; |
| 1185 | 1293 | } |
| 1186 | 1294 | } |
| 1187 | const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); | |
| 1295 | const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]); | |
| 1188 | 1296 | const next_index = self.index + linux_entry.d_reclen; |
| 1189 | 1297 | self.index = next_index; |
| 1190 | 1298 | |
| ... | ... | @@ -1668,39 +1776,29 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const |
| 1668 | 1776 | assert(it.next(debug.global_allocator) == null); |
| 1669 | 1777 | } |
| 1670 | 1778 | |
| 1671 | test "std.os" { | |
| 1672 | _ = @import("child_process.zig"); | |
| 1673 | _ = @import("darwin_errno.zig"); | |
| 1674 | _ = @import("darwin.zig"); | |
| 1675 | _ = @import("get_user_id.zig"); | |
| 1676 | _ = @import("linux/errno.zig"); | |
| 1677 | //_ = @import("linux_i386.zig"); | |
| 1678 | _ = @import("linux/x86_64.zig"); | |
| 1679 | _ = @import("linux/index.zig"); | |
| 1680 | _ = @import("path.zig"); | |
| 1681 | _ = @import("windows/index.zig"); | |
| 1682 | } | |
| 1683 | ||
| 1684 | ||
| 1685 | 1779 | // TODO make this a build variable that you can set |
| 1686 | 1780 | const unexpected_error_tracing = false; |
| 1781 | const UnexpectedError = error { | |
| 1782 | /// The Operating System returned an undocumented error code. | |
| 1783 | Unexpected, | |
| 1784 | }; | |
| 1687 | 1785 | |
| 1688 | 1786 | /// Call this when you made a syscall or something that sets errno |
| 1689 | 1787 | /// and you get an unexpected error. |
| 1690 | pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) { | |
| 1788 | pub fn unexpectedErrorPosix(errno: usize) UnexpectedError { | |
| 1691 | 1789 | if (unexpected_error_tracing) { |
| 1692 | 1790 | debug.warn("unexpected errno: {}\n", errno); |
| 1693 | debug.dumpStackTrace(); | |
| 1791 | debug.dumpCurrentStackTrace(null); | |
| 1694 | 1792 | } |
| 1695 | 1793 | return error.Unexpected; |
| 1696 | 1794 | } |
| 1697 | 1795 | |
| 1698 | 1796 | /// Call this when you made a windows DLL call or something that does SetLastError |
| 1699 | 1797 | /// and you get an unexpected error. |
| 1700 | pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) { | |
| 1798 | pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { | |
| 1701 | 1799 | if (unexpected_error_tracing) { |
| 1702 | 1800 | debug.warn("unexpected GetLastError(): {}\n", err); |
| 1703 | debug.dumpStackTrace(); | |
| 1801 | debug.dumpCurrentStackTrace(null); | |
| 1704 | 1802 | } |
| 1705 | 1803 | return error.Unexpected; |
| 1706 | 1804 | } |
| ... | ... | @@ -1812,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool { |
| 1812 | 1910 | } |
| 1813 | 1911 | } |
| 1814 | 1912 | } |
| 1913 | ||
| 1914 | pub const PosixSocketError = error { | |
| 1915 | /// Permission to create a socket of the specified type and/or | |
| 1916 | /// pro‐tocol is denied. | |
| 1917 | PermissionDenied, | |
| 1918 | ||
| 1919 | /// The implementation does not support the specified address family. | |
| 1920 | AddressFamilyNotSupported, | |
| 1921 | ||
| 1922 | /// Unknown protocol, or protocol family not available. | |
| 1923 | ProtocolFamilyNotAvailable, | |
| 1924 | ||
| 1925 | /// The per-process limit on the number of open file descriptors has been reached. | |
| 1926 | ProcessFdQuotaExceeded, | |
| 1927 | ||
| 1928 | /// The system-wide limit on the total number of open files has been reached. | |
| 1929 | SystemFdQuotaExceeded, | |
| 1930 | ||
| 1931 | /// Insufficient memory is available. The socket cannot be created until sufficient | |
| 1932 | /// resources are freed. | |
| 1933 | SystemResources, | |
| 1934 | ||
| 1935 | /// The protocol type or the specified protocol is not supported within this domain. | |
| 1936 | ProtocolNotSupported, | |
| 1937 | }; | |
| 1938 | ||
| 1939 | pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 { | |
| 1940 | const rc = posix.socket(domain, socket_type, protocol); | |
| 1941 | const err = posix.getErrno(rc); | |
| 1942 | switch (err) { | |
| 1943 | 0 => return i32(rc), | |
| 1944 | posix.EACCES => return PosixSocketError.PermissionDenied, | |
| 1945 | posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported, | |
| 1946 | posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable, | |
| 1947 | posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded, | |
| 1948 | posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded, | |
| 1949 | posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources, | |
| 1950 | posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported, | |
| 1951 | else => return unexpectedErrorPosix(err), | |
| 1952 | } | |
| 1953 | } | |
| 1954 | ||
| 1955 | pub const PosixBindError = error { | |
| 1956 | /// The address is protected, and the user is not the superuser. | |
| 1957 | /// For UNIX domain sockets: Search permission is denied on a component | |
| 1958 | /// of the path prefix. | |
| 1959 | AccessDenied, | |
| 1960 | ||
| 1961 | /// The given address is already in use, or in the case of Internet domain sockets, | |
| 1962 | /// The port number was specified as zero in the socket | |
| 1963 | /// address structure, but, upon attempting to bind to an ephemeral port, it was | |
| 1964 | /// determined that all port numbers in the ephemeral port range are currently in | |
| 1965 | /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7). | |
| 1966 | AddressInUse, | |
| 1967 | ||
| 1968 | /// sockfd is not a valid file descriptor. | |
| 1969 | InvalidFileDescriptor, | |
| 1970 | ||
| 1971 | /// The socket is already bound to an address, or addrlen is wrong, or addr is not | |
| 1972 | /// a valid address for this socket's domain. | |
| 1973 | InvalidSocketOrAddress, | |
| 1974 | ||
| 1975 | /// The file descriptor sockfd does not refer to a socket. | |
| 1976 | FileDescriptorNotASocket, | |
| 1977 | ||
| 1978 | /// A nonexistent interface was requested or the requested address was not local. | |
| 1979 | AddressNotAvailable, | |
| 1980 | ||
| 1981 | /// addr points outside the user's accessible address space. | |
| 1982 | PageFault, | |
| 1983 | ||
| 1984 | /// Too many symbolic links were encountered in resolving addr. | |
| 1985 | SymLinkLoop, | |
| 1986 | ||
| 1987 | /// addr is too long. | |
| 1988 | NameTooLong, | |
| 1989 | ||
| 1990 | /// A component in the directory prefix of the socket pathname does not exist. | |
| 1991 | FileNotFound, | |
| 1992 | ||
| 1993 | /// Insufficient kernel memory was available. | |
| 1994 | SystemResources, | |
| 1995 | ||
| 1996 | /// A component of the path prefix is not a directory. | |
| 1997 | NotDir, | |
| 1998 | ||
| 1999 | /// The socket inode would reside on a read-only filesystem. | |
| 2000 | ReadOnlyFileSystem, | |
| 2001 | ||
| 2002 | Unexpected, | |
| 2003 | }; | |
| 2004 | ||
| 2005 | /// addr is `&const T` where T is one of the sockaddr | |
| 2006 | pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void { | |
| 2007 | const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr)); | |
| 2008 | const err = posix.getErrno(rc); | |
| 2009 | switch (err) { | |
| 2010 | 0 => return, | |
| 2011 | posix.EACCES => return PosixBindError.AccessDenied, | |
| 2012 | posix.EADDRINUSE => return PosixBindError.AddressInUse, | |
| 2013 | posix.EBADF => return PosixBindError.InvalidFileDescriptor, | |
| 2014 | posix.EINVAL => return PosixBindError.InvalidSocketOrAddress, | |
| 2015 | posix.ENOTSOCK => return PosixBindError.FileDescriptorNotASocket, | |
| 2016 | posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable, | |
| 2017 | posix.EFAULT => return PosixBindError.PageFault, | |
| 2018 | posix.ELOOP => return PosixBindError.SymLinkLoop, | |
| 2019 | posix.ENAMETOOLONG => return PosixBindError.NameTooLong, | |
| 2020 | posix.ENOENT => return PosixBindError.FileNotFound, | |
| 2021 | posix.ENOMEM => return PosixBindError.SystemResources, | |
| 2022 | posix.ENOTDIR => return PosixBindError.NotDir, | |
| 2023 | posix.EROFS => return PosixBindError.ReadOnlyFileSystem, | |
| 2024 | else => return unexpectedErrorPosix(err), | |
| 2025 | } | |
| 2026 | } | |
| 2027 | ||
| 2028 | const PosixListenError = error { | |
| 2029 | /// Another socket is already listening on the same port. | |
| 2030 | /// For Internet domain sockets, the socket referred to by sockfd had not previously | |
| 2031 | /// been bound to an address and, upon attempting to bind it to an ephemeral port, it | |
| 2032 | /// was determined that all port numbers in the ephemeral port range are currently in | |
| 2033 | /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). | |
| 2034 | AddressInUse, | |
| 2035 | ||
| 2036 | /// The argument sockfd is not a valid file descriptor. | |
| 2037 | InvalidFileDescriptor, | |
| 2038 | ||
| 2039 | /// The file descriptor sockfd does not refer to a socket. | |
| 2040 | FileDescriptorNotASocket, | |
| 2041 | ||
| 2042 | /// The socket is not of a type that supports the listen() operation. | |
| 2043 | OperationNotSupported, | |
| 2044 | ||
| 2045 | Unexpected, | |
| 2046 | }; | |
| 2047 | ||
| 2048 | pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void { | |
| 2049 | const rc = posix.listen(sockfd, backlog); | |
| 2050 | const err = posix.getErrno(rc); | |
| 2051 | switch (err) { | |
| 2052 | 0 => return, | |
| 2053 | posix.EADDRINUSE => return PosixListenError.AddressInUse, | |
| 2054 | posix.EBADF => return PosixListenError.InvalidFileDescriptor, | |
| 2055 | posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket, | |
| 2056 | posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported, | |
| 2057 | else => return unexpectedErrorPosix(err), | |
| 2058 | } | |
| 2059 | } | |
| 2060 | ||
| 2061 | pub const PosixAcceptError = error { | |
| 2062 | /// The socket is marked nonblocking and no connections are present to be accepted. | |
| 2063 | WouldBlock, | |
| 2064 | ||
| 2065 | /// sockfd is not an open file descriptor. | |
| 2066 | FileDescriptorClosed, | |
| 2067 | ||
| 2068 | ConnectionAborted, | |
| 2069 | ||
| 2070 | /// The addr argument is not in a writable part of the user address space. | |
| 2071 | PageFault, | |
| 2072 | ||
| 2073 | /// Socket is not listening for connections, or addrlen is invalid (e.g., is negative), | |
| 2074 | /// or invalid value in flags. | |
| 2075 | InvalidSyscall, | |
| 2076 | ||
| 2077 | /// The per-process limit on the number of open file descriptors has been reached. | |
| 2078 | ProcessFdQuotaExceeded, | |
| 2079 | ||
| 2080 | /// The system-wide limit on the total number of open files has been reached. | |
| 2081 | SystemFdQuotaExceeded, | |
| 2082 | ||
| 2083 | /// Not enough free memory. This often means that the memory allocation is limited | |
| 2084 | /// by the socket buffer limits, not by the system memory. | |
| 2085 | SystemResources, | |
| 2086 | ||
| 2087 | /// The file descriptor sockfd does not refer to a socket. | |
| 2088 | FileDescriptorNotASocket, | |
| 2089 | ||
| 2090 | /// The referenced socket is not of type SOCK_STREAM. | |
| 2091 | OperationNotSupported, | |
| 2092 | ||
| 2093 | ProtocolFailure, | |
| 2094 | ||
| 2095 | /// Firewall rules forbid connection. | |
| 2096 | BlockedByFirewall, | |
| 2097 | ||
| 2098 | Unexpected, | |
| 2099 | }; | |
| 2100 | ||
| 2101 | pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!i32 { | |
| 2102 | while (true) { | |
| 2103 | var sockaddr_size = u32(@sizeOf(posix.sockaddr)); | |
| 2104 | const rc = posix.accept4(fd, addr, &sockaddr_size, flags); | |
| 2105 | const err = posix.getErrno(rc); | |
| 2106 | switch (err) { | |
| 2107 | 0 => return i32(rc), | |
| 2108 | posix.EINTR => continue, | |
| 2109 | else => return unexpectedErrorPosix(err), | |
| 2110 | ||
| 2111 | posix.EAGAIN => return PosixAcceptError.WouldBlock, | |
| 2112 | posix.EBADF => return PosixAcceptError.FileDescriptorClosed, | |
| 2113 | posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted, | |
| 2114 | posix.EFAULT => return PosixAcceptError.PageFault, | |
| 2115 | posix.EINVAL => return PosixAcceptError.InvalidSyscall, | |
| 2116 | posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded, | |
| 2117 | posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded, | |
| 2118 | posix.ENOBUFS, posix.ENOMEM => return PosixAcceptError.SystemResources, | |
| 2119 | posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket, | |
| 2120 | posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported, | |
| 2121 | posix.EPROTO => return PosixAcceptError.ProtocolFailure, | |
| 2122 | posix.EPERM => return PosixAcceptError.BlockedByFirewall, | |
| 2123 | } | |
| 2124 | } | |
| 2125 | } | |
| 2126 | ||
| 2127 | pub const LinuxEpollCreateError = error { | |
| 2128 | /// Invalid value specified in flags. | |
| 2129 | InvalidSyscall, | |
| 2130 | ||
| 2131 | /// The per-user limit on the number of epoll instances imposed by | |
| 2132 | /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further | |
| 2133 | /// details. | |
| 2134 | /// Or, The per-process limit on the number of open file descriptors has been reached. | |
| 2135 | ProcessFdQuotaExceeded, | |
| 2136 | ||
| 2137 | /// The system-wide limit on the total number of open files has been reached. | |
| 2138 | SystemFdQuotaExceeded, | |
| 2139 | ||
| 2140 | /// There was insufficient memory to create the kernel object. | |
| 2141 | SystemResources, | |
| 2142 | ||
| 2143 | Unexpected, | |
| 2144 | }; | |
| 2145 | ||
| 2146 | pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 { | |
| 2147 | const rc = posix.epoll_create1(flags); | |
| 2148 | const err = posix.getErrno(rc); | |
| 2149 | switch (err) { | |
| 2150 | 0 => return i32(rc), | |
| 2151 | else => return unexpectedErrorPosix(err), | |
| 2152 | ||
| 2153 | posix.EINVAL => return LinuxEpollCreateError.InvalidSyscall, | |
| 2154 | posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded, | |
| 2155 | posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded, | |
| 2156 | posix.ENOMEM => return LinuxEpollCreateError.SystemResources, | |
| 2157 | } | |
| 2158 | } | |
| 2159 | ||
| 2160 | pub const LinuxEpollCtlError = error { | |
| 2161 | /// epfd or fd is not a valid file descriptor. | |
| 2162 | InvalidFileDescriptor, | |
| 2163 | ||
| 2164 | /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered | |
| 2165 | /// with this epoll instance. | |
| 2166 | FileDescriptorAlreadyPresentInSet, | |
| 2167 | ||
| 2168 | /// epfd is not an epoll file descriptor, or fd is the same as epfd, or the requested | |
| 2169 | /// operation op is not supported by this interface, or | |
| 2170 | /// An invalid event type was specified along with EPOLLEXCLUSIVE in events, or | |
| 2171 | /// op was EPOLL_CTL_MOD and events included EPOLLEXCLUSIVE, or | |
| 2172 | /// op was EPOLL_CTL_MOD and the EPOLLEXCLUSIVE flag has previously been applied to | |
| 2173 | /// this epfd, fd pair, or | |
| 2174 | /// EPOLLEXCLUSIVE was specified in event and fd refers to an epoll instance. | |
| 2175 | InvalidSyscall, | |
| 2176 | ||
| 2177 | /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a | |
| 2178 | /// circular loop of epoll instances monitoring one another. | |
| 2179 | OperationCausesCircularLoop, | |
| 2180 | ||
| 2181 | /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll | |
| 2182 | /// instance. | |
| 2183 | FileDescriptorNotRegistered, | |
| 2184 | ||
| 2185 | /// There was insufficient memory to handle the requested op control operation. | |
| 2186 | SystemResources, | |
| 2187 | ||
| 2188 | /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while | |
| 2189 | /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance. | |
| 2190 | /// See epoll(7) for further details. | |
| 2191 | UserResourceLimitReached, | |
| 2192 | ||
| 2193 | /// The target file fd does not support epoll. This error can occur if fd refers to, | |
| 2194 | /// for example, a regular file or a directory. | |
| 2195 | FileDescriptorIncompatibleWithEpoll, | |
| 2196 | ||
| 2197 | Unexpected, | |
| 2198 | }; | |
| 2199 | ||
| 2200 | pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) LinuxEpollCtlError!void { | |
| 2201 | const rc = posix.epoll_ctl(epfd, op, fd, event); | |
| 2202 | const err = posix.getErrno(rc); | |
| 2203 | switch (err) { | |
| 2204 | 0 => return, | |
| 2205 | else => return unexpectedErrorPosix(err), | |
| 2206 | ||
| 2207 | posix.EBADF => return LinuxEpollCtlError.InvalidFileDescriptor, | |
| 2208 | posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet, | |
| 2209 | posix.EINVAL => return LinuxEpollCtlError.InvalidSyscall, | |
| 2210 | posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop, | |
| 2211 | posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered, | |
| 2212 | posix.ENOMEM => return LinuxEpollCtlError.SystemResources, | |
| 2213 | posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached, | |
| 2214 | posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll, | |
| 2215 | } | |
| 2216 | } | |
| 2217 | ||
| 2218 | pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize { | |
| 2219 | while (true) { | |
| 2220 | const rc = posix.epoll_wait(epfd, events.ptr, u32(events.len), timeout); | |
| 2221 | const err = posix.getErrno(rc); | |
| 2222 | switch (err) { | |
| 2223 | 0 => return rc, | |
| 2224 | posix.EINTR => continue, | |
| 2225 | posix.EBADF => unreachable, | |
| 2226 | posix.EFAULT => unreachable, | |
| 2227 | posix.EINVAL => unreachable, | |
| 2228 | else => unreachable, | |
| 2229 | } | |
| 2230 | } | |
| 2231 | } | |
| 2232 | ||
| 2233 | pub const PosixGetSockNameError = error { | |
| 2234 | /// Insufficient resources were available in the system to perform the operation. | |
| 2235 | SystemResources, | |
| 2236 | ||
| 2237 | Unexpected, | |
| 2238 | }; | |
| 2239 | ||
| 2240 | pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr { | |
| 2241 | var addr: posix.sockaddr = undefined; | |
| 2242 | var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr); | |
| 2243 | const rc = posix.getsockname(sockfd, &addr, &addrlen); | |
| 2244 | const err = posix.getErrno(rc); | |
| 2245 | switch (err) { | |
| 2246 | 0 => return addr, | |
| 2247 | else => return unexpectedErrorPosix(err), | |
| 2248 | ||
| 2249 | posix.EBADF => unreachable, | |
| 2250 | posix.EFAULT => unreachable, | |
| 2251 | posix.EINVAL => unreachable, | |
| 2252 | posix.ENOTSOCK => unreachable, | |
| 2253 | posix.ENOBUFS => return PosixGetSockNameError.SystemResources, | |
| 2254 | } | |
| 2255 | } | |
| 2256 | ||
| 2257 | pub const PosixConnectError = error { | |
| 2258 | /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket | |
| 2259 | /// file, or search permission is denied for one of the directories in the path prefix. | |
| 2260 | /// or | |
| 2261 | /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or | |
| 2262 | /// the connection request failed because of a local firewall rule. | |
| 2263 | PermissionDenied, | |
| 2264 | ||
| 2265 | /// Local address is already in use. | |
| 2266 | AddressInUse, | |
| 2267 | ||
| 2268 | /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an | |
| 2269 | /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers | |
| 2270 | /// in the ephemeral port range are currently in use. See the discussion of | |
| 2271 | /// /proc/sys/net/ipv4/ip_local_port_range in ip(7). | |
| 2272 | AddressNotAvailable, | |
| 2273 | ||
| 2274 | /// The passed address didn't have the correct address family in its sa_family field. | |
| 2275 | AddressFamilyNotSupported, | |
| 2276 | ||
| 2277 | /// Insufficient entries in the routing cache. | |
| 2278 | SystemResources, | |
| 2279 | ||
| 2280 | /// A connect() on a stream socket found no one listening on the remote address. | |
| 2281 | ConnectionRefused, | |
| 2282 | ||
| 2283 | /// Network is unreachable. | |
| 2284 | NetworkUnreachable, | |
| 2285 | ||
| 2286 | /// Timeout while attempting connection. The server may be too busy to accept new connections. Note | |
| 2287 | /// that for IP sockets the timeout may be very long when syncookies are enabled on the server. | |
| 2288 | ConnectionTimedOut, | |
| 2289 | ||
| 2290 | Unexpected, | |
| 2291 | }; | |
| 2292 | ||
| 2293 | pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void { | |
| 2294 | while (true) { | |
| 2295 | const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr)); | |
| 2296 | const err = posix.getErrno(rc); | |
| 2297 | switch (err) { | |
| 2298 | 0 => return, | |
| 2299 | else => return unexpectedErrorPosix(err), | |
| 2300 | ||
| 2301 | posix.EACCES => return PosixConnectError.PermissionDenied, | |
| 2302 | posix.EPERM => return PosixConnectError.PermissionDenied, | |
| 2303 | posix.EADDRINUSE => return PosixConnectError.AddressInUse, | |
| 2304 | posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable, | |
| 2305 | posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported, | |
| 2306 | posix.EAGAIN => return PosixConnectError.SystemResources, | |
| 2307 | posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed. | |
| 2308 | posix.EBADF => unreachable, // sockfd is not a valid open file descriptor. | |
| 2309 | posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused, | |
| 2310 | posix.EFAULT => unreachable, // The socket structure address is outside the user's address space. | |
| 2311 | posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately. | |
| 2312 | posix.EINTR => continue, | |
| 2313 | posix.EISCONN => unreachable, // The socket is already connected. | |
| 2314 | posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable, | |
| 2315 | posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | |
| 2316 | posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol. | |
| 2317 | posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut, | |
| 2318 | } | |
| 2319 | } | |
| 2320 | } | |
| 2321 | ||
| 2322 | /// Same as posixConnect except it is for blocking socket file descriptors. | |
| 2323 | /// It expects to receive EINPROGRESS. | |
| 2324 | pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void { | |
| 2325 | while (true) { | |
| 2326 | const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr)); | |
| 2327 | const err = posix.getErrno(rc); | |
| 2328 | switch (err) { | |
| 2329 | 0, posix.EINPROGRESS => return, | |
| 2330 | else => return unexpectedErrorPosix(err), | |
| 2331 | ||
| 2332 | posix.EACCES => return PosixConnectError.PermissionDenied, | |
| 2333 | posix.EPERM => return PosixConnectError.PermissionDenied, | |
| 2334 | posix.EADDRINUSE => return PosixConnectError.AddressInUse, | |
| 2335 | posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable, | |
| 2336 | posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported, | |
| 2337 | posix.EAGAIN => return PosixConnectError.SystemResources, | |
| 2338 | posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed. | |
| 2339 | posix.EBADF => unreachable, // sockfd is not a valid open file descriptor. | |
| 2340 | posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused, | |
| 2341 | posix.EFAULT => unreachable, // The socket structure address is outside the user's address space. | |
| 2342 | posix.EINTR => continue, | |
| 2343 | posix.EISCONN => unreachable, // The socket is already connected. | |
| 2344 | posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable, | |
| 2345 | posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | |
| 2346 | posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol. | |
| 2347 | posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut, | |
| 2348 | } | |
| 2349 | } | |
| 2350 | } | |
| 2351 | ||
| 2352 | pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void { | |
| 2353 | var err_code: i32 = undefined; | |
| 2354 | var size: u32 = @sizeOf(i32); | |
| 2355 | const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast(&u8, &err_code), &size); | |
| 2356 | assert(size == 4); | |
| 2357 | const err = posix.getErrno(rc); | |
| 2358 | switch (err) { | |
| 2359 | 0 => switch (err_code) { | |
| 2360 | 0 => return, | |
| 2361 | else => return unexpectedErrorPosix(err), | |
| 2362 | ||
| 2363 | posix.EACCES => return PosixConnectError.PermissionDenied, | |
| 2364 | posix.EPERM => return PosixConnectError.PermissionDenied, | |
| 2365 | posix.EADDRINUSE => return PosixConnectError.AddressInUse, | |
| 2366 | posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable, | |
| 2367 | posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported, | |
| 2368 | posix.EAGAIN => return PosixConnectError.SystemResources, | |
| 2369 | posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed. | |
| 2370 | posix.EBADF => unreachable, // sockfd is not a valid open file descriptor. | |
| 2371 | posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused, | |
| 2372 | posix.EFAULT => unreachable, // The socket structure address is outside the user's address space. | |
| 2373 | posix.EISCONN => unreachable, // The socket is already connected. | |
| 2374 | posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable, | |
| 2375 | posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | |
| 2376 | posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol. | |
| 2377 | posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut, | |
| 2378 | }, | |
| 2379 | else => return unexpectedErrorPosix(err), | |
| 2380 | posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor. | |
| 2381 | posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space. | |
| 2382 | posix.EINVAL => unreachable, | |
| 2383 | posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated. | |
| 2384 | posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | |
| 2385 | } | |
| 2386 | } |
std/os/linux/i386.zig deleted-505| ... | ... | @@ -1,505 +0,0 @@ |
| 1 | const std = @import("../../index.zig"); | |
| 2 | const linux = std.os.linux; | |
| 3 | const socklen_t = linux.socklen_t; | |
| 4 | const iovec = linux.iovec; | |
| 5 | ||
| 6 | pub const SYS_restart_syscall = 0; | |
| 7 | pub const SYS_exit = 1; | |
| 8 | pub const SYS_fork = 2; | |
| 9 | pub const SYS_read = 3; | |
| 10 | pub const SYS_write = 4; | |
| 11 | pub const SYS_open = 5; | |
| 12 | pub const SYS_close = 6; | |
| 13 | pub const SYS_waitpid = 7; | |
| 14 | pub const SYS_creat = 8; | |
| 15 | pub const SYS_link = 9; | |
| 16 | pub const SYS_unlink = 10; | |
| 17 | pub const SYS_execve = 11; | |
| 18 | pub const SYS_chdir = 12; | |
| 19 | pub const SYS_time = 13; | |
| 20 | pub const SYS_mknod = 14; | |
| 21 | pub const SYS_chmod = 15; | |
| 22 | pub const SYS_lchown = 16; | |
| 23 | pub const SYS_break = 17; | |
| 24 | pub const SYS_oldstat = 18; | |
| 25 | pub const SYS_lseek = 19; | |
| 26 | pub const SYS_getpid = 20; | |
| 27 | pub const SYS_mount = 21; | |
| 28 | pub const SYS_umount = 22; | |
| 29 | pub const SYS_setuid = 23; | |
| 30 | pub const SYS_getuid = 24; | |
| 31 | pub const SYS_stime = 25; | |
| 32 | pub const SYS_ptrace = 26; | |
| 33 | pub const SYS_alarm = 27; | |
| 34 | pub const SYS_oldfstat = 28; | |
| 35 | pub const SYS_pause = 29; | |
| 36 | pub const SYS_utime = 30; | |
| 37 | pub const SYS_stty = 31; | |
| 38 | pub const SYS_gtty = 32; | |
| 39 | pub const SYS_access = 33; | |
| 40 | pub const SYS_nice = 34; | |
| 41 | pub const SYS_ftime = 35; | |
| 42 | pub const SYS_sync = 36; | |
| 43 | pub const SYS_kill = 37; | |
| 44 | pub const SYS_rename = 38; | |
| 45 | pub const SYS_mkdir = 39; | |
| 46 | pub const SYS_rmdir = 40; | |
| 47 | pub const SYS_dup = 41; | |
| 48 | pub const SYS_pipe = 42; | |
| 49 | pub const SYS_times = 43; | |
| 50 | pub const SYS_prof = 44; | |
| 51 | pub const SYS_brk = 45; | |
| 52 | pub const SYS_setgid = 46; | |
| 53 | pub const SYS_getgid = 47; | |
| 54 | pub const SYS_signal = 48; | |
| 55 | pub const SYS_geteuid = 49; | |
| 56 | pub const SYS_getegid = 50; | |
| 57 | pub const SYS_acct = 51; | |
| 58 | pub const SYS_umount2 = 52; | |
| 59 | pub const SYS_lock = 53; | |
| 60 | pub const SYS_ioctl = 54; | |
| 61 | pub const SYS_fcntl = 55; | |
| 62 | pub const SYS_mpx = 56; | |
| 63 | pub const SYS_setpgid = 57; | |
| 64 | pub const SYS_ulimit = 58; | |
| 65 | pub const SYS_oldolduname = 59; | |
| 66 | pub const SYS_umask = 60; | |
| 67 | pub const SYS_chroot = 61; | |
| 68 | pub const SYS_ustat = 62; | |
| 69 | pub const SYS_dup2 = 63; | |
| 70 | pub const SYS_getppid = 64; | |
| 71 | pub const SYS_getpgrp = 65; | |
| 72 | pub const SYS_setsid = 66; | |
| 73 | pub const SYS_sigaction = 67; | |
| 74 | pub const SYS_sgetmask = 68; | |
| 75 | pub const SYS_ssetmask = 69; | |
| 76 | pub const SYS_setreuid = 70; | |
| 77 | pub const SYS_setregid = 71; | |
| 78 | pub const SYS_sigsuspend = 72; | |
| 79 | pub const SYS_sigpending = 73; | |
| 80 | pub const SYS_sethostname = 74; | |
| 81 | pub const SYS_setrlimit = 75; | |
| 82 | pub const SYS_getrlimit = 76; | |
| 83 | pub const SYS_getrusage = 77; | |
| 84 | pub const SYS_gettimeofday = 78; | |
| 85 | pub const SYS_settimeofday = 79; | |
| 86 | pub const SYS_getgroups = 80; | |
| 87 | pub const SYS_setgroups = 81; | |
| 88 | pub const SYS_select = 82; | |
| 89 | pub const SYS_symlink = 83; | |
| 90 | pub const SYS_oldlstat = 84; | |
| 91 | pub const SYS_readlink = 85; | |
| 92 | pub const SYS_uselib = 86; | |
| 93 | pub const SYS_swapon = 87; | |
| 94 | pub const SYS_reboot = 88; | |
| 95 | pub const SYS_readdir = 89; | |
| 96 | pub const SYS_mmap = 90; | |
| 97 | pub const SYS_munmap = 91; | |
| 98 | pub const SYS_truncate = 92; | |
| 99 | pub const SYS_ftruncate = 93; | |
| 100 | pub const SYS_fchmod = 94; | |
| 101 | pub const SYS_fchown = 95; | |
| 102 | pub const SYS_getpriority = 96; | |
| 103 | pub const SYS_setpriority = 97; | |
| 104 | pub const SYS_profil = 98; | |
| 105 | pub const SYS_statfs = 99; | |
| 106 | pub const SYS_fstatfs = 100; | |
| 107 | pub const SYS_ioperm = 101; | |
| 108 | pub const SYS_socketcall = 102; | |
| 109 | pub const SYS_syslog = 103; | |
| 110 | pub const SYS_setitimer = 104; | |
| 111 | pub const SYS_getitimer = 105; | |
| 112 | pub const SYS_stat = 106; | |
| 113 | pub const SYS_lstat = 107; | |
| 114 | pub const SYS_fstat = 108; | |
| 115 | pub const SYS_olduname = 109; | |
| 116 | pub const SYS_iopl = 110; | |
| 117 | pub const SYS_vhangup = 111; | |
| 118 | pub const SYS_idle = 112; | |
| 119 | pub const SYS_vm86old = 113; | |
| 120 | pub const SYS_wait4 = 114; | |
| 121 | pub const SYS_swapoff = 115; | |
| 122 | pub const SYS_sysinfo = 116; | |
| 123 | pub const SYS_ipc = 117; | |
| 124 | pub const SYS_fsync = 118; | |
| 125 | pub const SYS_sigreturn = 119; | |
| 126 | pub const SYS_clone = 120; | |
| 127 | pub const SYS_setdomainname = 121; | |
| 128 | pub const SYS_uname = 122; | |
| 129 | pub const SYS_modify_ldt = 123; | |
| 130 | pub const SYS_adjtimex = 124; | |
| 131 | pub const SYS_mprotect = 125; | |
| 132 | pub const SYS_sigprocmask = 126; | |
| 133 | pub const SYS_create_module = 127; | |
| 134 | pub const SYS_init_module = 128; | |
| 135 | pub const SYS_delete_module = 129; | |
| 136 | pub const SYS_get_kernel_syms = 130; | |
| 137 | pub const SYS_quotactl = 131; | |
| 138 | pub const SYS_getpgid = 132; | |
| 139 | pub const SYS_fchdir = 133; | |
| 140 | pub const SYS_bdflush = 134; | |
| 141 | pub const SYS_sysfs = 135; | |
| 142 | pub const SYS_personality = 136; | |
| 143 | pub const SYS_afs_syscall = 137; | |
| 144 | pub const SYS_setfsuid = 138; | |
| 145 | pub const SYS_setfsgid = 139; | |
| 146 | pub const SYS__llseek = 140; | |
| 147 | pub const SYS_getdents = 141; | |
| 148 | pub const SYS__newselect = 142; | |
| 149 | pub const SYS_flock = 143; | |
| 150 | pub const SYS_msync = 144; | |
| 151 | pub const SYS_readv = 145; | |
| 152 | pub const SYS_writev = 146; | |
| 153 | pub const SYS_getsid = 147; | |
| 154 | pub const SYS_fdatasync = 148; | |
| 155 | pub const SYS__sysctl = 149; | |
| 156 | pub const SYS_mlock = 150; | |
| 157 | pub const SYS_munlock = 151; | |
| 158 | pub const SYS_mlockall = 152; | |
| 159 | pub const SYS_munlockall = 153; | |
| 160 | pub const SYS_sched_setparam = 154; | |
| 161 | pub const SYS_sched_getparam = 155; | |
| 162 | pub const SYS_sched_setscheduler = 156; | |
| 163 | pub const SYS_sched_getscheduler = 157; | |
| 164 | pub const SYS_sched_yield = 158; | |
| 165 | pub const SYS_sched_get_priority_max = 159; | |
| 166 | pub const SYS_sched_get_priority_min = 160; | |
| 167 | pub const SYS_sched_rr_get_interval = 161; | |
| 168 | pub const SYS_nanosleep = 162; | |
| 169 | pub const SYS_mremap = 163; | |
| 170 | pub const SYS_setresuid = 164; | |
| 171 | pub const SYS_getresuid = 165; | |
| 172 | pub const SYS_vm86 = 166; | |
| 173 | pub const SYS_query_module = 167; | |
| 174 | pub const SYS_poll = 168; | |
| 175 | pub const SYS_nfsservctl = 169; | |
| 176 | pub const SYS_setresgid = 170; | |
| 177 | pub const SYS_getresgid = 171; | |
| 178 | pub const SYS_prctl = 172; | |
| 179 | pub const SYS_rt_sigreturn = 173; | |
| 180 | pub const SYS_rt_sigaction = 174; | |
| 181 | pub const SYS_rt_sigprocmask = 175; | |
| 182 | pub const SYS_rt_sigpending = 176; | |
| 183 | pub const SYS_rt_sigtimedwait = 177; | |
| 184 | pub const SYS_rt_sigqueueinfo = 178; | |
| 185 | pub const SYS_rt_sigsuspend = 179; | |
| 186 | pub const SYS_pread64 = 180; | |
| 187 | pub const SYS_pwrite64 = 181; | |
| 188 | pub const SYS_chown = 182; | |
| 189 | pub const SYS_getcwd = 183; | |
| 190 | pub const SYS_capget = 184; | |
| 191 | pub const SYS_capset = 185; | |
| 192 | pub const SYS_sigaltstack = 186; | |
| 193 | pub const SYS_sendfile = 187; | |
| 194 | pub const SYS_getpmsg = 188; | |
| 195 | pub const SYS_putpmsg = 189; | |
| 196 | pub const SYS_vfork = 190; | |
| 197 | pub const SYS_ugetrlimit = 191; | |
| 198 | pub const SYS_mmap2 = 192; | |
| 199 | pub const SYS_truncate64 = 193; | |
| 200 | pub const SYS_ftruncate64 = 194; | |
| 201 | pub const SYS_stat64 = 195; | |
| 202 | pub const SYS_lstat64 = 196; | |
| 203 | pub const SYS_fstat64 = 197; | |
| 204 | pub const SYS_lchown32 = 198; | |
| 205 | pub const SYS_getuid32 = 199; | |
| 206 | pub const SYS_getgid32 = 200; | |
| 207 | pub const SYS_geteuid32 = 201; | |
| 208 | pub const SYS_getegid32 = 202; | |
| 209 | pub const SYS_setreuid32 = 203; | |
| 210 | pub const SYS_setregid32 = 204; | |
| 211 | pub const SYS_getgroups32 = 205; | |
| 212 | pub const SYS_setgroups32 = 206; | |
| 213 | pub const SYS_fchown32 = 207; | |
| 214 | pub const SYS_setresuid32 = 208; | |
| 215 | pub const SYS_getresuid32 = 209; | |
| 216 | pub const SYS_setresgid32 = 210; | |
| 217 | pub const SYS_getresgid32 = 211; | |
| 218 | pub const SYS_chown32 = 212; | |
| 219 | pub const SYS_setuid32 = 213; | |
| 220 | pub const SYS_setgid32 = 214; | |
| 221 | pub const SYS_setfsuid32 = 215; | |
| 222 | pub const SYS_setfsgid32 = 216; | |
| 223 | pub const SYS_pivot_root = 217; | |
| 224 | pub const SYS_mincore = 218; | |
| 225 | pub const SYS_madvise = 219; | |
| 226 | pub const SYS_madvise1 = 219; | |
| 227 | pub const SYS_getdents64 = 220; | |
| 228 | pub const SYS_fcntl64 = 221; | |
| 229 | pub const SYS_gettid = 224; | |
| 230 | pub const SYS_readahead = 225; | |
| 231 | pub const SYS_setxattr = 226; | |
| 232 | pub const SYS_lsetxattr = 227; | |
| 233 | pub const SYS_fsetxattr = 228; | |
| 234 | pub const SYS_getxattr = 229; | |
| 235 | pub const SYS_lgetxattr = 230; | |
| 236 | pub const SYS_fgetxattr = 231; | |
| 237 | pub const SYS_listxattr = 232; | |
| 238 | pub const SYS_llistxattr = 233; | |
| 239 | pub const SYS_flistxattr = 234; | |
| 240 | pub const SYS_removexattr = 235; | |
| 241 | pub const SYS_lremovexattr = 236; | |
| 242 | pub const SYS_fremovexattr = 237; | |
| 243 | pub const SYS_tkill = 238; | |
| 244 | pub const SYS_sendfile64 = 239; | |
| 245 | pub const SYS_futex = 240; | |
| 246 | pub const SYS_sched_setaffinity = 241; | |
| 247 | pub const SYS_sched_getaffinity = 242; | |
| 248 | pub const SYS_set_thread_area = 243; | |
| 249 | pub const SYS_get_thread_area = 244; | |
| 250 | pub const SYS_io_setup = 245; | |
| 251 | pub const SYS_io_destroy = 246; | |
| 252 | pub const SYS_io_getevents = 247; | |
| 253 | pub const SYS_io_submit = 248; | |
| 254 | pub const SYS_io_cancel = 249; | |
| 255 | pub const SYS_fadvise64 = 250; | |
| 256 | pub const SYS_exit_group = 252; | |
| 257 | pub const SYS_lookup_dcookie = 253; | |
| 258 | pub const SYS_epoll_create = 254; | |
| 259 | pub const SYS_epoll_ctl = 255; | |
| 260 | pub const SYS_epoll_wait = 256; | |
| 261 | pub const SYS_remap_file_pages = 257; | |
| 262 | pub const SYS_set_tid_address = 258; | |
| 263 | pub const SYS_timer_create = 259; | |
| 264 | pub const SYS_timer_settime = SYS_timer_create+1; | |
| 265 | pub const SYS_timer_gettime = SYS_timer_create+2; | |
| 266 | pub const SYS_timer_getoverrun = SYS_timer_create+3; | |
| 267 | pub const SYS_timer_delete = SYS_timer_create+4; | |
| 268 | pub const SYS_clock_settime = SYS_timer_create+5; | |
| 269 | pub const SYS_clock_gettime = SYS_timer_create+6; | |
| 270 | pub const SYS_clock_getres = SYS_timer_create+7; | |
| 271 | pub const SYS_clock_nanosleep = SYS_timer_create+8; | |
| 272 | pub const SYS_statfs64 = 268; | |
| 273 | pub const SYS_fstatfs64 = 269; | |
| 274 | pub const SYS_tgkill = 270; | |
| 275 | pub const SYS_utimes = 271; | |
| 276 | pub const SYS_fadvise64_64 = 272; | |
| 277 | pub const SYS_vserver = 273; | |
| 278 | pub const SYS_mbind = 274; | |
| 279 | pub const SYS_get_mempolicy = 275; | |
| 280 | pub const SYS_set_mempolicy = 276; | |
| 281 | pub const SYS_mq_open = 277; | |
| 282 | pub const SYS_mq_unlink = SYS_mq_open+1; | |
| 283 | pub const SYS_mq_timedsend = SYS_mq_open+2; | |
| 284 | pub const SYS_mq_timedreceive = SYS_mq_open+3; | |
| 285 | pub const SYS_mq_notify = SYS_mq_open+4; | |
| 286 | pub const SYS_mq_getsetattr = SYS_mq_open+5; | |
| 287 | pub const SYS_kexec_load = 283; | |
| 288 | pub const SYS_waitid = 284; | |
| 289 | pub const SYS_add_key = 286; | |
| 290 | pub const SYS_request_key = 287; | |
| 291 | pub const SYS_keyctl = 288; | |
| 292 | pub const SYS_ioprio_set = 289; | |
| 293 | pub const SYS_ioprio_get = 290; | |
| 294 | pub const SYS_inotify_init = 291; | |
| 295 | pub const SYS_inotify_add_watch = 292; | |
| 296 | pub const SYS_inotify_rm_watch = 293; | |
| 297 | pub const SYS_migrate_pages = 294; | |
| 298 | pub const SYS_openat = 295; | |
| 299 | pub const SYS_mkdirat = 296; | |
| 300 | pub const SYS_mknodat = 297; | |
| 301 | pub const SYS_fchownat = 298; | |
| 302 | pub const SYS_futimesat = 299; | |
| 303 | pub const SYS_fstatat64 = 300; | |
| 304 | pub const SYS_unlinkat = 301; | |
| 305 | pub const SYS_renameat = 302; | |
| 306 | pub const SYS_linkat = 303; | |
| 307 | pub const SYS_symlinkat = 304; | |
| 308 | pub const SYS_readlinkat = 305; | |
| 309 | pub const SYS_fchmodat = 306; | |
| 310 | pub const SYS_faccessat = 307; | |
| 311 | pub const SYS_pselect6 = 308; | |
| 312 | pub const SYS_ppoll = 309; | |
| 313 | pub const SYS_unshare = 310; | |
| 314 | pub const SYS_set_robust_list = 311; | |
| 315 | pub const SYS_get_robust_list = 312; | |
| 316 | pub const SYS_splice = 313; | |
| 317 | pub const SYS_sync_file_range = 314; | |
| 318 | pub const SYS_tee = 315; | |
| 319 | pub const SYS_vmsplice = 316; | |
| 320 | pub const SYS_move_pages = 317; | |
| 321 | pub const SYS_getcpu = 318; | |
| 322 | pub const SYS_epoll_pwait = 319; | |
| 323 | pub const SYS_utimensat = 320; | |
| 324 | pub const SYS_signalfd = 321; | |
| 325 | pub const SYS_timerfd_create = 322; | |
| 326 | pub const SYS_eventfd = 323; | |
| 327 | pub const SYS_fallocate = 324; | |
| 328 | pub const SYS_timerfd_settime = 325; | |
| 329 | pub const SYS_timerfd_gettime = 326; | |
| 330 | pub const SYS_signalfd4 = 327; | |
| 331 | pub const SYS_eventfd2 = 328; | |
| 332 | pub const SYS_epoll_create1 = 329; | |
| 333 | pub const SYS_dup3 = 330; | |
| 334 | pub const SYS_pipe2 = 331; | |
| 335 | pub const SYS_inotify_init1 = 332; | |
| 336 | pub const SYS_preadv = 333; | |
| 337 | pub const SYS_pwritev = 334; | |
| 338 | pub const SYS_rt_tgsigqueueinfo = 335; | |
| 339 | pub const SYS_perf_event_open = 336; | |
| 340 | pub const SYS_recvmmsg = 337; | |
| 341 | pub const SYS_fanotify_init = 338; | |
| 342 | pub const SYS_fanotify_mark = 339; | |
| 343 | pub const SYS_prlimit64 = 340; | |
| 344 | pub const SYS_name_to_handle_at = 341; | |
| 345 | pub const SYS_open_by_handle_at = 342; | |
| 346 | pub const SYS_clock_adjtime = 343; | |
| 347 | pub const SYS_syncfs = 344; | |
| 348 | pub const SYS_sendmmsg = 345; | |
| 349 | pub const SYS_setns = 346; | |
| 350 | pub const SYS_process_vm_readv = 347; | |
| 351 | pub const SYS_process_vm_writev = 348; | |
| 352 | pub const SYS_kcmp = 349; | |
| 353 | pub const SYS_finit_module = 350; | |
| 354 | pub const SYS_sched_setattr = 351; | |
| 355 | pub const SYS_sched_getattr = 352; | |
| 356 | pub const SYS_renameat2 = 353; | |
| 357 | pub const SYS_seccomp = 354; | |
| 358 | pub const SYS_getrandom = 355; | |
| 359 | pub const SYS_memfd_create = 356; | |
| 360 | pub const SYS_bpf = 357; | |
| 361 | pub const SYS_execveat = 358; | |
| 362 | pub const SYS_socket = 359; | |
| 363 | pub const SYS_socketpair = 360; | |
| 364 | pub const SYS_bind = 361; | |
| 365 | pub const SYS_connect = 362; | |
| 366 | pub const SYS_listen = 363; | |
| 367 | pub const SYS_accept4 = 364; | |
| 368 | pub const SYS_getsockopt = 365; | |
| 369 | pub const SYS_setsockopt = 366; | |
| 370 | pub const SYS_getsockname = 367; | |
| 371 | pub const SYS_getpeername = 368; | |
| 372 | pub const SYS_sendto = 369; | |
| 373 | pub const SYS_sendmsg = 370; | |
| 374 | pub const SYS_recvfrom = 371; | |
| 375 | pub const SYS_recvmsg = 372; | |
| 376 | pub const SYS_shutdown = 373; | |
| 377 | pub const SYS_userfaultfd = 374; | |
| 378 | pub const SYS_membarrier = 375; | |
| 379 | pub const SYS_mlock2 = 376; | |
| 380 | ||
| 381 | ||
| 382 | pub const O_CREAT = 0o100; | |
| 383 | pub const O_EXCL = 0o200; | |
| 384 | pub const O_NOCTTY = 0o400; | |
| 385 | pub const O_TRUNC = 0o1000; | |
| 386 | pub const O_APPEND = 0o2000; | |
| 387 | pub const O_NONBLOCK = 0o4000; | |
| 388 | pub const O_DSYNC = 0o10000; | |
| 389 | pub const O_SYNC = 0o4010000; | |
| 390 | pub const O_RSYNC = 0o4010000; | |
| 391 | pub const O_DIRECTORY = 0o200000; | |
| 392 | pub const O_NOFOLLOW = 0o400000; | |
| 393 | pub const O_CLOEXEC = 0o2000000; | |
| 394 | ||
| 395 | pub const O_ASYNC = 0o20000; | |
| 396 | pub const O_DIRECT = 0o40000; | |
| 397 | pub const O_LARGEFILE = 0o100000; | |
| 398 | pub const O_NOATIME = 0o1000000; | |
| 399 | pub const O_PATH = 0o10000000; | |
| 400 | pub const O_TMPFILE = 0o20200000; | |
| 401 | pub const O_NDELAY = O_NONBLOCK; | |
| 402 | ||
| 403 | pub const F_DUPFD = 0; | |
| 404 | pub const F_GETFD = 1; | |
| 405 | pub const F_SETFD = 2; | |
| 406 | pub const F_GETFL = 3; | |
| 407 | pub const F_SETFL = 4; | |
| 408 | ||
| 409 | pub const F_SETOWN = 8; | |
| 410 | pub const F_GETOWN = 9; | |
| 411 | pub const F_SETSIG = 10; | |
| 412 | pub const F_GETSIG = 11; | |
| 413 | ||
| 414 | pub const F_GETLK = 12; | |
| 415 | pub const F_SETLK = 13; | |
| 416 | pub const F_SETLKW = 14; | |
| 417 | ||
| 418 | pub const F_SETOWN_EX = 15; | |
| 419 | pub const F_GETOWN_EX = 16; | |
| 420 | ||
| 421 | pub const F_GETOWNER_UIDS = 17; | |
| 422 | ||
| 423 | pub inline fn syscall0(number: usize) usize { | |
| 424 | return asm volatile ("int $0x80" | |
| 425 | : [ret] "={eax}" (-> usize) | |
| 426 | : [number] "{eax}" (number)); | |
| 427 | } | |
| 428 | ||
| 429 | pub inline fn syscall1(number: usize, arg1: usize) usize { | |
| 430 | return asm volatile ("int $0x80" | |
| 431 | : [ret] "={eax}" (-> usize) | |
| 432 | : [number] "{eax}" (number), | |
| 433 | [arg1] "{ebx}" (arg1)); | |
| 434 | } | |
| 435 | ||
| 436 | pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) usize { | |
| 437 | return asm volatile ("int $0x80" | |
| 438 | : [ret] "={eax}" (-> usize) | |
| 439 | : [number] "{eax}" (number), | |
| 440 | [arg1] "{ebx}" (arg1), | |
| 441 | [arg2] "{ecx}" (arg2)); | |
| 442 | } | |
| 443 | ||
| 444 | pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize { | |
| 445 | return asm volatile ("int $0x80" | |
| 446 | : [ret] "={eax}" (-> usize) | |
| 447 | : [number] "{eax}" (number), | |
| 448 | [arg1] "{ebx}" (arg1), | |
| 449 | [arg2] "{ecx}" (arg2), | |
| 450 | [arg3] "{edx}" (arg3)); | |
| 451 | } | |
| 452 | ||
| 453 | pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { | |
| 454 | return asm volatile ("int $0x80" | |
| 455 | : [ret] "={eax}" (-> usize) | |
| 456 | : [number] "{eax}" (number), | |
| 457 | [arg1] "{ebx}" (arg1), | |
| 458 | [arg2] "{ecx}" (arg2), | |
| 459 | [arg3] "{edx}" (arg3), | |
| 460 | [arg4] "{esi}" (arg4)); | |
| 461 | } | |
| 462 | ||
| 463 | pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, | |
| 464 | arg4: usize, arg5: usize) usize | |
| 465 | { | |
| 466 | return asm volatile ("int $0x80" | |
| 467 | : [ret] "={eax}" (-> usize) | |
| 468 | : [number] "{eax}" (number), | |
| 469 | [arg1] "{ebx}" (arg1), | |
| 470 | [arg2] "{ecx}" (arg2), | |
| 471 | [arg3] "{edx}" (arg3), | |
| 472 | [arg4] "{esi}" (arg4), | |
| 473 | [arg5] "{edi}" (arg5)); | |
| 474 | } | |
| 475 | ||
| 476 | pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, | |
| 477 | arg4: usize, arg5: usize, arg6: usize) usize | |
| 478 | { | |
| 479 | return asm volatile ("int $0x80" | |
| 480 | : [ret] "={eax}" (-> usize) | |
| 481 | : [number] "{eax}" (number), | |
| 482 | [arg1] "{ebx}" (arg1), | |
| 483 | [arg2] "{ecx}" (arg2), | |
| 484 | [arg3] "{edx}" (arg3), | |
| 485 | [arg4] "{esi}" (arg4), | |
| 486 | [arg5] "{edi}" (arg5), | |
| 487 | [arg6] "{ebp}" (arg6)); | |
| 488 | } | |
| 489 | ||
| 490 | pub nakedcc fn restore() void { | |
| 491 | asm volatile ( | |
| 492 | \\popl %%eax | |
| 493 | \\movl $119, %%eax | |
| 494 | \\int $0x80 | |
| 495 | : | |
| 496 | : | |
| 497 | : "rcx", "r11"); | |
| 498 | } | |
| 499 | ||
| 500 | pub nakedcc fn restore_rt() void { | |
| 501 | asm volatile ("int $0x80" | |
| 502 | : | |
| 503 | : [number] "{eax}" (usize(SYS_rt_sigreturn)) | |
| 504 | : "rcx", "r11"); | |
| 505 | } |
std/os/linux/index.zig+602-150| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const std = @import("../../index.zig"); |
| 2 | 2 | const assert = std.debug.assert; |
| 3 | 3 | const builtin = @import("builtin"); |
| 4 | const arch = switch (builtin.arch) { | |
| 4 | pub use switch (builtin.arch) { | |
| 5 | 5 | builtin.Arch.x86_64 => @import("x86_64.zig"), |
| 6 | 6 | builtin.Arch.i386 => @import("i386.zig"), |
| 7 | 7 | else => @compileError("unsupported arch"), |
| ... | ... | @@ -93,27 +93,6 @@ pub const O_RDONLY = 0o0; |
| 93 | 93 | pub const O_WRONLY = 0o1; |
| 94 | 94 | pub const O_RDWR = 0o2; |
| 95 | 95 | |
| 96 | pub const O_CREAT = arch.O_CREAT; | |
| 97 | pub const O_EXCL = arch.O_EXCL; | |
| 98 | pub const O_NOCTTY = arch.O_NOCTTY; | |
| 99 | pub const O_TRUNC = arch.O_TRUNC; | |
| 100 | pub const O_APPEND = arch.O_APPEND; | |
| 101 | pub const O_NONBLOCK = arch.O_NONBLOCK; | |
| 102 | pub const O_DSYNC = arch.O_DSYNC; | |
| 103 | pub const O_SYNC = arch.O_SYNC; | |
| 104 | pub const O_RSYNC = arch.O_RSYNC; | |
| 105 | pub const O_DIRECTORY = arch.O_DIRECTORY; | |
| 106 | pub const O_NOFOLLOW = arch.O_NOFOLLOW; | |
| 107 | pub const O_CLOEXEC = arch.O_CLOEXEC; | |
| 108 | ||
| 109 | pub const O_ASYNC = arch.O_ASYNC; | |
| 110 | pub const O_DIRECT = arch.O_DIRECT; | |
| 111 | pub const O_LARGEFILE = arch.O_LARGEFILE; | |
| 112 | pub const O_NOATIME = arch.O_NOATIME; | |
| 113 | pub const O_PATH = arch.O_PATH; | |
| 114 | pub const O_TMPFILE = arch.O_TMPFILE; | |
| 115 | pub const O_NDELAY = arch.O_NDELAY; | |
| 116 | ||
| 117 | 96 | pub const SEEK_SET = 0; |
| 118 | 97 | pub const SEEK_CUR = 1; |
| 119 | 98 | pub const SEEK_END = 2; |
| ... | ... | @@ -122,17 +101,6 @@ pub const SIG_BLOCK = 0; |
| 122 | 101 | pub const SIG_UNBLOCK = 1; |
| 123 | 102 | pub const SIG_SETMASK = 2; |
| 124 | 103 | |
| 125 | pub const SOCK_STREAM = 1; | |
| 126 | pub const SOCK_DGRAM = 2; | |
| 127 | pub const SOCK_RAW = 3; | |
| 128 | pub const SOCK_RDM = 4; | |
| 129 | pub const SOCK_SEQPACKET = 5; | |
| 130 | pub const SOCK_DCCP = 6; | |
| 131 | pub const SOCK_PACKET = 10; | |
| 132 | pub const SOCK_CLOEXEC = 0o2000000; | |
| 133 | pub const SOCK_NONBLOCK = 0o4000; | |
| 134 | ||
| 135 | ||
| 136 | 104 | pub const PROTO_ip = 0o000; |
| 137 | 105 | pub const PROTO_icmp = 0o001; |
| 138 | 106 | pub const PROTO_igmp = 0o002; |
| ... | ... | @@ -170,6 +138,20 @@ pub const PROTO_encap = 0o142; |
| 170 | 138 | pub const PROTO_pim = 0o147; |
| 171 | 139 | pub const PROTO_raw = 0o377; |
| 172 | 140 | |
| 141 | pub const SHUT_RD = 0; | |
| 142 | pub const SHUT_WR = 1; | |
| 143 | pub const SHUT_RDWR = 2; | |
| 144 | ||
| 145 | pub const SOCK_STREAM = 1; | |
| 146 | pub const SOCK_DGRAM = 2; | |
| 147 | pub const SOCK_RAW = 3; | |
| 148 | pub const SOCK_RDM = 4; | |
| 149 | pub const SOCK_SEQPACKET = 5; | |
| 150 | pub const SOCK_DCCP = 6; | |
| 151 | pub const SOCK_PACKET = 10; | |
| 152 | pub const SOCK_CLOEXEC = 0o2000000; | |
| 153 | pub const SOCK_NONBLOCK = 0o4000; | |
| 154 | ||
| 173 | 155 | pub const PF_UNSPEC = 0; |
| 174 | 156 | pub const PF_LOCAL = 1; |
| 175 | 157 | pub const PF_UNIX = PF_LOCAL; |
| ... | ... | @@ -214,7 +196,10 @@ pub const PF_CAIF = 37; |
| 214 | 196 | pub const PF_ALG = 38; |
| 215 | 197 | pub const PF_NFC = 39; |
| 216 | 198 | pub const PF_VSOCK = 40; |
| 217 | pub const PF_MAX = 41; | |
| 199 | pub const PF_KCM = 41; | |
| 200 | pub const PF_QIPCRTR = 42; | |
| 201 | pub const PF_SMC = 43; | |
| 202 | pub const PF_MAX = 44; | |
| 218 | 203 | |
| 219 | 204 | pub const AF_UNSPEC = PF_UNSPEC; |
| 220 | 205 | pub const AF_LOCAL = PF_LOCAL; |
| ... | ... | @@ -260,8 +245,137 @@ pub const AF_CAIF = PF_CAIF; |
| 260 | 245 | pub const AF_ALG = PF_ALG; |
| 261 | 246 | pub const AF_NFC = PF_NFC; |
| 262 | 247 | pub const AF_VSOCK = PF_VSOCK; |
| 248 | pub const AF_KCM = PF_KCM; | |
| 249 | pub const AF_QIPCRTR = PF_QIPCRTR; | |
| 250 | pub const AF_SMC = PF_SMC; | |
| 263 | 251 | pub const AF_MAX = PF_MAX; |
| 264 | 252 | |
| 253 | pub const SO_DEBUG = 1; | |
| 254 | pub const SO_REUSEADDR = 2; | |
| 255 | pub const SO_TYPE = 3; | |
| 256 | pub const SO_ERROR = 4; | |
| 257 | pub const SO_DONTROUTE = 5; | |
| 258 | pub const SO_BROADCAST = 6; | |
| 259 | pub const SO_SNDBUF = 7; | |
| 260 | pub const SO_RCVBUF = 8; | |
| 261 | pub const SO_KEEPALIVE = 9; | |
| 262 | pub const SO_OOBINLINE = 10; | |
| 263 | pub const SO_NO_CHECK = 11; | |
| 264 | pub const SO_PRIORITY = 12; | |
| 265 | pub const SO_LINGER = 13; | |
| 266 | pub const SO_BSDCOMPAT = 14; | |
| 267 | pub const SO_REUSEPORT = 15; | |
| 268 | pub const SO_PASSCRED = 16; | |
| 269 | pub const SO_PEERCRED = 17; | |
| 270 | pub const SO_RCVLOWAT = 18; | |
| 271 | pub const SO_SNDLOWAT = 19; | |
| 272 | pub const SO_RCVTIMEO = 20; | |
| 273 | pub const SO_SNDTIMEO = 21; | |
| 274 | pub const SO_ACCEPTCONN = 30; | |
| 275 | pub const SO_SNDBUFFORCE = 32; | |
| 276 | pub const SO_RCVBUFFORCE = 33; | |
| 277 | pub const SO_PROTOCOL = 38; | |
| 278 | pub const SO_DOMAIN = 39; | |
| 279 | ||
| 280 | pub const SO_SECURITY_AUTHENTICATION = 22; | |
| 281 | pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23; | |
| 282 | pub const SO_SECURITY_ENCRYPTION_NETWORK = 24; | |
| 283 | ||
| 284 | pub const SO_BINDTODEVICE = 25; | |
| 285 | ||
| 286 | pub const SO_ATTACH_FILTER = 26; | |
| 287 | pub const SO_DETACH_FILTER = 27; | |
| 288 | pub const SO_GET_FILTER = SO_ATTACH_FILTER; | |
| 289 | ||
| 290 | pub const SO_PEERNAME = 28; | |
| 291 | pub const SO_TIMESTAMP = 29; | |
| 292 | pub const SCM_TIMESTAMP = SO_TIMESTAMP; | |
| 293 | ||
| 294 | pub const SO_PEERSEC = 31; | |
| 295 | pub const SO_PASSSEC = 34; | |
| 296 | pub const SO_TIMESTAMPNS = 35; | |
| 297 | pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS; | |
| 298 | pub const SO_MARK = 36; | |
| 299 | pub const SO_TIMESTAMPING = 37; | |
| 300 | pub const SCM_TIMESTAMPING = SO_TIMESTAMPING; | |
| 301 | pub const SO_RXQ_OVFL = 40; | |
| 302 | pub const SO_WIFI_STATUS = 41; | |
| 303 | pub const SCM_WIFI_STATUS = SO_WIFI_STATUS; | |
| 304 | pub const SO_PEEK_OFF = 42; | |
| 305 | pub const SO_NOFCS = 43; | |
| 306 | pub const SO_LOCK_FILTER = 44; | |
| 307 | pub const SO_SELECT_ERR_QUEUE = 45; | |
| 308 | pub const SO_BUSY_POLL = 46; | |
| 309 | pub const SO_MAX_PACING_RATE = 47; | |
| 310 | pub const SO_BPF_EXTENSIONS = 48; | |
| 311 | pub const SO_INCOMING_CPU = 49; | |
| 312 | pub const SO_ATTACH_BPF = 50; | |
| 313 | pub const SO_DETACH_BPF = SO_DETACH_FILTER; | |
| 314 | pub const SO_ATTACH_REUSEPORT_CBPF = 51; | |
| 315 | pub const SO_ATTACH_REUSEPORT_EBPF = 52; | |
| 316 | pub const SO_CNX_ADVICE = 53; | |
| 317 | pub const SCM_TIMESTAMPING_OPT_STATS = 54; | |
| 318 | pub const SO_MEMINFO = 55; | |
| 319 | pub const SO_INCOMING_NAPI_ID = 56; | |
| 320 | pub const SO_COOKIE = 57; | |
| 321 | pub const SCM_TIMESTAMPING_PKTINFO = 58; | |
| 322 | pub const SO_PEERGROUPS = 59; | |
| 323 | pub const SO_ZEROCOPY = 60; | |
| 324 | ||
| 325 | pub const SOL_SOCKET = 1; | |
| 326 | ||
| 327 | pub const SOL_IP = 0; | |
| 328 | pub const SOL_IPV6 = 41; | |
| 329 | pub const SOL_ICMPV6 = 58; | |
| 330 | ||
| 331 | pub const SOL_RAW = 255; | |
| 332 | pub const SOL_DECNET = 261; | |
| 333 | pub const SOL_X25 = 262; | |
| 334 | pub const SOL_PACKET = 263; | |
| 335 | pub const SOL_ATM = 264; | |
| 336 | pub const SOL_AAL = 265; | |
| 337 | pub const SOL_IRDA = 266; | |
| 338 | pub const SOL_NETBEUI = 267; | |
| 339 | pub const SOL_LLC = 268; | |
| 340 | pub const SOL_DCCP = 269; | |
| 341 | pub const SOL_NETLINK = 270; | |
| 342 | pub const SOL_TIPC = 271; | |
| 343 | pub const SOL_RXRPC = 272; | |
| 344 | pub const SOL_PPPOL2TP = 273; | |
| 345 | pub const SOL_BLUETOOTH = 274; | |
| 346 | pub const SOL_PNPIPE = 275; | |
| 347 | pub const SOL_RDS = 276; | |
| 348 | pub const SOL_IUCV = 277; | |
| 349 | pub const SOL_CAIF = 278; | |
| 350 | pub const SOL_ALG = 279; | |
| 351 | pub const SOL_NFC = 280; | |
| 352 | pub const SOL_KCM = 281; | |
| 353 | pub const SOL_TLS = 282; | |
| 354 | ||
| 355 | pub const SOMAXCONN = 128; | |
| 356 | ||
| 357 | pub const MSG_OOB = 0x0001; | |
| 358 | pub const MSG_PEEK = 0x0002; | |
| 359 | pub const MSG_DONTROUTE = 0x0004; | |
| 360 | pub const MSG_CTRUNC = 0x0008; | |
| 361 | pub const MSG_PROXY = 0x0010; | |
| 362 | pub const MSG_TRUNC = 0x0020; | |
| 363 | pub const MSG_DONTWAIT = 0x0040; | |
| 364 | pub const MSG_EOR = 0x0080; | |
| 365 | pub const MSG_WAITALL = 0x0100; | |
| 366 | pub const MSG_FIN = 0x0200; | |
| 367 | pub const MSG_SYN = 0x0400; | |
| 368 | pub const MSG_CONFIRM = 0x0800; | |
| 369 | pub const MSG_RST = 0x1000; | |
| 370 | pub const MSG_ERRQUEUE = 0x2000; | |
| 371 | pub const MSG_NOSIGNAL = 0x4000; | |
| 372 | pub const MSG_MORE = 0x8000; | |
| 373 | pub const MSG_WAITFORONE = 0x10000; | |
| 374 | pub const MSG_BATCH = 0x40000; | |
| 375 | pub const MSG_ZEROCOPY = 0x4000000; | |
| 376 | pub const MSG_FASTOPEN = 0x20000000; | |
| 377 | pub const MSG_CMSG_CLOEXEC = 0x40000000; | |
| 378 | ||
| 265 | 379 | pub const DT_UNKNOWN = 0; |
| 266 | 380 | pub const DT_FIFO = 1; |
| 267 | 381 | pub const DT_CHR = 2; |
| ... | ... | @@ -364,6 +478,126 @@ pub const CLOCK_BOOTTIME_ALARM = 9; |
| 364 | 478 | pub const CLOCK_SGI_CYCLE = 10; |
| 365 | 479 | pub const CLOCK_TAI = 11; |
| 366 | 480 | |
| 481 | pub const CSIGNAL = 0x000000ff; | |
| 482 | pub const CLONE_VM = 0x00000100; | |
| 483 | pub const CLONE_FS = 0x00000200; | |
| 484 | pub const CLONE_FILES = 0x00000400; | |
| 485 | pub const CLONE_SIGHAND = 0x00000800; | |
| 486 | pub const CLONE_PTRACE = 0x00002000; | |
| 487 | pub const CLONE_VFORK = 0x00004000; | |
| 488 | pub const CLONE_PARENT = 0x00008000; | |
| 489 | pub const CLONE_THREAD = 0x00010000; | |
| 490 | pub const CLONE_NEWNS = 0x00020000; | |
| 491 | pub const CLONE_SYSVSEM = 0x00040000; | |
| 492 | pub const CLONE_SETTLS = 0x00080000; | |
| 493 | pub const CLONE_PARENT_SETTID = 0x00100000; | |
| 494 | pub const CLONE_CHILD_CLEARTID = 0x00200000; | |
| 495 | pub const CLONE_DETACHED = 0x00400000; | |
| 496 | pub const CLONE_UNTRACED = 0x00800000; | |
| 497 | pub const CLONE_CHILD_SETTID = 0x01000000; | |
| 498 | pub const CLONE_NEWCGROUP = 0x02000000; | |
| 499 | pub const CLONE_NEWUTS = 0x04000000; | |
| 500 | pub const CLONE_NEWIPC = 0x08000000; | |
| 501 | pub const CLONE_NEWUSER = 0x10000000; | |
| 502 | pub const CLONE_NEWPID = 0x20000000; | |
| 503 | pub const CLONE_NEWNET = 0x40000000; | |
| 504 | pub const CLONE_IO = 0x80000000; | |
| 505 | ||
| 506 | pub const MS_RDONLY = 1; | |
| 507 | pub const MS_NOSUID = 2; | |
| 508 | pub const MS_NODEV = 4; | |
| 509 | pub const MS_NOEXEC = 8; | |
| 510 | pub const MS_SYNCHRONOUS = 16; | |
| 511 | pub const MS_REMOUNT = 32; | |
| 512 | pub const MS_MANDLOCK = 64; | |
| 513 | pub const MS_DIRSYNC = 128; | |
| 514 | pub const MS_NOATIME = 1024; | |
| 515 | pub const MS_NODIRATIME = 2048; | |
| 516 | pub const MS_BIND = 4096; | |
| 517 | pub const MS_MOVE = 8192; | |
| 518 | pub const MS_REC = 16384; | |
| 519 | pub const MS_SILENT = 32768; | |
| 520 | pub const MS_POSIXACL = (1<<16); | |
| 521 | pub const MS_UNBINDABLE = (1<<17); | |
| 522 | pub const MS_PRIVATE = (1<<18); | |
| 523 | pub const MS_SLAVE = (1<<19); | |
| 524 | pub const MS_SHARED = (1<<20); | |
| 525 | pub const MS_RELATIME = (1<<21); | |
| 526 | pub const MS_KERNMOUNT = (1<<22); | |
| 527 | pub const MS_I_VERSION = (1<<23); | |
| 528 | pub const MS_STRICTATIME = (1<<24); | |
| 529 | pub const MS_LAZYTIME = (1<<25); | |
| 530 | pub const MS_NOREMOTELOCK = (1<<27); | |
| 531 | pub const MS_NOSEC = (1<<28); | |
| 532 | pub const MS_BORN = (1<<29); | |
| 533 | pub const MS_ACTIVE = (1<<30); | |
| 534 | pub const MS_NOUSER = (1<<31); | |
| 535 | ||
| 536 | pub const MS_RMT_MASK = (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME); | |
| 537 | ||
| 538 | pub const MS_MGC_VAL = 0xc0ed0000; | |
| 539 | pub const MS_MGC_MSK = 0xffff0000; | |
| 540 | ||
| 541 | pub const MNT_FORCE = 1; | |
| 542 | pub const MNT_DETACH = 2; | |
| 543 | pub const MNT_EXPIRE = 4; | |
| 544 | pub const UMOUNT_NOFOLLOW = 8; | |
| 545 | ||
| 546 | ||
| 547 | pub const S_IFMT = 0o170000; | |
| 548 | ||
| 549 | pub const S_IFDIR = 0o040000; | |
| 550 | pub const S_IFCHR = 0o020000; | |
| 551 | pub const S_IFBLK = 0o060000; | |
| 552 | pub const S_IFREG = 0o100000; | |
| 553 | pub const S_IFIFO = 0o010000; | |
| 554 | pub const S_IFLNK = 0o120000; | |
| 555 | pub const S_IFSOCK = 0o140000; | |
| 556 | ||
| 557 | pub const S_ISUID = 0o4000; | |
| 558 | pub const S_ISGID = 0o2000; | |
| 559 | pub const S_ISVTX = 0o1000; | |
| 560 | pub const S_IRUSR = 0o400; | |
| 561 | pub const S_IWUSR = 0o200; | |
| 562 | pub const S_IXUSR = 0o100; | |
| 563 | pub const S_IRWXU = 0o700; | |
| 564 | pub const S_IRGRP = 0o040; | |
| 565 | pub const S_IWGRP = 0o020; | |
| 566 | pub const S_IXGRP = 0o010; | |
| 567 | pub const S_IRWXG = 0o070; | |
| 568 | pub const S_IROTH = 0o004; | |
| 569 | pub const S_IWOTH = 0o002; | |
| 570 | pub const S_IXOTH = 0o001; | |
| 571 | pub const S_IRWXO = 0o007; | |
| 572 | ||
| 573 | pub fn S_ISREG(m: u32) bool { | |
| 574 | return m & S_IFMT == S_IFREG; | |
| 575 | } | |
| 576 | ||
| 577 | pub fn S_ISDIR(m: u32) bool { | |
| 578 | return m & S_IFMT == S_IFDIR; | |
| 579 | } | |
| 580 | ||
| 581 | pub fn S_ISCHR(m: u32) bool { | |
| 582 | return m & S_IFMT == S_IFCHR; | |
| 583 | } | |
| 584 | ||
| 585 | pub fn S_ISBLK(m: u32) bool { | |
| 586 | return m & S_IFMT == S_IFBLK; | |
| 587 | } | |
| 588 | ||
| 589 | pub fn S_ISFIFO(m: u32) bool { | |
| 590 | return m & S_IFMT == S_IFIFO; | |
| 591 | } | |
| 592 | ||
| 593 | pub fn S_ISLNK(m: u32) bool { | |
| 594 | return m & S_IFMT == S_IFLNK; | |
| 595 | } | |
| 596 | ||
| 597 | pub fn S_ISSOCK(m: u32) bool { | |
| 598 | return m & S_IFMT == S_IFSOCK; | |
| 599 | } | |
| 600 | ||
| 367 | 601 | pub const TFD_NONBLOCK = O_NONBLOCK; |
| 368 | 602 | pub const TFD_CLOEXEC = O_CLOEXEC; |
| 369 | 603 | |
| ... | ... | @@ -394,65 +628,81 @@ pub fn getErrno(r: usize) usize { |
| 394 | 628 | } |
| 395 | 629 | |
| 396 | 630 | pub fn dup2(old: i32, new: i32) usize { |
| 397 | return arch.syscall2(arch.SYS_dup2, usize(old), usize(new)); | |
| 631 | return syscall2(SYS_dup2, usize(old), usize(new)); | |
| 398 | 632 | } |
| 399 | 633 | |
| 400 | 634 | pub fn chdir(path: &const u8) usize { |
| 401 | return arch.syscall1(arch.SYS_chdir, @ptrToInt(path)); | |
| 635 | return syscall1(SYS_chdir, @ptrToInt(path)); | |
| 636 | } | |
| 637 | ||
| 638 | pub fn chroot(path: &const u8) usize { | |
| 639 | return syscall1(SYS_chroot, @ptrToInt(path)); | |
| 402 | 640 | } |
| 403 | 641 | |
| 404 | 642 | pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize { |
| 405 | return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); | |
| 643 | return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); | |
| 406 | 644 | } |
| 407 | 645 | |
| 408 | 646 | pub fn fork() usize { |
| 409 | return arch.syscall0(arch.SYS_fork); | |
| 647 | return syscall0(SYS_fork); | |
| 410 | 648 | } |
| 411 | 649 | |
| 412 | 650 | pub fn getcwd(buf: &u8, size: usize) usize { |
| 413 | return arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size); | |
| 651 | return syscall2(SYS_getcwd, @ptrToInt(buf), size); | |
| 414 | 652 | } |
| 415 | 653 | |
| 416 | 654 | pub fn getdents(fd: i32, dirp: &u8, count: usize) usize { |
| 417 | return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count); | |
| 655 | return syscall3(SYS_getdents, usize(fd), @ptrToInt(dirp), count); | |
| 418 | 656 | } |
| 419 | 657 | |
| 420 | 658 | pub fn isatty(fd: i32) bool { |
| 421 | 659 | var wsz: winsize = undefined; |
| 422 | return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; | |
| 660 | return syscall3(SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; | |
| 423 | 661 | } |
| 424 | 662 | |
| 425 | 663 | pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) usize { |
| 426 | return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 664 | return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 427 | 665 | } |
| 428 | 666 | |
| 429 | 667 | pub fn mkdir(path: &const u8, mode: u32) usize { |
| 430 | return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode); | |
| 668 | return syscall2(SYS_mkdir, @ptrToInt(path), mode); | |
| 669 | } | |
| 670 | ||
| 671 | pub fn mount(special: &const u8, dir: &const u8, fstype: &const u8, flags: usize, data: usize) usize { | |
| 672 | return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data); | |
| 673 | } | |
| 674 | ||
| 675 | pub fn umount(special: &const u8) usize { | |
| 676 | return syscall2(SYS_umount2, @ptrToInt(special), 0); | |
| 677 | } | |
| 678 | ||
| 679 | pub fn umount2(special: &const u8, flags: u32) usize { | |
| 680 | return syscall2(SYS_umount2, @ptrToInt(special), flags); | |
| 431 | 681 | } |
| 432 | 682 | |
| 433 | 683 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { |
| 434 | return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), | |
| 684 | return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), | |
| 435 | 685 | @bitCast(usize, offset)); |
| 436 | 686 | } |
| 437 | 687 | |
| 438 | 688 | pub fn munmap(address: &u8, length: usize) usize { |
| 439 | return arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length); | |
| 689 | return syscall2(SYS_munmap, @ptrToInt(address), length); | |
| 440 | 690 | } |
| 441 | 691 | |
| 442 | 692 | pub fn read(fd: i32, buf: &u8, count: usize) usize { |
| 443 | return arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count); | |
| 693 | return syscall3(SYS_read, usize(fd), @ptrToInt(buf), count); | |
| 444 | 694 | } |
| 445 | 695 | |
| 446 | 696 | pub fn rmdir(path: &const u8) usize { |
| 447 | return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)); | |
| 697 | return syscall1(SYS_rmdir, @ptrToInt(path)); | |
| 448 | 698 | } |
| 449 | 699 | |
| 450 | 700 | pub fn symlink(existing: &const u8, new: &const u8) usize { |
| 451 | return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); | |
| 701 | return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); | |
| 452 | 702 | } |
| 453 | 703 | |
| 454 | 704 | pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize { |
| 455 | return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset); | |
| 705 | return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset); | |
| 456 | 706 | } |
| 457 | 707 | |
| 458 | 708 | pub fn pipe(fd: &[2]i32) usize { |
| ... | ... | @@ -460,84 +710,136 @@ pub fn pipe(fd: &[2]i32) usize { |
| 460 | 710 | } |
| 461 | 711 | |
| 462 | 712 | pub fn pipe2(fd: &[2]i32, flags: usize) usize { |
| 463 | return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags); | |
| 713 | return syscall2(SYS_pipe2, @ptrToInt(fd), flags); | |
| 464 | 714 | } |
| 465 | 715 | |
| 466 | 716 | pub fn write(fd: i32, buf: &const u8, count: usize) usize { |
| 467 | return arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count); | |
| 717 | return syscall3(SYS_write, usize(fd), @ptrToInt(buf), count); | |
| 468 | 718 | } |
| 469 | 719 | |
| 470 | 720 | pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) usize { |
| 471 | return arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset); | |
| 721 | return syscall4(SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset); | |
| 472 | 722 | } |
| 473 | 723 | |
| 474 | 724 | pub fn rename(old: &const u8, new: &const u8) usize { |
| 475 | return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)); | |
| 725 | return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); | |
| 476 | 726 | } |
| 477 | 727 | |
| 478 | 728 | pub fn open(path: &const u8, flags: u32, perm: usize) usize { |
| 479 | return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm); | |
| 729 | return syscall3(SYS_open, @ptrToInt(path), flags, perm); | |
| 480 | 730 | } |
| 481 | 731 | |
| 482 | 732 | pub fn create(path: &const u8, perm: usize) usize { |
| 483 | return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm); | |
| 733 | return syscall2(SYS_creat, @ptrToInt(path), perm); | |
| 484 | 734 | } |
| 485 | 735 | |
| 486 | 736 | pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) usize { |
| 487 | return arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode); | |
| 737 | return syscall4(SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode); | |
| 488 | 738 | } |
| 489 | 739 | |
| 490 | 740 | pub fn close(fd: i32) usize { |
| 491 | return arch.syscall1(arch.SYS_close, usize(fd)); | |
| 741 | return syscall1(SYS_close, usize(fd)); | |
| 492 | 742 | } |
| 493 | 743 | |
| 494 | 744 | pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { |
| 495 | return arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos); | |
| 745 | return syscall3(SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos); | |
| 496 | 746 | } |
| 497 | 747 | |
| 498 | 748 | pub fn exit(status: i32) noreturn { |
| 499 | _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); | |
| 749 | _ = syscall1(SYS_exit, @bitCast(usize, isize(status))); | |
| 500 | 750 | unreachable; |
| 501 | 751 | } |
| 502 | 752 | |
| 503 | 753 | pub fn getrandom(buf: &u8, count: usize, flags: u32) usize { |
| 504 | return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags)); | |
| 754 | return syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags)); | |
| 505 | 755 | } |
| 506 | 756 | |
| 507 | 757 | pub fn kill(pid: i32, sig: i32) usize { |
| 508 | return arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig)); | |
| 758 | return syscall2(SYS_kill, @bitCast(usize, isize(pid)), usize(sig)); | |
| 509 | 759 | } |
| 510 | 760 | |
| 511 | 761 | pub fn unlink(path: &const u8) usize { |
| 512 | return arch.syscall1(arch.SYS_unlink, @ptrToInt(path)); | |
| 762 | return syscall1(SYS_unlink, @ptrToInt(path)); | |
| 513 | 763 | } |
| 514 | 764 | |
| 515 | 765 | pub fn waitpid(pid: i32, status: &i32, options: i32) usize { |
| 516 | return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); | |
| 766 | return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); | |
| 517 | 767 | } |
| 518 | 768 | |
| 519 | 769 | pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize { |
| 520 | return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); | |
| 770 | return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); | |
| 521 | 771 | } |
| 522 | 772 | |
| 523 | 773 | pub fn setuid(uid: u32) usize { |
| 524 | return arch.syscall1(arch.SYS_setuid, uid); | |
| 774 | return syscall1(SYS_setuid, uid); | |
| 525 | 775 | } |
| 526 | 776 | |
| 527 | 777 | pub fn setgid(gid: u32) usize { |
| 528 | return arch.syscall1(arch.SYS_setgid, gid); | |
| 778 | return syscall1(SYS_setgid, gid); | |
| 529 | 779 | } |
| 530 | 780 | |
| 531 | 781 | pub fn setreuid(ruid: u32, euid: u32) usize { |
| 532 | return arch.syscall2(arch.SYS_setreuid, ruid, euid); | |
| 782 | return syscall2(SYS_setreuid, ruid, euid); | |
| 533 | 783 | } |
| 534 | 784 | |
| 535 | 785 | pub fn setregid(rgid: u32, egid: u32) usize { |
| 536 | return arch.syscall2(arch.SYS_setregid, rgid, egid); | |
| 786 | return syscall2(SYS_setregid, rgid, egid); | |
| 787 | } | |
| 788 | ||
| 789 | pub fn getuid() u32 { | |
| 790 | return u32(syscall0(SYS_getuid)); | |
| 791 | } | |
| 792 | ||
| 793 | pub fn getgid() u32 { | |
| 794 | return u32(syscall0(SYS_getgid)); | |
| 795 | } | |
| 796 | ||
| 797 | pub fn geteuid() u32 { | |
| 798 | return u32(syscall0(SYS_geteuid)); | |
| 799 | } | |
| 800 | ||
| 801 | pub fn getegid() u32 { | |
| 802 | return u32(syscall0(SYS_getegid)); | |
| 803 | } | |
| 804 | ||
| 805 | pub fn seteuid(euid: u32) usize { | |
| 806 | return syscall1(SYS_seteuid, euid); | |
| 807 | } | |
| 808 | ||
| 809 | pub fn setegid(egid: u32) usize { | |
| 810 | return syscall1(SYS_setegid, egid); | |
| 811 | } | |
| 812 | ||
| 813 | pub fn getresuid(ruid: &u32, euid: &u32, suid: &u32) usize { | |
| 814 | return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid)); | |
| 815 | } | |
| 816 | ||
| 817 | pub fn getresgid(rgid: &u32, egid: &u32, sgid: &u32) usize { | |
| 818 | return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid)); | |
| 819 | } | |
| 820 | ||
| 821 | pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize { | |
| 822 | return syscall3(SYS_setresuid, ruid, euid, suid); | |
| 823 | } | |
| 824 | ||
| 825 | pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize { | |
| 826 | return syscall3(SYS_setresgid, rgid, egid, sgid); | |
| 827 | } | |
| 828 | ||
| 829 | pub fn getgroups(size: usize, list: &u32) usize { | |
| 830 | return syscall2(SYS_getgroups, size, @ptrToInt(list)); | |
| 831 | } | |
| 832 | ||
| 833 | pub fn setgroups(size: usize, list: &const u32) usize { | |
| 834 | return syscall2(SYS_setgroups, size, @ptrToInt(list)); | |
| 835 | } | |
| 836 | ||
| 837 | pub fn getpid() i32 { | |
| 838 | return @bitCast(i32, u32(syscall0(SYS_getpid))); | |
| 537 | 839 | } |
| 538 | 840 | |
| 539 | 841 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize { |
| 540 | return arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8); | |
| 842 | return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8); | |
| 541 | 843 | } |
| 542 | 844 | |
| 543 | 845 | pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize { |
| ... | ... | @@ -548,11 +850,11 @@ pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigacti |
| 548 | 850 | .handler = act.handler, |
| 549 | 851 | .flags = act.flags | SA_RESTORER, |
| 550 | 852 | .mask = undefined, |
| 551 | .restorer = @ptrCast(extern fn()void, arch.restore_rt), | |
| 853 | .restorer = @ptrCast(extern fn()void, restore_rt), | |
| 552 | 854 | }; |
| 553 | 855 | var ksa_old: k_sigaction = undefined; |
| 554 | 856 | @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8); |
| 555 | const result = arch.syscall4(arch.SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); | |
| 857 | const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); | |
| 556 | 858 | const err = getErrno(result); |
| 557 | 859 | if (err != 0) { |
| 558 | 860 | return result; |
| ... | ... | @@ -592,22 +894,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len; |
| 592 | 894 | pub fn raise(sig: i32) usize { |
| 593 | 895 | var set: sigset_t = undefined; |
| 594 | 896 | blockAppSignals(&set); |
| 595 | const tid = i32(arch.syscall0(arch.SYS_gettid)); | |
| 596 | const ret = arch.syscall2(arch.SYS_tkill, usize(tid), usize(sig)); | |
| 897 | const tid = i32(syscall0(SYS_gettid)); | |
| 898 | const ret = syscall2(SYS_tkill, usize(tid), usize(sig)); | |
| 597 | 899 | restoreSignals(&set); |
| 598 | 900 | return ret; |
| 599 | 901 | } |
| 600 | 902 | |
| 601 | 903 | fn blockAllSignals(set: &sigset_t) void { |
| 602 | _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8); | |
| 904 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8); | |
| 603 | 905 | } |
| 604 | 906 | |
| 605 | 907 | fn blockAppSignals(set: &sigset_t) void { |
| 606 | _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8); | |
| 908 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8); | |
| 607 | 909 | } |
| 608 | 910 | |
| 609 | 911 | fn restoreSignals(set: &sigset_t) void { |
| 610 | _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8); | |
| 912 | _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8); | |
| 611 | 913 | } |
| 612 | 914 | |
| 613 | 915 | pub fn sigaddset(set: &sigset_t, sig: u6) void { |
| ... | ... | @@ -620,30 +922,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool { |
| 620 | 922 | return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0; |
| 621 | 923 | } |
| 622 | 924 | |
| 623 | ||
| 925 | pub const in_port_t = u16; | |
| 624 | 926 | pub const sa_family_t = u16; |
| 625 | 927 | pub const socklen_t = u32; |
| 626 | pub const in_addr = u32; | |
| 627 | pub const in6_addr = [16]u8; | |
| 628 | 928 | |
| 629 | pub const sockaddr = extern struct { | |
| 630 | family: sa_family_t, | |
| 631 | port: u16, | |
| 632 | data: [12]u8, | |
| 929 | pub const sockaddr = extern union { | |
| 930 | in: sockaddr_in, | |
| 931 | in6: sockaddr_in6, | |
| 633 | 932 | }; |
| 634 | 933 | |
| 635 | 934 | pub const sockaddr_in = extern struct { |
| 636 | 935 | family: sa_family_t, |
| 637 | port: u16, | |
| 638 | addr: in_addr, | |
| 936 | port: in_port_t, | |
| 937 | addr: u32, | |
| 639 | 938 | zero: [8]u8, |
| 640 | 939 | }; |
| 641 | 940 | |
| 642 | 941 | pub const sockaddr_in6 = extern struct { |
| 643 | 942 | family: sa_family_t, |
| 644 | port: u16, | |
| 943 | port: in_port_t, | |
| 645 | 944 | flowinfo: u32, |
| 646 | addr: in6_addr, | |
| 945 | addr: [16]u8, | |
| 647 | 946 | scope_id: u32, |
| 648 | 947 | }; |
| 649 | 948 | |
| ... | ... | @@ -653,61 +952,61 @@ pub const iovec = extern struct { |
| 653 | 952 | }; |
| 654 | 953 | |
| 655 | 954 | pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize { |
| 656 | return arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)); | |
| 955 | return syscall3(SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)); | |
| 657 | 956 | } |
| 658 | 957 | |
| 659 | 958 | pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize { |
| 660 | return arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)); | |
| 959 | return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)); | |
| 661 | 960 | } |
| 662 | 961 | |
| 663 | pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize { | |
| 664 | return arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol)); | |
| 962 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { | |
| 963 | return syscall3(SYS_socket, domain, socket_type, protocol); | |
| 665 | 964 | } |
| 666 | 965 | |
| 667 | pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize { | |
| 668 | return arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen)); | |
| 966 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize { | |
| 967 | return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen)); | |
| 669 | 968 | } |
| 670 | 969 | |
| 671 | pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize { | |
| 672 | return arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen)); | |
| 970 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: &u8, noalias optlen: &socklen_t) usize { | |
| 971 | return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); | |
| 673 | 972 | } |
| 674 | 973 | |
| 675 | pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) usize { | |
| 676 | return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags); | |
| 974 | pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize { | |
| 975 | return syscall3(SYS_sendmsg, usize(fd), @ptrToInt(msg), flags); | |
| 677 | 976 | } |
| 678 | 977 | |
| 679 | 978 | pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) usize { |
| 680 | return arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len)); | |
| 979 | return syscall3(SYS_connect, usize(fd), @ptrToInt(addr), usize(len)); | |
| 681 | 980 | } |
| 682 | 981 | |
| 683 | pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) usize { | |
| 684 | return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags); | |
| 982 | pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize { | |
| 983 | return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags); | |
| 685 | 984 | } |
| 686 | 985 | |
| 687 | 986 | pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, |
| 688 | 987 | noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize |
| 689 | 988 | { |
| 690 | return arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | |
| 989 | return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | |
| 691 | 990 | } |
| 692 | 991 | |
| 693 | 992 | pub fn shutdown(fd: i32, how: i32) usize { |
| 694 | return arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how)); | |
| 993 | return syscall2(SYS_shutdown, usize(fd), usize(how)); | |
| 695 | 994 | } |
| 696 | 995 | |
| 697 | 996 | pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize { |
| 698 | return arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len)); | |
| 997 | return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len)); | |
| 699 | 998 | } |
| 700 | 999 | |
| 701 | pub fn listen(fd: i32, backlog: i32) usize { | |
| 702 | return arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog)); | |
| 1000 | pub fn listen(fd: i32, backlog: u32) usize { | |
| 1001 | return syscall2(SYS_listen, usize(fd), backlog); | |
| 703 | 1002 | } |
| 704 | 1003 | |
| 705 | 1004 | pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize { |
| 706 | return arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)); | |
| 1005 | return syscall6(SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)); | |
| 707 | 1006 | } |
| 708 | 1007 | |
| 709 | 1008 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { |
| 710 | return arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])); | |
| 1009 | return syscall4(SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])); | |
| 711 | 1010 | } |
| 712 | 1011 | |
| 713 | 1012 | pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize { |
| ... | ... | @@ -715,52 +1014,86 @@ pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize { |
| 715 | 1014 | } |
| 716 | 1015 | |
| 717 | 1016 | pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) usize { |
| 718 | return arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags); | |
| 719 | } | |
| 720 | ||
| 721 | // error NameTooLong; | |
| 722 | // error SystemResources; | |
| 723 | // error Io; | |
| 724 | // | |
| 725 | // pub fn if_nametoindex(name: []u8) !u32 { | |
| 726 | // var ifr: ifreq = undefined; | |
| 727 | // | |
| 728 | // if (name.len >= ifr.ifr_name.len) { | |
| 729 | // return error.NameTooLong; | |
| 730 | // } | |
| 731 | // | |
| 732 | // const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); | |
| 733 | // const socket_err = getErrno(socket_ret); | |
| 734 | // if (socket_err > 0) { | |
| 735 | // return error.SystemResources; | |
| 736 | // } | |
| 737 | // const socket_fd = i32(socket_ret); | |
| 738 | // @memcpy(&ifr.ifr_name[0], &name[0], name.len); | |
| 739 | // ifr.ifr_name[name.len] = 0; | |
| 740 | // const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr); | |
| 741 | // close(socket_fd); | |
| 742 | // const ioctl_err = getErrno(ioctl_ret); | |
| 743 | // if (ioctl_err > 0) { | |
| 744 | // return error.Io; | |
| 745 | // } | |
| 746 | // return ifr.ifr_ifindex; | |
| 747 | // } | |
| 748 | ||
| 749 | pub const Stat = arch.Stat; | |
| 750 | pub const timespec = arch.timespec; | |
| 1017 | return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags); | |
| 1018 | } | |
| 751 | 1019 | |
| 752 | 1020 | pub fn fstat(fd: i32, stat_buf: &Stat) usize { |
| 753 | return arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf)); | |
| 1021 | return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf)); | |
| 1022 | } | |
| 1023 | ||
| 1024 | pub fn stat(pathname: &const u8, statbuf: &Stat) usize { | |
| 1025 | return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf)); | |
| 1026 | } | |
| 1027 | ||
| 1028 | pub fn lstat(pathname: &const u8, statbuf: &Stat) usize { | |
| 1029 | return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf)); | |
| 1030 | } | |
| 1031 | ||
| 1032 | pub fn listxattr(path: &const u8, list: &u8, size: usize) usize { | |
| 1033 | return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size); | |
| 1034 | } | |
| 1035 | ||
| 1036 | pub fn llistxattr(path: &const u8, list: &u8, size: usize) usize { | |
| 1037 | return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size); | |
| 1038 | } | |
| 1039 | ||
| 1040 | pub fn flistxattr(fd: usize, list: &u8, size: usize) usize { | |
| 1041 | return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size); | |
| 1042 | } | |
| 1043 | ||
| 1044 | pub fn getxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize { | |
| 1045 | return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size); | |
| 1046 | } | |
| 1047 | ||
| 1048 | pub fn lgetxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize { | |
| 1049 | return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size); | |
| 1050 | } | |
| 1051 | ||
| 1052 | pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize { | |
| 1053 | return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size); | |
| 1054 | } | |
| 1055 | ||
| 1056 | pub fn setxattr(path: &const u8, name: &const u8, value: &const void, | |
| 1057 | size: usize, flags: usize) usize { | |
| 1058 | ||
| 1059 | return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), | |
| 1060 | size, flags); | |
| 754 | 1061 | } |
| 755 | 1062 | |
| 756 | pub const epoll_data = extern union { | |
| 1063 | pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void, | |
| 1064 | size: usize, flags: usize) usize { | |
| 1065 | ||
| 1066 | return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), | |
| 1067 | size, flags); | |
| 1068 | } | |
| 1069 | ||
| 1070 | pub fn fsetxattr(fd: usize, name: &const u8, value: &const void, | |
| 1071 | size: usize, flags: usize) usize { | |
| 1072 | ||
| 1073 | return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), | |
| 1074 | size, flags); | |
| 1075 | } | |
| 1076 | ||
| 1077 | pub fn removexattr(path: &const u8, name: &const u8) usize { | |
| 1078 | return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name)); | |
| 1079 | } | |
| 1080 | ||
| 1081 | pub fn lremovexattr(path: &const u8, name: &const u8) usize { | |
| 1082 | return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name)); | |
| 1083 | } | |
| 1084 | ||
| 1085 | pub fn fremovexattr(fd: usize, name: &const u8) usize { | |
| 1086 | return syscall2(SYS_fremovexattr, fd, @ptrToInt(name)); | |
| 1087 | } | |
| 1088 | ||
| 1089 | pub const epoll_data = packed union { | |
| 757 | 1090 | ptr: usize, |
| 758 | 1091 | fd: i32, |
| 759 | 1092 | @"u32": u32, |
| 760 | 1093 | @"u64": u64, |
| 761 | 1094 | }; |
| 762 | 1095 | |
| 763 | pub const epoll_event = extern struct { | |
| 1096 | pub const epoll_event = packed struct { | |
| 764 | 1097 | events: u32, |
| 765 | 1098 | data: epoll_data, |
| 766 | 1099 | }; |
| ... | ... | @@ -770,19 +1103,19 @@ pub fn epoll_create() usize { |
| 770 | 1103 | } |
| 771 | 1104 | |
| 772 | 1105 | pub fn epoll_create1(flags: usize) usize { |
| 773 | return arch.syscall1(arch.SYS_epoll_create1, flags); | |
| 1106 | return syscall1(SYS_epoll_create1, flags); | |
| 774 | 1107 | } |
| 775 | 1108 | |
| 776 | pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) usize { | |
| 777 | return arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev)); | |
| 1109 | pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: &epoll_event) usize { | |
| 1110 | return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev)); | |
| 778 | 1111 | } |
| 779 | 1112 | |
| 780 | 1113 | pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: u32, timeout: i32) usize { |
| 781 | return arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout)); | |
| 1114 | return syscall4(SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout)); | |
| 782 | 1115 | } |
| 783 | 1116 | |
| 784 | 1117 | pub fn timerfd_create(clockid: i32, flags: u32) usize { |
| 785 | return arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags)); | |
| 1118 | return syscall2(SYS_timerfd_create, usize(clockid), usize(flags)); | |
| 786 | 1119 | } |
| 787 | 1120 | |
| 788 | 1121 | pub const itimerspec = extern struct { |
| ... | ... | @@ -791,11 +1124,130 @@ pub const itimerspec = extern struct { |
| 791 | 1124 | }; |
| 792 | 1125 | |
| 793 | 1126 | pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize { |
| 794 | return arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value)); | |
| 1127 | return syscall2(SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value)); | |
| 795 | 1128 | } |
| 796 | 1129 | |
| 797 | 1130 | pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) usize { |
| 798 | return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value)); | |
| 1131 | return syscall4(SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value)); | |
| 1132 | } | |
| 1133 | ||
| 1134 | pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330; | |
| 1135 | pub const _LINUX_CAPABILITY_U32S_1 = 1; | |
| 1136 | ||
| 1137 | pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026; | |
| 1138 | pub const _LINUX_CAPABILITY_U32S_2 = 2; | |
| 1139 | ||
| 1140 | pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522; | |
| 1141 | pub const _LINUX_CAPABILITY_U32S_3 = 2; | |
| 1142 | ||
| 1143 | pub const VFS_CAP_REVISION_MASK = 0xFF000000; | |
| 1144 | pub const VFS_CAP_REVISION_SHIFT = 24; | |
| 1145 | pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK; | |
| 1146 | pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001; | |
| 1147 | ||
| 1148 | pub const VFS_CAP_REVISION_1 = 0x01000000; | |
| 1149 | pub const VFS_CAP_U32_1 = 1; | |
| 1150 | pub const XATTR_CAPS_SZ_1 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_1); | |
| 1151 | ||
| 1152 | pub const VFS_CAP_REVISION_2 = 0x02000000; | |
| 1153 | pub const VFS_CAP_U32_2 = 2; | |
| 1154 | pub const XATTR_CAPS_SZ_2 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_2); | |
| 1155 | ||
| 1156 | pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2; | |
| 1157 | pub const VFS_CAP_U32 = VFS_CAP_U32_2; | |
| 1158 | pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2; | |
| 1159 | ||
| 1160 | pub const vfs_cap_data = extern struct { | |
| 1161 | //all of these are mandated as little endian | |
| 1162 | //when on disk. | |
| 1163 | const Data = struct { | |
| 1164 | permitted: u32, | |
| 1165 | inheritable: u32, | |
| 1166 | }; | |
| 1167 | ||
| 1168 | magic_etc: u32, | |
| 1169 | data: [VFS_CAP_U32]Data, | |
| 1170 | }; | |
| 1171 | ||
| 1172 | ||
| 1173 | pub const CAP_CHOWN = 0; | |
| 1174 | pub const CAP_DAC_OVERRIDE = 1; | |
| 1175 | pub const CAP_DAC_READ_SEARCH = 2; | |
| 1176 | pub const CAP_FOWNER = 3; | |
| 1177 | pub const CAP_FSETID = 4; | |
| 1178 | pub const CAP_KILL = 5; | |
| 1179 | pub const CAP_SETGID = 6; | |
| 1180 | pub const CAP_SETUID = 7; | |
| 1181 | pub const CAP_SETPCAP = 8; | |
| 1182 | pub const CAP_LINUX_IMMUTABLE = 9; | |
| 1183 | pub const CAP_NET_BIND_SERVICE = 10; | |
| 1184 | pub const CAP_NET_BROADCAST = 11; | |
| 1185 | pub const CAP_NET_ADMIN = 12; | |
| 1186 | pub const CAP_NET_RAW = 13; | |
| 1187 | pub const CAP_IPC_LOCK = 14; | |
| 1188 | pub const CAP_IPC_OWNER = 15; | |
| 1189 | pub const CAP_SYS_MODULE = 16; | |
| 1190 | pub const CAP_SYS_RAWIO = 17; | |
| 1191 | pub const CAP_SYS_CHROOT = 18; | |
| 1192 | pub const CAP_SYS_PTRACE = 19; | |
| 1193 | pub const CAP_SYS_PACCT = 20; | |
| 1194 | pub const CAP_SYS_ADMIN = 21; | |
| 1195 | pub const CAP_SYS_BOOT = 22; | |
| 1196 | pub const CAP_SYS_NICE = 23; | |
| 1197 | pub const CAP_SYS_RESOURCE = 24; | |
| 1198 | pub const CAP_SYS_TIME = 25; | |
| 1199 | pub const CAP_SYS_TTY_CONFIG = 26; | |
| 1200 | pub const CAP_MKNOD = 27; | |
| 1201 | pub const CAP_LEASE = 28; | |
| 1202 | pub const CAP_AUDIT_WRITE = 29; | |
| 1203 | pub const CAP_AUDIT_CONTROL = 30; | |
| 1204 | pub const CAP_SETFCAP = 31; | |
| 1205 | pub const CAP_MAC_OVERRIDE = 32; | |
| 1206 | pub const CAP_MAC_ADMIN = 33; | |
| 1207 | pub const CAP_SYSLOG = 34; | |
| 1208 | pub const CAP_WAKE_ALARM = 35; | |
| 1209 | pub const CAP_BLOCK_SUSPEND = 36; | |
| 1210 | pub const CAP_AUDIT_READ = 37; | |
| 1211 | pub const CAP_LAST_CAP = CAP_AUDIT_READ; | |
| 1212 | ||
| 1213 | pub fn cap_valid(u8: x) bool { | |
| 1214 | return x >= 0 and x <= CAP_LAST_CAP; | |
| 1215 | } | |
| 1216 | ||
| 1217 | pub fn CAP_TO_MASK(cap: u8) u32 { | |
| 1218 | return u32(1) << u5(cap & 31); | |
| 1219 | } | |
| 1220 | ||
| 1221 | pub fn CAP_TO_INDEX(cap: u8) u8 { | |
| 1222 | return cap >> 5; | |
| 1223 | } | |
| 1224 | ||
| 1225 | pub const cap_t = extern struct { | |
| 1226 | hdrp: &cap_user_header_t, | |
| 1227 | datap: &cap_user_data_t, | |
| 1228 | }; | |
| 1229 | ||
| 1230 | pub const cap_user_header_t = extern struct { | |
| 1231 | version: u32, | |
| 1232 | pid: usize, | |
| 1233 | }; | |
| 1234 | ||
| 1235 | pub const cap_user_data_t = extern struct { | |
| 1236 | effective: u32, | |
| 1237 | permitted: u32, | |
| 1238 | inheritable: u32, | |
| 1239 | }; | |
| 1240 | ||
| 1241 | pub fn unshare(flags: usize) usize { | |
| 1242 | return syscall1(SYS_unshare, usize(flags)); | |
| 1243 | } | |
| 1244 | ||
| 1245 | pub fn capget(hdrp: &cap_user_header_t, datap: &cap_user_data_t) usize { | |
| 1246 | return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap)); | |
| 1247 | } | |
| 1248 | ||
| 1249 | pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize { | |
| 1250 | return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap)); | |
| 799 | 1251 | } |
| 800 | 1252 | |
| 801 | 1253 | test "import linux test" { |
std/os/linux/x86_64.zig+8| ... | ... | @@ -488,3 +488,11 @@ pub const timespec = extern struct { |
| 488 | 488 | tv_sec: isize, |
| 489 | 489 | tv_nsec: isize, |
| 490 | 490 | }; |
| 491 | ||
| 492 | pub const dirent = extern struct { | |
| 493 | d_ino: usize, | |
| 494 | d_off: usize, | |
| 495 | d_reclen: u16, | |
| 496 | d_name: u8, // field address is the address of first byte of name | |
| 497 | }; | |
| 498 |
std/os/test.zig created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | const std = @import("../index.zig"); | |
| 2 | const os = std.os; | |
| 3 | const assert = std.debug.assert; | |
| 4 | const io = std.io; | |
| 5 | ||
| 6 | const a = std.debug.global_allocator; | |
| 7 | ||
| 8 | const builtin = @import("builtin"); | |
| 9 | ||
| 10 | test "makePath, put some files in it, deleteTree" { | |
| 11 | if (builtin.os == builtin.Os.windows) { | |
| 12 | // TODO implement os.Dir for windows | |
| 13 | // https://github.com/zig-lang/zig/issues/709 | |
| 14 | return; | |
| 15 | } | |
| 16 | try os.makePath(a, "os_test_tmp/b/c"); | |
| 17 | try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense"); | |
| 18 | try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah"); | |
| 19 | try os.deleteTree(a, "os_test_tmp"); | |
| 20 | if (os.Dir.open(a, "os_test_tmp")) |dir| { | |
| 21 | @panic("expected error"); | |
| 22 | } else |err| { | |
| 23 | assert(err == error.PathNotFound); | |
| 24 | } | |
| 25 | } |
std/rand.zig deleted-240| ... | ... | @@ -1,240 +0,0 @@ |
| 1 | const std = @import("index.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const assert = std.debug.assert; | |
| 4 | const rand_test = @import("rand_test.zig"); | |
| 5 | const mem = std.mem; | |
| 6 | const math = std.math; | |
| 7 | ||
| 8 | pub const MT19937_32 = MersenneTwister( | |
| 9 | u32, 624, 397, 31, | |
| 10 | 0x9908B0DF, | |
| 11 | 11, 0xFFFFFFFF, | |
| 12 | 7, 0x9D2C5680, | |
| 13 | 15, 0xEFC60000, | |
| 14 | 18, 1812433253); | |
| 15 | ||
| 16 | pub const MT19937_64 = MersenneTwister( | |
| 17 | u64, 312, 156, 31, | |
| 18 | 0xB5026F5AA96619E9, | |
| 19 | 29, 0x5555555555555555, | |
| 20 | 17, 0x71D67FFFEDA60000, | |
| 21 | 37, 0xFFF7EEE000000000, | |
| 22 | 43, 6364136223846793005); | |
| 23 | ||
| 24 | /// Use `init` to initialize this state. | |
| 25 | pub const Rand = struct { | |
| 26 | const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32; | |
| 27 | ||
| 28 | rng: Rng, | |
| 29 | ||
| 30 | /// Initialize random state with the given seed. | |
| 31 | pub fn init(seed: usize) Rand { | |
| 32 | return Rand { | |
| 33 | .rng = Rng.init(seed), | |
| 34 | }; | |
| 35 | } | |
| 36 | ||
| 37 | /// Get an integer or boolean with random bits. | |
| 38 | pub fn scalar(r: &Rand, comptime T: type) T { | |
| 39 | if (T == usize) { | |
| 40 | return r.rng.get(); | |
| 41 | } else if (T == bool) { | |
| 42 | return (r.rng.get() & 0b1) == 0; | |
| 43 | } else { | |
| 44 | var result: [@sizeOf(T)]u8 = undefined; | |
| 45 | r.fillBytes(result[0..]); | |
| 46 | return mem.readInt(result, T, builtin.Endian.Little); | |
| 47 | } | |
| 48 | } | |
| 49 | ||
| 50 | /// Fill `buf` with randomness. | |
| 51 | pub fn fillBytes(r: &Rand, buf: []u8) void { | |
| 52 | var bytes_left = buf.len; | |
| 53 | while (bytes_left >= @sizeOf(usize)) { | |
| 54 | mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little); | |
| 55 | bytes_left -= @sizeOf(usize); | |
| 56 | } | |
| 57 | if (bytes_left > 0) { | |
| 58 | var rand_val_array: [@sizeOf(usize)]u8 = undefined; | |
| 59 | mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little); | |
| 60 | while (bytes_left > 0) { | |
| 61 | buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left]; | |
| 62 | bytes_left -= 1; | |
| 63 | } | |
| 64 | } | |
| 65 | } | |
| 66 | ||
| 67 | /// Get a random unsigned integer with even distribution between `start` | |
| 68 | /// inclusive and `end` exclusive. | |
| 69 | pub fn range(r: &Rand, comptime T: type, start: T, end: T) T { | |
| 70 | assert(start <= end); | |
| 71 | if (T.is_signed) { | |
| 72 | const uint = @IntType(false, T.bit_count); | |
| 73 | if (start >= 0 and end >= 0) { | |
| 74 | return T(r.range(uint, uint(start), uint(end))); | |
| 75 | } else if (start < 0 and end < 0) { | |
| 76 | // Can't overflow because the range is over signed ints | |
| 77 | return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable; | |
| 78 | } else if (start < 0 and end >= 0) { | |
| 79 | const end_uint = uint(end); | |
| 80 | const total_range = math.absCast(start) + end_uint; | |
| 81 | const value = r.range(uint, 0, total_range); | |
| 82 | const result = if (value < end_uint) x: { | |
| 83 | break :x T(value); | |
| 84 | } else if (value == end_uint) x: { | |
| 85 | break :x start; | |
| 86 | } else x: { | |
| 87 | // Can't overflow because the range is over signed ints | |
| 88 | break :x math.negateCast(value - end_uint) catch unreachable; | |
| 89 | }; | |
| 90 | return result; | |
| 91 | } else { | |
| 92 | unreachable; | |
| 93 | } | |
| 94 | } else { | |
| 95 | const total_range = end - start; | |
| 96 | const leftover = @maxValue(T) % total_range; | |
| 97 | const upper_bound = @maxValue(T) - leftover; | |
| 98 | var rand_val_array: [@sizeOf(T)]u8 = undefined; | |
| 99 | ||
| 100 | while (true) { | |
| 101 | r.fillBytes(rand_val_array[0..]); | |
| 102 | const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little); | |
| 103 | if (rand_val < upper_bound) { | |
| 104 | return start + (rand_val % total_range); | |
| 105 | } | |
| 106 | } | |
| 107 | } | |
| 108 | } | |
| 109 | ||
| 110 | /// Get a floating point value in the range 0.0..1.0. | |
| 111 | pub fn float(r: &Rand, comptime T: type) T { | |
| 112 | // TODO Implement this way instead: | |
| 113 | // const int = @int_type(false, @sizeOf(T) * 8); | |
| 114 | // const mask = ((1 << @float_mantissa_bit_count(T)) - 1); | |
| 115 | // const rand_bits = r.rng.scalar(int) & mask; | |
| 116 | // return @float_compose(T, false, 0, rand_bits) - 1.0 | |
| 117 | const int_type = @IntType(false, @sizeOf(T) * 8); | |
| 118 | const precision = if (T == f32) | |
| 119 | 16777216 | |
| 120 | else if (T == f64) | |
| 121 | 9007199254740992 | |
| 122 | else | |
| 123 | @compileError("unknown floating point type") | |
| 124 | ; | |
| 125 | return T(r.range(int_type, 0, precision)) / T(precision); | |
| 126 | } | |
| 127 | }; | |
| 128 | ||
| 129 | fn MersenneTwister( | |
| 130 | comptime int: type, comptime n: usize, comptime m: usize, comptime r: int, | |
| 131 | comptime a: int, | |
| 132 | comptime u: math.Log2Int(int), comptime d: int, | |
| 133 | comptime s: math.Log2Int(int), comptime b: int, | |
| 134 | comptime t: math.Log2Int(int), comptime c: int, | |
| 135 | comptime l: math.Log2Int(int), comptime f: int) type | |
| 136 | { | |
| 137 | return struct { | |
| 138 | const Self = this; | |
| 139 | ||
| 140 | array: [n]int, | |
| 141 | index: usize, | |
| 142 | ||
| 143 | pub fn init(seed: int) Self { | |
| 144 | var mt = Self { | |
| 145 | .array = undefined, | |
| 146 | .index = n, | |
| 147 | }; | |
| 148 | ||
| 149 | var prev_value = seed; | |
| 150 | mt.array[0] = prev_value; | |
| 151 | var i: usize = 1; | |
| 152 | while (i < n) : (i += 1) { | |
| 153 | prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2))); | |
| 154 | mt.array[i] = prev_value; | |
| 155 | } | |
| 156 | return mt; | |
| 157 | } | |
| 158 | ||
| 159 | pub fn get(mt: &Self) int { | |
| 160 | const mag01 = []int{0, a}; | |
| 161 | const LM: int = (1 << r) - 1; | |
| 162 | const UM = ~LM; | |
| 163 | ||
| 164 | if (mt.index >= n) { | |
| 165 | var i: usize = 0; | |
| 166 | ||
| 167 | while (i < n - m) : (i += 1) { | |
| 168 | const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM); | |
| 169 | mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[usize(x & 0x1)]; | |
| 170 | } | |
| 171 | ||
| 172 | while (i < n - 1) : (i += 1) { | |
| 173 | const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM); | |
| 174 | mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[usize(x & 0x1)]; | |
| 175 | ||
| 176 | } | |
| 177 | const x = (mt.array[i] & UM) | (mt.array[0] & LM); | |
| 178 | mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[usize(x & 0x1)]; | |
| 179 | ||
| 180 | mt.index = 0; | |
| 181 | } | |
| 182 | ||
| 183 | var x = mt.array[mt.index]; | |
| 184 | mt.index += 1; | |
| 185 | ||
| 186 | x ^= ((x >> u) & d); | |
| 187 | x ^= ((x << s) & b); | |
| 188 | x ^= ((x << t) & c); | |
| 189 | x ^= (x >> l); | |
| 190 | ||
| 191 | return x; | |
| 192 | } | |
| 193 | }; | |
| 194 | } | |
| 195 | ||
| 196 | test "rand float 32" { | |
| 197 | var r = Rand.init(42); | |
| 198 | var i: usize = 0; | |
| 199 | while (i < 1000) : (i += 1) { | |
| 200 | const val = r.float(f32); | |
| 201 | assert(val >= 0.0); | |
| 202 | assert(val < 1.0); | |
| 203 | } | |
| 204 | } | |
| 205 | ||
| 206 | test "rand.MT19937_64" { | |
| 207 | var rng = MT19937_64.init(rand_test.mt64_seed); | |
| 208 | for (rand_test.mt64_data) |value| { | |
| 209 | assert(value == rng.get()); | |
| 210 | } | |
| 211 | } | |
| 212 | ||
| 213 | test "rand.MT19937_32" { | |
| 214 | var rng = MT19937_32.init(rand_test.mt32_seed); | |
| 215 | for (rand_test.mt32_data) |value| { | |
| 216 | assert(value == rng.get()); | |
| 217 | } | |
| 218 | } | |
| 219 | ||
| 220 | test "rand.Rand.range" { | |
| 221 | var r = Rand.init(42); | |
| 222 | testRange(&r, -4, 3); | |
| 223 | testRange(&r, -4, -1); | |
| 224 | testRange(&r, 10, 14); | |
| 225 | } | |
| 226 | ||
| 227 | fn testRange(r: &Rand, start: i32, end: i32) void { | |
| 228 | const count = usize(end - start); | |
| 229 | var values_buffer = []bool{false} ** 20; | |
| 230 | const values = values_buffer[0..count]; | |
| 231 | var i: usize = 0; | |
| 232 | while (i < count) { | |
| 233 | const value = r.range(i32, start, end); | |
| 234 | const index = usize(value - start); | |
| 235 | if (!values[index]) { | |
| 236 | i += 1; | |
| 237 | values[index] = true; | |
| 238 | } | |
| 239 | } | |
| 240 | } |
std/rand/index.zig created+652| ... | ... | @@ -0,0 +1,652 @@ |
| 1 | // The engines provided here should be initialized from an external source. For now, getRandomBytes | |
| 2 | // from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using | |
| 3 | // a normal PRNG will be faster and use substantially less stack space. | |
| 4 | // | |
| 5 | // ``` | |
| 6 | // var buf: [8]u8 = undefined; | |
| 7 | // try std.os.getRandomBytes(buf[0..]); | |
| 8 | // const seed = mem.readInt(buf[0..8], u64, builtin.Endian.Little); | |
| 9 | // | |
| 10 | // var r = DefaultPrng.init(seed); | |
| 11 | // | |
| 12 | // const s = r.random.scalar(u64); | |
| 13 | // ``` | |
| 14 | // | |
| 15 | // TODO(tiehuis): Benchmark these against other reference implementations. | |
| 16 | ||
| 17 | const std = @import("../index.zig"); | |
| 18 | const builtin = @import("builtin"); | |
| 19 | const assert = std.debug.assert; | |
| 20 | const mem = std.mem; | |
| 21 | const math = std.math; | |
| 22 | ||
| 23 | // When you need fast unbiased random numbers | |
| 24 | pub const DefaultPrng = Xoroshiro128; | |
| 25 | ||
| 26 | // When you need cryptographically secure random numbers | |
| 27 | pub const DefaultCsprng = Isaac64; | |
| 28 | ||
| 29 | pub const Random = struct { | |
| 30 | fillFn: fn(r: &Random, buf: []u8) void, | |
| 31 | ||
| 32 | /// Read random bytes into the specified buffer until fill. | |
| 33 | pub fn bytes(r: &Random, buf: []u8) void { | |
| 34 | r.fillFn(r, buf); | |
| 35 | } | |
| 36 | ||
| 37 | /// Return a random integer/boolean type. | |
| 38 | pub fn scalar(r: &Random, comptime T: type) T { | |
| 39 | var rand_bytes: [@sizeOf(T)]u8 = undefined; | |
| 40 | r.bytes(rand_bytes[0..]); | |
| 41 | ||
| 42 | if (T == bool) { | |
| 43 | return rand_bytes[0] & 0b1 == 0; | |
| 44 | } else { | |
| 45 | // NOTE: Cannot @bitCast array to integer type. | |
| 46 | return mem.readInt(rand_bytes, T, builtin.Endian.Little); | |
| 47 | } | |
| 48 | } | |
| 49 | ||
| 50 | /// Get a random unsigned integer with even distribution between `start` | |
| 51 | /// inclusive and `end` exclusive. | |
| 52 | pub fn range(r: &Random, comptime T: type, start: T, end: T) T { | |
| 53 | assert(start <= end); | |
| 54 | if (T.is_signed) { | |
| 55 | const uint = @IntType(false, T.bit_count); | |
| 56 | if (start >= 0 and end >= 0) { | |
| 57 | return T(r.range(uint, uint(start), uint(end))); | |
| 58 | } else if (start < 0 and end < 0) { | |
| 59 | // Can't overflow because the range is over signed ints | |
| 60 | return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable; | |
| 61 | } else if (start < 0 and end >= 0) { | |
| 62 | const end_uint = uint(end); | |
| 63 | const total_range = math.absCast(start) + end_uint; | |
| 64 | const value = r.range(uint, 0, total_range); | |
| 65 | const result = if (value < end_uint) x: { | |
| 66 | break :x T(value); | |
| 67 | } else if (value == end_uint) x: { | |
| 68 | break :x start; | |
| 69 | } else x: { | |
| 70 | // Can't overflow because the range is over signed ints | |
| 71 | break :x math.negateCast(value - end_uint) catch unreachable; | |
| 72 | }; | |
| 73 | return result; | |
| 74 | } else { | |
| 75 | unreachable; | |
| 76 | } | |
| 77 | } else { | |
| 78 | const total_range = end - start; | |
| 79 | const leftover = @maxValue(T) % total_range; | |
| 80 | const upper_bound = @maxValue(T) - leftover; | |
| 81 | var rand_val_array: [@sizeOf(T)]u8 = undefined; | |
| 82 | ||
| 83 | while (true) { | |
| 84 | r.bytes(rand_val_array[0..]); | |
| 85 | const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little); | |
| 86 | if (rand_val < upper_bound) { | |
| 87 | return start + (rand_val % total_range); | |
| 88 | } | |
| 89 | } | |
| 90 | } | |
| 91 | } | |
| 92 | ||
| 93 | /// Return a floating point value evenly distributed in the range [0, 1). | |
| 94 | pub fn float(r: &Random, comptime T: type) T { | |
| 95 | // Generate a uniform value between [1, 2) and scale down to [0, 1). | |
| 96 | // Note: The lowest mantissa bit is always set to 0 so we only use half the available range. | |
| 97 | switch (T) { | |
| 98 | f32 => { | |
| 99 | const s = r.scalar(u32); | |
| 100 | const repr = (0x7f << 23) | (s >> 9); | |
| 101 | return @bitCast(f32, repr) - 1.0; | |
| 102 | }, | |
| 103 | f64 => { | |
| 104 | const s = r.scalar(u64); | |
| 105 | const repr = (0x3ff << 52) | (s >> 12); | |
| 106 | return @bitCast(f64, repr) - 1.0; | |
| 107 | }, | |
| 108 | else => @compileError("unknown floating point type"), | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | /// Return a floating point value normally distributed in the range [0, 1]. | |
| 113 | pub fn floatNorm(r: &Random, comptime T: type) T { | |
| 114 | // TODO(tiehuis): See https://www.doornik.com/research/ziggurat.pdf | |
| 115 | @compileError("floatNorm is unimplemented"); | |
| 116 | } | |
| 117 | ||
| 118 | /// Return a exponentially distributed float between (0, @maxValue(f64)) | |
| 119 | pub fn floatExp(r: &Random, comptime T: type) T { | |
| 120 | @compileError("floatExp is unimplemented"); | |
| 121 | } | |
| 122 | ||
| 123 | /// Shuffle a slice into a random order. | |
| 124 | pub fn shuffle(r: &Random, comptime T: type, buf: []T) void { | |
| 125 | if (buf.len < 2) { | |
| 126 | return; | |
| 127 | } | |
| 128 | ||
| 129 | var i: usize = 0; | |
| 130 | while (i < buf.len - 1) : (i += 1) { | |
| 131 | const j = r.range(usize, i, buf.len); | |
| 132 | mem.swap(T, &buf[i], &buf[j]); | |
| 133 | } | |
| 134 | } | |
| 135 | }; | |
| 136 | ||
| 137 | // Generator to extend 64-bit seed values into longer sequences. | |
| 138 | // | |
| 139 | // The number of cycles is thus limited to 64-bits regardless of the engine, but this | |
| 140 | // is still plenty for practical purposes. | |
| 141 | const SplitMix64 = struct { | |
| 142 | s: u64, | |
| 143 | ||
| 144 | pub fn init(seed: u64) SplitMix64 { | |
| 145 | return SplitMix64 { .s = seed }; | |
| 146 | } | |
| 147 | ||
| 148 | pub fn next(self: &SplitMix64) u64 { | |
| 149 | self.s +%= 0x9e3779b97f4a7c15; | |
| 150 | ||
| 151 | var z = self.s; | |
| 152 | z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9; | |
| 153 | z = (z ^ (z >> 27)) *% 0x94d049bb133111eb; | |
| 154 | return z ^ (z >> 31); | |
| 155 | } | |
| 156 | }; | |
| 157 | ||
| 158 | test "splitmix64 sequence" { | |
| 159 | var r = SplitMix64.init(0xaeecf86f7878dd75); | |
| 160 | ||
| 161 | const seq = []const u64 { | |
| 162 | 0x5dbd39db0178eb44, | |
| 163 | 0xa9900fb66b397da3, | |
| 164 | 0x5c1a28b1aeebcf5c, | |
| 165 | 0x64a963238f776912, | |
| 166 | 0xc6d4177b21d1c0ab, | |
| 167 | 0xb2cbdbdb5ea35394, | |
| 168 | }; | |
| 169 | ||
| 170 | for (seq) |s| { | |
| 171 | std.debug.assert(s == r.next()); | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | // PCG32 - http://www.pcg-random.org/ | |
| 176 | // | |
| 177 | // PRNG | |
| 178 | pub const Pcg = struct { | |
| 179 | const default_multiplier = 6364136223846793005; | |
| 180 | ||
| 181 | random: Random, | |
| 182 | ||
| 183 | s: u64, | |
| 184 | i: u64, | |
| 185 | ||
| 186 | pub fn init(init_s: u64) Pcg { | |
| 187 | var pcg = Pcg { | |
| 188 | .random = Random { .fillFn = fill }, | |
| 189 | .s = undefined, | |
| 190 | .i = undefined, | |
| 191 | }; | |
| 192 | ||
| 193 | pcg.seed(init_s); | |
| 194 | return pcg; | |
| 195 | } | |
| 196 | ||
| 197 | fn next(self: &Pcg) u32 { | |
| 198 | const l = self.s; | |
| 199 | self.s = l *% default_multiplier +% (self.i | 1); | |
| 200 | ||
| 201 | const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27); | |
| 202 | const rot = u32(l >> 59); | |
| 203 | ||
| 204 | return (xor_s >> u5(rot)) | (xor_s << u5((0 -% rot) & 31)); | |
| 205 | } | |
| 206 | ||
| 207 | fn seed(self: &Pcg, init_s: u64) void { | |
| 208 | // Pcg requires 128-bits of seed. | |
| 209 | var gen = SplitMix64.init(init_s); | |
| 210 | self.seedTwo(gen.next(), gen.next()); | |
| 211 | } | |
| 212 | ||
| 213 | fn seedTwo(self: &Pcg, init_s: u64, init_i: u64) void { | |
| 214 | self.s = 0; | |
| 215 | self.i = (init_s << 1) | 1; | |
| 216 | self.s = self.s *% default_multiplier +% self.i; | |
| 217 | self.s +%= init_i; | |
| 218 | self.s = self.s *% default_multiplier +% self.i; | |
| 219 | } | |
| 220 | ||
| 221 | fn fill(r: &Random, buf: []u8) void { | |
| 222 | const self = @fieldParentPtr(Pcg, "random", r); | |
| 223 | ||
| 224 | var i: usize = 0; | |
| 225 | const aligned_len = buf.len - (buf.len & 7); | |
| 226 | ||
| 227 | // Complete 4 byte segments. | |
| 228 | while (i < aligned_len) : (i += 4) { | |
| 229 | var n = self.next(); | |
| 230 | comptime var j: usize = 0; | |
| 231 | inline while (j < 4) : (j += 1) { | |
| 232 | buf[i + j] = @truncate(u8, n); | |
| 233 | n >>= 8; | |
| 234 | } | |
| 235 | } | |
| 236 | ||
| 237 | // Remaining. (cuts the stream) | |
| 238 | if (i != buf.len) { | |
| 239 | var n = self.next(); | |
| 240 | while (i < buf.len) : (i += 1) { | |
| 241 | buf[i] = @truncate(u8, n); | |
| 242 | n >>= 4; | |
| 243 | } | |
| 244 | } | |
| 245 | } | |
| 246 | }; | |
| 247 | ||
| 248 | test "pcg sequence" { | |
| 249 | var r = Pcg.init(0); | |
| 250 | const s0: u64 = 0x9394bf54ce5d79de; | |
| 251 | const s1: u64 = 0x84e9c579ef59bbf7; | |
| 252 | r.seedTwo(s0, s1); | |
| 253 | ||
| 254 | const seq = []const u32 { | |
| 255 | 2881561918, | |
| 256 | 3063928540, | |
| 257 | 1199791034, | |
| 258 | 2487695858, | |
| 259 | 1479648952, | |
| 260 | 3247963454, | |
| 261 | }; | |
| 262 | ||
| 263 | for (seq) |s| { | |
| 264 | std.debug.assert(s == r.next()); | |
| 265 | } | |
| 266 | } | |
| 267 | ||
| 268 | // Xoroshiro128+ - http://xoroshiro.di.unimi.it/ | |
| 269 | // | |
| 270 | // PRNG | |
| 271 | pub const Xoroshiro128 = struct { | |
| 272 | random: Random, | |
| 273 | ||
| 274 | s: [2]u64, | |
| 275 | ||
| 276 | pub fn init(init_s: u64) Xoroshiro128 { | |
| 277 | var x = Xoroshiro128 { | |
| 278 | .random = Random { .fillFn = fill }, | |
| 279 | .s = undefined, | |
| 280 | }; | |
| 281 | ||
| 282 | x.seed(init_s); | |
| 283 | return x; | |
| 284 | } | |
| 285 | ||
| 286 | fn next(self: &Xoroshiro128) u64 { | |
| 287 | const s0 = self.s[0]; | |
| 288 | var s1 = self.s[1]; | |
| 289 | const r = s0 +% s1; | |
| 290 | ||
| 291 | s1 ^= s0; | |
| 292 | self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14); | |
| 293 | self.s[1] = math.rotl(u64, s1, u8(36)); | |
| 294 | ||
| 295 | return r; | |
| 296 | } | |
| 297 | ||
| 298 | // Skip 2^64 places ahead in the sequence | |
| 299 | fn jump(self: &Xoroshiro128) void { | |
| 300 | var s0: u64 = 0; | |
| 301 | var s1: u64 = 0; | |
| 302 | ||
| 303 | const table = []const u64 { | |
| 304 | 0xbeac0467eba5facb, | |
| 305 | 0xd86b048b86aa9922 | |
| 306 | }; | |
| 307 | ||
| 308 | inline for (table) |entry| { | |
| 309 | var b: usize = 0; | |
| 310 | while (b < 64) : (b += 1) { | |
| 311 | if ((entry & (u64(1) << u6(b))) != 0) { | |
| 312 | s0 ^= self.s[0]; | |
| 313 | s1 ^= self.s[1]; | |
| 314 | } | |
| 315 | _ = self.next(); | |
| 316 | } | |
| 317 | } | |
| 318 | ||
| 319 | self.s[0] = s0; | |
| 320 | self.s[1] = s1; | |
| 321 | } | |
| 322 | ||
| 323 | fn seed(self: &Xoroshiro128, init_s: u64) void { | |
| 324 | // Xoroshiro requires 128-bits of seed. | |
| 325 | var gen = SplitMix64.init(init_s); | |
| 326 | ||
| 327 | self.s[0] = gen.next(); | |
| 328 | self.s[1] = gen.next(); | |
| 329 | } | |
| 330 | ||
| 331 | fn fill(r: &Random, buf: []u8) void { | |
| 332 | const self = @fieldParentPtr(Xoroshiro128, "random", r); | |
| 333 | ||
| 334 | var i: usize = 0; | |
| 335 | const aligned_len = buf.len - (buf.len & 7); | |
| 336 | ||
| 337 | // Complete 8 byte segments. | |
| 338 | while (i < aligned_len) : (i += 8) { | |
| 339 | var n = self.next(); | |
| 340 | comptime var j: usize = 0; | |
| 341 | inline while (j < 8) : (j += 1) { | |
| 342 | buf[i + j] = @truncate(u8, n); | |
| 343 | n >>= 8; | |
| 344 | } | |
| 345 | } | |
| 346 | ||
| 347 | // Remaining. (cuts the stream) | |
| 348 | if (i != buf.len) { | |
| 349 | var n = self.next(); | |
| 350 | while (i < buf.len) : (i += 1) { | |
| 351 | buf[i] = @truncate(u8, n); | |
| 352 | n >>= 8; | |
| 353 | } | |
| 354 | } | |
| 355 | } | |
| 356 | }; | |
| 357 | ||
| 358 | test "xoroshiro sequence" { | |
| 359 | var r = Xoroshiro128.init(0); | |
| 360 | r.s[0] = 0xaeecf86f7878dd75; | |
| 361 | r.s[1] = 0x01cd153642e72622; | |
| 362 | ||
| 363 | const seq1 = []const u64 { | |
| 364 | 0xb0ba0da5bb600397, | |
| 365 | 0x18a08afde614dccc, | |
| 366 | 0xa2635b956a31b929, | |
| 367 | 0xabe633c971efa045, | |
| 368 | 0x9ac19f9706ca3cac, | |
| 369 | 0xf62b426578c1e3fb, | |
| 370 | }; | |
| 371 | ||
| 372 | for (seq1) |s| { | |
| 373 | std.debug.assert(s == r.next()); | |
| 374 | } | |
| 375 | ||
| 376 | ||
| 377 | r.jump(); | |
| 378 | ||
| 379 | const seq2 = []const u64 { | |
| 380 | 0x95344a13556d3e22, | |
| 381 | 0xb4fb32dafa4d00df, | |
| 382 | 0xb2011d9ccdcfe2dd, | |
| 383 | 0x05679a9b2119b908, | |
| 384 | 0xa860a1da7c9cd8a0, | |
| 385 | 0x658a96efe3f86550, | |
| 386 | }; | |
| 387 | ||
| 388 | for (seq2) |s| { | |
| 389 | std.debug.assert(s == r.next()); | |
| 390 | } | |
| 391 | } | |
| 392 | ||
| 393 | // ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html | |
| 394 | // | |
| 395 | // CSPRNG | |
| 396 | // | |
| 397 | // Follows the general idea of the implementation from here with a few shortcuts. | |
| 398 | // https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html | |
| 399 | pub const Isaac64 = struct { | |
| 400 | random: Random, | |
| 401 | ||
| 402 | r: [256]u64, | |
| 403 | m: [256]u64, | |
| 404 | a: u64, | |
| 405 | b: u64, | |
| 406 | c: u64, | |
| 407 | i: usize, | |
| 408 | ||
| 409 | pub fn init(init_s: u64) Isaac64 { | |
| 410 | var isaac = Isaac64 { | |
| 411 | .random = Random { .fillFn = fill }, | |
| 412 | .r = undefined, | |
| 413 | .m = undefined, | |
| 414 | .a = undefined, | |
| 415 | .b = undefined, | |
| 416 | .c = undefined, | |
| 417 | .i = undefined, | |
| 418 | }; | |
| 419 | ||
| 420 | // seed == 0 => same result as the unseeded reference implementation | |
| 421 | isaac.seed(init_s, 1); | |
| 422 | return isaac; | |
| 423 | } | |
| 424 | ||
| 425 | fn step(self: &Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void { | |
| 426 | const x = self.m[base + m1]; | |
| 427 | self.a = mix +% self.m[base + m2]; | |
| 428 | ||
| 429 | const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len]; | |
| 430 | self.m[base + m1] = y; | |
| 431 | ||
| 432 | self.b = x +% self.m[(y >> 11) % self.m.len]; | |
| 433 | self.r[self.r.len - 1 - base - m1] = self.b; | |
| 434 | } | |
| 435 | ||
| 436 | fn refill(self: &Isaac64) void { | |
| 437 | const midpoint = self.r.len / 2; | |
| 438 | ||
| 439 | self.c +%= 1; | |
| 440 | self.b +%= self.c; | |
| 441 | ||
| 442 | { | |
| 443 | var i: usize = 0; | |
| 444 | while (i < midpoint) : (i += 4) { | |
| 445 | self.step( ~(self.a ^ (self.a << 21)), i + 0, 0, midpoint); | |
| 446 | self.step( self.a ^ (self.a >> 5) , i + 1, 0, midpoint); | |
| 447 | self.step( self.a ^ (self.a << 12) , i + 2, 0, midpoint); | |
| 448 | self.step( self.a ^ (self.a >> 33) , i + 3, 0, midpoint); | |
| 449 | } | |
| 450 | } | |
| 451 | ||
| 452 | { | |
| 453 | var i: usize = 0; | |
| 454 | while (i < midpoint) : (i += 4) { | |
| 455 | self.step( ~(self.a ^ (self.a << 21)), i + 0, midpoint, 0); | |
| 456 | self.step( self.a ^ (self.a >> 5) , i + 1, midpoint, 0); | |
| 457 | self.step( self.a ^ (self.a << 12) , i + 2, midpoint, 0); | |
| 458 | self.step( self.a ^ (self.a >> 33) , i + 3, midpoint, 0); | |
| 459 | } | |
| 460 | } | |
| 461 | ||
| 462 | self.i = 0; | |
| 463 | } | |
| 464 | ||
| 465 | fn next(self: &Isaac64) u64 { | |
| 466 | if (self.i >= self.r.len) { | |
| 467 | self.refill(); | |
| 468 | } | |
| 469 | ||
| 470 | const value = self.r[self.i]; | |
| 471 | self.i += 1; | |
| 472 | return value; | |
| 473 | } | |
| 474 | ||
| 475 | fn seed(self: &Isaac64, init_s: u64, comptime rounds: usize) void { | |
| 476 | // We ignore the multi-pass requirement since we don't currently expose full access to | |
| 477 | // seeding the self.m array completely. | |
| 478 | mem.set(u64, self.m[0..], 0); | |
| 479 | self.m[0] = init_s; | |
| 480 | ||
| 481 | // prescrambled golden ratio constants | |
| 482 | var a = []const u64 { | |
| 483 | 0x647c4677a2884b7c, | |
| 484 | 0xb9f8b322c73ac862, | |
| 485 | 0x8c0ea5053d4712a0, | |
| 486 | 0xb29b2e824a595524, | |
| 487 | 0x82f053db8355e0ce, | |
| 488 | 0x48fe4a0fa5a09315, | |
| 489 | 0xae985bf2cbfc89ed, | |
| 490 | 0x98f5704f6c44c0ab, | |
| 491 | }; | |
| 492 | ||
| 493 | comptime var i: usize = 0; | |
| 494 | inline while (i < rounds) : (i += 1) { | |
| 495 | var j: usize = 0; | |
| 496 | while (j < self.m.len) : (j += 8) { | |
| 497 | comptime var x1: usize = 0; | |
| 498 | inline while (x1 < 8) : (x1 += 1) { | |
| 499 | a[x1] +%= self.m[j + x1]; | |
| 500 | } | |
| 501 | ||
| 502 | a[0] -%= a[4]; a[5] ^= a[7] >> 9; a[7] +%= a[0]; | |
| 503 | a[1] -%= a[5]; a[6] ^= a[0] << 9; a[0] +%= a[1]; | |
| 504 | a[2] -%= a[6]; a[7] ^= a[1] >> 23; a[1] +%= a[2]; | |
| 505 | a[3] -%= a[7]; a[0] ^= a[2] << 15; a[2] +%= a[3]; | |
| 506 | a[4] -%= a[0]; a[1] ^= a[3] >> 14; a[3] +%= a[4]; | |
| 507 | a[5] -%= a[1]; a[2] ^= a[4] << 20; a[4] +%= a[5]; | |
| 508 | a[6] -%= a[2]; a[3] ^= a[5] >> 17; a[5] +%= a[6]; | |
| 509 | a[7] -%= a[3]; a[4] ^= a[6] << 14; a[6] +%= a[7]; | |
| 510 | ||
| 511 | comptime var x2: usize = 0; | |
| 512 | inline while (x2 < 8) : (x2 += 1) { | |
| 513 | self.m[j + x2] = a[x2]; | |
| 514 | } | |
| 515 | } | |
| 516 | } | |
| 517 | ||
| 518 | mem.set(u64, self.r[0..], 0); | |
| 519 | self.a = 0; | |
| 520 | self.b = 0; | |
| 521 | self.c = 0; | |
| 522 | self.i = self.r.len; // trigger refill on first value | |
| 523 | } | |
| 524 | ||
| 525 | fn fill(r: &Random, buf: []u8) void { | |
| 526 | const self = @fieldParentPtr(Isaac64, "random", r); | |
| 527 | ||
| 528 | var i: usize = 0; | |
| 529 | const aligned_len = buf.len - (buf.len & 7); | |
| 530 | ||
| 531 | // Fill complete 64-byte segments | |
| 532 | while (i < aligned_len) : (i += 8) { | |
| 533 | var n = self.next(); | |
| 534 | comptime var j: usize = 0; | |
| 535 | inline while (j < 8) : (j += 1) { | |
| 536 | buf[i + j] = @truncate(u8, n); | |
| 537 | n >>= 8; | |
| 538 | } | |
| 539 | } | |
| 540 | ||
| 541 | // Fill trailing, ignoring excess (cut the stream). | |
| 542 | if (i != buf.len) { | |
| 543 | var n = self.next(); | |
| 544 | while (i < buf.len) : (i += 1) { | |
| 545 | buf[i] = @truncate(u8, n); | |
| 546 | n >>= 8; | |
| 547 | } | |
| 548 | } | |
| 549 | } | |
| 550 | }; | |
| 551 | ||
| 552 | test "isaac64 sequence" { | |
| 553 | var r = Isaac64.init(0); | |
| 554 | ||
| 555 | // from reference implementation | |
| 556 | const seq = []const u64 { | |
| 557 | 0xf67dfba498e4937c, | |
| 558 | 0x84a5066a9204f380, | |
| 559 | 0xfee34bd5f5514dbb, | |
| 560 | 0x4d1664739b8f80d6, | |
| 561 | 0x8607459ab52a14aa, | |
| 562 | 0x0e78bc5a98529e49, | |
| 563 | 0xfe5332822ad13777, | |
| 564 | 0x556c27525e33d01a, | |
| 565 | 0x08643ca615f3149f, | |
| 566 | 0xd0771faf3cb04714, | |
| 567 | 0x30e86f68a37b008d, | |
| 568 | 0x3074ebc0488a3adf, | |
| 569 | 0x270645ea7a2790bc, | |
| 570 | 0x5601a0a8d3763c6a, | |
| 571 | 0x2f83071f53f325dd, | |
| 572 | 0xb9090f3d42d2d2ea, | |
| 573 | }; | |
| 574 | ||
| 575 | for (seq) |s| { | |
| 576 | std.debug.assert(s == r.next()); | |
| 577 | } | |
| 578 | } | |
| 579 | ||
| 580 | // Actual Random helper function tests, pcg engine is assumed correct. | |
| 581 | test "Random float" { | |
| 582 | var prng = DefaultPrng.init(0); | |
| 583 | ||
| 584 | var i: usize = 0; | |
| 585 | while (i < 1000) : (i += 1) { | |
| 586 | const val1 = prng.random.float(f32); | |
| 587 | std.debug.assert(val1 >= 0.0); | |
| 588 | std.debug.assert(val1 < 1.0); | |
| 589 | ||
| 590 | const val2 = prng.random.float(f64); | |
| 591 | std.debug.assert(val2 >= 0.0); | |
| 592 | std.debug.assert(val2 < 1.0); | |
| 593 | } | |
| 594 | } | |
| 595 | ||
| 596 | test "Random scalar" { | |
| 597 | var prng = DefaultPrng.init(0); | |
| 598 | const s = prng .random.scalar(u64); | |
| 599 | } | |
| 600 | ||
| 601 | test "Random bytes" { | |
| 602 | var prng = DefaultPrng.init(0); | |
| 603 | var buf: [2048]u8 = undefined; | |
| 604 | prng.random.bytes(buf[0..]); | |
| 605 | } | |
| 606 | ||
| 607 | test "Random shuffle" { | |
| 608 | var prng = DefaultPrng.init(0); | |
| 609 | ||
| 610 | var seq = []const u8 { 0, 1, 2, 3, 4 }; | |
| 611 | var seen = []bool {false} ** 5; | |
| 612 | ||
| 613 | var i: usize = 0; | |
| 614 | while (i < 1000) : (i += 1) { | |
| 615 | prng.random.shuffle(u8, seq[0..]); | |
| 616 | seen[seq[0]] = true; | |
| 617 | std.debug.assert(sumArray(seq[0..]) == 10); | |
| 618 | } | |
| 619 | ||
| 620 | // we should see every entry at the head at least once | |
| 621 | for (seen) |e| { | |
| 622 | std.debug.assert(e == true); | |
| 623 | } | |
| 624 | } | |
| 625 | ||
| 626 | fn sumArray(s: []const u8) u32 { | |
| 627 | var r: u32 = 0; | |
| 628 | for (s) |e| r += e; | |
| 629 | return r; | |
| 630 | } | |
| 631 | ||
| 632 | test "Random range" { | |
| 633 | var prng = DefaultPrng.init(0); | |
| 634 | testRange(&prng.random, -4, 3); | |
| 635 | testRange(&prng.random, -4, -1); | |
| 636 | testRange(&prng.random, 10, 14); | |
| 637 | } | |
| 638 | ||
| 639 | fn testRange(r: &Random, start: i32, end: i32) void { | |
| 640 | const count = usize(end - start); | |
| 641 | var values_buffer = []bool{false} ** 20; | |
| 642 | const values = values_buffer[0..count]; | |
| 643 | var i: usize = 0; | |
| 644 | while (i < count) { | |
| 645 | const value = r.range(i32, start, end); | |
| 646 | const index = usize(value - start); | |
| 647 | if (!values[index]) { | |
| 648 | i += 1; | |
| 649 | values[index] = true; | |
| 650 | } | |
| 651 | } | |
| 652 | } |
std/rand_test.zig deleted-507| ... | ... | @@ -1,507 +0,0 @@ |
| 1 | pub const mt64_seed = 0xb334e49d0977c37e; | |
| 2 | pub const mt64_data = []u64 { | |
| 3 | 0x2ad1a63fab6d25a9, 0xb7143aba12569814, 0xc1b60d8d49e53e8, 0x5652adfc8da656dc, | |
| 4 | 0x43e3beb6d9e484a9, 0x17b09b71e9418ff7, 0x541646292686cfa4, 0x260457071268ecfc, | |
| 5 | 0x1627af31774e1dc1, 0x362a49b34ed75bb3, 0x7acf72002fe0f733, 0x3aaaf2e7b9409452, | |
| 6 | 0x9cfc2d9908115c2, 0x6e81a7f16ae613e9, 0xfc4da89c04acf3c7, 0x6984b6adb4feb9ae, | |
| 7 | 0x6a128b334e27b03d, 0xcc45a2b02937871a, 0xe585b229e00b2283, 0x7a92c0664a6f678a, | |
| 8 | 0x972735011bdc0744, 0xb494e743d658a084, 0x1eda3c4e7b1b2d0c, 0x4c7adb3831d87332, | |
| 9 | 0x12f8c7355f5ec631, 0xfc2bcb6be7d60eba, 0x74b95b47895f8687, 0x171de6fe92b97f5a, | |
| 10 | 0x86383730f52719ac, 0xe4e43ce0f61274f6, 0x514f7e072d96f19c, 0xabef324fbc6cb7fe, | |
| 11 | 0x7534b945b742f14f, 0x47f9efe33265adbe, 0x7bcab027a0abf16b, 0x3312a2b34225bff7, | |
| 12 | 0xb61455ce8c2e3e0b, 0x2b81008deeee4d94, 0x743b0b2b4974c7b6, 0xfc219101fd665f7d, | |
| 13 | 0x863d78891cbfe5e5, 0x7531bb1839181778, 0xf614359a65356e72, 0xfcdd1f6e3f250bdd, | |
| 14 | 0x528e10bd536eed5b, 0x9f69386ac60cd618, 0xbf5f242706817f01, 0x8e7da8070072cf64, | |
| 15 | 0xaa318b622da0667f, 0xc9580540fb7efd66, 0xb5d996deccd02e0e, 0x81c6a799ea3f5a41, | |
| 16 | 0xe6b896f4e21a8550, 0xde5206f177a24ceb, 0x53343e81639ec0b6, 0x5a6edb63d08be9f6, | |
| 17 | 0x3602c2892f7da1b9, 0xda84f4259841bdea, 0x5880e169a7746e45, 0x57cddb5ffd3c2423, | |
| 18 | 0x28fe1166fe7b8595, 0x92136c9decb42243, 0xa8c4199818ca7d62, 0x5042cd96f62854dd, | |
| 19 | 0x22b2d38c3f21f8d0, 0x73a2bfccf1b5f7bb, 0xaba3718f40b6984e, 0x9c1f5dc3e399f5f0, | |
| 20 | 0x9cf463f95369c149, 0xa7546d69e4232e18, 0x9ea57317d19ab7fc, 0xfb13c83d830731fb, | |
| 21 | 0x635a123eaa099259, 0x9a2fe7d0ba6e3c5c, 0x40b903cd0d0d3b4e, 0xc8210eb2d2e941cb, | |
| 22 | 0xd2582d4b1e016484, 0x1d048030875af39c, 0xb51c31a6c193d76f, 0x5ce9b801b8d61626, | |
| 23 | 0x2bae30455cbb0022, 0xba54df5998b2443f, 0x927abb9342c9a90a, 0xc431eb7df3e06727, | |
| 24 | 0x726f885d3da88d5, 0x7d85ff1ca4260280, 0xaf3fecf8f019817, 0x31d39105d6fc4fe8, | |
| 25 | 0x262d9842dbafd4bd, 0x54c28a2876e62e39, 0x95a986e24e214dde, 0xbf677a1abd2e553, | |
| 26 | 0x48ac890ff787b2b6, 0x2890ec1c67c539f4, 0x7ce88bf3975882c3, 0x88ef340414a29c88, | |
| 27 | 0xe30de9c88a00805b, 0xe772225e3ee6c68a, 0xa3a7d0921c5d5816, 0x8354957227b1663f, | |
| 28 | 0xb5b65ded7c747cbc, 0x93b4a12ff2e8fcea, 0x6359579c3c438b3c, 0x45b2c12e9722f2bd, | |
| 29 | 0x659a604414f19e1, 0x4ec9a149d4219ca5, 0xd830290dd6aebe2b, 0xabc7874a6b4827f8, | |
| 30 | 0xc91be5dd875847e7, 0x5b761d39f3f96aee, 0x5749dffad692b6c8, 0x86c94840cbd249d2, | |
| 31 | 0x411a466e886ad7, 0x27dca1f51aebb9a0, 0x1cceb093fbab7a42, 0x7140c2d6706e927c, | |
| 32 | 0x6881fdb87299a92f, 0xa81a28de171f3c47, 0x8fa9a1b3bb5dfb2a, 0xae076853e3e0abde, | |
| 33 | 0xe76572308ecd6b54, 0x6cd926c2e2760d8a, 0xdf080266cfbe3dc3, 0xb99b961999765d7b, | |
| 34 | 0xadb5d4e2b896ddf1, 0x8d3aaf4c83c83c56, 0x9b66e4f6eb65bef7, 0x7a81c3bf785eb1df, | |
| 35 | 0xc53f02b3e8c38647, 0xcdfeb25ee787759d, 0xead5e734d64ab5f6, 0x7930d87af1072499, | |
| 36 | 0xf30690a71d88ad6e, 0x73c347923c84728a, 0x3f2b588221003fe4, 0xe747052d0b453af2, | |
| 37 | 0xabe6fa70539b5edf, 0x4db6d1530d628c2, 0x4ec929af434eb1b0, 0x15afbe39886181ff, | |
| 38 | 0xa9141b9c89a07b80, 0x7d33f966c6232057, 0x8ddcb412f34a491d, 0xa74472b8ecc1e2f2, | |
| 39 | 0x34d745de1cb7de2e, 0x6cf67091309e5e93, 0xfb25004efa59450a, 0x3355947066522286, | |
| 40 | 0x5a8cffdf079dac21, 0x419445d6e6825887, 0x6e9c064f84381dcf, 0xbbcaf462a3a8ad76, | |
| 41 | 0x75836c68d6c1a13e, 0xf38141565d5c3759, 0x8c65989142ffa802, 0x106067ec26e6463, | |
| 42 | 0xadfac5e3a80de9c2, 0xc48b16e2df25b9f2, 0xa3257889c33669e6, 0x5bc760d4d65a1745, | |
| 43 | 0x303cd31fead81139, 0xfb97f78cade31e1d, 0xb888b8e05820a469, 0x7ebb8e44d47f54d9, | |
| 44 | 0xce76cdbb5ecdc529, 0xb1eb29949a099d52, 0xb6affc1b240a7eb3, 0x22977eac542906f1, | |
| 45 | 0x9b105b391ff729df, 0x83371186b2834968, 0xd5b893f382ea9e90, 0x5d17aa80a1fd4854, | |
| 46 | 0xe8ed8525eb29210c, 0xc789f3cd36c4dae3, 0x556e50a5f46b73fb, 0xef1d129b523dff77, | |
| 47 | 0x851de0f53f6707f9, 0x8deeeadfb1fa8bfc, 0x3d8c89c0e08c4f2e, 0xecfaaea537123333, | |
| 48 | 0x5bc9053d2dfd7669, 0x408c5bb2e880a9a2, 0x495726b3f3248219, 0x2b23cca4a6ea1ccc, | |
| 49 | 0x1df3663045092d61, 0xaf977a46e965e45b, 0x43a2facfff7f97e, 0x9b7714344c7b51e, | |
| 50 | 0x35643b24efb0559a, 0x502820785dc1af13, 0xbf82d2775b46433d, 0x1db626f2e16ca66, | |
| 51 | 0x744b031447c1e27d, 0x99e79898612f4606, 0xda02a728d234821f, 0xcf00c6fbb637a6e9, | |
| 52 | 0x242f2963196fd8b, 0x7aed8efc2dd562bb, 0x6204fb5d3dc6208a, 0x3e84861182fc7f6, | |
| 53 | 0xd14c4ee5aeef5c7a, 0x3749fbef94378dc1, 0x8fe710ec5cfc8566, 0xf43d7e495d5384d7, | |
| 54 | 0x8ff6396f1f1ce7c4, 0xf1252a6b6f86b42c, 0xddbbd098d6dca83f, 0x4e228724a227232a, | |
| 55 | 0x92a5a52ba2b24fa8, 0xdfc172b03fde669c, 0x34ee55adf7f0711c, 0x21d181e79b8000bc, | |
| 56 | 0xc788b1f48b37b693, 0x544fc4cfed0e0f92, 0xafca0c6de41789cc, 0xbb37bb5107ef97f8, | |
| 57 | 0xb9d62bf1dc0f6c95, 0xc78b5a36110dfb1, 0x1d615b658f39657e, 0x2bb2cd04cabcc360, | |
| 58 | 0xe563488ece6362f0, 0x213b56ce006fecc6, 0xc38207089fed0270, 0xa33199ff4a51d095, | |
| 59 | 0x1802ad28fb1896b1, 0xbead8f18c164a332, 0xceb5149101aa450f, 0x39ad89851ee8b62a, | |
| 60 | 0x317229aafabf37c4, 0xee68b8b9bf3520b3, 0xe4db499288350f04, 0xf8ea27feddb0ae7a, | |
| 61 | 0xa17235067b489c42, 0xbf4a570245f95d78, 0x8065c67e1d1537ab, 0xbd9357fb1b30aee5, | |
| 62 | 0xc224166ebeb24c42, 0xf9baf8ccd01b53bf, 0x5c13775c3fea8038, 0x4ea66f6d650ce62d, | |
| 63 | 0x470592ed81c140f2, 0xc2d0eb6f7999321f, 0x85d762f20290dc0c, 0x9f7d0d13936f6e78, | |
| 64 | 0x41f1fd2d20f2d62d, 0x891cb19ce1af2c2f, 0xe7ff34c3b29c3719, 0x246743f43126c69c, | |
| 65 | 0xea4b2da3195ebab9, 0x4831e4de995187dc, 0x7fb8969bbee45ce5, 0xe35b483da73c44ed, | |
| 66 | 0xf89158ca9af36227, 0x9fc7f34a35469a7a, 0xd02483ebca6564e7, 0xca00da156aaeda03, | |
| 67 | 0x303d1514646822f1, 0x226832ae582b8eac, 0xf772d719e413504e, 0x87603b928c068ab1, | |
| 68 | 0x4dc1552230e9b883, 0xef8c5e9db946fc87, 0x935581290bf7a4ee, 0xca632d2c7674bf2, | |
| 69 | 0xd8a3933b80d39efd, 0xf026574d0ffee6fb, 0xe4412d0dcd2fe94f, 0x668916490a2983ec, | |
| 70 | 0x73b1fe84a995718, 0x729bedefe21cc0e7, 0xd3a770f1c683b98f, 0x5d597a96323a10c2, | |
| 71 | 0xfbb7834bbf5fed23, 0xf3546c805a42ccdd, 0x9ef3e2164bb31a0c, 0x388363ce6c6c2253, | |
| 72 | 0x8120f4a949f017cb, 0x925a61942bbd3d10, 0xa03182d8599c0521, 0x2412e23004b40ebb, | |
| 73 | 0x35010a126bf2aecc, 0x21147869a1a84ca7, 0x53cba503b6127b98, 0x10c89dd62ab3591c, | |
| 74 | 0xf4c7f84faaf9f5f1, 0x8b4a37a2e844b97b, 0x23ddeb236a0bd9af, 0x4fd51d7207f49e62, | |
| 75 | 0x6cdab447c27706b2, 0x9e8f54b9a2d1a790, 0x191aed85d4d77087, 0xf74ecf5015265af6, | |
| 76 | 0x45925e25404922a1, 0xcf5467a0f5b42b98, 0x73590809c85c728c, 0xc16beeda74a1a1b8, | |
| 77 | 0xc3bbe7999803dd6a, 0x1a368bb32eec184, 0xafad2d86b7bb574f, 0xdc7c7b8960dc921a, | |
| 78 | 0xd9b68d854f5e0ae1, 0xe9e1a6a16efe0bea, 0x304a15bd6ca1cb14, 0x713ce3144e0af4b9, | |
| 79 | 0xc50eb410981be1d2, 0xb0fba6119bf7a300, 0x7a107296731fd314, 0xdd764898a90042b3, | |
| 80 | 0x8a69973262da3bc8, 0x29c6b9d048596c44, 0x62581bd20da76f1b, 0x4d1a3941d6d3e4bb, | |
| 81 | 0x19c447306245055, 0xb2978afcd04ba357, 0x7c01cdefcfe24432, 0xc4b268314411deae, | |
| 82 | 0x5ba56d49da714765, 0x33299186ac6dfd09, 0xede087aec096ef0d, 0xf758da2c7bcf9ddb, | |
| 83 | 0x5ea6c40d56824cdd, 0x121ff879d6ba905b, 0xb5fed0c42b616f5c, 0x21029cdc347de152, | |
| 84 | 0xb251d93f4cd7bf4a, 0xaedcb2dc6402cf13, 0x840e5e0d96e89407, 0x6a92fd328efcc6ef, | |
| 85 | 0xc63f5d8f6fcadcbd, 0x405bd64d1621128e, 0xe1318888172f58ed, 0x1009c9764d49da2b, | |
| 86 | 0x4bc0592cbfdf9f91, 0x972f0e080dfecd02, 0xa1cb961958eeb6aa, 0x6ee6467ad8c20aca, | |
| 87 | 0xb3f1c738390d6a83, 0x6504eb7ac498650d, 0xdf7dda67f198f59f, 0x72615652e56a82c3, | |
| 88 | 0x85e0fa2dfb51755a, 0x98b1f92a3d2ad940, 0xce81d51d875c0045, 0x437004d0be0a4d69, | |
| 89 | 0x64065895526f896c, 0xe1e1fea920785d49, 0x7d507ffd56fda19a, 0x17309b625cecb42, | |
| 90 | 0x67b6d83f0fd0f572, 0x5178665a5bcd38f4, 0x3c49fda2d35a8606, 0x7f058d2cb0ad351c, | |
| 91 | 0xfb95691559245416, 0xc991b857662b1b9f, 0x9e6d0f4e19774f96, 0x26cc7502212ca578, | |
| 92 | 0x3466110f03225e49, 0x2ae4958375eab9f3, 0x939a8d94c8871191, 0xa27356548ac6b28d, | |
| 93 | 0xacf86d43ec3aa030, 0xe0d16c7fa0b13a8c, 0x408ec2b2f8da531b, 0xde72494115ee4e83, | |
| 94 | 0xd26d7f79a02c5b1e, 0x2b6f835520c97f6a, 0x1f30f008b109ae7d, 0x698dbf9acaa222f1, | |
| 95 | 0xbd55de40838376d5, 0xebe53822cec7eb80, 0x7ce900793008d2bc, 0x494fc7d10e8331bb, | |
| 96 | 0x53509b90bdb7d588, 0x62aa920e9554b2f2, 0xe103098542011b6f, 0xeb722b9523d68af8, | |
| 97 | 0xb71b1a6ea2c6591b, 0x97cd7da55c940270, 0x8ab70184427e45dc, 0x6cb6907427808465, | |
| 98 | 0xf69232a42dbe7475, 0xbc9816d429fa8909, 0xef1e74244539d41b, 0x5569b6d10440d5c, | |
| 99 | 0x7dda6817985c8ef5, 0xb270ed19cc8161b3, 0x87d80b66c8a15db0, 0x96966684c3ba47fb, | |
| 100 | 0x996669bc87aff3bf, 0x17c015383c793f2, 0xa4b5de41fc69f61a, 0x14a0eb4e3055742f, | |
| 101 | 0x5f0da5a7a2b8bc79, 0x5fe0353728aac023, 0x1554daf4abe92eed, 0x545722dac774b6a4, | |
| 102 | 0x733fc54174f2e0d1, 0x3478ef85dd994316, 0x58ba2ac090ef7575, 0xa66b9b0cbc77b6e2, | |
| 103 | 0xdc78cab5c708a3ee, 0x97a30c27be510f61, 0xb95d0b06fc0910b6, 0xdc80bdc42f79a25f, | |
| 104 | 0x5cadc438e65b3070, 0x6263df49ce691b9c, 0xa7ce160daa64416b, 0xa4f8bfedb57288c1, | |
| 105 | 0xa51714e187bbcfe9, 0xe25df4e9fc44644c, 0xeaf1854b3116ce11, 0xde1b8f810991a604, | |
| 106 | 0xd4fc2e365e99be4b, 0x8d1b0d2799527e06, 0x7cac59eaf46baba, 0x4fa63c74d2dabaf1, | |
| 107 | 0x4f6c5d5e676733a6, 0x7ab7ddb9c1b789b7, 0x5d9beb4877a37034, 0x5e96bc9de3985bcb, | |
| 108 | 0x72bab4dcb75b3228, 0xfa40f33c4d799e1f, 0x73e6f61a69984a6b, 0x7499c9af466cf22f, | |
| 109 | 0x42fab9136bfa64dd, 0xd5e8e39513b6fffd, 0x8eda1fd5ad8cd51d, 0x95338744859dff44, | |
| 110 | 0x4f0c5e5ae768c729, 0x5bc92c60495ae348, 0xcbb48c170ac21168, 0x8374aa2440eeb138, | |
| 111 | 0x70b663d6f6d70ca9, 0x11264ca6dd79e5a0, 0xf058a2c156974514, 0x36820eefc435ba63, | |
| 112 | 0xd7b69f3d0c0c27a1, 0xe1a2eddf3b41d205, 0x80508ec93b038bc8, 0xd7e0429bd511ff37, | |
| 113 | 0x7bf55a4e87e183b8, 0x4cb370ce7edb4bea, 0x26fbd0b31dcef45b, 0xf7acbd6781419fa6, | |
| 114 | 0xf7849659f05c90c, 0xb686271ea57a47c6, 0x16f3f839dbfb4e1b, 0x906872b08b2c61a, | |
| 115 | 0xc30c86d0a0203c15, 0xdaf238a6aa4fc9f7, 0x2399aa09ad2c069a, 0xf133c3aca703f545, | |
| 116 | 0x868a10304a1c98ba, 0x60ef0607f46f7e90, 0xe4e69f26931e11a5, 0x487b8f6bd6d92941, | |
| 117 | 0xd10cb2971798c0c7, 0x7126d81aa4bd0106, 0xcb620311dc84ab82, 0x26f8734a7a356bb2, | |
| 118 | 0xcf9b9eeb02ee978c, 0x8a9ff0285d4d6b30, 0xe30e3b957e2cc7f8, 0x7c15a09e4d275809, | |
| 119 | 0xdf723ae1dda5d167, 0xac212e4f6264bba2, 0xe3d60920ed983308, 0x91b403cbc91e290c, | |
| 120 | 0xcdb905b012aff7c7, 0xb5ee73d45f900897, 0xafacc7cd7f5d52e7, 0xa8653272621165d6, | |
| 121 | 0x90e2efc485ddd0d1, 0x56ef1ca9097b1a96, 0xc7a20f85777eb0a, 0xf4cec0271a50eae9, | |
| 122 | 0x21acd76442024973, 0x19a46be82a4abdbe, 0x1bc12e0b8bf41fbb, 0x3766fe3d8e5119f2, | |
| 123 | 0x7fea355c4c18e8ad, 0xd08b496a24fb8017, 0xe1a7cfaa0877aa2, 0xd37ad9e2a2a3fa96, | |
| 124 | 0xaa362ba0e696f679, 0x7e7de89142c3aca5, 0x2dedb0842a3575b8, 0xb74c1e1d9082fe5b, | |
| 125 | 0xb1ae74323699140f, 0x73623f80c727a6ea, 0x132ed204b0f10441, 0xc3e6ebe8ffc252bf, | |
| 126 | 0x5f15cffb8286dce0, 0x66dab32df780fa8f, 0xeb00da7b25ea99e4, 0x113ad2448fafb671, | |
| 127 | 0xee065c10a8f1924f, 0x2fcb7367cc01fe5, 0x484338f5c2d0aacd, 0xecfacd785e42d7a6, | |
| 128 | 0x11513f845de8af3a, 0xd11be6b29054de0d, 0x2536e5d2856af9b7, 0x60ab519760acd4c4, | |
| 129 | 0x6bfe010250a831ac, 0xb28a93e44b53b21b, 0x281cf9b233858583, 0x4ca6139abc79a710, | |
| 130 | 0x5717d33616d77a95, 0x9ba52d2b7dfe71b5, 0x32e1c543476aa17d, 0xae242cc75806b7fa, | |
| 131 | 0xa1415cb8fde770da, 0x3956c67542dc004d, 0x3a6f51518fdd20ce, 0x448c848f6c936d93, | |
| 132 | 0x8fec38ff51bb5fab, 0x7463816cfc0754ac, 0x83b38e531ba39e73, 0xf9fc84dcf4f8c93e, | |
| 133 | 0xdf20dbe8b91c3d6f, 0xec65939ac9516f9a, 0x888346f6c1aaa94a, 0xe42cabb108f60d95, | |
| 134 | 0x39bb2e46b0599fa9, 0x529335ed75acba9e, 0x6a8767c5d00776c4, 0x8243346104fe61a5, | |
| 135 | 0x7a2bd0339b3e9bac, 0xb68ccdf14473f4ba, 0xa06f389531ab553a, 0xc7c6f074fc2882d3, | |
| 136 | 0x50a5fd6e6d0df962, 0xd7c0000d194139b7, 0x5ae27ef4033f873d, 0x4e7abe8a6d3570f8, | |
| 137 | 0x27011ccd3885e709, 0x3dae53f7b7a8924a, 0xa9086c9b2b86fb71, 0xa3f9e534a399e62c, | |
| 138 | 0x9f2f0379f9a33ec6, 0xceb51af95d4472bd, 0x15aa534182f8465, 0x96373b9cd28a627b, | |
| 139 | 0x9fdce0ad99d41907, 0x2755bb0f52b8c239, 0x2f2e241b6aa7d243, 0xf040afbacb2f6001, | |
| 140 | 0x552267c5f8b4c1b0, 0x22bfb3f0b58f9e48, 0x6bff8de368dbee3a, 0x652025c63d4069ce, | |
| 141 | 0x743eb697b25f9c90, 0x8a3742c9dbf67b1c, 0xaf3bcfc260d7e69, 0x491facaa59b7e1d, | |
| 142 | 0xd07d0761e6535fcd, 0x79ef09d9d3859232, 0xe0e0a013317d9207, 0x4b94baecf6fe4b4e, | |
| 143 | 0x574576ed054cfc38, 0x90e90edd1a26f0aa, 0x616d32a371af78c6, 0x392cea9c34ffb0a8, | |
| 144 | 0x692a6e730c33ac6f, 0x9e4b92ef425b78a6, 0x291d4c962d2f3e7c, 0x5f0f8ebb67f308fc, | |
| 145 | 0xc1a0faf70ec747a3, 0x641da9550cd89392, 0x6adbe38115f09648, 0x3a51980fb324da0d, | |
| 146 | 0xee894f2b5c17a380, 0x58788fa693f767c9, 0xc9f490ff5d88c4c0, 0x2ca6e8b204aa3070, | |
| 147 | 0x7693837d7910c40c, 0x9240e04f16051720, 0xab773072d922faa2, 0xacb6892db8362872, | |
| 148 | 0x5ac8b4d130613c0e, 0x65cd5ac259c653cb, 0x9647e0276864f3f8, 0xe207c57ee9237a53, | |
| 149 | 0xe41f2663482a8fdb, 0xf605931fce8b95bd, 0x5b0247a9009255d2, 0xae949df3ab5a4ab5, | |
| 150 | 0xc0e912dacbb72c42, 0x4226971e6351f33a, 0xd98d41f9f0fdb6c3, 0x64bf6a0af66782d5, | |
| 151 | 0xb4ca689b3959bf46, 0xb4cbf621b4970922, 0xe9f27469c2412fe6, 0xb529d406d27c785e, | |
| 152 | 0xf33be21f2672ec78, 0x34b3c4c4603656cd, 0x4a7efe099a0ae9d1, 0xa6ad5b909667945b, | |
| 153 | 0xe20850e47ab440f7, 0x68739e1b4fa069e5, 0x4c191300a9207cf4, 0x9b613a1a38160c98, | |
| 154 | 0x2cc631eb015081c9, 0x52af80aad7b676f4, 0x904b38943300ca8f, 0x50a515c0d302620f, | |
| 155 | 0x52ae95b8a0c1f36c, 0x6a62ab87786774e2, 0x17ea45367ad58985, 0x92959c57166aa21b, | |
| 156 | 0x2a9d91bd1a9716b4, 0x552c2f8528220174, 0xd665856c96b47d17, 0x14c6cba13b6dca3b, | |
| 157 | 0x865f1c93ec9000d0, 0x23dda8b5e161910e, 0xc191ac4342717953, 0x6783fdb95e098f1d, | |
| 158 | 0x1a4c26a5cad1e8ee, 0xde96e2a1e33e3046, 0xa57e65bedcf9047e, 0xa1cdef163fe7f80c, | |
| 159 | 0xeb0abcc13feeb7b2, 0xaa158c61b0e44470, 0x98dc901679caf85b, 0x954046758f8d2e96, | |
| 160 | 0x56db5e99c5d8c68, 0x7bb8d36962a4ac81, 0x2e301b4ecb03821, 0x121c1b2df70f0e1c, | |
| 161 | 0x3fbdad1e8faa0543, 0x6efb222398a2f88b, 0x65760de4d96338e0, 0x15b2c58a67fb43fa, | |
| 162 | 0x22f1532c89367d77, 0x1f726ffdad411d9e, 0x42572b54dcedf3ba, 0x3f8e0f6e9f0bbb7b, | |
| 163 | 0x4b0e705c86571a1c, 0xf8c9b04f8bd75117, 0x67ed2e9e4545557, 0x57e8853f681bbf8c, | |
| 164 | 0x6f99d1fd5fdbf582, 0xd2aa9bd48ad692e2, 0x2efc88bddecfe616, 0x8e9779a1e119abf4, | |
| 165 | 0x52dfee4722a20b75, 0x79465be3aea146d6, 0x588997dbcbd5f005, 0x79bda8bcc5d4c650, | |
| 166 | 0x2384e131ed3b5330, 0x229cb1d89738aa26, 0x1526d1a020a96507, 0xc7b6ac961a740cb9, | |
| 167 | 0xe78cec14478c4f71, 0xaba61cfd8f1e2a71, 0x24123c8a37ae66f3, 0xbad8b07709aa215d, | |
| 168 | 0x7896fa53fd2418e7, 0x72265842e8c4f955, 0x9f6331fd80527661, 0x7c649eeddb382c9d, | |
| 169 | 0xd3b0708dd6b5ae84, 0xeda51f244551e15, 0xb7822c860b93dd44, 0xdf9afcc3c9cac88f, | |
| 170 | 0x9244b9816573be70, 0xf3d103887cc4ce2d, 0xb3295c2e5bcb0218, 0x85243b7a2e0af441, | |
| 171 | 0xbffd3df508d06098, 0x4908b967f6765c12, 0x8886ac94c0dabb, 0x9c7865af133eb6c0, | |
| 172 | 0x5946fee66e64d7b2, 0x7737bc5af713087f, 0xbec815a80782dd5d, 0xe7672cfe0f7945fb, | |
| 173 | 0xe1f80b6df5beece1, 0x5b749d3a22450fd6, 0xaf34a567bf838668, 0xa72a177d20943ceb, | |
| 174 | 0x257c45c1601c4922, 0x3d7c68f6fe36ce59, 0x1b8ef47186e06c96, 0x8040426656154c17, | |
| 175 | 0xc15f74f980647bda, 0x36389393336a78be, 0x15d174ed5536afe2, 0x51e702e8adb61f63, | |
| 176 | 0xc9c95ca3f1c08f30, 0x6653094c8531c93a, 0xf7be5dfc2eb3b5b, 0xb5e21ec5c63850b0, | |
| 177 | 0x9ab5f082e01021a5, 0x75c4ca38d7678fb1, 0xb20bd13e05e5bd67, 0x3378133e631fbaee, | |
| 178 | 0x17cb3686511aeb6e, 0x4c0dea4c80ec7bc, 0x21fe874bf5509300, 0xece4f84e34d52e54, | |
| 179 | 0x3f2649803ca9918b, 0xdb493adeac5c60f5, 0x7c02a1d153afedd, 0x2d08ceda0fef7967, | |
| 180 | 0x6a32e018e432b0ea, 0x86479f3ea38ad57e, 0x84e3e04f1e5877be, 0x41b898cb02772049, | |
| 181 | 0xd6dded3714d71084, 0x9df5b2f3a0ab275d, 0xd5ab652dfa73ee0a, 0x4633e03fa37d6edb, | |
| 182 | 0x226314b8c4b937ff, 0x45d66a00ab031188, 0xb93ce1cfbcd1eaa0, 0xf88e0756f7e7c1c1, | |
| 183 | 0xf3611966fed51e03, 0x81235048c662d9f7, 0xcc8275f866147b4f, 0xd3b3ca0f5033a863, | |
| 184 | 0x970212eb8c2b3429, 0xec848dd58f3449d6, 0xa1d527af824d09f2, 0x60bd5e91448b9cf4, | |
| 185 | 0x1210ddfac603aa88, 0xcbf4270f3407e25a, 0x212955fec55466a0, 0x3afeaef4c9ccc793, | |
| 186 | 0xdd114286ec304817, 0x849e6ae3c2cf794f, 0x71c08228d6a05310, 0x177e77779d155b11, | |
| 187 | 0xdc59148f219a9c04, 0xb0702a7802d5276d, 0x56085d6761aee015, 0x3f79ce06bcfb4f3, | |
| 188 | 0x459a1f917f8f3e0, 0xe4ea5635e8bcd512, 0xa88e99b63f135a39, 0x95bd628d77d39446, | |
| 189 | 0xe6432158ef4c7d98, 0xb349cd3d1c74369e, 0x25b1a32db58efb0a, 0xc2add3a44cecc0b5, | |
| 190 | 0x5d676629f23010b5, 0x9890b3a62599408e, 0xef68ea8144d97805, 0x429e0fda34046a85, | |
| 191 | 0x7723d9043053bf52, 0xbb78842d9b67ae91, 0x9155ef932192e6a3, 0xdb523ea403d39f6b, | |
| 192 | 0xdb8fa1eee23ea58, 0x7c735492524a3448, 0xc580cb82e81505, 0xb0be6a006414841c, | |
| 193 | 0xdec2e763b5cedaa5, 0x8da58bb23638af5f, 0xb0e6b33f6736e7d0, 0x8146bbcd3dd4df61, | |
| 194 | 0x978080148a8989bb, 0x7f8119caa3308095, 0x4e88c318ea0604f3, 0x6ee5262f16b3cf83, | |
| 195 | 0xc44395c7a578ace9, 0x92016ee635de27e1, 0xb8dc5ceb36e67fd2, 0x95c851d65bd35f8c, | |
| 196 | 0xbe393620503c49fa, 0x42af183b92eac923, 0xfef0e660435135ce, 0x262d67d480451ed1, | |
| 197 | 0x590f92e1ee0502b3, 0x18825c97d49e3700, 0x2cd8c30a848c9acf, 0x1025c7747fda0115, | |
| 198 | 0x54109f23e82590aa, 0x93917bf1f8325981, 0xda674b183fa0e3cf, 0x2a0b2467eb8aefc5, | |
| 199 | 0xb0085eb83468793c, 0x607cabb2c9d3a81b, 0xe7a6b6013804d665, 0x67629a769c1efede, | |
| 200 | 0x2830ab6ef6d10166, 0xffd02b0655332bd4, 0x19bd056c3117568f, 0x385a834785662c6f, | |
| 201 | 0x938b5d56bd5f7248, 0x969afe82dd4829c8, 0xf455d4ace41c797d, 0x23d9cd67eff27512, | |
| 202 | 0x2b0c7037ecb322e2, 0x73df193328258bda, 0x5d7ee05cf2054f93, 0xdabfbd5b46b61cea, | |
| 203 | 0xcea02d82546b96de, 0x2245d5e74d5f60ae, 0x842ca45f8ef2a44, 0x7505cc4e1c3060d8, | |
| 204 | 0x869146ac8e68565e, 0x22ea711fb30e73e3, 0x53cd64736898a0c0, 0xfa88458b920684df, | |
| 205 | 0xc3ae23f451e0616f, 0xe2dd69393141ff32, 0x98863ab129bcd866, 0x8c9756a40dd5b834, | |
| 206 | 0x2eeeef78c36fede5, 0xe84d2eb23e22153b, 0xb0ccc2f7ac541d78, 0x151faba0f513acfa, | |
| 207 | 0x4300e3cea0260717, 0xaba308c6d857d2d0, 0x5eb25dd325256c6a, 0x3342627b68038da4, | |
| 208 | 0x70d7d75526da35, 0x80ff3f5ea2ac3cf1, 0xe7434f2f026394b0, 0xa7c5ff17f7d2cb07, | |
| 209 | 0xdfed0bb33a06ff78, 0x485cc64d38ce2596, 0x88db8580147aa8fc, 0xf52a5111d693b973, | |
| 210 | 0xeeaa031c02b370a8, 0xbb3b1678222d0e81, 0x27b569f2a6630939, 0x2b301fa3e50efeb8, | |
| 211 | 0x4dbc1f85bf3f8972, 0xb37e4f2cb75a825b, 0x3c8848e0f1777cc7, 0x8fae2e6938ba00aa, | |
| 212 | 0xfb4674b50884992c, 0x2b765005b85b7388, 0xaaf0007fb9662ce5, 0x684bd59009a4ad65, | |
| 213 | 0x221ffead3d73ab35, 0xccfe6d02d46856b5, 0x54d3323359e1b114, 0xcb412202ed42f097, | |
| 214 | 0x15d63df422771b9b, 0x71852bca1581d14f, 0xf30dcbb6cf891e63, 0x478fb1eed3cc5a10, | |
| 215 | 0x849a3b52bc5bb196, 0x4c1a98dbc546dd81, 0x846dc8c2258ec4f8, 0xbd4da447c7340bd0, | |
| 216 | 0x8f1ee1d6a85b9db0, 0x123ebfa8aaec07f2, 0xae34948e375d4477, 0xd466a4177842d8e4, | |
| 217 | 0xd5108efeb19cac6, 0x3266f7db8f133bdb, 0xe69af4e5d8d767e4, 0xea0efc0331df64a2, | |
| 218 | 0xb879052746ed72ed, 0x2c8233cc84de4144, 0xdcd5dda825186731, 0xb9e3b679d268f34c, | |
| 219 | 0x7ce12e2fa95bda8b, 0xa34afd12e611a4c1, 0x6043d06ee7619f90, 0xca3a3d4813c0addf, | |
| 220 | 0x6e97a61d1e4b3c4f, 0x8cdeae467a4bb292, 0xf08a6c69e70076b5, 0x97aa5c3180d3edbe, | |
| 221 | 0xc39813e1573904d5, 0x42577549d026e8c8, 0xaf5827ffe259b62a, 0x9e1d48596c4f0b24, | |
| 222 | 0xab9dd230ba8efb64, 0x81769493b85868d4, 0x715b45c5e3952245, 0x84735e138d228f35, | |
| 223 | 0xf4f987da7d19c74d, 0x1bdc77979baf29b, 0x785b3640158e0278, 0x77fc9d00681bcdd, | |
| 224 | 0xb5980cc490dcab93, 0x9062c158196b8244, 0xc16af5418cc97c4a, 0xdd4a4e9e8e00e524, | |
| 225 | 0x870b554b629277f1, 0xf90ff72bb54322c0, 0xd4c273bc2199823, 0xeebc75970d438466, | |
| 226 | 0xe4cad67413074a53, 0x6eccde71bd09dc0c, 0x14278b0ca6b910b4, 0x6e8895f17cdb933c, | |
| 227 | 0xa0b3987821416e11, 0x71b7d24b81fa769f, 0x1d3b1a805b885a58, 0x1bc737b1719736a, | |
| 228 | 0xea4d1dbb8823037, 0xe50ce48c8469adbd, 0x34c2d5e6c41a888e, 0x446a756eb06dc3a4, | |
| 229 | 0xbac5ed8a8f90262, 0x7f1b76e0c707ab9d, 0xb31323309b94a12e, 0xf58269b9852f986e, | |
| 230 | 0x3b74c2b338c244fc, 0x879b46f23a4deae4, 0x3f2591e34cdce1c9, 0x73c6f81eb560ed5c, | |
| 231 | 0xd2aa923c7a5c18a9, 0x7170c1f7621cace9, 0xa18b327b11b951a, 0x2b36315510f56370, | |
| 232 | 0x5cfed2f703dfc0bb, 0x1e43b99175054c07, 0x392dfa3210e8013b, 0x65e0c5c0454ee693, | |
| 233 | 0x2a795f6f493349db, 0x17995ebdfe848db0, 0xf23174b823a52cf7, 0xaac6ef104bfd396e, | |
| 234 | 0xfa0f5b29156eeccd, 0x9ccb3590a6e88c1a, 0x2edae0b1b80aafab, 0x1e1e92baae39aa30, | |
| 235 | 0x24475af89cec7f33, 0xacdbeceaadb9936c, 0x7725948da8586e93, 0xcc05595e17947215, | |
| 236 | 0x1f3cbde17a508faa, 0x2795f58ff5c8919b, 0x309658d1748f30d3, 0xe90c11962e5ed4bb, | |
| 237 | 0xc22b876286d32e27, 0x495c8b667c6ea3dd, 0x84263045f7d6eab5, 0xf8d3a9ab1494a315, | |
| 238 | 0xabc42cf769a21d9d, 0x3fef7fb40bdf3a81, 0xfd35336e188925a3, 0xd472bdaf277ab26d, | |
| 239 | 0x4949e8ff51da2307, 0xbec86dce960ff3b, 0x1aa1ce4f70256b10, 0xd52986ff8cd700ea, | |
| 240 | 0x364d8efc0f5afad6, 0xca3d1958f57a9050, 0x17a0a2ec122dc677, 0x7992695be3363fd6, | |
| 241 | 0x5c66a265e0607da8, 0x7250114e050bb917, 0x30cd3a70bc7b723d, 0x7b77433392b3fbf8, | |
| 242 | 0x295bb7bf46318b38, 0xdb15025af2a71c65, 0x26a82b21ef67f50c, 0x14a5573d4fc798c1, | |
| 243 | 0xd8cad4642ec68e5e, 0x9276d7f60142822c, 0xf7b8efc27522e52f, 0xd0a3f36f6d340bed, | |
| 244 | 0x341260fb11765c02, 0xcd1d394d796702cc, 0x7d483ef031eb3346, 0x74eaab49374576c1, | |
| 245 | 0xa073bea32a71a273, 0xd65ce2552993b5cf, 0x8670afe77caaeb16, 0xb607f1455d072a47, | |
| 246 | 0x30ed96be92809559, 0xa58380a503c23c9c, 0x916aa68fb957a30d, 0x30c5a675bf19738c, | |
| 247 | 0xd4cbad34e4e4b886, 0xd6cb83061f2b0ebf, 0xceddb4040f535fa9, 0x778c586927b1e247, | |
| 248 | 0xe4bb5c4b6e0f3c3d, 0x3e857d671db80667, 0x2b909dd8725f1fa2, 0x558ffd0772db7841, | |
| 249 | 0x710f9638d3edb2c4, 0x21a4ccee53d46556, 0xf76e8e4737b9628b, 0x71cd157f23581c71, | |
| 250 | 0x68d8fded9b66efd6, 0x7d9f5e182c0b9457, 0x2140757748a217ff, 0xdd1e5365520b77a4, | |
| 251 | 0x644d8e4b2f30dcfa, 0xa1de42f4e9791564, 0x70e148ababfe9f86, 0xb97f463e0ac7daec, | |
| 252 | 0x82844f729d9fa554, 0x5c8475e84470c924, 0x3a83de748eac32fd, 0x68725fbc9c202c5b, | |
| 253 | }; | |
| 254 | ||
| 255 | pub const mt32_seed = 0x7dc0d160; | |
| 256 | pub const mt32_data = []u32 { | |
| 257 | 0x59327332, 0x200858fa, 0xab53c028, 0x5c442427, | |
| 258 | 0xd8be0287, 0x3b69d304, 0x15fdf62f, 0x59b8ecd, | |
| 259 | 0x6d7ab30c, 0x3a3dd6f1, 0xc1b9773e, 0xa12fb017, | |
| 260 | 0xa805b5c1, 0x4a313ba5, 0xd82c790c, 0x8de311f2, | |
| 261 | 0xe7cb23dd, 0x784b2efb, 0x9743487c, 0x73e2f2fb, | |
| 262 | 0x1a7ac286, 0xaef90d, 0x6c0a4514, 0xae1d83aa, | |
| 263 | 0x412fcca1, 0x3acd2d28, 0xde78292f, 0x13237756, | |
| 264 | 0xdd6cdeba, 0x44ae4df9, 0x3e9902eb, 0x39e1cf20, | |
| 265 | 0x62f561b9, 0x6cbdf531, 0x4a000673, 0xb1c82daa, | |
| 266 | 0x896156ca, 0x75e410f2, 0x9c69e72c, 0x396b42bb, | |
| 267 | 0x25c97ec0, 0xe12173f1, 0x8dcd42e5, 0x82aac3e3, | |
| 268 | 0xcdc1c84d, 0x13509c0c, 0x46a696d2, 0xb89ad987, | |
| 269 | 0x92da5e7f, 0xaa87d8a9, 0xe433ff57, 0x80a7ee49, | |
| 270 | 0xd387cfcc, 0x7dc47d92, 0x21516140, 0x989ca465, | |
| 271 | 0xf2a8e002, 0x73b99ddb, 0x2204108f, 0x27e84890, | |
| 272 | 0x371c81c0, 0x9f581854, 0xc0841c35, 0x770f6804, | |
| 273 | 0x87c55f4e, 0xd29516bb, 0x2b6d6bde, 0x5541f6ee, | |
| 274 | 0x1ec9b182, 0x7d599729, 0x4f4b9a14, 0x6f8c8562, | |
| 275 | 0x2d5151aa, 0xb54f5bc, 0xa252452b, 0x2a4266da, | |
| 276 | 0x25a6b75d, 0x2d11106e, 0xc5d77943, 0xb10b6e0b, | |
| 277 | 0xeb5cae4a, 0x43a0dd53, 0xa40bea1f, 0x63e632c2, | |
| 278 | 0xf420b6ce, 0x8b080233, 0x7f70ae87, 0xf460f0d6, | |
| 279 | 0x147c7e74, 0x710692ea, 0xa0a7d8fb, 0xe7f05808, | |
| 280 | 0xa6173aaf, 0xae608de0, 0x8702036, 0xbf1bfc7b, | |
| 281 | 0xf14cd548, 0xbbc7553d, 0x5358dd1d, 0xcc0c1fe5, | |
| 282 | 0xfab6f78d, 0x9365c118, 0xf64216a3, 0xb4bdcf1b, | |
| 283 | 0xc90b8a7a, 0x8b7b78a, 0x4c7b6854, 0xba7b5628, | |
| 284 | 0xdd728c15, 0xcb1f8905, 0xa63e2342, 0xa78822, | |
| 285 | 0xbda61b18, 0x160a59fa, 0xeccf473b, 0xc5a445b5, | |
| 286 | 0x7aa86430, 0x362e0d7c, 0x8006a0cb, 0x8b11586f, | |
| 287 | 0x6677bba9, 0x6208cf27, 0xeec9b5, 0x3dfedfc9, | |
| 288 | 0x886cc0e8, 0x32ed77ca, 0x43525faf, 0x9786354a, | |
| 289 | 0x1a2eb378, 0xf0e6b168, 0x49064b09, 0x8ab39681, | |
| 290 | 0x7b6655fc, 0x35adb168, 0xc417d430, 0x2784288a, | |
| 291 | 0xea17836, 0xc85006e7, 0x673dfdc3, 0x42765688, | |
| 292 | 0xc2b9251, 0x840a45b, 0xcac98e2f, 0x1a6f9777, | |
| 293 | 0x34959b23, 0xf0dcec81, 0xcaa2c6c8, 0x1cf93061, | |
| 294 | 0x787e598d, 0xd5d9e31e, 0x14e08791, 0xd9d9d782, | |
| 295 | 0xef162f23, 0x238f4113, 0x23f42107, 0x6ed5cc3f, | |
| 296 | 0xa55e5a7c, 0x4650595, 0x5217da8b, 0x6eeaacdc, | |
| 297 | 0xb453d7b1, 0xfa1ff004, 0xb9d17f74, 0x2bd6a53e, | |
| 298 | 0xe4c2d9dd, 0xed66375e, 0xf8215568, 0x9bcadbb3, | |
| 299 | 0x9c4f9d51, 0xff68312, 0x82308422, 0x83e990b0, | |
| 300 | 0x38b6135b, 0x70e2aa13, 0xa30065d2, 0x6396a00, | |
| 301 | 0x77d423bc, 0xa93abf0a, 0xc7bb8c31, 0x5d7bd3d3, | |
| 302 | 0x6a374f2e, 0xe4b5bc88, 0x39f6e512, 0xd6aea995, | |
| 303 | 0x878c1bfa, 0x4636014d, 0x9caa2c09, 0x7ac4758b, | |
| 304 | 0xbd3b957e, 0x518c2fd6, 0xea009a2e, 0x542bf419, | |
| 305 | 0x59090006, 0xb1d94703, 0xe0d9eefc, 0xe7fccb17, | |
| 306 | 0x40111951, 0xf2560485, 0xb50ce9e1, 0xd7a1ee51, | |
| 307 | 0x28dffa99, 0x41d12275, 0xdd89a365, 0xf22eda29, | |
| 308 | 0x104f94ee, 0xe669983b, 0x6346a250, 0x86326fc5, | |
| 309 | 0xb7f347df, 0x3849a39f, 0xf433929a, 0xeea5155, | |
| 310 | 0x4cf9b778, 0x6bd7926a, 0xcda9496, 0xf430d7a2, | |
| 311 | 0x41637670, 0xaf3bbad6, 0xeb66e44e, 0x2499605d, | |
| 312 | 0x9988920d, 0xf9d652ef, 0x67aa80c0, 0x505073c9, | |
| 313 | 0x85cd418f, 0x9f83fb65, 0xf50b3eac, 0x812ba6bd, | |
| 314 | 0x74d61788, 0x86d64f3b, 0xb1f8fc1c, 0x3e2af667, | |
| 315 | 0x4d118a2, 0xd028ffa9, 0x32e88a44, 0x4ed9ba35, | |
| 316 | 0xea3c7030, 0xffe44aaf, 0x5e39c467, 0xeabcfebb, | |
| 317 | 0x53e656ec, 0xced701d0, 0x31020b02, 0x4b4c1dc5, | |
| 318 | 0x8744885c, 0xa8e93656, 0x3ef457e5, 0x272bde23, | |
| 319 | 0xe541477c, 0x3ad3ac04, 0x63eaa692, 0x81055cf9, | |
| 320 | 0x3ff5f782, 0xa8efe6bc, 0x15f37656, 0xaaaebf1d, | |
| 321 | 0xf73d461a, 0xe8b2c0b5, 0x5035ff48, 0x3a95e34b, | |
| 322 | 0x6f21d94f, 0x6f6d1f96, 0xdaf79f37, 0x826f69f3, | |
| 323 | 0x209a00b8, 0x2ad1b2f2, 0x2c64fb45, 0xcf8bf26e, | |
| 324 | 0x9befcff2, 0xc08f6951, 0x96d98205, 0xa267dcb5, | |
| 325 | 0xbc43ec5, 0xee6a7e1c, 0x49224eae, 0x14e820e, | |
| 326 | 0xbb340212, 0x68ed572c, 0x45e9e623, 0x1297f3af, | |
| 327 | 0x49a98ed2, 0xddd34ae8, 0x211838ab, 0x47e7652d, | |
| 328 | 0xb40430c6, 0xc8d3bd7, 0x4352356e, 0xf0e5cac9, | |
| 329 | 0x21880df4, 0xc16b343a, 0xd9ed7350, 0x17fe1f65, | |
| 330 | 0x6637192e, 0xd81c93aa, 0x7d6e17d2, 0xd407b13f, | |
| 331 | 0x425da072, 0x380d423d, 0x6ce57b22, 0x7b17ed17, | |
| 332 | 0x95fbf626, 0x768303d6, 0x76ab6b3e, 0x591491e3, | |
| 333 | 0x259f79ab, 0xd4babeaf, 0x9c7de2f8, 0x4fe6cb58, | |
| 334 | 0xf43680a9, 0x651a1266, 0x730ea3c8, 0x9188d4c5, | |
| 335 | 0x12d01e34, 0x47afb2e9, 0xb4b76d35, 0x5e5164bc, | |
| 336 | 0xc864fc46, 0x5d018aa7, 0x17fac975, 0x5a775fbd, | |
| 337 | 0x40e6fa14, 0x7a00b683, 0x99e4e102, 0x2f933b90, | |
| 338 | 0x474e14ba, 0xde1b0754, 0xe84aba2b, 0xb386cd43, | |
| 339 | 0x17ca77c9, 0x7b4f38ef, 0x803ea1a8, 0x93553947, | |
| 340 | 0x806c8224, 0x2608451e, 0x63157fe3, 0xaf53930e, | |
| 341 | 0x5dfe8c16, 0x65592bda, 0x7086eb3f, 0x838e6a50, | |
| 342 | 0xa27836d9, 0xf2f16d92, 0xdc0a981, 0xfbf8f915, | |
| 343 | 0x2caea00d, 0x86bb3e18, 0x6d94c209, 0x3bbbeb6c, | |
| 344 | 0x114d68f4, 0xc271e48f, 0xa3350dc1, 0xb8d55eb4, | |
| 345 | 0x68be5ee1, 0xbf22ef29, 0xd6e0aa54, 0x48f7219, | |
| 346 | 0x21aca253, 0xfbf07910, 0xfcdd61a8, 0x118a09b, | |
| 347 | 0x3f2bbde6, 0x46eea63f, 0xdb51ed16, 0xf8a9fc36, | |
| 348 | 0x31614dc0, 0xdd84f54d, 0xd2b66065, 0xdae0af99, | |
| 349 | 0x6d071a51, 0xbdbac46c, 0x15deee25, 0xf792e64c, | |
| 350 | 0x910194e8, 0xfc989a8f, 0x919727fd, 0x6f93a56c, | |
| 351 | 0x2df36e9a, 0xd395b948, 0xb026b54a, 0xf0938a5, | |
| 352 | 0xe9c64399, 0xb5cda15b, 0xb7b8dd41, 0x7146f944, | |
| 353 | 0x8d41ce2f, 0x47c74099, 0x2e5a8e5f, 0x28f7a19c, | |
| 354 | 0xef7a8ef9, 0x6a763eb9, 0xf13a3ec4, 0x9f352360, | |
| 355 | 0x42317561, 0x6c6a0ca5, 0x5e40b472, 0x3ddaadd4, | |
| 356 | 0x2f5d14eb, 0x5dd49aeb, 0xc89edb24, 0xa2da269b, | |
| 357 | 0x5cf0a38b, 0x8e2f435c, 0x40970e54, 0xa2cb730e, | |
| 358 | 0xf9d8c301, 0x8ef29fb1, 0xf08b1840, 0x7d45e4a2, | |
| 359 | 0xa0fe4ce1, 0x939a21c4, 0xfdeebfea, 0x4c661550, | |
| 360 | 0xdd304d1c, 0x3cdb078d, 0x94ae8db2, 0x4f6b4287, | |
| 361 | 0xffe64fa8, 0x50384bb0, 0x16cf5ed3, 0xa91a8fec, | |
| 362 | 0xdb8ebb1, 0x59c2898b, 0xd587edc9, 0xdec2e75a, | |
| 363 | 0x496ccdd2, 0x897db91d, 0xf8ea5149, 0x6bed4bad, | |
| 364 | 0xce76e472, 0x43c7f976, 0xb055dc01, 0x7ffd5671, | |
| 365 | 0xe193b86a, 0xe288ce11, 0x514d531e, 0xa42fa47e, | |
| 366 | 0xe7c0e194, 0xffc059ba, 0x26548e36, 0xe1f10d92, | |
| 367 | 0x3ef5d95e, 0xa6e69282, 0xffacb09e, 0xf4a16ff5, | |
| 368 | 0x9b7f03bd, 0x588c54b4, 0xc2b6eaa1, 0x2d83acdc, | |
| 369 | 0x7fdbb606, 0x2b160650, 0x9923e57e, 0x32bd23bd, | |
| 370 | 0x50cd6d4c, 0x205d901f, 0x810a9935, 0x27ce6e7a, | |
| 371 | 0xe0c6c66, 0xac06c99c, 0x4326aa9b, 0xe1af1e90, | |
| 372 | 0xe358c8b1, 0x2f601c2a, 0xefca77e7, 0x1a7ed2f8, | |
| 373 | 0x8ad2e191, 0xe5520809, 0x27084438, 0xe4d8e782, | |
| 374 | 0x5e8a4038, 0x87bba694, 0x65f07eba, 0x616f8f07, | |
| 375 | 0xc5565d9, 0x555955e4, 0xf41c2caa, 0xb085fbf5, | |
| 376 | 0xa5f9d9ff, 0x418fa0df, 0xec5a576d, 0x7fc332ab, | |
| 377 | 0x7683ed33, 0x968ef54b, 0x834d598d, 0x6833f356, | |
| 378 | 0x59dc7e7f, 0x779661dc, 0x58942dd4, 0x80387aab, | |
| 379 | 0xf6dac9e5, 0xe043be04, 0x2ae4f872, 0x881f8d01, | |
| 380 | 0x82cfd69d, 0x931f4648, 0x2a76ab31, 0xa3f1dd7c, | |
| 381 | 0xd7f4826a, 0xe74918da, 0xe4c98636, 0x441164f, | |
| 382 | 0x15a0e9aa, 0xce7480ad, 0xba39076b, 0x233aa8d, | |
| 383 | 0x6c32f0e6, 0x169c62bf, 0xa2cd17f6, 0xb5590084, | |
| 384 | 0xb2036f00, 0x18315935, 0x11e9c9c7, 0x25c77861, | |
| 385 | 0x41596cda, 0x635e5e02, 0x8f396cc, 0x4cd00d8d, | |
| 386 | 0xd665597e, 0x90f891ef, 0x547b93ee, 0x376959c1, | |
| 387 | 0xdc5fa80, 0x9b4797a6, 0x53673041, 0x25ab117a, | |
| 388 | 0x7b8b8292, 0xf4e99584, 0x5139da98, 0x30e2afeb, | |
| 389 | 0xff2664b9, 0x591eb6f0, 0x9e87e602, 0xf5e26193, | |
| 390 | 0x61831f07, 0xabc139f9, 0x984eda0a, 0xaea1b8da, | |
| 391 | 0x65c7410d, 0x2b84800d, 0x1d3cfec3, 0xd05cb8a1, | |
| 392 | 0x4529641b, 0x7d6712e6, 0xc38cbde7, 0xacad7787, | |
| 393 | 0xd8482f3a, 0xa5662eaa, 0x24836ee9, 0xf3b5cc97, | |
| 394 | 0x50a581ae, 0xff6004b6, 0x650fc547, 0x161898b1, | |
| 395 | 0xa7593447, 0x325827dd, 0xf1844a1a, 0x7eb56de2, | |
| 396 | 0x89882452, 0xfebb49a, 0xfe86ae9c, 0x7dba98b1, | |
| 397 | 0x1d65adb5, 0xb71acffa, 0x861215af, 0xc0f1496, | |
| 398 | 0x70967c72, 0x3803d127, 0x6c8fdd84, 0xe40991f1, | |
| 399 | 0x1343e3a, 0xf57b4e73, 0x25f34f76, 0xaebcdee8, | |
| 400 | 0x8752d71f, 0xfc710e54, 0x34f3af44, 0xfa7dea4e, | |
| 401 | 0x477d4d83, 0x42640ff1, 0x2c5c31ce, 0xa82de5e4, | |
| 402 | 0xcc813271, 0x4d40bf86, 0x4e416095, 0xb5ac332c, | |
| 403 | 0xd2d44703, 0xe4c5ef57, 0xde193a29, 0xbf3e7974, | |
| 404 | 0xbb313d75, 0x8dc973d5, 0x301b2657, 0x44dc5064, | |
| 405 | 0x8c58c633, 0x83424c74, 0xb7cbf7ac, 0xa04238c2, | |
| 406 | 0x6ceabd59, 0xd25e6fd0, 0x3409167, 0x42d6ef80, | |
| 407 | 0x1f47c437, 0xdb21e45f, 0x2fd48e29, 0x9498cfb7, | |
| 408 | 0xc9e4cb12, 0xc6dcf0df, 0xa1633c39, 0x1b349670, | |
| 409 | 0xf76d4a64, 0x15ecd8dd, 0x777bb76d, 0xc46008e7, | |
| 410 | 0x23d94e44, 0x78aa07de, 0x2eeac782, 0x3757b114, | |
| 411 | 0x2b22de2a, 0x37726519, 0xf107546d, 0xe9847f74, | |
| 412 | 0x449a4ea6, 0x2e31fa5a, 0xd719ea88, 0xb2115c87, | |
| 413 | 0xfa6b7231, 0xf72fc9ff, 0xcd22bc37, 0x9080778a, | |
| 414 | 0x93430a21, 0x97c24360, 0x6e5b1a76, 0x5e8baa7c, | |
| 415 | 0x300c94f8, 0x2843d9da, 0xdceac0ae, 0xeeed885, | |
| 416 | 0x1898ffd0, 0xa3bbee3c, 0xc16f8fd7, 0x82992b68, | |
| 417 | 0x39c153b6, 0x1b3ba4c8, 0x41e7c3ac, 0xcdf8f06a, | |
| 418 | 0xd40b8ae6, 0x4982b6c2, 0xb32f7437, 0x22ed3691, | |
| 419 | 0x16579a2a, 0xff9de457, 0xc421e8e4, 0x17c8f6cb, | |
| 420 | 0xa5c4a8da, 0x49bd8afa, 0xe2be081c, 0x95170f28, | |
| 421 | 0xd679fbdf, 0xcf39d563, 0x4e2d2ee9, 0x39471096, | |
| 422 | 0x3918bef0, 0x279b7679, 0xa5281a0f, 0x49481d6f, | |
| 423 | 0x11f95ee1, 0xd9df649f, 0x2993eb27, 0x48ad815f, | |
| 424 | 0x99cf306d, 0xca9457e4, 0xc27c51d2, 0xc2a838ec, | |
| 425 | 0x537faf4c, 0x55dccddf, 0x8df5aeb8, 0xabb317ca, | |
| 426 | 0xfc1bcf6b, 0x669c2b1b, 0x719b62d5, 0x6b9325cf, | |
| 427 | 0xc123d0d3, 0x2ddc6ace, 0x27fdc30a, 0xd3f93cd8, | |
| 428 | 0x704f5486, 0xd3f448ec, 0xbbd1e32c, 0x3bcd4c0b, | |
| 429 | 0x86f8166, 0x957db888, 0x899b6a5e, 0x270dc8b7, | |
| 430 | 0xff16222e, 0x51e139a8, 0x3d8b4b9f, 0x68d20818, | |
| 431 | 0xa639ad00, 0x4c2e0fd2, 0xb4949cdc, 0x2ab6eb32, | |
| 432 | 0xdd0c67ad, 0xd2208cbe, 0xcd17a0bc, 0xacc541f7, | |
| 433 | 0xfa9e714f, 0x316d31a7, 0xed79fa91, 0xb5c0e980, | |
| 434 | 0x412ecc9b, 0x9815753, 0xd0df1f43, 0x8e37dbb9, | |
| 435 | 0xe640df75, 0x379c2fb6, 0xc7ed26a4, 0xc5190400, | |
| 436 | 0x1cc81b53, 0xcb0b0cd5, 0x360f061b, 0x6d90284e, | |
| 437 | 0x83c05bd0, 0xbd80bae9, 0xd584ef12, 0x228a46ec, | |
| 438 | 0x657c4fbe, 0x5ca1043c, 0x852aca0f, 0x31ce950, | |
| 439 | 0x33ee2cd8, 0x3cdecbf7, 0x787ef08c, 0xea610ee, | |
| 440 | 0x47c1db89, 0x90eeda11, 0x74f8d429, 0x51d3a4c5, | |
| 441 | 0x3135b401, 0x2e14783c, 0xb9af855c, 0xb66348d9, | |
| 442 | 0xa3a47387, 0x6eb72af1, 0x7bb56088, 0xc664542d, | |
| 443 | 0x7ed96b8, 0x995870a8, 0x385b1fd6, 0xa430680d, | |
| 444 | 0x98a883ec, 0x2497a389, 0x7a880627, 0x8350ba9d, | |
| 445 | 0x4cb35c33, 0x30bf6b14, 0x8695a469, 0x9a81e44b, | |
| 446 | 0x8bb27c9a, 0xbfb6a4dd, 0xbae7cf6e, 0x4ebccc87, | |
| 447 | 0xb712ed3d, 0x31e90365, 0xcc1fa63f, 0x32b93df6, | |
| 448 | 0xbad4c7bc, 0xb2570e17, 0x73fa21be, 0x5c02a8d2, | |
| 449 | 0x94446d75, 0x7265f3ad, 0xd58487a2, 0x919b7a07, | |
| 450 | 0xbe2d0e05, 0xd36ccf4f, 0x6d5c66d7, 0x8448522f, | |
| 451 | 0x8409c294, 0x6f1c7af7, 0x173a13bc, 0x1b3e4a0b, | |
| 452 | 0x705b941b, 0x77eb584f, 0x85b68458, 0x8e3ad1ac, | |
| 453 | 0x4aa99702, 0x7ae1b24c, 0x899ba29c, 0x860a3711, | |
| 454 | 0xabe53a4f, 0x37870133, 0x1ed7cb89, 0xea539762, | |
| 455 | 0x4ba64130, 0x48517a2d, 0xce0a869d, 0x937ba48, | |
| 456 | 0xd0f234c4, 0xf9b2cf26, 0xc3c311f0, 0x153d09a9, | |
| 457 | 0x404d3af9, 0x9f7edbc1, 0xbdcecded, 0x97969ba8, | |
| 458 | 0x3379437, 0xadd3c893, 0x7c024639, 0x459390b, | |
| 459 | 0xcb7c7320, 0xa5c63725, 0x65907e3e, 0xbf70583b, | |
| 460 | 0xcebb601b, 0x4edfb286, 0x9350336f, 0xdfb4be76, | |
| 461 | 0x88b56f39, 0x9937d7f9, 0xa12a286d, 0x34f141c, | |
| 462 | 0xa2e75c15, 0xd69a7060, 0x931340c3, 0x22447f25, | |
| 463 | 0xe8aed82c, 0xd76a9ae7, 0xc967288, 0xe572facd, | |
| 464 | 0xbe82b0ee, 0x10f5dce1, 0x4f03ee35, 0x2340b923, | |
| 465 | 0xf4fb6bd0, 0x64adbf01, 0x3d277a0a, 0x39e76f2c, | |
| 466 | 0xe3c024d9, 0x57869c82, 0x743b7826, 0xf66f1574, | |
| 467 | 0xc93965c, 0xf86a552, 0x13557069, 0x9e0845de, | |
| 468 | 0xaee084f9, 0x5eafaedb, 0xc06f5f3, 0x9051f6ea, | |
| 469 | 0x98fceda2, 0x2af2f8cc, 0x6c41b5a8, 0xc1af74de, | |
| 470 | 0x57302276, 0x253923c9, 0xd79996b3, 0x8ecb3141, | |
| 471 | 0x641387cc, 0xf87a4101, 0x96a50c76, 0xbcf24a11, | |
| 472 | 0x87b6bb6, 0x58ee501b, 0xaa859695, 0xb2eed107, | |
| 473 | 0x554173f0, 0xb12ec0e6, 0x57785c1b, 0x53685c9a, | |
| 474 | 0x114c3163, 0x9383cf19, 0x31fd7cdf, 0xaeb8225c, | |
| 475 | 0x58774fe7, 0x54700ad4, 0xad418726, 0xf055b71c, | |
| 476 | 0x7d31237f, 0xdd97cad5, 0xcdd5325e, 0x42f2acf4, | |
| 477 | 0x4bed262b, 0x7a8faaf2, 0x2b1eafdd, 0xa1b806ac, | |
| 478 | 0x26965c6e, 0xb41b7168, 0x15e2e70b, 0x7daa8e13, | |
| 479 | 0x6198aa5a, 0xc9b8b94c, 0x339b5754, 0xcd3b285c, | |
| 480 | 0xffd1486c, 0xf224979a, 0xafb89ec5, 0x222058c, | |
| 481 | 0xcb4814d0, 0x2b0e7c7d, 0x9eb25b84, 0x271564b0, | |
| 482 | 0xbb72e076, 0x48251020, 0x18008023, 0x48d10005, | |
| 483 | 0x4a452eaa, 0xb2365308, 0x19cdb632, 0x1fd56d04, | |
| 484 | 0xffa5ff2a, 0xaba89e42, 0x388fc17d, 0xea61c00f, | |
| 485 | 0x5156273d, 0x776f1a56, 0x8d539d28, 0x289c01cb, | |
| 486 | 0x857aa71f, 0x348e411f, 0xc9eb3c91, 0x67a61079, | |
| 487 | 0xe4276a0f, 0x45bdc15f, 0x8e0a698e, 0xbdefc310, | |
| 488 | 0x82377ba6, 0x3bfbf404, 0xcbf22c79, 0x35f501bc, | |
| 489 | 0xb16044a7, 0xeffdb8, 0xdbac383d, 0x7816663f, | |
| 490 | 0x18f5a318, 0x3d04f1cb, 0x735da9b4, 0x75e339a1, | |
| 491 | 0x5b6c55f, 0x1c18887e, 0xf698e14f, 0x338a6da1, | |
| 492 | 0xdac85699, 0x1aca7768, 0x8eb0fa7a, 0xc98fa71d, | |
| 493 | 0x3b794408, 0x92913041, 0xf8dc8827, 0x1cf706e9, | |
| 494 | 0x3aeee292, 0x321dbaa8, 0xee1eb8d1, 0x23554be9, | |
| 495 | 0x811c7804, 0xf0f4de6b, 0xd457e382, 0xeda56795, | |
| 496 | 0xeffdfc71, 0xf2a52829, 0xa7460732, 0x2c1321c0, | |
| 497 | 0x2f734db0, 0xf04ecb0b, 0xec7d777e, 0x43c54317, | |
| 498 | 0xccaa74cd, 0xfe49dd9d, 0x4c509829, 0x278f9bd7, | |
| 499 | 0x581dc500, 0x4ad38c2e, 0xcbee1047, 0x13302c1c, | |
| 500 | 0xbc0cb734, 0xc1c8f234, 0x1df52b35, 0xd8815548, | |
| 501 | 0x319edefb, 0x437cebe5, 0x3dcb6026, 0xe9d4f93f, | |
| 502 | 0xb2661154, 0xeb8c15a0, 0xb008505, 0x5f869981, | |
| 503 | 0xf5588ca4, 0xd6929c5b, 0xa3dd13d1, 0xdc863314, | |
| 504 | 0x891a454f, 0x91737e49, 0x5064d4d8, 0x2fd32675, | |
| 505 | 0xadefe9b1, 0xdde32b11, 0x741bbd6, 0x3b4363a9, | |
| 506 | 0xb121d9e8, 0x916ca61d, 0x38c0af15, 0x5e3dfd72, | |
| 507 | }; |
std/sort.zig+78-78| ... | ... | @@ -67,7 +67,7 @@ const Iterator = struct { |
| 67 | 67 | self.numerator -= self.denominator; |
| 68 | 68 | self.decimal += 1; |
| 69 | 69 | } |
| 70 | ||
| 70 | ||
| 71 | 71 | return Range {.start = start, .end = self.decimal}; |
| 72 | 72 | } |
| 73 | 73 | |
| ... | ... | @@ -82,7 +82,7 @@ const Iterator = struct { |
| 82 | 82 | self.numerator_step -= self.denominator; |
| 83 | 83 | self.decimal_step += 1; |
| 84 | 84 | } |
| 85 | ||
| 85 | ||
| 86 | 86 | return (self.decimal_step < self.size); |
| 87 | 87 | } |
| 88 | 88 | |
| ... | ... | @@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 219 | 219 | var B1 = iterator.nextRange(); |
| 220 | 220 | var A2 = iterator.nextRange(); |
| 221 | 221 | var B2 = iterator.nextRange(); |
| 222 | ||
| 222 | ||
| 223 | 223 | if (lessThan(items[B1.end - 1], items[A1.start])) { |
| 224 | 224 | // the two ranges are in reverse order, so copy them in reverse order into the cache |
| 225 | 225 | mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]); |
| ... | ... | @@ -230,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 230 | 230 | } else { |
| 231 | 231 | // if A1, B1, A2, and B2 are all in order, skip doing anything else |
| 232 | 232 | if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue; |
| 233 | ||
| 233 | ||
| 234 | 234 | // copy A1 and B1 into the cache in the same order |
| 235 | 235 | mem.copy(T, cache[0..], items[A1.start..A1.end]); |
| 236 | 236 | mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]); |
| 237 | 237 | } |
| 238 | 238 | A1 = Range.init(A1.start, B1.end); |
| 239 | ||
| 239 | ||
| 240 | 240 | // merge A2 and B2 into the cache |
| 241 | 241 | if (lessThan(items[B2.end - 1], items[A2.start])) { |
| 242 | 242 | // the two ranges are in reverse order, so copy them in reverse order into the cache |
| ... | ... | @@ -251,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 251 | 251 | mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]); |
| 252 | 252 | } |
| 253 | 253 | A2 = Range.init(A2.start, B2.end); |
| 254 | ||
| 254 | ||
| 255 | 255 | // merge A1 and A2 from the cache into the items |
| 256 | 256 | const A3 = Range.init(0, A1.length()); |
| 257 | 257 | const B3 = Range.init(A1.length(), A1.length() + A2.length()); |
| 258 | ||
| 258 | ||
| 259 | 259 | if (lessThan(cache[B3.end - 1], cache[A3.start])) { |
| 260 | 260 | // the two ranges are in reverse order, so copy them in reverse order into the items |
| 261 | 261 | mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]); |
| ... | ... | @@ -269,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 269 | 269 | mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]); |
| 270 | 270 | } |
| 271 | 271 | } |
| 272 | ||
| 272 | ||
| 273 | 273 | // we merged two levels at the same time, so we're done with this level already |
| 274 | 274 | // (iterator.nextLevel() is called again at the bottom of this outer merge loop) |
| 275 | 275 | _ = iterator.nextLevel(); |
| 276 | ||
| 276 | ||
| 277 | 277 | } else { |
| 278 | 278 | iterator.begin(); |
| 279 | 279 | while (!iterator.finished()) { |
| 280 | 280 | var A = iterator.nextRange(); |
| 281 | 281 | var B = iterator.nextRange(); |
| 282 | ||
| 282 | ||
| 283 | 283 | if (lessThan(items[B.end - 1], items[A.start])) { |
| 284 | 284 | // the two ranges are in reverse order, so a simple rotation should fix it |
| 285 | 285 | mem.rotate(T, items[A.start..B.end], A.length()); |
| ... | ... | @@ -301,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 301 | 301 | // 6. merge each A block with any B values that follow, using the cache or the second internal buffer |
| 302 | 302 | // 7. sort the second internal buffer if it exists |
| 303 | 303 | // 8. redistribute the two internal buffers back into the items |
| 304 | ||
| 304 | ||
| 305 | 305 | var block_size: usize = math.sqrt(iterator.length()); |
| 306 | 306 | var buffer_size = iterator.length()/block_size + 1; |
| 307 | ||
| 307 | ||
| 308 | 308 | // as an optimization, we really only need to pull out the internal buffers once for each level of merges |
| 309 | 309 | // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level |
| 310 | 310 | var A: Range = undefined; |
| ... | ... | @@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 322 | 322 | |
| 323 | 323 | var buffer1 = Range.init(0, 0); |
| 324 | 324 | var buffer2 = Range.init(0, 0); |
| 325 | ||
| 325 | ||
| 326 | 326 | // find two internal buffers of size 'buffer_size' each |
| 327 | 327 | find = buffer_size + buffer_size; |
| 328 | 328 | var find_separately = false; |
| 329 | ||
| 329 | ||
| 330 | 330 | if (block_size <= cache.len) { |
| 331 | 331 | // if every A block fits into the cache then we won't need the second internal buffer, |
| 332 | 332 | // so we really only need to find 'buffer_size' unique values |
| ... | ... | @@ -336,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 336 | 336 | find = buffer_size; |
| 337 | 337 | find_separately = true; |
| 338 | 338 | } |
| 339 | ||
| 339 | ||
| 340 | 340 | // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each), |
| 341 | 341 | // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values, |
| 342 | 342 | // OR if we couldn't find that many unique values, we need the largest possible buffer we can get |
| 343 | ||
| 343 | ||
| 344 | 344 | // in the case where it couldn't find a single buffer of at least √A unique values, |
| 345 | 345 | // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace) |
| 346 | 346 | iterator.begin(); |
| 347 | 347 | while (!iterator.finished()) { |
| 348 | 348 | A = iterator.nextRange(); |
| 349 | 349 | B = iterator.nextRange(); |
| 350 | ||
| 350 | ||
| 351 | 351 | // just store information about where the values will be pulled from and to, |
| 352 | 352 | // as well as how many values there are, to create the two internal buffers |
| 353 | ||
| 353 | ||
| 354 | 354 | // check A for the number of unique values we need to fill an internal buffer |
| 355 | 355 | // these values will be pulled out to the start of A |
| 356 | 356 | last = A.start; |
| ... | ... | @@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 360 | 360 | if (index == A.end) break; |
| 361 | 361 | } |
| 362 | 362 | index = last; |
| 363 | ||
| 363 | ||
| 364 | 364 | if (count >= buffer_size) { |
| 365 | 365 | // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer |
| 366 | 366 | pull[pull_index] = Pull { |
| ... | ... | @@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 370 | 370 | .to = A.start, |
| 371 | 371 | }; |
| 372 | 372 | pull_index = 1; |
| 373 | ||
| 373 | ||
| 374 | 374 | if (count == buffer_size + buffer_size) { |
| 375 | 375 | // we were able to find a single contiguous section containing 2√A unique values, |
| 376 | 376 | // so this section can be used to contain both of the internal buffers we'll need |
| ... | ... | @@ -405,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 405 | 405 | .to = A.start, |
| 406 | 406 | }; |
| 407 | 407 | } |
| 408 | ||
| 408 | ||
| 409 | 409 | // check B for the number of unique values we need to fill an internal buffer |
| 410 | 410 | // these values will be pulled out to the end of B |
| 411 | 411 | last = B.end - 1; |
| ... | ... | @@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 415 | 415 | if (index == B.start) break; |
| 416 | 416 | } |
| 417 | 417 | index = last; |
| 418 | ||
| 418 | ||
| 419 | 419 | if (count >= buffer_size) { |
| 420 | 420 | // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe |
| 421 | 421 | pull[pull_index] = Pull { |
| ... | ... | @@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 425 | 425 | .to = B.end, |
| 426 | 426 | }; |
| 427 | 427 | pull_index = 1; |
| 428 | ||
| 428 | ||
| 429 | 429 | if (count == buffer_size + buffer_size) { |
| 430 | 430 | // we were able to find a single contiguous section containing 2√A unique values, |
| 431 | 431 | // so this section can be used to contain both of the internal buffers we'll need |
| ... | ... | @@ -449,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 449 | 449 | // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray, |
| 450 | 450 | // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2 |
| 451 | 451 | if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count; |
| 452 | ||
| 452 | ||
| 453 | 453 | // we found a second buffer in an 'B' subarray containing √A unique values, so we're done! |
| 454 | 454 | buffer2 = Range.init(B.end - count, B.end); |
| 455 | 455 | break; |
| ... | ... | @@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 465 | 465 | }; |
| 466 | 466 | } |
| 467 | 467 | } |
| 468 | ||
| 468 | ||
| 469 | 469 | // pull out the two ranges so we can use them as internal buffers |
| 470 | 470 | pull_index = 0; |
| 471 | 471 | while (pull_index < 2) : (pull_index += 1) { |
| 472 | 472 | const length = pull[pull_index].count; |
| 473 | ||
| 473 | ||
| 474 | 474 | if (pull[pull_index].to < pull[pull_index].from) { |
| 475 | 475 | // we're pulling the values out to the left, which means the start of an A subarray |
| 476 | 476 | index = pull[pull_index].from; |
| ... | ... | @@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 493 | 493 | } |
| 494 | 494 | } |
| 495 | 495 | } |
| 496 | ||
| 496 | ||
| 497 | 497 | // adjust block_size and buffer_size based on the values we were able to pull out |
| 498 | 498 | buffer_size = buffer1.length(); |
| 499 | 499 | block_size = iterator.length()/buffer_size + 1; |
| 500 | ||
| 500 | ||
| 501 | 501 | // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks, |
| 502 | 502 | // so this was originally here to test the math for adjusting block_size above |
| 503 | 503 | // assert((iterator.length() + 1)/block_size <= buffer_size); |
| 504 | ||
| 504 | ||
| 505 | 505 | // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort! |
| 506 | 506 | iterator.begin(); |
| 507 | 507 | while (!iterator.finished()) { |
| 508 | 508 | A = iterator.nextRange(); |
| 509 | 509 | B = iterator.nextRange(); |
| 510 | ||
| 510 | ||
| 511 | 511 | // remove any parts of A or B that are being used by the internal buffers |
| 512 | 512 | start = A.start; |
| 513 | 513 | if (start == pull[0].range.start) { |
| 514 | 514 | if (pull[0].from > pull[0].to) { |
| 515 | 515 | A.start += pull[0].count; |
| 516 | ||
| 516 | ||
| 517 | 517 | // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge |
| 518 | 518 | // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4, |
| 519 | 519 | // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal |
| ... | ... | @@ -532,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 532 | 532 | if (B.length() == 0) continue; |
| 533 | 533 | } |
| 534 | 534 | } |
| 535 | ||
| 535 | ||
| 536 | 536 | if (lessThan(items[B.end - 1], items[A.start])) { |
| 537 | 537 | // the two ranges are in reverse order, so a simple rotation should fix it |
| 538 | 538 | mem.rotate(T, items[A.start..B.end], A.length()); |
| 539 | 539 | } else if (lessThan(items[A.end], items[A.end - 1])) { |
| 540 | 540 | // these two ranges weren't already in order, so we'll need to merge them! |
| 541 | 541 | var findA: usize = undefined; |
| 542 | ||
| 542 | ||
| 543 | 543 | // break the remainder of A into blocks. firstA is the uneven-sized first A block |
| 544 | 544 | var blockA = Range.init(A.start, A.end); |
| 545 | 545 | var firstA = Range.init(A.start, A.start + blockA.length() % block_size); |
| 546 | ||
| 546 | ||
| 547 | 547 | // swap the first value of each A block with the value in buffer1 |
| 548 | 548 | var indexA = buffer1.start; |
| 549 | 549 | index = firstA.end; |
| 550 | 550 | while (index < blockA.end) : ({indexA += 1; index += block_size;}) { |
| 551 | 551 | mem.swap(T, &items[indexA], &items[index]); |
| 552 | 552 | } |
| 553 | ||
| 553 | ||
| 554 | 554 | // start rolling the A blocks through the B blocks! |
| 555 | 555 | // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well |
| 556 | 556 | var lastA = firstA; |
| ... | ... | @@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 558 | 558 | var blockB = Range.init(B.start, B.start + math.min(block_size, B.length())); |
| 559 | 559 | blockA.start += firstA.length(); |
| 560 | 560 | indexA = buffer1.start; |
| 561 | ||
| 561 | ||
| 562 | 562 | // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it |
| 563 | 563 | // otherwise, if the second buffer is available, block swap the contents into that |
| 564 | 564 | if (lastA.length() <= cache.len) { |
| ... | ... | @@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 566 | 566 | } else if (buffer2.length() > 0) { |
| 567 | 567 | blockSwap(T, items, lastA.start, buffer2.start, lastA.length()); |
| 568 | 568 | } |
| 569 | ||
| 569 | ||
| 570 | 570 | if (blockA.length() > 0) { |
| 571 | 571 | while (true) { |
| 572 | 572 | // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, |
| ... | ... | @@ -575,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 575 | 575 | // figure out where to split the previous B block, and rotate it at the split |
| 576 | 576 | const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan); |
| 577 | 577 | const B_remaining = lastB.end - B_split; |
| 578 | ||
| 578 | ||
| 579 | 579 | // swap the minimum A block to the beginning of the rolling A blocks |
| 580 | 580 | var minA = blockA.start; |
| 581 | 581 | findA = minA + block_size; |
| ... | ... | @@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 585 | 585 | } |
| 586 | 586 | } |
| 587 | 587 | blockSwap(T, items, blockA.start, minA, block_size); |
| 588 | ||
| 588 | ||
| 589 | 589 | // swap the first item of the previous A block back with its original value, which is stored in buffer1 |
| 590 | 590 | mem.swap(T, &items[blockA.start], &items[indexA]); |
| 591 | 591 | indexA += 1; |
| 592 | ||
| 592 | ||
| 593 | 593 | // locally merge the previous A block with the B values that follow it |
| 594 | 594 | // if lastA fits into the external cache we'll use that (with MergeExternal), |
| 595 | 595 | // or if the second internal buffer exists we'll use that (with MergeInternal), |
| 596 | 596 | // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace) |
| 597 | ||
| 597 | ||
| 598 | 598 | if (lastA.length() <= cache.len) { |
| 599 | 599 | mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]); |
| 600 | 600 | } else if (buffer2.length() > 0) { |
| ... | ... | @@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 602 | 602 | } else { |
| 603 | 603 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan); |
| 604 | 604 | } |
| 605 | ||
| 605 | ||
| 606 | 606 | if (buffer2.length() > 0 or block_size <= cache.len) { |
| 607 | 607 | // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway |
| 608 | 608 | if (block_size <= cache.len) { |
| ... | ... | @@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 610 | 610 | } else { |
| 611 | 611 | blockSwap(T, items, blockA.start, buffer2.start, block_size); |
| 612 | 612 | } |
| 613 | ||
| 613 | ||
| 614 | 614 | // this is equivalent to rotating, but faster |
| 615 | 615 | // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it |
| 616 | 616 | // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs |
| ... | ... | @@ -619,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 619 | 619 | // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation |
| 620 | 620 | mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split); |
| 621 | 621 | } |
| 622 | ||
| 622 | ||
| 623 | 623 | // update the range for the remaining A blocks, and the range remaining from the B block after it was split |
| 624 | 624 | lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size); |
| 625 | 625 | lastB = Range.init(lastA.end, lastA.end + B_remaining); |
| 626 | ||
| 626 | ||
| 627 | 627 | // if there are no more A blocks remaining, this step is finished! |
| 628 | 628 | blockA.start += block_size; |
| 629 | 629 | if (blockA.length() == 0) |
| 630 | 630 | break; |
| 631 | ||
| 631 | ||
| 632 | 632 | } else if (blockB.length() < block_size) { |
| 633 | 633 | // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation |
| 634 | 634 | // the cache is disabled here since it might contain the contents of the previous A block |
| 635 | 635 | mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start); |
| 636 | ||
| 636 | ||
| 637 | 637 | lastB = Range.init(blockA.start, blockA.start + blockB.length()); |
| 638 | 638 | blockA.start += blockB.length(); |
| 639 | 639 | blockA.end += blockB.length(); |
| ... | ... | @@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 642 | 642 | // roll the leftmost A block to the end by swapping it with the next B block |
| 643 | 643 | blockSwap(T, items, blockA.start, blockB.start, block_size); |
| 644 | 644 | lastB = Range.init(blockA.start, blockA.start + block_size); |
| 645 | ||
| 645 | ||
| 646 | 646 | blockA.start += block_size; |
| 647 | 647 | blockA.end += block_size; |
| 648 | 648 | blockB.start += block_size; |
| 649 | ||
| 649 | ||
| 650 | 650 | if (blockB.end > B.end - block_size) { |
| 651 | 651 | blockB.end = B.end; |
| 652 | 652 | } else { |
| ... | ... | @@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 655 | 655 | } |
| 656 | 656 | } |
| 657 | 657 | } |
| 658 | ||
| 658 | ||
| 659 | 659 | // merge the last A block with the remaining B values |
| 660 | 660 | if (lastA.length() <= cache.len) { |
| 661 | 661 | mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]); |
| ... | ... | @@ -666,14 +666,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 666 | 666 | } |
| 667 | 667 | } |
| 668 | 668 | } |
| 669 | ||
| 669 | ||
| 670 | 670 | // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up |
| 671 | 671 | // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer |
| 672 | ||
| 672 | ||
| 673 | 673 | // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort, |
| 674 | 674 | // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here |
| 675 | 675 | insertionSort(T, items[buffer2.start..buffer2.end], lessThan); |
| 676 | ||
| 676 | ||
| 677 | 677 | pull_index = 0; |
| 678 | 678 | while (pull_index < 2) : (pull_index += 1) { |
| 679 | 679 | var unique = pull[pull_index].count * 2; |
| ... | ... | @@ -702,7 +702,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 702 | 702 | } |
| 703 | 703 | } |
| 704 | 704 | } |
| 705 | ||
| 705 | ||
| 706 | 706 | // double the size of each A and B subarray that will be merged in the next level |
| 707 | 707 | if (!iterator.nextLevel()) break; |
| 708 | 708 | } |
| ... | ... | @@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons |
| 711 | 711 | // merge operation without a buffer |
| 712 | 712 | fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void { |
| 713 | 713 | if (A_arg.length() == 0 or B_arg.length() == 0) return; |
| 714 | ||
| 714 | ||
| 715 | 715 | // this just repeatedly binary searches into B and rotates A into position. |
| 716 | 716 | // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here, |
| 717 | 717 | // but I decided to stick with this because it had better situational performance |
| 718 | // | |
| 718 | // | |
| 719 | 719 | // (Hwang and Lin is designed for merging subarrays of very different sizes, |
| 720 | 720 | // but WikiSort almost always uses subarrays that are roughly the same size) |
| 721 | // | |
| 721 | // | |
| 722 | 722 | // normally this is incredibly suboptimal, but this function is only called |
| 723 | 723 | // when none of the A or B blocks in any subarray contained 2√A unique values, |
| 724 | 724 | // which places a hard limit on the number of times this will ACTUALLY need |
| 725 | 725 | // to binary search and rotate. |
| 726 | // | |
| 726 | // | |
| 727 | 727 | // according to my analysis the worst case is √A rotations performed on √A items |
| 728 | 728 | // once the constant factors are removed, which ends up being O(n) |
| 729 | // | |
| 729 | // | |
| 730 | 730 | // again, this is NOT a general-purpose solution – it only works well in this case! |
| 731 | 731 | // kind of like how the O(n^2) insertion sort is used in some places |
| 732 | 732 | |
| 733 | 733 | var A = *A_arg; |
| 734 | 734 | var B = *B_arg; |
| 735 | ||
| 735 | ||
| 736 | 736 | while (true) { |
| 737 | 737 | // find the first place in B where the first item in A needs to be inserted |
| 738 | 738 | const mid = binaryFirst(T, items, items[A.start], B, lessThan); |
| 739 | ||
| 739 | ||
| 740 | 740 | // rotate A into place |
| 741 | 741 | const amount = mid - A.end; |
| 742 | 742 | mem.rotate(T, items[A.start..mid], A.length()); |
| 743 | 743 | if (B.end == mid) break; |
| 744 | ||
| 744 | ||
| 745 | 745 | // calculate the new A and B ranges |
| 746 | 746 | B.start = mid; |
| 747 | 747 | A = Range.init(A.start + amount, B.start); |
| ... | ... | @@ -757,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, |
| 757 | 757 | var A_count: usize = 0; |
| 758 | 758 | var B_count: usize = 0; |
| 759 | 759 | var insert: usize = 0; |
| 760 | ||
| 760 | ||
| 761 | 761 | if (B.length() > 0 and A.length() > 0) { |
| 762 | 762 | while (true) { |
| 763 | 763 | if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) { |
| ... | ... | @@ -773,7 +773,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, |
| 773 | 773 | } |
| 774 | 774 | } |
| 775 | 775 | } |
| 776 | ||
| 776 | ||
| 777 | 777 | // swap the remainder of A into the final array |
| 778 | 778 | blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count); |
| 779 | 779 | } |
| ... | ... | @@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s |
| 790 | 790 | fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize { |
| 791 | 791 | if (range.length() == 0) return range.start; |
| 792 | 792 | const skip = math.max(range.length()/unique, usize(1)); |
| 793 | ||
| 793 | ||
| 794 | 794 | var index = range.start + skip; |
| 795 | 795 | while (lessThan(items[index - 1], value)) : (index += skip) { |
| 796 | 796 | if (index >= range.end - skip) { |
| 797 | 797 | return binaryFirst(T, items, value, Range.init(index, range.end), lessThan); |
| 798 | 798 | } |
| 799 | 799 | } |
| 800 | ||
| 800 | ||
| 801 | 801 | return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan); |
| 802 | 802 | } |
| 803 | 803 | |
| 804 | 804 | fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize { |
| 805 | 805 | if (range.length() == 0) return range.start; |
| 806 | 806 | const skip = math.max(range.length()/unique, usize(1)); |
| 807 | ||
| 807 | ||
| 808 | 808 | var index = range.end - skip; |
| 809 | 809 | while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) { |
| 810 | 810 | if (index < range.start + skip) { |
| 811 | 811 | return binaryFirst(T, items, value, Range.init(range.start, index), lessThan); |
| 812 | 812 | } |
| 813 | 813 | } |
| 814 | ||
| 814 | ||
| 815 | 815 | return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan); |
| 816 | 816 | } |
| 817 | 817 | |
| 818 | 818 | fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize { |
| 819 | 819 | if (range.length() == 0) return range.start; |
| 820 | 820 | const skip = math.max(range.length()/unique, usize(1)); |
| 821 | ||
| 821 | ||
| 822 | 822 | var index = range.start + skip; |
| 823 | 823 | while (!lessThan(value, items[index - 1])) : (index += skip) { |
| 824 | 824 | if (index >= range.end - skip) { |
| 825 | 825 | return binaryLast(T, items, value, Range.init(index, range.end), lessThan); |
| 826 | 826 | } |
| 827 | 827 | } |
| 828 | ||
| 828 | ||
| 829 | 829 | return binaryLast(T, items, value, Range.init(index - skip, index), lessThan); |
| 830 | 830 | } |
| 831 | 831 | |
| 832 | 832 | fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize { |
| 833 | 833 | if (range.length() == 0) return range.start; |
| 834 | 834 | const skip = math.max(range.length()/unique, usize(1)); |
| 835 | ||
| 835 | ||
| 836 | 836 | var index = range.end - skip; |
| 837 | 837 | while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) { |
| 838 | 838 | if (index < range.start + skip) { |
| 839 | 839 | return binaryLast(T, items, value, Range.init(range.start, index), lessThan); |
| 840 | 840 | } |
| 841 | 841 | } |
| 842 | ||
| 842 | ||
| 843 | 843 | return binaryLast(T, items, value, Range.init(index, index + skip), lessThan); |
| 844 | 844 | } |
| 845 | 845 | |
| ... | ... | @@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less |
| 885 | 885 | const A_last = A.end; |
| 886 | 886 | const B_last = B.end; |
| 887 | 887 | var insert_index: usize = 0; |
| 888 | ||
| 888 | ||
| 889 | 889 | while (true) { |
| 890 | 890 | if (!lessThan(from[B_index], from[A_index])) { |
| 891 | 891 | into[insert_index] = from[A_index]; |
| ... | ... | @@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, |
| 916 | 916 | var insert_index: usize = A.start; |
| 917 | 917 | const A_last = A.length(); |
| 918 | 918 | const B_last = B.end; |
| 919 | ||
| 919 | ||
| 920 | 920 | if (B.length() > 0 and A.length() > 0) { |
| 921 | 921 | while (true) { |
| 922 | 922 | if (!lessThan(items[B_index], cache[A_index])) { |
| ... | ... | @@ -932,7 +932,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, |
| 932 | 932 | } |
| 933 | 933 | } |
| 934 | 934 | } |
| 935 | ||
| 935 | ||
| 936 | 936 | // copy the remainder of A into the final array |
| 937 | 937 | mem.copy(T, items[insert_index..], cache[A_index..A_last]); |
| 938 | 938 | } |
| ... | ... | @@ -1081,17 +1081,17 @@ test "another sort case" { |
| 1081 | 1081 | } |
| 1082 | 1082 | |
| 1083 | 1083 | test "sort fuzz testing" { |
| 1084 | var rng = std.rand.Rand.init(0x12345678); | |
| 1084 | var prng = std.rand.DefaultPrng.init(0x12345678); | |
| 1085 | 1085 | const test_case_count = 10; |
| 1086 | 1086 | var i: usize = 0; |
| 1087 | 1087 | while (i < test_case_count) : (i += 1) { |
| 1088 | fuzzTest(&rng); | |
| 1088 | fuzzTest(&prng.random); | |
| 1089 | 1089 | } |
| 1090 | 1090 | } |
| 1091 | 1091 | |
| 1092 | 1092 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; |
| 1093 | 1093 | |
| 1094 | fn fuzzTest(rng: &std.rand.Rand) void { | |
| 1094 | fn fuzzTest(rng: &std.rand.Random) void { | |
| 1095 | 1095 | const array_size = rng.range(usize, 0, 1000); |
| 1096 | 1096 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 1097 | 1097 | var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable; |
std/special/build_file_template.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | |
| 3 | pub fn build(b: &Builder) !void { | |
| 3 | pub fn build(b: &Builder) void { | |
| 4 | 4 | const mode = b.standardReleaseOptions(); |
| 5 | 5 | const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); |
| 6 | 6 | exe.setBuildMode(mode); |
std/special/builtin.zig+25-8| ... | ... | @@ -14,26 +14,43 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn |
| 14 | 14 | } |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | // Note that memset does not return `dest`, like the libc API. | |
| 18 | // The semantics of memset is dictated by the corresponding | |
| 19 | // LLVM intrinsics, not by the libc API. | |
| 20 | export fn memset(dest: ?&u8, c: u8, n: usize) void { | |
| 17 | export fn memset(dest: ?&u8, c: u8, n: usize) ?&u8 { | |
| 21 | 18 | @setRuntimeSafety(false); |
| 22 | 19 | |
| 23 | 20 | var index: usize = 0; |
| 24 | 21 | while (index != n) : (index += 1) |
| 25 | 22 | (??dest)[index] = c; |
| 23 | ||
| 24 | return dest; | |
| 26 | 25 | } |
| 27 | 26 | |
| 28 | // Note that memcpy does not return `dest`, like the libc API. | |
| 29 | // The semantics of memcpy is dictated by the corresponding | |
| 30 | // LLVM intrinsics, not by the libc API. | |
| 31 | export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) void { | |
| 27 | export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) ?&u8 { | |
| 32 | 28 | @setRuntimeSafety(false); |
| 33 | 29 | |
| 34 | 30 | var index: usize = 0; |
| 35 | 31 | while (index != n) : (index += 1) |
| 36 | 32 | (??dest)[index] = (??src)[index]; |
| 33 | ||
| 34 | return dest; | |
| 35 | } | |
| 36 | ||
| 37 | export fn memmove(dest: ?&u8, src: ?&const u8, n: usize) ?&u8 { | |
| 38 | @setRuntimeSafety(false); | |
| 39 | ||
| 40 | if (@ptrToInt(dest) < @ptrToInt(src)) { | |
| 41 | var index: usize = 0; | |
| 42 | while (index != n) : (index += 1) { | |
| 43 | (??dest)[index] = (??src)[index]; | |
| 44 | } | |
| 45 | } else { | |
| 46 | var index = n; | |
| 47 | while (index != 0) { | |
| 48 | index -= 1; | |
| 49 | (??dest)[index] = (??src)[index]; | |
| 50 | } | |
| 51 | } | |
| 52 | ||
| 53 | return dest; | |
| 37 | 54 | } |
| 38 | 55 | |
| 39 | 56 | comptime { |
std/zig/ast.zig+1470-100| ... | ... | @@ -11,34 +11,108 @@ pub const Node = struct { |
| 11 | 11 | pub const Id = enum { |
| 12 | 12 | Root, |
| 13 | 13 | VarDecl, |
| 14 | Use, | |
| 15 | ErrorSetDecl, | |
| 16 | ContainerDecl, | |
| 17 | StructField, | |
| 18 | UnionTag, | |
| 19 | EnumTag, | |
| 14 | 20 | Identifier, |
| 21 | AsyncAttribute, | |
| 15 | 22 | FnProto, |
| 16 | 23 | ParamDecl, |
| 17 | 24 | Block, |
| 25 | Defer, | |
| 26 | Comptime, | |
| 27 | Payload, | |
| 28 | PointerPayload, | |
| 29 | PointerIndexPayload, | |
| 30 | Else, | |
| 31 | Switch, | |
| 32 | SwitchCase, | |
| 33 | SwitchElse, | |
| 34 | While, | |
| 35 | For, | |
| 36 | If, | |
| 18 | 37 | InfixOp, |
| 19 | 38 | PrefixOp, |
| 39 | SuffixOp, | |
| 40 | GroupedExpression, | |
| 41 | ControlFlowExpression, | |
| 42 | Suspend, | |
| 43 | FieldInitializer, | |
| 20 | 44 | IntegerLiteral, |
| 21 | 45 | FloatLiteral, |
| 22 | 46 | StringLiteral, |
| 47 | MultilineStringLiteral, | |
| 48 | CharLiteral, | |
| 49 | BoolLiteral, | |
| 50 | NullLiteral, | |
| 51 | UndefinedLiteral, | |
| 52 | ThisLiteral, | |
| 53 | Asm, | |
| 54 | AsmInput, | |
| 55 | AsmOutput, | |
| 56 | Unreachable, | |
| 57 | ErrorType, | |
| 58 | VarType, | |
| 23 | 59 | BuiltinCall, |
| 24 | 60 | LineComment, |
| 61 | TestDecl, | |
| 25 | 62 | }; |
| 26 | 63 | |
| 27 | 64 | pub fn iterate(base: &Node, index: usize) ?&Node { |
| 28 | 65 | return switch (base.id) { |
| 29 | 66 | Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index), |
| 30 | 67 | Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index), |
| 68 | Id.Use => @fieldParentPtr(NodeUse, "base", base).iterate(index), | |
| 69 | Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).iterate(index), | |
| 70 | Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).iterate(index), | |
| 71 | Id.StructField => @fieldParentPtr(NodeStructField, "base", base).iterate(index), | |
| 72 | Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).iterate(index), | |
| 73 | Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).iterate(index), | |
| 31 | 74 | Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index), |
| 75 | Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).iterate(index), | |
| 32 | 76 | Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index), |
| 33 | 77 | Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index), |
| 34 | 78 | Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index), |
| 79 | Id.Defer => @fieldParentPtr(NodeDefer, "base", base).iterate(index), | |
| 80 | Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).iterate(index), | |
| 81 | Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index), | |
| 82 | Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).iterate(index), | |
| 83 | Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).iterate(index), | |
| 84 | Id.Else => @fieldParentPtr(NodeSwitch, "base", base).iterate(index), | |
| 85 | Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index), | |
| 86 | Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index), | |
| 87 | Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index), | |
| 88 | Id.While => @fieldParentPtr(NodeWhile, "base", base).iterate(index), | |
| 89 | Id.For => @fieldParentPtr(NodeFor, "base", base).iterate(index), | |
| 90 | Id.If => @fieldParentPtr(NodeIf, "base", base).iterate(index), | |
| 35 | 91 | Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index), |
| 36 | 92 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index), |
| 93 | Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index), | |
| 94 | Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).iterate(index), | |
| 95 | Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).iterate(index), | |
| 96 | Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).iterate(index), | |
| 97 | Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).iterate(index), | |
| 37 | 98 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index), |
| 38 | 99 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index), |
| 39 | 100 | Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index), |
| 101 | Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).iterate(index), | |
| 102 | Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).iterate(index), | |
| 103 | Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).iterate(index), | |
| 104 | Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).iterate(index), | |
| 105 | Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index), | |
| 106 | Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).iterate(index), | |
| 107 | Id.Asm => @fieldParentPtr(NodeAsm, "base", base).iterate(index), | |
| 108 | Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).iterate(index), | |
| 109 | Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).iterate(index), | |
| 110 | Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).iterate(index), | |
| 111 | Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index), | |
| 112 | Id.VarType => @fieldParentPtr(NodeVarType, "base", base).iterate(index), | |
| 40 | 113 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index), |
| 41 | 114 | Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index), |
| 115 | Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index), | |
| 42 | 116 | }; |
| 43 | 117 | } |
| 44 | 118 | |
| ... | ... | @@ -46,17 +120,54 @@ pub const Node = struct { |
| 46 | 120 | return switch (base.id) { |
| 47 | 121 | Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(), |
| 48 | 122 | Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(), |
| 123 | Id.Use => @fieldParentPtr(NodeUse, "base", base).firstToken(), | |
| 124 | Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).firstToken(), | |
| 125 | Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).firstToken(), | |
| 126 | Id.StructField => @fieldParentPtr(NodeStructField, "base", base).firstToken(), | |
| 127 | Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).firstToken(), | |
| 128 | Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).firstToken(), | |
| 49 | 129 | Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(), |
| 130 | Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).firstToken(), | |
| 50 | 131 | Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(), |
| 51 | 132 | Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(), |
| 52 | 133 | Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(), |
| 134 | Id.Defer => @fieldParentPtr(NodeDefer, "base", base).firstToken(), | |
| 135 | Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).firstToken(), | |
| 136 | Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(), | |
| 137 | Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).firstToken(), | |
| 138 | Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).firstToken(), | |
| 139 | Id.Else => @fieldParentPtr(NodeSwitch, "base", base).firstToken(), | |
| 140 | Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(), | |
| 141 | Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(), | |
| 142 | Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(), | |
| 143 | Id.While => @fieldParentPtr(NodeWhile, "base", base).firstToken(), | |
| 144 | Id.For => @fieldParentPtr(NodeFor, "base", base).firstToken(), | |
| 145 | Id.If => @fieldParentPtr(NodeIf, "base", base).firstToken(), | |
| 53 | 146 | Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(), |
| 54 | 147 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(), |
| 148 | Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(), | |
| 149 | Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).firstToken(), | |
| 150 | Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).firstToken(), | |
| 151 | Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).firstToken(), | |
| 152 | Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).firstToken(), | |
| 55 | 153 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(), |
| 56 | 154 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(), |
| 57 | 155 | Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(), |
| 156 | Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).firstToken(), | |
| 157 | Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).firstToken(), | |
| 158 | Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).firstToken(), | |
| 159 | Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).firstToken(), | |
| 160 | Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(), | |
| 161 | Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).firstToken(), | |
| 162 | Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).firstToken(), | |
| 163 | Id.Asm => @fieldParentPtr(NodeAsm, "base", base).firstToken(), | |
| 164 | Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).firstToken(), | |
| 165 | Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).firstToken(), | |
| 166 | Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(), | |
| 167 | Id.VarType => @fieldParentPtr(NodeVarType, "base", base).firstToken(), | |
| 58 | 168 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(), |
| 59 | 169 | Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(), |
| 170 | Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(), | |
| 60 | 171 | }; |
| 61 | 172 | } |
| 62 | 173 | |
| ... | ... | @@ -64,17 +175,54 @@ pub const Node = struct { |
| 64 | 175 | return switch (base.id) { |
| 65 | 176 | Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(), |
| 66 | 177 | Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(), |
| 178 | Id.Use => @fieldParentPtr(NodeUse, "base", base).lastToken(), | |
| 179 | Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).lastToken(), | |
| 180 | Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).lastToken(), | |
| 181 | Id.StructField => @fieldParentPtr(NodeStructField, "base", base).lastToken(), | |
| 182 | Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).lastToken(), | |
| 183 | Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).lastToken(), | |
| 67 | 184 | Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(), |
| 185 | Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).lastToken(), | |
| 68 | 186 | Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(), |
| 69 | 187 | Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(), |
| 70 | 188 | Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(), |
| 189 | Id.Defer => @fieldParentPtr(NodeDefer, "base", base).lastToken(), | |
| 190 | Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).lastToken(), | |
| 191 | Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(), | |
| 192 | Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).lastToken(), | |
| 193 | Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).lastToken(), | |
| 194 | Id.Else => @fieldParentPtr(NodeElse, "base", base).lastToken(), | |
| 195 | Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(), | |
| 196 | Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(), | |
| 197 | Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(), | |
| 198 | Id.While => @fieldParentPtr(NodeWhile, "base", base).lastToken(), | |
| 199 | Id.For => @fieldParentPtr(NodeFor, "base", base).lastToken(), | |
| 200 | Id.If => @fieldParentPtr(NodeIf, "base", base).lastToken(), | |
| 71 | 201 | Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(), |
| 72 | 202 | Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(), |
| 203 | Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(), | |
| 204 | Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).lastToken(), | |
| 205 | Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).lastToken(), | |
| 206 | Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).lastToken(), | |
| 207 | Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).lastToken(), | |
| 73 | 208 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(), |
| 74 | 209 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(), |
| 75 | 210 | Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(), |
| 211 | Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).lastToken(), | |
| 212 | Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).lastToken(), | |
| 213 | Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).lastToken(), | |
| 214 | Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).lastToken(), | |
| 215 | Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(), | |
| 216 | Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).lastToken(), | |
| 217 | Id.Asm => @fieldParentPtr(NodeAsm, "base", base).lastToken(), | |
| 218 | Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).lastToken(), | |
| 219 | Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).lastToken(), | |
| 220 | Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).lastToken(), | |
| 221 | Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(), | |
| 222 | Id.VarType => @fieldParentPtr(NodeVarType, "base", base).lastToken(), | |
| 76 | 223 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(), |
| 77 | 224 | Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(), |
| 225 | Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(), | |
| 78 | 226 | }; |
| 79 | 227 | } |
| 80 | 228 | }; |
| ... | ... | @@ -148,6 +296,190 @@ pub const NodeVarDecl = struct { |
| 148 | 296 | } |
| 149 | 297 | }; |
| 150 | 298 | |
| 299 | pub const NodeUse = struct { | |
| 300 | base: Node, | |
| 301 | visib_token: ?Token, | |
| 302 | expr: &Node, | |
| 303 | semicolon_token: Token, | |
| 304 | ||
| 305 | pub fn iterate(self: &NodeUse, index: usize) ?&Node { | |
| 306 | var i = index; | |
| 307 | ||
| 308 | if (i < 1) return self.expr; | |
| 309 | i -= 1; | |
| 310 | ||
| 311 | return null; | |
| 312 | } | |
| 313 | ||
| 314 | pub fn firstToken(self: &NodeUse) Token { | |
| 315 | if (self.visib_token) |visib_token| return visib_token; | |
| 316 | return self.expr.firstToken(); | |
| 317 | } | |
| 318 | ||
| 319 | pub fn lastToken(self: &NodeUse) Token { | |
| 320 | return self.semicolon_token; | |
| 321 | } | |
| 322 | }; | |
| 323 | ||
| 324 | pub const NodeErrorSetDecl = struct { | |
| 325 | base: Node, | |
| 326 | error_token: Token, | |
| 327 | decls: ArrayList(&NodeIdentifier), | |
| 328 | rbrace_token: Token, | |
| 329 | ||
| 330 | pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node { | |
| 331 | var i = index; | |
| 332 | ||
| 333 | if (i < self.decls.len) return &self.decls.at(i).base; | |
| 334 | i -= self.decls.len; | |
| 335 | ||
| 336 | return null; | |
| 337 | } | |
| 338 | ||
| 339 | pub fn firstToken(self: &NodeErrorSetDecl) Token { | |
| 340 | return self.error_token; | |
| 341 | } | |
| 342 | ||
| 343 | pub fn lastToken(self: &NodeErrorSetDecl) Token { | |
| 344 | return self.rbrace_token; | |
| 345 | } | |
| 346 | }; | |
| 347 | ||
| 348 | pub const NodeContainerDecl = struct { | |
| 349 | base: Node, | |
| 350 | ltoken: Token, | |
| 351 | layout: Layout, | |
| 352 | kind: Kind, | |
| 353 | init_arg_expr: InitArg, | |
| 354 | fields_and_decls: ArrayList(&Node), | |
| 355 | rbrace_token: Token, | |
| 356 | ||
| 357 | const Layout = enum { | |
| 358 | Auto, | |
| 359 | Extern, | |
| 360 | Packed, | |
| 361 | }; | |
| 362 | ||
| 363 | const Kind = enum { | |
| 364 | Struct, | |
| 365 | Enum, | |
| 366 | Union, | |
| 367 | }; | |
| 368 | ||
| 369 | const InitArg = union(enum) { | |
| 370 | None, | |
| 371 | Enum, | |
| 372 | Type: &Node, | |
| 373 | }; | |
| 374 | ||
| 375 | pub fn iterate(self: &NodeContainerDecl, index: usize) ?&Node { | |
| 376 | var i = index; | |
| 377 | ||
| 378 | switch (self.init_arg_expr) { | |
| 379 | InitArg.Type => |t| { | |
| 380 | if (i < 1) return t; | |
| 381 | i -= 1; | |
| 382 | }, | |
| 383 | InitArg.None, | |
| 384 | InitArg.Enum => { } | |
| 385 | } | |
| 386 | ||
| 387 | if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i); | |
| 388 | i -= self.fields_and_decls.len; | |
| 389 | ||
| 390 | return null; | |
| 391 | } | |
| 392 | ||
| 393 | pub fn firstToken(self: &NodeContainerDecl) Token { | |
| 394 | return self.ltoken; | |
| 395 | } | |
| 396 | ||
| 397 | pub fn lastToken(self: &NodeContainerDecl) Token { | |
| 398 | return self.rbrace_token; | |
| 399 | } | |
| 400 | }; | |
| 401 | ||
| 402 | pub const NodeStructField = struct { | |
| 403 | base: Node, | |
| 404 | name_token: Token, | |
| 405 | type_expr: &Node, | |
| 406 | ||
| 407 | pub fn iterate(self: &NodeStructField, index: usize) ?&Node { | |
| 408 | var i = index; | |
| 409 | ||
| 410 | if (i < 1) return self.type_expr; | |
| 411 | i -= 1; | |
| 412 | ||
| 413 | return null; | |
| 414 | } | |
| 415 | ||
| 416 | pub fn firstToken(self: &NodeStructField) Token { | |
| 417 | return self.name_token; | |
| 418 | } | |
| 419 | ||
| 420 | pub fn lastToken(self: &NodeStructField) Token { | |
| 421 | return self.type_expr.lastToken(); | |
| 422 | } | |
| 423 | }; | |
| 424 | ||
| 425 | pub const NodeUnionTag = struct { | |
| 426 | base: Node, | |
| 427 | name_token: Token, | |
| 428 | type_expr: ?&Node, | |
| 429 | ||
| 430 | pub fn iterate(self: &NodeUnionTag, index: usize) ?&Node { | |
| 431 | var i = index; | |
| 432 | ||
| 433 | if (self.type_expr) |type_expr| { | |
| 434 | if (i < 1) return type_expr; | |
| 435 | i -= 1; | |
| 436 | } | |
| 437 | ||
| 438 | return null; | |
| 439 | } | |
| 440 | ||
| 441 | pub fn firstToken(self: &NodeUnionTag) Token { | |
| 442 | return self.name_token; | |
| 443 | } | |
| 444 | ||
| 445 | pub fn lastToken(self: &NodeUnionTag) Token { | |
| 446 | if (self.type_expr) |type_expr| { | |
| 447 | return type_expr.lastToken(); | |
| 448 | } | |
| 449 | ||
| 450 | return self.name_token; | |
| 451 | } | |
| 452 | }; | |
| 453 | ||
| 454 | pub const NodeEnumTag = struct { | |
| 455 | base: Node, | |
| 456 | name_token: Token, | |
| 457 | value: ?&Node, | |
| 458 | ||
| 459 | pub fn iterate(self: &NodeEnumTag, index: usize) ?&Node { | |
| 460 | var i = index; | |
| 461 | ||
| 462 | if (self.value) |value| { | |
| 463 | if (i < 1) return value; | |
| 464 | i -= 1; | |
| 465 | } | |
| 466 | ||
| 467 | return null; | |
| 468 | } | |
| 469 | ||
| 470 | pub fn firstToken(self: &NodeEnumTag) Token { | |
| 471 | return self.name_token; | |
| 472 | } | |
| 473 | ||
| 474 | pub fn lastToken(self: &NodeEnumTag) Token { | |
| 475 | if (self.value) |value| { | |
| 476 | return value.lastToken(); | |
| 477 | } | |
| 478 | ||
| 479 | return self.name_token; | |
| 480 | } | |
| 481 | }; | |
| 482 | ||
| 151 | 483 | pub const NodeIdentifier = struct { |
| 152 | 484 | base: Node, |
| 153 | 485 | name_token: Token, |
| ... | ... | @@ -165,6 +497,36 @@ pub const NodeIdentifier = struct { |
| 165 | 497 | } |
| 166 | 498 | }; |
| 167 | 499 | |
| 500 | pub const NodeAsyncAttribute = struct { | |
| 501 | base: Node, | |
| 502 | async_token: Token, | |
| 503 | allocator_type: ?&Node, | |
| 504 | rangle_bracket: ?Token, | |
| 505 | ||
| 506 | pub fn iterate(self: &NodeAsyncAttribute, index: usize) ?&Node { | |
| 507 | var i = index; | |
| 508 | ||
| 509 | if (self.allocator_type) |allocator_type| { | |
| 510 | if (i < 1) return allocator_type; | |
| 511 | i -= 1; | |
| 512 | } | |
| 513 | ||
| 514 | return null; | |
| 515 | } | |
| 516 | ||
| 517 | pub fn firstToken(self: &NodeAsyncAttribute) Token { | |
| 518 | return self.async_token; | |
| 519 | } | |
| 520 | ||
| 521 | pub fn lastToken(self: &NodeAsyncAttribute) Token { | |
| 522 | if (self.rangle_bracket) |rangle_bracket| { | |
| 523 | return rangle_bracket; | |
| 524 | } | |
| 525 | ||
| 526 | return self.async_token; | |
| 527 | } | |
| 528 | }; | |
| 529 | ||
| 168 | 530 | pub const NodeFnProto = struct { |
| 169 | 531 | base: Node, |
| 170 | 532 | visib_token: ?Token, |
| ... | ... | @@ -176,13 +538,13 @@ pub const NodeFnProto = struct { |
| 176 | 538 | extern_token: ?Token, |
| 177 | 539 | inline_token: ?Token, |
| 178 | 540 | cc_token: ?Token, |
| 541 | async_attr: ?&NodeAsyncAttribute, | |
| 179 | 542 | body_node: ?&Node, |
| 180 | 543 | lib_name: ?&Node, // populated if this is an extern declaration |
| 181 | 544 | align_expr: ?&Node, // populated if align(A) is present |
| 182 | 545 | |
| 183 | 546 | pub const ReturnType = union(enum) { |
| 184 | 547 | Explicit: &Node, |
| 185 | Infer: Token, | |
| 186 | 548 | InferErrorSet: &Node, |
| 187 | 549 | }; |
| 188 | 550 | |
| ... | ... | @@ -204,7 +566,6 @@ pub const NodeFnProto = struct { |
| 204 | 566 | if (i < 1) return node; |
| 205 | 567 | i -= 1; |
| 206 | 568 | }, |
| 207 | ReturnType.Infer => {}, | |
| 208 | 569 | } |
| 209 | 570 | |
| 210 | 571 | if (self.align_expr) |align_expr| { |
| ... | ... | @@ -238,7 +599,6 @@ pub const NodeFnProto = struct { |
| 238 | 599 | // TODO allow this and next prong to share bodies since the types are the same |
| 239 | 600 | ReturnType.Explicit => |node| return node.lastToken(), |
| 240 | 601 | ReturnType.InferErrorSet => |node| return node.lastToken(), |
| 241 | ReturnType.Infer => |token| return token, | |
| 242 | 602 | } |
| 243 | 603 | } |
| 244 | 604 | }; |
| ... | ... | @@ -275,9 +635,10 @@ pub const NodeParamDecl = struct { |
| 275 | 635 | |
| 276 | 636 | pub const NodeBlock = struct { |
| 277 | 637 | base: Node, |
| 278 | begin_token: Token, | |
| 279 | end_token: Token, | |
| 638 | label: ?Token, | |
| 639 | lbrace: Token, | |
| 280 | 640 | statements: ArrayList(&Node), |
| 641 | rbrace: Token, | |
| 281 | 642 | |
| 282 | 643 | pub fn iterate(self: &NodeBlock, index: usize) ?&Node { |
| 283 | 644 | var i = index; |
| ... | ... | @@ -289,190 +650,1199 @@ pub const NodeBlock = struct { |
| 289 | 650 | } |
| 290 | 651 | |
| 291 | 652 | pub fn firstToken(self: &NodeBlock) Token { |
| 292 | return self.begin_token; | |
| 653 | if (self.label) |label| { | |
| 654 | return label; | |
| 655 | } | |
| 656 | ||
| 657 | return self.lbrace; | |
| 293 | 658 | } |
| 294 | 659 | |
| 295 | 660 | pub fn lastToken(self: &NodeBlock) Token { |
| 296 | return self.end_token; | |
| 661 | return self.rbrace; | |
| 297 | 662 | } |
| 298 | 663 | }; |
| 299 | 664 | |
| 300 | pub const NodeInfixOp = struct { | |
| 665 | pub const NodeDefer = struct { | |
| 301 | 666 | base: Node, |
| 302 | op_token: Token, | |
| 303 | lhs: &Node, | |
| 304 | op: InfixOp, | |
| 305 | rhs: &Node, | |
| 667 | defer_token: Token, | |
| 668 | kind: Kind, | |
| 669 | expr: &Node, | |
| 306 | 670 | |
| 307 | const InfixOp = enum { | |
| 308 | EqualEqual, | |
| 309 | BangEqual, | |
| 310 | Period, | |
| 671 | const Kind = enum { | |
| 672 | Error, | |
| 673 | Unconditional, | |
| 311 | 674 | }; |
| 312 | 675 | |
| 313 | pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node { | |
| 676 | pub fn iterate(self: &NodeDefer, index: usize) ?&Node { | |
| 314 | 677 | var i = index; |
| 315 | 678 | |
| 316 | if (i < 1) return self.lhs; | |
| 679 | if (i < 1) return self.expr; | |
| 317 | 680 | i -= 1; |
| 318 | 681 | |
| 319 | switch (self.op) { | |
| 320 | InfixOp.EqualEqual, | |
| 321 | InfixOp.BangEqual, | |
| 322 | InfixOp.Period => {}, | |
| 323 | } | |
| 682 | return null; | |
| 683 | } | |
| 324 | 684 | |
| 325 | if (i < 1) return self.rhs; | |
| 685 | pub fn firstToken(self: &NodeDefer) Token { | |
| 686 | return self.defer_token; | |
| 687 | } | |
| 688 | ||
| 689 | pub fn lastToken(self: &NodeDefer) Token { | |
| 690 | return self.expr.lastToken(); | |
| 691 | } | |
| 692 | }; | |
| 693 | ||
| 694 | pub const NodeComptime = struct { | |
| 695 | base: Node, | |
| 696 | comptime_token: Token, | |
| 697 | expr: &Node, | |
| 698 | ||
| 699 | pub fn iterate(self: &NodeComptime, index: usize) ?&Node { | |
| 700 | var i = index; | |
| 701 | ||
| 702 | if (i < 1) return self.expr; | |
| 326 | 703 | i -= 1; |
| 327 | 704 | |
| 328 | 705 | return null; |
| 329 | 706 | } |
| 330 | 707 | |
| 331 | pub fn firstToken(self: &NodeInfixOp) Token { | |
| 332 | return self.lhs.firstToken(); | |
| 708 | pub fn firstToken(self: &NodeComptime) Token { | |
| 709 | return self.comptime_token; | |
| 333 | 710 | } |
| 334 | 711 | |
| 335 | pub fn lastToken(self: &NodeInfixOp) Token { | |
| 336 | return self.rhs.lastToken(); | |
| 712 | pub fn lastToken(self: &NodeComptime) Token { | |
| 713 | return self.expr.lastToken(); | |
| 337 | 714 | } |
| 338 | 715 | }; |
| 339 | 716 | |
| 340 | pub const NodePrefixOp = struct { | |
| 717 | pub const NodePayload = struct { | |
| 341 | 718 | base: Node, |
| 342 | op_token: Token, | |
| 343 | op: PrefixOp, | |
| 344 | rhs: &Node, | |
| 345 | ||
| 346 | const PrefixOp = union(enum) { | |
| 347 | Return, | |
| 348 | Try, | |
| 349 | AddrOf: AddrOfInfo, | |
| 350 | }; | |
| 351 | const AddrOfInfo = struct { | |
| 352 | align_expr: ?&Node, | |
| 353 | bit_offset_start_token: ?Token, | |
| 354 | bit_offset_end_token: ?Token, | |
| 355 | const_token: ?Token, | |
| 356 | volatile_token: ?Token, | |
| 357 | }; | |
| 719 | lpipe: Token, | |
| 720 | error_symbol: &NodeIdentifier, | |
| 721 | rpipe: Token, | |
| 358 | 722 | |
| 359 | pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node { | |
| 723 | pub fn iterate(self: &NodePayload, index: usize) ?&Node { | |
| 360 | 724 | var i = index; |
| 361 | 725 | |
| 362 | switch (self.op) { | |
| 363 | PrefixOp.Return, | |
| 364 | PrefixOp.Try => {}, | |
| 365 | PrefixOp.AddrOf => |addr_of_info| { | |
| 366 | if (addr_of_info.align_expr) |align_expr| { | |
| 367 | if (i < 1) return align_expr; | |
| 368 | i -= 1; | |
| 369 | } | |
| 370 | }, | |
| 371 | } | |
| 372 | ||
| 373 | if (i < 1) return self.rhs; | |
| 726 | if (i < 1) return &self.error_symbol.base; | |
| 374 | 727 | i -= 1; |
| 375 | 728 | |
| 376 | 729 | return null; |
| 377 | 730 | } |
| 378 | 731 | |
| 379 | pub fn firstToken(self: &NodePrefixOp) Token { | |
| 380 | return self.op_token; | |
| 732 | pub fn firstToken(self: &NodePayload) Token { | |
| 733 | return self.lpipe; | |
| 381 | 734 | } |
| 382 | 735 | |
| 383 | pub fn lastToken(self: &NodePrefixOp) Token { | |
| 384 | return self.rhs.lastToken(); | |
| 736 | pub fn lastToken(self: &NodePayload) Token { | |
| 737 | return self.rpipe; | |
| 385 | 738 | } |
| 386 | 739 | }; |
| 387 | 740 | |
| 388 | pub const NodeIntegerLiteral = struct { | |
| 741 | pub const NodePointerPayload = struct { | |
| 389 | 742 | base: Node, |
| 390 | token: Token, | |
| 743 | lpipe: Token, | |
| 744 | is_ptr: bool, | |
| 745 | value_symbol: &NodeIdentifier, | |
| 746 | rpipe: Token, | |
| 747 | ||
| 748 | pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node { | |
| 749 | var i = index; | |
| 750 | ||
| 751 | if (i < 1) return &self.value_symbol.base; | |
| 752 | i -= 1; | |
| 391 | 753 | |
| 392 | pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node { | |
| 393 | 754 | return null; |
| 394 | 755 | } |
| 395 | 756 | |
| 396 | pub fn firstToken(self: &NodeIntegerLiteral) Token { | |
| 397 | return self.token; | |
| 757 | pub fn firstToken(self: &NodePointerPayload) Token { | |
| 758 | return self.lpipe; | |
| 398 | 759 | } |
| 399 | 760 | |
| 400 | pub fn lastToken(self: &NodeIntegerLiteral) Token { | |
| 401 | return self.token; | |
| 761 | pub fn lastToken(self: &NodePointerPayload) Token { | |
| 762 | return self.rpipe; | |
| 402 | 763 | } |
| 403 | 764 | }; |
| 404 | 765 | |
| 405 | pub const NodeFloatLiteral = struct { | |
| 766 | pub const NodePointerIndexPayload = struct { | |
| 406 | 767 | base: Node, |
| 407 | token: Token, | |
| 768 | lpipe: Token, | |
| 769 | is_ptr: bool, | |
| 770 | value_symbol: &NodeIdentifier, | |
| 771 | index_symbol: ?&NodeIdentifier, | |
| 772 | rpipe: Token, | |
| 773 | ||
| 774 | pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node { | |
| 775 | var i = index; | |
| 776 | ||
| 777 | if (i < 1) return &self.value_symbol.base; | |
| 778 | i -= 1; | |
| 779 | ||
| 780 | if (self.index_symbol) |index_symbol| { | |
| 781 | if (i < 1) return &index_symbol.base; | |
| 782 | i -= 1; | |
| 783 | } | |
| 408 | 784 | |
| 409 | pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node { | |
| 410 | 785 | return null; |
| 411 | 786 | } |
| 412 | 787 | |
| 413 | pub fn firstToken(self: &NodeFloatLiteral) Token { | |
| 414 | return self.token; | |
| 788 | pub fn firstToken(self: &NodePointerIndexPayload) Token { | |
| 789 | return self.lpipe; | |
| 415 | 790 | } |
| 416 | 791 | |
| 417 | pub fn lastToken(self: &NodeFloatLiteral) Token { | |
| 418 | return self.token; | |
| 792 | pub fn lastToken(self: &NodePointerIndexPayload) Token { | |
| 793 | return self.rpipe; | |
| 419 | 794 | } |
| 420 | 795 | }; |
| 421 | 796 | |
| 422 | pub const NodeBuiltinCall = struct { | |
| 797 | pub const NodeElse = struct { | |
| 423 | 798 | base: Node, |
| 424 | builtin_token: Token, | |
| 425 | params: ArrayList(&Node), | |
| 426 | rparen_token: Token, | |
| 799 | else_token: Token, | |
| 800 | payload: ?&NodePayload, | |
| 801 | body: &Node, | |
| 427 | 802 | |
| 428 | pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node { | |
| 803 | pub fn iterate(self: &NodeElse, index: usize) ?&Node { | |
| 429 | 804 | var i = index; |
| 430 | 805 | |
| 431 | if (i < self.params.len) return self.params.at(i); | |
| 432 | i -= self.params.len; | |
| 806 | if (self.payload) |payload| { | |
| 807 | if (i < 1) return &payload.base; | |
| 808 | i -= 1; | |
| 809 | } | |
| 810 | ||
| 811 | if (i < 1) return self.body; | |
| 812 | i -= 1; | |
| 433 | 813 | |
| 434 | 814 | return null; |
| 435 | 815 | } |
| 436 | 816 | |
| 437 | pub fn firstToken(self: &NodeBuiltinCall) Token { | |
| 438 | return self.builtin_token; | |
| 817 | pub fn firstToken(self: &NodeElse) Token { | |
| 818 | return self.else_token; | |
| 439 | 819 | } |
| 440 | 820 | |
| 441 | pub fn lastToken(self: &NodeBuiltinCall) Token { | |
| 442 | return self.rparen_token; | |
| 821 | pub fn lastToken(self: &NodeElse) Token { | |
| 822 | return self.body.lastToken(); | |
| 443 | 823 | } |
| 444 | 824 | }; |
| 445 | 825 | |
| 446 | pub const NodeStringLiteral = struct { | |
| 826 | pub const NodeSwitch = struct { | |
| 447 | 827 | base: Node, |
| 448 | token: Token, | |
| 828 | switch_token: Token, | |
| 829 | expr: &Node, | |
| 830 | cases: ArrayList(&NodeSwitchCase), | |
| 831 | rbrace: Token, | |
| 832 | ||
| 833 | pub fn iterate(self: &NodeSwitch, index: usize) ?&Node { | |
| 834 | var i = index; | |
| 835 | ||
| 836 | if (i < 1) return self.expr; | |
| 837 | i -= 1; | |
| 838 | ||
| 839 | if (i < self.cases.len) return &self.cases.at(i).base; | |
| 840 | i -= self.cases.len; | |
| 449 | 841 | |
| 450 | pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node { | |
| 451 | 842 | return null; |
| 452 | 843 | } |
| 453 | 844 | |
| 454 | pub fn firstToken(self: &NodeStringLiteral) Token { | |
| 455 | return self.token; | |
| 845 | pub fn firstToken(self: &NodeSwitch) Token { | |
| 846 | return self.switch_token; | |
| 456 | 847 | } |
| 457 | 848 | |
| 458 | pub fn lastToken(self: &NodeStringLiteral) Token { | |
| 459 | return self.token; | |
| 849 | pub fn lastToken(self: &NodeSwitch) Token { | |
| 850 | return self.rbrace; | |
| 460 | 851 | } |
| 461 | 852 | }; |
| 462 | 853 | |
| 463 | pub const NodeLineComment = struct { | |
| 854 | pub const NodeSwitchCase = struct { | |
| 464 | 855 | base: Node, |
| 465 | lines: ArrayList(Token), | |
| 856 | items: ArrayList(&Node), | |
| 857 | payload: ?&NodePointerPayload, | |
| 858 | expr: &Node, | |
| 859 | ||
| 860 | pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node { | |
| 861 | var i = index; | |
| 862 | ||
| 863 | if (i < self.items.len) return self.items.at(i); | |
| 864 | i -= self.items.len; | |
| 865 | ||
| 866 | if (self.payload) |payload| { | |
| 867 | if (i < 1) return &payload.base; | |
| 868 | i -= 1; | |
| 869 | } | |
| 870 | ||
| 871 | if (i < 1) return self.expr; | |
| 872 | i -= 1; | |
| 466 | 873 | |
| 467 | pub fn iterate(self: &NodeLineComment, index: usize) ?&Node { | |
| 468 | 874 | return null; |
| 469 | 875 | } |
| 470 | 876 | |
| 471 | pub fn firstToken(self: &NodeLineComment) Token { | |
| 472 | return self.lines.at(0); | |
| 877 | pub fn firstToken(self: &NodeSwitchCase) Token { | |
| 878 | return self.items.at(0).firstToken(); | |
| 473 | 879 | } |
| 474 | 880 | |
| 475 | pub fn lastToken(self: &NodeLineComment) Token { | |
| 881 | pub fn lastToken(self: &NodeSwitchCase) Token { | |
| 882 | return self.expr.lastToken(); | |
| 883 | } | |
| 884 | }; | |
| 885 | ||
| 886 | pub const NodeSwitchElse = struct { | |
| 887 | base: Node, | |
| 888 | token: Token, | |
| 889 | ||
| 890 | pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node { | |
| 891 | return null; | |
| 892 | } | |
| 893 | ||
| 894 | pub fn firstToken(self: &NodeSwitchElse) Token { | |
| 895 | return self.token; | |
| 896 | } | |
| 897 | ||
| 898 | pub fn lastToken(self: &NodeSwitchElse) Token { | |
| 899 | return self.token; | |
| 900 | } | |
| 901 | }; | |
| 902 | ||
| 903 | pub const NodeWhile = struct { | |
| 904 | base: Node, | |
| 905 | label: ?Token, | |
| 906 | inline_token: ?Token, | |
| 907 | while_token: Token, | |
| 908 | condition: &Node, | |
| 909 | payload: ?&NodePointerPayload, | |
| 910 | continue_expr: ?&Node, | |
| 911 | body: &Node, | |
| 912 | @"else": ?&NodeElse, | |
| 913 | ||
| 914 | pub fn iterate(self: &NodeWhile, index: usize) ?&Node { | |
| 915 | var i = index; | |
| 916 | ||
| 917 | if (i < 1) return self.condition; | |
| 918 | i -= 1; | |
| 919 | ||
| 920 | if (self.payload) |payload| { | |
| 921 | if (i < 1) return &payload.base; | |
| 922 | i -= 1; | |
| 923 | } | |
| 924 | ||
| 925 | if (self.continue_expr) |continue_expr| { | |
| 926 | if (i < 1) return continue_expr; | |
| 927 | i -= 1; | |
| 928 | } | |
| 929 | ||
| 930 | if (i < 1) return self.body; | |
| 931 | i -= 1; | |
| 932 | ||
| 933 | if (self.@"else") |@"else"| { | |
| 934 | if (i < 1) return &@"else".base; | |
| 935 | i -= 1; | |
| 936 | } | |
| 937 | ||
| 938 | return null; | |
| 939 | } | |
| 940 | ||
| 941 | pub fn firstToken(self: &NodeWhile) Token { | |
| 942 | if (self.label) |label| { | |
| 943 | return label; | |
| 944 | } | |
| 945 | ||
| 946 | if (self.inline_token) |inline_token| { | |
| 947 | return inline_token; | |
| 948 | } | |
| 949 | ||
| 950 | return self.while_token; | |
| 951 | } | |
| 952 | ||
| 953 | pub fn lastToken(self: &NodeWhile) Token { | |
| 954 | if (self.@"else") |@"else"| { | |
| 955 | return @"else".body.lastToken(); | |
| 956 | } | |
| 957 | ||
| 958 | return self.body.lastToken(); | |
| 959 | } | |
| 960 | }; | |
| 961 | ||
| 962 | pub const NodeFor = struct { | |
| 963 | base: Node, | |
| 964 | label: ?Token, | |
| 965 | inline_token: ?Token, | |
| 966 | for_token: Token, | |
| 967 | array_expr: &Node, | |
| 968 | payload: ?&NodePointerIndexPayload, | |
| 969 | body: &Node, | |
| 970 | @"else": ?&NodeElse, | |
| 971 | ||
| 972 | pub fn iterate(self: &NodeFor, index: usize) ?&Node { | |
| 973 | var i = index; | |
| 974 | ||
| 975 | if (i < 1) return self.array_expr; | |
| 976 | i -= 1; | |
| 977 | ||
| 978 | if (self.payload) |payload| { | |
| 979 | if (i < 1) return &payload.base; | |
| 980 | i -= 1; | |
| 981 | } | |
| 982 | ||
| 983 | if (i < 1) return self.body; | |
| 984 | i -= 1; | |
| 985 | ||
| 986 | if (self.@"else") |@"else"| { | |
| 987 | if (i < 1) return &@"else".base; | |
| 988 | i -= 1; | |
| 989 | } | |
| 990 | ||
| 991 | return null; | |
| 992 | } | |
| 993 | ||
| 994 | pub fn firstToken(self: &NodeFor) Token { | |
| 995 | if (self.label) |label| { | |
| 996 | return label; | |
| 997 | } | |
| 998 | ||
| 999 | if (self.inline_token) |inline_token| { | |
| 1000 | return inline_token; | |
| 1001 | } | |
| 1002 | ||
| 1003 | return self.for_token; | |
| 1004 | } | |
| 1005 | ||
| 1006 | pub fn lastToken(self: &NodeFor) Token { | |
| 1007 | if (self.@"else") |@"else"| { | |
| 1008 | return @"else".body.lastToken(); | |
| 1009 | } | |
| 1010 | ||
| 1011 | return self.body.lastToken(); | |
| 1012 | } | |
| 1013 | }; | |
| 1014 | ||
| 1015 | pub const NodeIf = struct { | |
| 1016 | base: Node, | |
| 1017 | if_token: Token, | |
| 1018 | condition: &Node, | |
| 1019 | payload: ?&NodePointerPayload, | |
| 1020 | body: &Node, | |
| 1021 | @"else": ?&NodeElse, | |
| 1022 | ||
| 1023 | pub fn iterate(self: &NodeIf, index: usize) ?&Node { | |
| 1024 | var i = index; | |
| 1025 | ||
| 1026 | if (i < 1) return self.condition; | |
| 1027 | i -= 1; | |
| 1028 | ||
| 1029 | if (self.payload) |payload| { | |
| 1030 | if (i < 1) return &payload.base; | |
| 1031 | i -= 1; | |
| 1032 | } | |
| 1033 | ||
| 1034 | if (i < 1) return self.body; | |
| 1035 | i -= 1; | |
| 1036 | ||
| 1037 | if (self.@"else") |@"else"| { | |
| 1038 | if (i < 1) return &@"else".base; | |
| 1039 | i -= 1; | |
| 1040 | } | |
| 1041 | ||
| 1042 | return null; | |
| 1043 | } | |
| 1044 | ||
| 1045 | pub fn firstToken(self: &NodeIf) Token { | |
| 1046 | return self.if_token; | |
| 1047 | } | |
| 1048 | ||
| 1049 | pub fn lastToken(self: &NodeIf) Token { | |
| 1050 | if (self.@"else") |@"else"| { | |
| 1051 | return @"else".body.lastToken(); | |
| 1052 | } | |
| 1053 | ||
| 1054 | return self.body.lastToken(); | |
| 1055 | } | |
| 1056 | }; | |
| 1057 | ||
| 1058 | pub const NodeInfixOp = struct { | |
| 1059 | base: Node, | |
| 1060 | op_token: Token, | |
| 1061 | lhs: &Node, | |
| 1062 | op: InfixOp, | |
| 1063 | rhs: &Node, | |
| 1064 | ||
| 1065 | const InfixOp = union(enum) { | |
| 1066 | Add, | |
| 1067 | AddWrap, | |
| 1068 | ArrayCat, | |
| 1069 | ArrayMult, | |
| 1070 | Assign, | |
| 1071 | AssignBitAnd, | |
| 1072 | AssignBitOr, | |
| 1073 | AssignBitShiftLeft, | |
| 1074 | AssignBitShiftRight, | |
| 1075 | AssignBitXor, | |
| 1076 | AssignDiv, | |
| 1077 | AssignMinus, | |
| 1078 | AssignMinusWrap, | |
| 1079 | AssignMod, | |
| 1080 | AssignPlus, | |
| 1081 | AssignPlusWrap, | |
| 1082 | AssignTimes, | |
| 1083 | AssignTimesWarp, | |
| 1084 | BangEqual, | |
| 1085 | BitAnd, | |
| 1086 | BitOr, | |
| 1087 | BitShiftLeft, | |
| 1088 | BitShiftRight, | |
| 1089 | BitXor, | |
| 1090 | BoolAnd, | |
| 1091 | BoolOr, | |
| 1092 | Catch: ?&NodePayload, | |
| 1093 | Div, | |
| 1094 | EqualEqual, | |
| 1095 | ErrorUnion, | |
| 1096 | GreaterOrEqual, | |
| 1097 | GreaterThan, | |
| 1098 | LessOrEqual, | |
| 1099 | LessThan, | |
| 1100 | MergeErrorSets, | |
| 1101 | Mod, | |
| 1102 | Mult, | |
| 1103 | MultWrap, | |
| 1104 | Period, | |
| 1105 | Range, | |
| 1106 | Sub, | |
| 1107 | SubWrap, | |
| 1108 | UnwrapMaybe, | |
| 1109 | }; | |
| 1110 | ||
| 1111 | pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node { | |
| 1112 | var i = index; | |
| 1113 | ||
| 1114 | if (i < 1) return self.lhs; | |
| 1115 | i -= 1; | |
| 1116 | ||
| 1117 | switch (self.op) { | |
| 1118 | InfixOp.Catch => |maybe_payload| { | |
| 1119 | if (maybe_payload) |payload| { | |
| 1120 | if (i < 1) return &payload.base; | |
| 1121 | i -= 1; | |
| 1122 | } | |
| 1123 | }, | |
| 1124 | ||
| 1125 | InfixOp.Add, | |
| 1126 | InfixOp.AddWrap, | |
| 1127 | InfixOp.ArrayCat, | |
| 1128 | InfixOp.ArrayMult, | |
| 1129 | InfixOp.Assign, | |
| 1130 | InfixOp.AssignBitAnd, | |
| 1131 | InfixOp.AssignBitOr, | |
| 1132 | InfixOp.AssignBitShiftLeft, | |
| 1133 | InfixOp.AssignBitShiftRight, | |
| 1134 | InfixOp.AssignBitXor, | |
| 1135 | InfixOp.AssignDiv, | |
| 1136 | InfixOp.AssignMinus, | |
| 1137 | InfixOp.AssignMinusWrap, | |
| 1138 | InfixOp.AssignMod, | |
| 1139 | InfixOp.AssignPlus, | |
| 1140 | InfixOp.AssignPlusWrap, | |
| 1141 | InfixOp.AssignTimes, | |
| 1142 | InfixOp.AssignTimesWarp, | |
| 1143 | InfixOp.BangEqual, | |
| 1144 | InfixOp.BitAnd, | |
| 1145 | InfixOp.BitOr, | |
| 1146 | InfixOp.BitShiftLeft, | |
| 1147 | InfixOp.BitShiftRight, | |
| 1148 | InfixOp.BitXor, | |
| 1149 | InfixOp.BoolAnd, | |
| 1150 | InfixOp.BoolOr, | |
| 1151 | InfixOp.Div, | |
| 1152 | InfixOp.EqualEqual, | |
| 1153 | InfixOp.ErrorUnion, | |
| 1154 | InfixOp.GreaterOrEqual, | |
| 1155 | InfixOp.GreaterThan, | |
| 1156 | InfixOp.LessOrEqual, | |
| 1157 | InfixOp.LessThan, | |
| 1158 | InfixOp.MergeErrorSets, | |
| 1159 | InfixOp.Mod, | |
| 1160 | InfixOp.Mult, | |
| 1161 | InfixOp.MultWrap, | |
| 1162 | InfixOp.Period, | |
| 1163 | InfixOp.Range, | |
| 1164 | InfixOp.Sub, | |
| 1165 | InfixOp.SubWrap, | |
| 1166 | InfixOp.UnwrapMaybe => {}, | |
| 1167 | } | |
| 1168 | ||
| 1169 | if (i < 1) return self.rhs; | |
| 1170 | i -= 1; | |
| 1171 | ||
| 1172 | return null; | |
| 1173 | } | |
| 1174 | ||
| 1175 | pub fn firstToken(self: &NodeInfixOp) Token { | |
| 1176 | return self.lhs.firstToken(); | |
| 1177 | } | |
| 1178 | ||
| 1179 | pub fn lastToken(self: &NodeInfixOp) Token { | |
| 1180 | return self.rhs.lastToken(); | |
| 1181 | } | |
| 1182 | }; | |
| 1183 | ||
| 1184 | pub const NodePrefixOp = struct { | |
| 1185 | base: Node, | |
| 1186 | op_token: Token, | |
| 1187 | op: PrefixOp, | |
| 1188 | rhs: &Node, | |
| 1189 | ||
| 1190 | const PrefixOp = union(enum) { | |
| 1191 | AddrOf: AddrOfInfo, | |
| 1192 | ArrayType: &Node, | |
| 1193 | Await, | |
| 1194 | BitNot, | |
| 1195 | BoolNot, | |
| 1196 | Cancel, | |
| 1197 | Deref, | |
| 1198 | MaybeType, | |
| 1199 | Negation, | |
| 1200 | NegationWrap, | |
| 1201 | Resume, | |
| 1202 | SliceType: AddrOfInfo, | |
| 1203 | Try, | |
| 1204 | UnwrapMaybe, | |
| 1205 | }; | |
| 1206 | ||
| 1207 | const AddrOfInfo = struct { | |
| 1208 | align_expr: ?&Node, | |
| 1209 | bit_offset_start_token: ?Token, | |
| 1210 | bit_offset_end_token: ?Token, | |
| 1211 | const_token: ?Token, | |
| 1212 | volatile_token: ?Token, | |
| 1213 | }; | |
| 1214 | ||
| 1215 | pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node { | |
| 1216 | var i = index; | |
| 1217 | ||
| 1218 | switch (self.op) { | |
| 1219 | PrefixOp.SliceType => |addr_of_info| { | |
| 1220 | if (addr_of_info.align_expr) |align_expr| { | |
| 1221 | if (i < 1) return align_expr; | |
| 1222 | i -= 1; | |
| 1223 | } | |
| 1224 | }, | |
| 1225 | PrefixOp.AddrOf => |addr_of_info| { | |
| 1226 | if (addr_of_info.align_expr) |align_expr| { | |
| 1227 | if (i < 1) return align_expr; | |
| 1228 | i -= 1; | |
| 1229 | } | |
| 1230 | }, | |
| 1231 | PrefixOp.ArrayType => |size_expr| { | |
| 1232 | if (i < 1) return size_expr; | |
| 1233 | i -= 1; | |
| 1234 | }, | |
| 1235 | PrefixOp.Await, | |
| 1236 | PrefixOp.BitNot, | |
| 1237 | PrefixOp.BoolNot, | |
| 1238 | PrefixOp.Cancel, | |
| 1239 | PrefixOp.Deref, | |
| 1240 | PrefixOp.MaybeType, | |
| 1241 | PrefixOp.Negation, | |
| 1242 | PrefixOp.NegationWrap, | |
| 1243 | PrefixOp.Try, | |
| 1244 | PrefixOp.Resume, | |
| 1245 | PrefixOp.UnwrapMaybe => {}, | |
| 1246 | } | |
| 1247 | ||
| 1248 | if (i < 1) return self.rhs; | |
| 1249 | i -= 1; | |
| 1250 | ||
| 1251 | return null; | |
| 1252 | } | |
| 1253 | ||
| 1254 | pub fn firstToken(self: &NodePrefixOp) Token { | |
| 1255 | return self.op_token; | |
| 1256 | } | |
| 1257 | ||
| 1258 | pub fn lastToken(self: &NodePrefixOp) Token { | |
| 1259 | return self.rhs.lastToken(); | |
| 1260 | } | |
| 1261 | }; | |
| 1262 | ||
| 1263 | pub const NodeFieldInitializer = struct { | |
| 1264 | base: Node, | |
| 1265 | period_token: Token, | |
| 1266 | name_token: Token, | |
| 1267 | expr: &Node, | |
| 1268 | ||
| 1269 | pub fn iterate(self: &NodeFieldInitializer, index: usize) ?&Node { | |
| 1270 | var i = index; | |
| 1271 | ||
| 1272 | if (i < 1) return self.expr; | |
| 1273 | i -= 1; | |
| 1274 | ||
| 1275 | return null; | |
| 1276 | } | |
| 1277 | ||
| 1278 | pub fn firstToken(self: &NodeFieldInitializer) Token { | |
| 1279 | return self.period_token; | |
| 1280 | } | |
| 1281 | ||
| 1282 | pub fn lastToken(self: &NodeFieldInitializer) Token { | |
| 1283 | return self.expr.lastToken(); | |
| 1284 | } | |
| 1285 | }; | |
| 1286 | ||
| 1287 | pub const NodeSuffixOp = struct { | |
| 1288 | base: Node, | |
| 1289 | lhs: &Node, | |
| 1290 | op: SuffixOp, | |
| 1291 | rtoken: Token, | |
| 1292 | ||
| 1293 | const SuffixOp = union(enum) { | |
| 1294 | Call: CallInfo, | |
| 1295 | ArrayAccess: &Node, | |
| 1296 | Slice: SliceRange, | |
| 1297 | ArrayInitializer: ArrayList(&Node), | |
| 1298 | StructInitializer: ArrayList(&NodeFieldInitializer), | |
| 1299 | }; | |
| 1300 | ||
| 1301 | const CallInfo = struct { | |
| 1302 | params: ArrayList(&Node), | |
| 1303 | async_attr: ?&NodeAsyncAttribute, | |
| 1304 | }; | |
| 1305 | ||
| 1306 | const SliceRange = struct { | |
| 1307 | start: &Node, | |
| 1308 | end: ?&Node, | |
| 1309 | }; | |
| 1310 | ||
| 1311 | pub fn iterate(self: &NodeSuffixOp, index: usize) ?&Node { | |
| 1312 | var i = index; | |
| 1313 | ||
| 1314 | if (i < 1) return self.lhs; | |
| 1315 | i -= 1; | |
| 1316 | ||
| 1317 | switch (self.op) { | |
| 1318 | SuffixOp.Call => |call_info| { | |
| 1319 | if (i < call_info.params.len) return call_info.params.at(i); | |
| 1320 | i -= call_info.params.len; | |
| 1321 | }, | |
| 1322 | SuffixOp.ArrayAccess => |index_expr| { | |
| 1323 | if (i < 1) return index_expr; | |
| 1324 | i -= 1; | |
| 1325 | }, | |
| 1326 | SuffixOp.Slice => |range| { | |
| 1327 | if (i < 1) return range.start; | |
| 1328 | i -= 1; | |
| 1329 | ||
| 1330 | if (range.end) |end| { | |
| 1331 | if (i < 1) return end; | |
| 1332 | i -= 1; | |
| 1333 | } | |
| 1334 | }, | |
| 1335 | SuffixOp.ArrayInitializer => |exprs| { | |
| 1336 | if (i < exprs.len) return exprs.at(i); | |
| 1337 | i -= exprs.len; | |
| 1338 | }, | |
| 1339 | SuffixOp.StructInitializer => |fields| { | |
| 1340 | if (i < fields.len) return &fields.at(i).base; | |
| 1341 | i -= fields.len; | |
| 1342 | }, | |
| 1343 | } | |
| 1344 | ||
| 1345 | return null; | |
| 1346 | } | |
| 1347 | ||
| 1348 | pub fn firstToken(self: &NodeSuffixOp) Token { | |
| 1349 | return self.lhs.firstToken(); | |
| 1350 | } | |
| 1351 | ||
| 1352 | pub fn lastToken(self: &NodeSuffixOp) Token { | |
| 1353 | return self.rtoken; | |
| 1354 | } | |
| 1355 | }; | |
| 1356 | ||
| 1357 | pub const NodeGroupedExpression = struct { | |
| 1358 | base: Node, | |
| 1359 | lparen: Token, | |
| 1360 | expr: &Node, | |
| 1361 | rparen: Token, | |
| 1362 | ||
| 1363 | pub fn iterate(self: &NodeGroupedExpression, index: usize) ?&Node { | |
| 1364 | var i = index; | |
| 1365 | ||
| 1366 | if (i < 1) return self.expr; | |
| 1367 | i -= 1; | |
| 1368 | ||
| 1369 | return null; | |
| 1370 | } | |
| 1371 | ||
| 1372 | pub fn firstToken(self: &NodeGroupedExpression) Token { | |
| 1373 | return self.lparen; | |
| 1374 | } | |
| 1375 | ||
| 1376 | pub fn lastToken(self: &NodeGroupedExpression) Token { | |
| 1377 | return self.rparen; | |
| 1378 | } | |
| 1379 | }; | |
| 1380 | ||
| 1381 | pub const NodeControlFlowExpression = struct { | |
| 1382 | base: Node, | |
| 1383 | ltoken: Token, | |
| 1384 | kind: Kind, | |
| 1385 | rhs: ?&Node, | |
| 1386 | ||
| 1387 | const Kind = union(enum) { | |
| 1388 | Break: ?Token, | |
| 1389 | Continue: ?Token, | |
| 1390 | Return, | |
| 1391 | }; | |
| 1392 | ||
| 1393 | pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node { | |
| 1394 | var i = index; | |
| 1395 | ||
| 1396 | if (self.rhs) |rhs| { | |
| 1397 | if (i < 1) return rhs; | |
| 1398 | i -= 1; | |
| 1399 | } | |
| 1400 | ||
| 1401 | return null; | |
| 1402 | } | |
| 1403 | ||
| 1404 | pub fn firstToken(self: &NodeControlFlowExpression) Token { | |
| 1405 | return self.ltoken; | |
| 1406 | } | |
| 1407 | ||
| 1408 | pub fn lastToken(self: &NodeControlFlowExpression) Token { | |
| 1409 | if (self.rhs) |rhs| { | |
| 1410 | return rhs.lastToken(); | |
| 1411 | } | |
| 1412 | ||
| 1413 | switch (self.kind) { | |
| 1414 | Kind.Break => |maybe_blk_token| { | |
| 1415 | if (maybe_blk_token) |blk_token| { | |
| 1416 | return blk_token; | |
| 1417 | } | |
| 1418 | }, | |
| 1419 | Kind.Continue => |maybe_blk_token| { | |
| 1420 | if (maybe_blk_token) |blk_token| { | |
| 1421 | return blk_token; | |
| 1422 | } | |
| 1423 | }, | |
| 1424 | Kind.Return => return self.ltoken, | |
| 1425 | } | |
| 1426 | ||
| 1427 | return self.ltoken; | |
| 1428 | } | |
| 1429 | }; | |
| 1430 | ||
| 1431 | pub const NodeSuspend = struct { | |
| 1432 | base: Node, | |
| 1433 | suspend_token: Token, | |
| 1434 | payload: ?&NodePayload, | |
| 1435 | body: ?&Node, | |
| 1436 | ||
| 1437 | pub fn iterate(self: &NodeSuspend, index: usize) ?&Node { | |
| 1438 | var i = index; | |
| 1439 | ||
| 1440 | if (self.payload) |payload| { | |
| 1441 | if (i < 1) return &payload.base; | |
| 1442 | i -= 1; | |
| 1443 | } | |
| 1444 | ||
| 1445 | if (self.body) |body| { | |
| 1446 | if (i < 1) return body; | |
| 1447 | i -= 1; | |
| 1448 | } | |
| 1449 | ||
| 1450 | return null; | |
| 1451 | } | |
| 1452 | ||
| 1453 | pub fn firstToken(self: &NodeSuspend) Token { | |
| 1454 | return self.suspend_token; | |
| 1455 | } | |
| 1456 | ||
| 1457 | pub fn lastToken(self: &NodeSuspend) Token { | |
| 1458 | if (self.body) |body| { | |
| 1459 | return body.lastToken(); | |
| 1460 | } | |
| 1461 | ||
| 1462 | if (self.payload) |payload| { | |
| 1463 | return payload.lastToken(); | |
| 1464 | } | |
| 1465 | ||
| 1466 | return self.suspend_token; | |
| 1467 | } | |
| 1468 | }; | |
| 1469 | ||
| 1470 | pub const NodeIntegerLiteral = struct { | |
| 1471 | base: Node, | |
| 1472 | token: Token, | |
| 1473 | ||
| 1474 | pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node { | |
| 1475 | return null; | |
| 1476 | } | |
| 1477 | ||
| 1478 | pub fn firstToken(self: &NodeIntegerLiteral) Token { | |
| 1479 | return self.token; | |
| 1480 | } | |
| 1481 | ||
| 1482 | pub fn lastToken(self: &NodeIntegerLiteral) Token { | |
| 1483 | return self.token; | |
| 1484 | } | |
| 1485 | }; | |
| 1486 | ||
| 1487 | pub const NodeFloatLiteral = struct { | |
| 1488 | base: Node, | |
| 1489 | token: Token, | |
| 1490 | ||
| 1491 | pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node { | |
| 1492 | return null; | |
| 1493 | } | |
| 1494 | ||
| 1495 | pub fn firstToken(self: &NodeFloatLiteral) Token { | |
| 1496 | return self.token; | |
| 1497 | } | |
| 1498 | ||
| 1499 | pub fn lastToken(self: &NodeFloatLiteral) Token { | |
| 1500 | return self.token; | |
| 1501 | } | |
| 1502 | }; | |
| 1503 | ||
| 1504 | pub const NodeBuiltinCall = struct { | |
| 1505 | base: Node, | |
| 1506 | builtin_token: Token, | |
| 1507 | params: ArrayList(&Node), | |
| 1508 | rparen_token: Token, | |
| 1509 | ||
| 1510 | pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node { | |
| 1511 | var i = index; | |
| 1512 | ||
| 1513 | if (i < self.params.len) return self.params.at(i); | |
| 1514 | i -= self.params.len; | |
| 1515 | ||
| 1516 | return null; | |
| 1517 | } | |
| 1518 | ||
| 1519 | pub fn firstToken(self: &NodeBuiltinCall) Token { | |
| 1520 | return self.builtin_token; | |
| 1521 | } | |
| 1522 | ||
| 1523 | pub fn lastToken(self: &NodeBuiltinCall) Token { | |
| 1524 | return self.rparen_token; | |
| 1525 | } | |
| 1526 | }; | |
| 1527 | ||
| 1528 | pub const NodeStringLiteral = struct { | |
| 1529 | base: Node, | |
| 1530 | token: Token, | |
| 1531 | ||
| 1532 | pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node { | |
| 1533 | return null; | |
| 1534 | } | |
| 1535 | ||
| 1536 | pub fn firstToken(self: &NodeStringLiteral) Token { | |
| 1537 | return self.token; | |
| 1538 | } | |
| 1539 | ||
| 1540 | pub fn lastToken(self: &NodeStringLiteral) Token { | |
| 1541 | return self.token; | |
| 1542 | } | |
| 1543 | }; | |
| 1544 | ||
| 1545 | pub const NodeMultilineStringLiteral = struct { | |
| 1546 | base: Node, | |
| 1547 | tokens: ArrayList(Token), | |
| 1548 | ||
| 1549 | pub fn iterate(self: &NodeMultilineStringLiteral, index: usize) ?&Node { | |
| 1550 | return null; | |
| 1551 | } | |
| 1552 | ||
| 1553 | pub fn firstToken(self: &NodeMultilineStringLiteral) Token { | |
| 1554 | return self.tokens.at(0); | |
| 1555 | } | |
| 1556 | ||
| 1557 | pub fn lastToken(self: &NodeMultilineStringLiteral) Token { | |
| 1558 | return self.tokens.at(self.tokens.len - 1); | |
| 1559 | } | |
| 1560 | }; | |
| 1561 | ||
| 1562 | pub const NodeCharLiteral = struct { | |
| 1563 | base: Node, | |
| 1564 | token: Token, | |
| 1565 | ||
| 1566 | pub fn iterate(self: &NodeCharLiteral, index: usize) ?&Node { | |
| 1567 | return null; | |
| 1568 | } | |
| 1569 | ||
| 1570 | pub fn firstToken(self: &NodeCharLiteral) Token { | |
| 1571 | return self.token; | |
| 1572 | } | |
| 1573 | ||
| 1574 | pub fn lastToken(self: &NodeCharLiteral) Token { | |
| 1575 | return self.token; | |
| 1576 | } | |
| 1577 | }; | |
| 1578 | ||
| 1579 | pub const NodeBoolLiteral = struct { | |
| 1580 | base: Node, | |
| 1581 | token: Token, | |
| 1582 | ||
| 1583 | pub fn iterate(self: &NodeBoolLiteral, index: usize) ?&Node { | |
| 1584 | return null; | |
| 1585 | } | |
| 1586 | ||
| 1587 | pub fn firstToken(self: &NodeBoolLiteral) Token { | |
| 1588 | return self.token; | |
| 1589 | } | |
| 1590 | ||
| 1591 | pub fn lastToken(self: &NodeBoolLiteral) Token { | |
| 1592 | return self.token; | |
| 1593 | } | |
| 1594 | }; | |
| 1595 | ||
| 1596 | pub const NodeNullLiteral = struct { | |
| 1597 | base: Node, | |
| 1598 | token: Token, | |
| 1599 | ||
| 1600 | pub fn iterate(self: &NodeNullLiteral, index: usize) ?&Node { | |
| 1601 | return null; | |
| 1602 | } | |
| 1603 | ||
| 1604 | pub fn firstToken(self: &NodeNullLiteral) Token { | |
| 1605 | return self.token; | |
| 1606 | } | |
| 1607 | ||
| 1608 | pub fn lastToken(self: &NodeNullLiteral) Token { | |
| 1609 | return self.token; | |
| 1610 | } | |
| 1611 | }; | |
| 1612 | ||
| 1613 | pub const NodeUndefinedLiteral = struct { | |
| 1614 | base: Node, | |
| 1615 | token: Token, | |
| 1616 | ||
| 1617 | pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node { | |
| 1618 | return null; | |
| 1619 | } | |
| 1620 | ||
| 1621 | pub fn firstToken(self: &NodeUndefinedLiteral) Token { | |
| 1622 | return self.token; | |
| 1623 | } | |
| 1624 | ||
| 1625 | pub fn lastToken(self: &NodeUndefinedLiteral) Token { | |
| 1626 | return self.token; | |
| 1627 | } | |
| 1628 | }; | |
| 1629 | ||
| 1630 | pub const NodeThisLiteral = struct { | |
| 1631 | base: Node, | |
| 1632 | token: Token, | |
| 1633 | ||
| 1634 | pub fn iterate(self: &NodeThisLiteral, index: usize) ?&Node { | |
| 1635 | return null; | |
| 1636 | } | |
| 1637 | ||
| 1638 | pub fn firstToken(self: &NodeThisLiteral) Token { | |
| 1639 | return self.token; | |
| 1640 | } | |
| 1641 | ||
| 1642 | pub fn lastToken(self: &NodeThisLiteral) Token { | |
| 1643 | return self.token; | |
| 1644 | } | |
| 1645 | }; | |
| 1646 | ||
| 1647 | pub const NodeAsmOutput = struct { | |
| 1648 | base: Node, | |
| 1649 | symbolic_name: &NodeIdentifier, | |
| 1650 | constraint: &NodeStringLiteral, | |
| 1651 | kind: Kind, | |
| 1652 | ||
| 1653 | const Kind = union(enum) { | |
| 1654 | Variable: &NodeIdentifier, | |
| 1655 | Return: &Node | |
| 1656 | }; | |
| 1657 | ||
| 1658 | pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node { | |
| 1659 | var i = index; | |
| 1660 | ||
| 1661 | if (i < 1) return &self.symbolic_name.base; | |
| 1662 | i -= 1; | |
| 1663 | ||
| 1664 | if (i < 1) return &self.constraint.base; | |
| 1665 | i -= 1; | |
| 1666 | ||
| 1667 | switch (self.kind) { | |
| 1668 | Kind.Variable => |variable_name| { | |
| 1669 | if (i < 1) return &variable_name.base; | |
| 1670 | i -= 1; | |
| 1671 | }, | |
| 1672 | Kind.Return => |return_type| { | |
| 1673 | if (i < 1) return return_type; | |
| 1674 | i -= 1; | |
| 1675 | } | |
| 1676 | } | |
| 1677 | ||
| 1678 | return null; | |
| 1679 | } | |
| 1680 | ||
| 1681 | pub fn firstToken(self: &NodeAsmOutput) Token { | |
| 1682 | return self.symbolic_name.firstToken(); | |
| 1683 | } | |
| 1684 | ||
| 1685 | pub fn lastToken(self: &NodeAsmOutput) Token { | |
| 1686 | return switch (self.kind) { | |
| 1687 | Kind.Variable => |variable_name| variable_name.lastToken(), | |
| 1688 | Kind.Return => |return_type| return_type.lastToken(), | |
| 1689 | }; | |
| 1690 | } | |
| 1691 | }; | |
| 1692 | ||
| 1693 | pub const NodeAsmInput = struct { | |
| 1694 | base: Node, | |
| 1695 | symbolic_name: &NodeIdentifier, | |
| 1696 | constraint: &NodeStringLiteral, | |
| 1697 | expr: &Node, | |
| 1698 | ||
| 1699 | pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node { | |
| 1700 | var i = index; | |
| 1701 | ||
| 1702 | if (i < 1) return &self.symbolic_name.base; | |
| 1703 | i -= 1; | |
| 1704 | ||
| 1705 | if (i < 1) return &self.constraint.base; | |
| 1706 | i -= 1; | |
| 1707 | ||
| 1708 | if (i < 1) return self.expr; | |
| 1709 | i -= 1; | |
| 1710 | ||
| 1711 | return null; | |
| 1712 | } | |
| 1713 | ||
| 1714 | pub fn firstToken(self: &NodeAsmInput) Token { | |
| 1715 | return self.symbolic_name.firstToken(); | |
| 1716 | } | |
| 1717 | ||
| 1718 | pub fn lastToken(self: &NodeAsmInput) Token { | |
| 1719 | return self.expr.lastToken(); | |
| 1720 | } | |
| 1721 | }; | |
| 1722 | ||
| 1723 | pub const NodeAsm = struct { | |
| 1724 | base: Node, | |
| 1725 | asm_token: Token, | |
| 1726 | is_volatile: bool, | |
| 1727 | template: Token, | |
| 1728 | //tokens: ArrayList(AsmToken), | |
| 1729 | outputs: ArrayList(&NodeAsmOutput), | |
| 1730 | inputs: ArrayList(&NodeAsmInput), | |
| 1731 | cloppers: ArrayList(&NodeStringLiteral), | |
| 1732 | rparen: Token, | |
| 1733 | ||
| 1734 | pub fn iterate(self: &NodeAsm, index: usize) ?&Node { | |
| 1735 | var i = index; | |
| 1736 | ||
| 1737 | if (i < self.outputs.len) return &self.outputs.at(index).base; | |
| 1738 | i -= self.outputs.len; | |
| 1739 | ||
| 1740 | if (i < self.inputs.len) return &self.inputs.at(index).base; | |
| 1741 | i -= self.inputs.len; | |
| 1742 | ||
| 1743 | if (i < self.cloppers.len) return &self.cloppers.at(index).base; | |
| 1744 | i -= self.cloppers.len; | |
| 1745 | ||
| 1746 | return null; | |
| 1747 | } | |
| 1748 | ||
| 1749 | pub fn firstToken(self: &NodeAsm) Token { | |
| 1750 | return self.asm_token; | |
| 1751 | } | |
| 1752 | ||
| 1753 | pub fn lastToken(self: &NodeAsm) Token { | |
| 1754 | return self.rparen; | |
| 1755 | } | |
| 1756 | }; | |
| 1757 | ||
| 1758 | pub const NodeUnreachable = struct { | |
| 1759 | base: Node, | |
| 1760 | token: Token, | |
| 1761 | ||
| 1762 | pub fn iterate(self: &NodeUnreachable, index: usize) ?&Node { | |
| 1763 | return null; | |
| 1764 | } | |
| 1765 | ||
| 1766 | pub fn firstToken(self: &NodeUnreachable) Token { | |
| 1767 | return self.token; | |
| 1768 | } | |
| 1769 | ||
| 1770 | pub fn lastToken(self: &NodeUnreachable) Token { | |
| 1771 | return self.token; | |
| 1772 | } | |
| 1773 | }; | |
| 1774 | ||
| 1775 | pub const NodeErrorType = struct { | |
| 1776 | base: Node, | |
| 1777 | token: Token, | |
| 1778 | ||
| 1779 | pub fn iterate(self: &NodeErrorType, index: usize) ?&Node { | |
| 1780 | return null; | |
| 1781 | } | |
| 1782 | ||
| 1783 | pub fn firstToken(self: &NodeErrorType) Token { | |
| 1784 | return self.token; | |
| 1785 | } | |
| 1786 | ||
| 1787 | pub fn lastToken(self: &NodeErrorType) Token { | |
| 1788 | return self.token; | |
| 1789 | } | |
| 1790 | }; | |
| 1791 | ||
| 1792 | pub const NodeVarType = struct { | |
| 1793 | base: Node, | |
| 1794 | token: Token, | |
| 1795 | ||
| 1796 | pub fn iterate(self: &NodeVarType, index: usize) ?&Node { | |
| 1797 | return null; | |
| 1798 | } | |
| 1799 | ||
| 1800 | pub fn firstToken(self: &NodeVarType) Token { | |
| 1801 | return self.token; | |
| 1802 | } | |
| 1803 | ||
| 1804 | pub fn lastToken(self: &NodeVarType) Token { | |
| 1805 | return self.token; | |
| 1806 | } | |
| 1807 | }; | |
| 1808 | ||
| 1809 | pub const NodeLineComment = struct { | |
| 1810 | base: Node, | |
| 1811 | lines: ArrayList(Token), | |
| 1812 | ||
| 1813 | pub fn iterate(self: &NodeLineComment, index: usize) ?&Node { | |
| 1814 | return null; | |
| 1815 | } | |
| 1816 | ||
| 1817 | pub fn firstToken(self: &NodeLineComment) Token { | |
| 1818 | return self.lines.at(0); | |
| 1819 | } | |
| 1820 | ||
| 1821 | pub fn lastToken(self: &NodeLineComment) Token { | |
| 476 | 1822 | return self.lines.at(self.lines.len - 1); |
| 477 | 1823 | } |
| 478 | 1824 | }; |
| 1825 | ||
| 1826 | pub const NodeTestDecl = struct { | |
| 1827 | base: Node, | |
| 1828 | test_token: Token, | |
| 1829 | name: &Node, | |
| 1830 | body_node: &Node, | |
| 1831 | ||
| 1832 | pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node { | |
| 1833 | var i = index; | |
| 1834 | ||
| 1835 | if (i < 1) return self.body_node; | |
| 1836 | i -= 1; | |
| 1837 | ||
| 1838 | return null; | |
| 1839 | } | |
| 1840 | ||
| 1841 | pub fn firstToken(self: &NodeTestDecl) Token { | |
| 1842 | return self.test_token; | |
| 1843 | } | |
| 1844 | ||
| 1845 | pub fn lastToken(self: &NodeTestDecl) Token { | |
| 1846 | return self.body_node.lastToken(); | |
| 1847 | } | |
| 1848 | }; |
std/zig/parser.zig+4109-485| ... | ... | @@ -53,20 +53,33 @@ pub const Parser = struct { |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | const TopLevelDeclCtx = struct { |
| 56 | decls: &ArrayList(&ast.Node), | |
| 56 | 57 | visib_token: ?Token, |
| 57 | 58 | extern_token: ?Token, |
| 59 | lib_name: ?&ast.Node, | |
| 60 | }; | |
| 61 | ||
| 62 | const ContainerExternCtx = struct { | |
| 63 | dest_ptr: DestPtr, | |
| 64 | ltoken: Token, | |
| 65 | layout: ast.NodeContainerDecl.Layout, | |
| 58 | 66 | }; |
| 59 | 67 | |
| 60 | 68 | const DestPtr = union(enum) { |
| 61 | 69 | Field: &&ast.Node, |
| 62 | 70 | NullableField: &?&ast.Node, |
| 63 | List: &ArrayList(&ast.Node), | |
| 64 | 71 | |
| 65 | pub fn store(self: &const DestPtr, value: &ast.Node) !void { | |
| 72 | pub fn store(self: &const DestPtr, value: &ast.Node) void { | |
| 66 | 73 | switch (*self) { |
| 67 | 74 | DestPtr.Field => |ptr| *ptr = value, |
| 68 | 75 | DestPtr.NullableField => |ptr| *ptr = value, |
| 69 | DestPtr.List => |list| try list.append(value), | |
| 76 | } | |
| 77 | } | |
| 78 | ||
| 79 | pub fn get(self: &const DestPtr) &ast.Node { | |
| 80 | switch (*self) { | |
| 81 | DestPtr.Field => |ptr| return *ptr, | |
| 82 | DestPtr.NullableField => |ptr| return ??*ptr, | |
| 70 | 83 | } |
| 71 | 84 | } |
| 72 | 85 | }; |
| ... | ... | @@ -76,21 +89,69 @@ pub const Parser = struct { |
| 76 | 89 | ptr: &Token, |
| 77 | 90 | }; |
| 78 | 91 | |
| 92 | const RevertState = struct { | |
| 93 | parser: Parser, | |
| 94 | tokenizer: Tokenizer, | |
| 95 | ||
| 96 | // We expect, that if something is optional, then there is a field, | |
| 97 | // that needs to be set to null, when we revert. | |
| 98 | ptr: &?&ast.Node, | |
| 99 | }; | |
| 100 | ||
| 101 | const ExprListCtx = struct { | |
| 102 | list: &ArrayList(&ast.Node), | |
| 103 | end: Token.Id, | |
| 104 | ptr: &Token, | |
| 105 | }; | |
| 106 | ||
| 107 | const ElseCtx = struct { | |
| 108 | payload: ?DestPtr, | |
| 109 | body: DestPtr, | |
| 110 | }; | |
| 111 | ||
| 112 | fn ListSave(comptime T: type) type { | |
| 113 | return struct { | |
| 114 | list: &ArrayList(T), | |
| 115 | ptr: &Token, | |
| 116 | }; | |
| 117 | } | |
| 118 | ||
| 119 | const LabelCtx = struct { | |
| 120 | label: ?Token, | |
| 121 | dest_ptr: DestPtr, | |
| 122 | }; | |
| 123 | ||
| 124 | const InlineCtx = struct { | |
| 125 | label: ?Token, | |
| 126 | inline_token: ?Token, | |
| 127 | dest_ptr: DestPtr, | |
| 128 | }; | |
| 129 | ||
| 130 | const LoopCtx = struct { | |
| 131 | label: ?Token, | |
| 132 | inline_token: ?Token, | |
| 133 | loop_token: Token, | |
| 134 | dest_ptr: DestPtr, | |
| 135 | }; | |
| 136 | ||
| 137 | const AsyncEndCtx = struct { | |
| 138 | dest_ptr: DestPtr, | |
| 139 | attribute: &ast.NodeAsyncAttribute, | |
| 140 | }; | |
| 141 | ||
| 79 | 142 | const State = union(enum) { |
| 80 | 143 | TopLevel, |
| 81 | TopLevelExtern: ?Token, | |
| 144 | TopLevelExtern: TopLevelDeclCtx, | |
| 82 | 145 | TopLevelDecl: TopLevelDeclCtx, |
| 83 | Expression: DestPtr, | |
| 84 | ExpectOperand, | |
| 85 | Operand: &ast.Node, | |
| 86 | AfterOperand, | |
| 87 | InfixOp: &ast.NodeInfixOp, | |
| 88 | PrefixOp: &ast.NodePrefixOp, | |
| 146 | ContainerExtern: ContainerExternCtx, | |
| 147 | ContainerDecl: &ast.NodeContainerDecl, | |
| 148 | SliceOrArrayAccess: &ast.NodeSuffixOp, | |
| 89 | 149 | AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo, |
| 90 | TypeExpr: DestPtr, | |
| 91 | 150 | VarDecl: &ast.NodeVarDecl, |
| 92 | 151 | VarDeclAlign: &ast.NodeVarDecl, |
| 93 | 152 | VarDeclEq: &ast.NodeVarDecl, |
| 153 | IfToken: @TagType(Token.Id), | |
| 154 | IfTokenSave: ExpectTokenSave, | |
| 94 | 155 | ExpectToken: @TagType(Token.Id), |
| 95 | 156 | ExpectTokenSave: ExpectTokenSave, |
| 96 | 157 | FnProto: &ast.NodeFnProto, |
| ... | ... | @@ -99,10 +160,73 @@ pub const Parser = struct { |
| 99 | 160 | ParamDecl: &ast.NodeFnProto, |
| 100 | 161 | ParamDeclComma, |
| 101 | 162 | FnDef: &ast.NodeFnProto, |
| 163 | LabeledExpression: LabelCtx, | |
| 164 | Inline: InlineCtx, | |
| 165 | While: LoopCtx, | |
| 166 | For: LoopCtx, | |
| 102 | 167 | Block: &ast.NodeBlock, |
| 168 | Else: &?&ast.NodeElse, | |
| 169 | WhileContinueExpr: &?&ast.Node, | |
| 103 | 170 | Statement: &ast.NodeBlock, |
| 104 | ExprListItemOrEnd: &ArrayList(&ast.Node), | |
| 105 | ExprListCommaOrEnd: &ArrayList(&ast.Node), | |
| 171 | Semicolon: &const &const ast.Node, | |
| 172 | AsmOutputItems: &ArrayList(&ast.NodeAsmOutput), | |
| 173 | AsmInputItems: &ArrayList(&ast.NodeAsmInput), | |
| 174 | AsmClopperItems: &ArrayList(&ast.NodeStringLiteral), | |
| 175 | ExprListItemOrEnd: ExprListCtx, | |
| 176 | ExprListCommaOrEnd: ExprListCtx, | |
| 177 | FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer), | |
| 178 | FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer), | |
| 179 | FieldListCommaOrEnd: &ast.NodeContainerDecl, | |
| 180 | SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase), | |
| 181 | SuspendBody: &ast.NodeSuspend, | |
| 182 | AsyncEnd: AsyncEndCtx, | |
| 183 | Payload: &?&ast.NodePayload, | |
| 184 | PointerPayload: &?&ast.NodePointerPayload, | |
| 185 | PointerIndexPayload: &?&ast.NodePointerIndexPayload, | |
| 186 | SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase), | |
| 187 | SwitchCaseItem: &ArrayList(&ast.Node), | |
| 188 | SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node), | |
| 189 | ||
| 190 | /// A state that can be appended before any other State. If an error occures, | |
| 191 | /// the parser will first try looking for the closest optional state. If an | |
| 192 | /// optional state is found, the parser will revert to the state it was in | |
| 193 | /// when the optional was added. This will polute the arena allocator with | |
| 194 | /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes. | |
| 195 | Optional: RevertState, | |
| 196 | ||
| 197 | Expression: DestPtr, | |
| 198 | RangeExpressionBegin: DestPtr, | |
| 199 | RangeExpressionEnd: DestPtr, | |
| 200 | AssignmentExpressionBegin: DestPtr, | |
| 201 | AssignmentExpressionEnd: DestPtr, | |
| 202 | UnwrapExpressionBegin: DestPtr, | |
| 203 | UnwrapExpressionEnd: DestPtr, | |
| 204 | BoolOrExpressionBegin: DestPtr, | |
| 205 | BoolOrExpressionEnd: DestPtr, | |
| 206 | BoolAndExpressionBegin: DestPtr, | |
| 207 | BoolAndExpressionEnd: DestPtr, | |
| 208 | ComparisonExpressionBegin: DestPtr, | |
| 209 | ComparisonExpressionEnd: DestPtr, | |
| 210 | BinaryOrExpressionBegin: DestPtr, | |
| 211 | BinaryOrExpressionEnd: DestPtr, | |
| 212 | BinaryXorExpressionBegin: DestPtr, | |
| 213 | BinaryXorExpressionEnd: DestPtr, | |
| 214 | BinaryAndExpressionBegin: DestPtr, | |
| 215 | BinaryAndExpressionEnd: DestPtr, | |
| 216 | BitShiftExpressionBegin: DestPtr, | |
| 217 | BitShiftExpressionEnd: DestPtr, | |
| 218 | AdditionExpressionBegin: DestPtr, | |
| 219 | AdditionExpressionEnd: DestPtr, | |
| 220 | MultiplyExpressionBegin: DestPtr, | |
| 221 | MultiplyExpressionEnd: DestPtr, | |
| 222 | CurlySuffixExpressionBegin: DestPtr, | |
| 223 | CurlySuffixExpressionEnd: DestPtr, | |
| 224 | TypeExprBegin: DestPtr, | |
| 225 | TypeExprEnd: DestPtr, | |
| 226 | PrefixOpExpression: DestPtr, | |
| 227 | SuffixOpExpressionBegin: DestPtr, | |
| 228 | SuffixOpExpressionEnd: DestPtr, | |
| 229 | PrimaryExpression: DestPtr, | |
| 106 | 230 | }; |
| 107 | 231 | |
| 108 | 232 | /// Returns an AST tree, allocated with the parser's allocator. |
| ... | ... | @@ -167,88 +291,199 @@ pub const Parser = struct { |
| 167 | 291 | State.TopLevel => { |
| 168 | 292 | const token = self.getNextToken(); |
| 169 | 293 | switch (token.id) { |
| 170 | Token.Id.Keyword_pub, Token.Id.Keyword_export => { | |
| 171 | stack.append(State { .TopLevelExtern = token }) catch unreachable; | |
| 294 | Token.Id.Keyword_test => { | |
| 295 | stack.append(State.TopLevel) catch unreachable; | |
| 296 | ||
| 297 | const name_token = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue; | |
| 298 | const lbrace = (try self.eatToken(&stack, Token.Id.LBrace)) ?? continue; | |
| 299 | ||
| 300 | const name = try self.createStringLiteral(arena, name_token); | |
| 301 | const block = try self.createBlock(arena, (?Token)(null), token); | |
| 302 | const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, &name.base, block); | |
| 303 | stack.append(State { .Block = block }) catch unreachable; | |
| 172 | 304 | continue; |
| 173 | 305 | }, |
| 174 | 306 | Token.Id.Eof => { |
| 175 | 307 | root_node.eof_token = token; |
| 176 | 308 | return Tree {.root_node = root_node, .arena_allocator = arena_allocator}; |
| 177 | 309 | }, |
| 310 | Token.Id.Keyword_pub, Token.Id.Keyword_export => { | |
| 311 | stack.append(State.TopLevel) catch unreachable; | |
| 312 | try stack.append(State { | |
| 313 | .TopLevelExtern = TopLevelDeclCtx { | |
| 314 | .decls = &root_node.decls, | |
| 315 | .visib_token = token, | |
| 316 | .extern_token = null, | |
| 317 | .lib_name = null, | |
| 318 | } | |
| 319 | }); | |
| 320 | continue; | |
| 321 | }, | |
| 322 | Token.Id.Keyword_comptime => { | |
| 323 | const node = try arena.create(ast.NodeComptime); | |
| 324 | *node = ast.NodeComptime { | |
| 325 | .base = self.initNode(ast.Node.Id.Comptime), | |
| 326 | .comptime_token = token, | |
| 327 | .expr = undefined, | |
| 328 | }; | |
| 329 | try root_node.decls.append(&node.base); | |
| 330 | stack.append(State.TopLevel) catch unreachable; | |
| 331 | try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); | |
| 332 | continue; | |
| 333 | }, | |
| 178 | 334 | else => { |
| 179 | 335 | self.putBackToken(token); |
| 180 | stack.append(State { .TopLevelExtern = null }) catch unreachable; | |
| 336 | stack.append(State.TopLevel) catch unreachable; | |
| 337 | try stack.append(State { | |
| 338 | .TopLevelExtern = TopLevelDeclCtx { | |
| 339 | .decls = &root_node.decls, | |
| 340 | .visib_token = null, | |
| 341 | .extern_token = null, | |
| 342 | .lib_name = null, | |
| 343 | } | |
| 344 | }); | |
| 181 | 345 | continue; |
| 182 | 346 | }, |
| 183 | 347 | } |
| 184 | 348 | }, |
| 185 | State.TopLevelExtern => |visib_token| { | |
| 349 | State.TopLevelExtern => |ctx| { | |
| 186 | 350 | const token = self.getNextToken(); |
| 187 | if (token.id == Token.Id.Keyword_extern) { | |
| 188 | stack.append(State { | |
| 189 | .TopLevelDecl = TopLevelDeclCtx { | |
| 190 | .visib_token = visib_token, | |
| 191 | .extern_token = token, | |
| 192 | }, | |
| 193 | }) catch unreachable; | |
| 194 | continue; | |
| 195 | } | |
| 196 | self.putBackToken(token); | |
| 197 | stack.append(State { | |
| 198 | .TopLevelDecl = TopLevelDeclCtx { | |
| 199 | .visib_token = visib_token, | |
| 200 | .extern_token = null, | |
| 351 | switch (token.id) { | |
| 352 | Token.Id.Keyword_use => { | |
| 353 | const node = try arena.create(ast.NodeUse); | |
| 354 | *node = ast.NodeUse { | |
| 355 | .base = self.initNode(ast.Node.Id.Use), | |
| 356 | .visib_token = ctx.visib_token, | |
| 357 | .expr = undefined, | |
| 358 | .semicolon_token = undefined, | |
| 359 | }; | |
| 360 | try ctx.decls.append(&node.base); | |
| 361 | ||
| 362 | stack.append(State { | |
| 363 | .ExpectTokenSave = ExpectTokenSave { | |
| 364 | .id = Token.Id.Semicolon, | |
| 365 | .ptr = &node.semicolon_token, | |
| 366 | } | |
| 367 | }) catch unreachable; | |
| 368 | try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); | |
| 369 | continue; | |
| 201 | 370 | }, |
| 202 | }) catch unreachable; | |
| 203 | continue; | |
| 371 | Token.Id.Keyword_extern => { | |
| 372 | const lib_name_token = self.getNextToken(); | |
| 373 | const lib_name = blk: { | |
| 374 | if (lib_name_token.id == Token.Id.StringLiteral) { | |
| 375 | const res = try self.createStringLiteral(arena, lib_name_token); | |
| 376 | break :blk &res.base; | |
| 377 | } else { | |
| 378 | self.putBackToken(lib_name_token); | |
| 379 | break :blk null; | |
| 380 | } | |
| 381 | }; | |
| 382 | ||
| 383 | stack.append(State { | |
| 384 | .TopLevelDecl = TopLevelDeclCtx { | |
| 385 | .decls = ctx.decls, | |
| 386 | .visib_token = ctx.visib_token, | |
| 387 | .extern_token = token, | |
| 388 | .lib_name = lib_name, | |
| 389 | }, | |
| 390 | }) catch unreachable; | |
| 391 | continue; | |
| 392 | }, | |
| 393 | else => { | |
| 394 | self.putBackToken(token); | |
| 395 | stack.append(State { .TopLevelDecl = ctx }) catch unreachable; | |
| 396 | continue; | |
| 397 | } | |
| 398 | } | |
| 204 | 399 | }, |
| 205 | 400 | State.TopLevelDecl => |ctx| { |
| 206 | 401 | const token = self.getNextToken(); |
| 207 | 402 | switch (token.id) { |
| 208 | 403 | Token.Id.Keyword_var, Token.Id.Keyword_const => { |
| 209 | stack.append(State.TopLevel) catch unreachable; | |
| 210 | 404 | // TODO shouldn't need these casts |
| 211 | const var_decl_node = try self.createAttachVarDecl(arena, &root_node.decls, ctx.visib_token, | |
| 212 | token, (?Token)(null), ctx.extern_token); | |
| 213 | try stack.append(State { .VarDecl = var_decl_node }); | |
| 405 | const var_decl_node = try self.createAttachVarDecl(arena, ctx.decls, ctx.visib_token, | |
| 406 | token, (?Token)(null), ctx.extern_token, ctx.lib_name); | |
| 407 | stack.append(State { .VarDecl = var_decl_node }) catch unreachable; | |
| 214 | 408 | continue; |
| 215 | 409 | }, |
| 216 | 410 | Token.Id.Keyword_fn => { |
| 217 | stack.append(State.TopLevel) catch unreachable; | |
| 218 | 411 | // TODO shouldn't need these casts |
| 219 | const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, token, | |
| 220 | ctx.extern_token, (?Token)(null), ctx.visib_token, (?Token)(null)); | |
| 221 | try stack.append(State { .FnDef = fn_proto }); | |
| 412 | const fn_proto = try self.createAttachFnProto(arena, ctx.decls, token, | |
| 413 | ctx.extern_token, ctx.lib_name, (?Token)(null), ctx.visib_token, (?Token)(null)); | |
| 414 | stack.append(State { .FnDef = fn_proto }) catch unreachable; | |
| 222 | 415 | try stack.append(State { .FnProto = fn_proto }); |
| 223 | 416 | continue; |
| 224 | 417 | }, |
| 225 | Token.Id.StringLiteral => { | |
| 226 | @panic("TODO extern with string literal"); | |
| 227 | }, | |
| 228 | 418 | Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { |
| 229 | stack.append(State.TopLevel) catch unreachable; | |
| 230 | const fn_token = try self.eatToken(Token.Id.Keyword_fn); | |
| 231 | 419 | // TODO shouldn't need this cast |
| 232 | const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, fn_token, | |
| 233 | ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null)); | |
| 234 | try stack.append(State { .FnDef = fn_proto }); | |
| 420 | const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined), | |
| 421 | ctx.extern_token, ctx.lib_name, (?Token)(token), (?Token)(null), (?Token)(null)); | |
| 422 | stack.append(State { .FnDef = fn_proto }) catch unreachable; | |
| 423 | try stack.append(State { .FnProto = fn_proto }); | |
| 424 | try stack.append(State { | |
| 425 | .ExpectTokenSave = ExpectTokenSave { | |
| 426 | .id = Token.Id.Keyword_fn, | |
| 427 | .ptr = &fn_proto.fn_token, | |
| 428 | } | |
| 429 | }); | |
| 430 | continue; | |
| 431 | }, | |
| 432 | Token.Id.Keyword_async => { | |
| 433 | // TODO shouldn't need this cast | |
| 434 | const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined), | |
| 435 | ctx.extern_token, ctx.lib_name, (?Token)(null), (?Token)(null), (?Token)(null)); | |
| 436 | ||
| 437 | const async_node = try arena.create(ast.NodeAsyncAttribute); | |
| 438 | *async_node = ast.NodeAsyncAttribute { | |
| 439 | .base = self.initNode(ast.Node.Id.AsyncAttribute), | |
| 440 | .async_token = token, | |
| 441 | .allocator_type = null, | |
| 442 | .rangle_bracket = null, | |
| 443 | }; | |
| 444 | ||
| 445 | fn_proto.async_attr = async_node; | |
| 446 | stack.append(State { .FnDef = fn_proto }) catch unreachable; | |
| 235 | 447 | try stack.append(State { .FnProto = fn_proto }); |
| 448 | try stack.append(State { | |
| 449 | .ExpectTokenSave = ExpectTokenSave { | |
| 450 | .id = Token.Id.Keyword_fn, | |
| 451 | .ptr = &fn_proto.fn_token, | |
| 452 | } | |
| 453 | }); | |
| 454 | ||
| 455 | const langle_bracket = self.getNextToken(); | |
| 456 | if (langle_bracket.id != Token.Id.AngleBracketLeft) { | |
| 457 | self.putBackToken(langle_bracket); | |
| 458 | continue; | |
| 459 | } | |
| 460 | ||
| 461 | async_node.rangle_bracket = Token(undefined); | |
| 462 | try stack.append(State { | |
| 463 | .ExpectTokenSave = ExpectTokenSave { | |
| 464 | .id = Token.Id.AngleBracketRight, | |
| 465 | .ptr = &??async_node.rangle_bracket, | |
| 466 | } | |
| 467 | }); | |
| 468 | try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } }); | |
| 469 | continue; | |
| 470 | }, | |
| 471 | else => { | |
| 472 | try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id)); | |
| 236 | 473 | continue; |
| 237 | 474 | }, |
| 238 | else => return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id)), | |
| 239 | 475 | } |
| 240 | 476 | }, |
| 241 | 477 | State.VarDecl => |var_decl| { |
| 242 | var_decl.name_token = try self.eatToken(Token.Id.Identifier); | |
| 243 | 478 | stack.append(State { .VarDeclAlign = var_decl }) catch unreachable; |
| 244 | ||
| 245 | const next_token = self.getNextToken(); | |
| 246 | if (next_token.id == Token.Id.Colon) { | |
| 247 | try stack.append(State { .TypeExpr = DestPtr {.NullableField = &var_decl.type_node} }); | |
| 248 | continue; | |
| 249 | } | |
| 250 | ||
| 251 | self.putBackToken(next_token); | |
| 479 | try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} }); | |
| 480 | try stack.append(State { .IfToken = Token.Id.Colon }); | |
| 481 | try stack.append(State { | |
| 482 | .ExpectTokenSave = ExpectTokenSave { | |
| 483 | .id = Token.Id.Identifier, | |
| 484 | .ptr = &var_decl.name_token, | |
| 485 | } | |
| 486 | }); | |
| 252 | 487 | continue; |
| 253 | 488 | }, |
| 254 | 489 | State.VarDeclAlign => |var_decl| { |
| ... | ... | @@ -256,9 +491,9 @@ pub const Parser = struct { |
| 256 | 491 | |
| 257 | 492 | const next_token = self.getNextToken(); |
| 258 | 493 | if (next_token.id == Token.Id.Keyword_align) { |
| 259 | _ = try self.eatToken(Token.Id.LParen); | |
| 260 | 494 | try stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 261 | 495 | try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} }); |
| 496 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 262 | 497 | continue; |
| 263 | 498 | } |
| 264 | 499 | |
| ... | ... | @@ -284,422 +519,2191 @@ pub const Parser = struct { |
| 284 | 519 | var_decl.semicolon_token = token; |
| 285 | 520 | continue; |
| 286 | 521 | } |
| 287 | return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id)); | |
| 288 | }, | |
| 289 | State.ExpectToken => |token_id| { | |
| 290 | _ = try self.eatToken(token_id); | |
| 291 | continue; | |
| 292 | }, | |
| 293 | ||
| 294 | State.ExpectTokenSave => |expect_token_save| { | |
| 295 | *expect_token_save.ptr = try self.eatToken(expect_token_save.id); | |
| 522 | try self.parseError(&stack, token, "expected '=' or ';', found {}", @tagName(token.id)); | |
| 296 | 523 | continue; |
| 297 | 524 | }, |
| 298 | 525 | |
| 299 | State.Expression => |dest_ptr| { | |
| 300 | // save the dest_ptr for later | |
| 301 | stack.append(state) catch unreachable; | |
| 302 | try stack.append(State.ExpectOperand); | |
| 303 | continue; | |
| 304 | }, | |
| 305 | State.ExpectOperand => { | |
| 306 | // we'll either get an operand (like 1 or x), | |
| 307 | // or a prefix operator (like ~ or return). | |
| 526 | State.ContainerExtern => |ctx| { | |
| 308 | 527 | const token = self.getNextToken(); |
| 309 | switch (token.id) { | |
| 310 | Token.Id.Keyword_return => { | |
| 311 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 312 | ast.NodePrefixOp.PrefixOp.Return) }); | |
| 313 | try stack.append(State.ExpectOperand); | |
| 314 | continue; | |
| 315 | }, | |
| 316 | Token.Id.Keyword_try => { | |
| 317 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 318 | ast.NodePrefixOp.PrefixOp.Try) }); | |
| 319 | try stack.append(State.ExpectOperand); | |
| 320 | continue; | |
| 321 | }, | |
| 322 | Token.Id.Ampersand => { | |
| 323 | const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{ | |
| 324 | .AddrOf = ast.NodePrefixOp.AddrOfInfo { | |
| 325 | .align_expr = null, | |
| 326 | .bit_offset_start_token = null, | |
| 327 | .bit_offset_end_token = null, | |
| 328 | .const_token = null, | |
| 329 | .volatile_token = null, | |
| 330 | } | |
| 331 | }); | |
| 332 | try stack.append(State { .PrefixOp = prefix_op }); | |
| 333 | try stack.append(State.ExpectOperand); | |
| 334 | try stack.append(State { .AddrOfModifiers = &prefix_op.op.AddrOf }); | |
| 335 | continue; | |
| 336 | }, | |
| 337 | Token.Id.Identifier => { | |
| 338 | try stack.append(State { | |
| 339 | .Operand = &(try self.createIdentifier(arena, token)).base | |
| 340 | }); | |
| 341 | try stack.append(State.AfterOperand); | |
| 342 | continue; | |
| 343 | }, | |
| 344 | Token.Id.IntegerLiteral => { | |
| 345 | try stack.append(State { | |
| 346 | .Operand = &(try self.createIntegerLiteral(arena, token)).base | |
| 347 | }); | |
| 348 | try stack.append(State.AfterOperand); | |
| 349 | continue; | |
| 350 | }, | |
| 351 | Token.Id.FloatLiteral => { | |
| 352 | try stack.append(State { | |
| 353 | .Operand = &(try self.createFloatLiteral(arena, token)).base | |
| 354 | }); | |
| 355 | try stack.append(State.AfterOperand); | |
| 356 | continue; | |
| 528 | ||
| 529 | const node = try arena.create(ast.NodeContainerDecl); | |
| 530 | *node = ast.NodeContainerDecl { | |
| 531 | .base = self.initNode(ast.Node.Id.ContainerDecl), | |
| 532 | .ltoken = ctx.ltoken, | |
| 533 | .layout = ctx.layout, | |
| 534 | .kind = switch (token.id) { | |
| 535 | Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct, | |
| 536 | Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union, | |
| 537 | Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum, | |
| 538 | else => { | |
| 539 | try self.parseError(&stack, token, "expected {}, {} or {}, found {}", | |
| 540 | @tagName(Token.Id.Keyword_struct), | |
| 541 | @tagName(Token.Id.Keyword_union), | |
| 542 | @tagName(Token.Id.Keyword_enum), | |
| 543 | @tagName(token.id)); | |
| 544 | continue; | |
| 545 | }, | |
| 357 | 546 | }, |
| 358 | Token.Id.Builtin => { | |
| 359 | const node = try arena.create(ast.NodeBuiltinCall); | |
| 360 | *node = ast.NodeBuiltinCall { | |
| 361 | .base = self.initNode(ast.Node.Id.BuiltinCall), | |
| 362 | .builtin_token = token, | |
| 363 | .params = ArrayList(&ast.Node).init(arena), | |
| 364 | .rparen_token = undefined, | |
| 365 | }; | |
| 366 | try stack.append(State { | |
| 367 | .Operand = &node.base | |
| 368 | }); | |
| 369 | try stack.append(State.AfterOperand); | |
| 370 | try stack.append(State {.ExprListItemOrEnd = &node.params }); | |
| 371 | try stack.append(State { | |
| 372 | .ExpectTokenSave = ExpectTokenSave { | |
| 373 | .id = Token.Id.LParen, | |
| 374 | .ptr = &node.rparen_token, | |
| 375 | }, | |
| 376 | }); | |
| 377 | continue; | |
| 547 | .init_arg_expr = undefined, | |
| 548 | .fields_and_decls = ArrayList(&ast.Node).init(arena), | |
| 549 | .rbrace_token = undefined, | |
| 550 | }; | |
| 551 | ctx.dest_ptr.store(&node.base); | |
| 552 | ||
| 553 | stack.append(State { .ContainerDecl = node }) catch unreachable; | |
| 554 | try stack.append(State { .ExpectToken = Token.Id.LBrace }); | |
| 555 | ||
| 556 | const lparen = self.getNextToken(); | |
| 557 | if (lparen.id != Token.Id.LParen) { | |
| 558 | self.putBackToken(lparen); | |
| 559 | node.init_arg_expr = ast.NodeContainerDecl.InitArg.None; | |
| 560 | continue; | |
| 561 | } | |
| 562 | ||
| 563 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 564 | ||
| 565 | const init_arg_token = self.getNextToken(); | |
| 566 | switch (init_arg_token.id) { | |
| 567 | Token.Id.Keyword_enum => { | |
| 568 | node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum; | |
| 378 | 569 | }, |
| 379 | Token.Id.StringLiteral => { | |
| 380 | const node = try arena.create(ast.NodeStringLiteral); | |
| 381 | *node = ast.NodeStringLiteral { | |
| 382 | .base = self.initNode(ast.Node.Id.StringLiteral), | |
| 383 | .token = token, | |
| 384 | }; | |
| 570 | else => { | |
| 571 | self.putBackToken(init_arg_token); | |
| 572 | node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined }; | |
| 385 | 573 | try stack.append(State { |
| 386 | .Operand = &node.base | |
| 574 | .Expression = DestPtr { | |
| 575 | .Field = &node.init_arg_expr.Type | |
| 576 | } | |
| 387 | 577 | }); |
| 388 | try stack.append(State.AfterOperand); | |
| 389 | continue; | |
| 390 | 578 | }, |
| 391 | ||
| 392 | else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)), | |
| 393 | 579 | } |
| 580 | continue; | |
| 394 | 581 | }, |
| 395 | 582 | |
| 396 | State.AfterOperand => { | |
| 397 | // we'll either get an infix operator (like != or ^), | |
| 398 | // or a postfix operator (like () or {}), | |
| 399 | // otherwise this expression is done (like on a ; or else). | |
| 400 | var token = self.getNextToken(); | |
| 583 | State.ContainerDecl => |container_decl| { | |
| 584 | const token = self.getNextToken(); | |
| 585 | ||
| 401 | 586 | switch (token.id) { |
| 402 | Token.Id.EqualEqual => { | |
| 403 | try stack.append(State { | |
| 404 | .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.EqualEqual) | |
| 405 | }); | |
| 406 | try stack.append(State.ExpectOperand); | |
| 407 | continue; | |
| 587 | Token.Id.Identifier => { | |
| 588 | switch (container_decl.kind) { | |
| 589 | ast.NodeContainerDecl.Kind.Struct => { | |
| 590 | const node = try arena.create(ast.NodeStructField); | |
| 591 | *node = ast.NodeStructField { | |
| 592 | .base = self.initNode(ast.Node.Id.StructField), | |
| 593 | .name_token = token, | |
| 594 | .type_expr = undefined, | |
| 595 | }; | |
| 596 | try container_decl.fields_and_decls.append(&node.base); | |
| 597 | ||
| 598 | stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable; | |
| 599 | try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } }); | |
| 600 | try stack.append(State { .ExpectToken = Token.Id.Colon }); | |
| 601 | continue; | |
| 602 | }, | |
| 603 | ast.NodeContainerDecl.Kind.Union => { | |
| 604 | const node = try arena.create(ast.NodeUnionTag); | |
| 605 | *node = ast.NodeUnionTag { | |
| 606 | .base = self.initNode(ast.Node.Id.UnionTag), | |
| 607 | .name_token = token, | |
| 608 | .type_expr = null, | |
| 609 | }; | |
| 610 | try container_decl.fields_and_decls.append(&node.base); | |
| 611 | ||
| 612 | stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable; | |
| 613 | ||
| 614 | const next = self.getNextToken(); | |
| 615 | if (next.id != Token.Id.Colon) { | |
| 616 | self.putBackToken(next); | |
| 617 | continue; | |
| 618 | } | |
| 619 | ||
| 620 | try stack.append(State { .Expression = DestPtr { .NullableField = &node.type_expr } }); | |
| 621 | continue; | |
| 622 | }, | |
| 623 | ast.NodeContainerDecl.Kind.Enum => { | |
| 624 | const node = try arena.create(ast.NodeEnumTag); | |
| 625 | *node = ast.NodeEnumTag { | |
| 626 | .base = self.initNode(ast.Node.Id.EnumTag), | |
| 627 | .name_token = token, | |
| 628 | .value = null, | |
| 629 | }; | |
| 630 | try container_decl.fields_and_decls.append(&node.base); | |
| 631 | ||
| 632 | stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable; | |
| 633 | ||
| 634 | const next = self.getNextToken(); | |
| 635 | if (next.id != Token.Id.Equal) { | |
| 636 | self.putBackToken(next); | |
| 637 | continue; | |
| 638 | } | |
| 639 | ||
| 640 | try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } }); | |
| 641 | continue; | |
| 642 | }, | |
| 643 | } | |
| 408 | 644 | }, |
| 409 | Token.Id.BangEqual => { | |
| 645 | Token.Id.Keyword_pub, Token.Id.Keyword_export => { | |
| 646 | stack.append(State{ .ContainerDecl = container_decl }) catch unreachable; | |
| 410 | 647 | try stack.append(State { |
| 411 | .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BangEqual) | |
| 648 | .TopLevelExtern = TopLevelDeclCtx { | |
| 649 | .decls = &container_decl.fields_and_decls, | |
| 650 | .visib_token = token, | |
| 651 | .extern_token = null, | |
| 652 | .lib_name = null, | |
| 653 | } | |
| 412 | 654 | }); |
| 413 | try stack.append(State.ExpectOperand); | |
| 414 | 655 | continue; |
| 415 | 656 | }, |
| 416 | Token.Id.Period => { | |
| 417 | try stack.append(State { | |
| 418 | .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period) | |
| 419 | }); | |
| 420 | try stack.append(State.ExpectOperand); | |
| 657 | Token.Id.RBrace => { | |
| 658 | container_decl.rbrace_token = token; | |
| 421 | 659 | continue; |
| 422 | 660 | }, |
| 423 | 661 | else => { |
| 424 | // no postfix/infix operator after this operand. | |
| 425 | 662 | self.putBackToken(token); |
| 426 | // reduce the stack | |
| 427 | var expression: &ast.Node = stack.pop().Operand; | |
| 428 | while (true) { | |
| 429 | switch (stack.pop()) { | |
| 430 | State.Expression => |dest_ptr| { | |
| 431 | // we're done | |
| 432 | try dest_ptr.store(expression); | |
| 433 | break; | |
| 434 | }, | |
| 435 | State.InfixOp => |infix_op| { | |
| 436 | infix_op.rhs = expression; | |
| 437 | infix_op.lhs = stack.pop().Operand; | |
| 438 | expression = &infix_op.base; | |
| 439 | continue; | |
| 440 | }, | |
| 441 | State.PrefixOp => |prefix_op| { | |
| 442 | prefix_op.rhs = expression; | |
| 443 | expression = &prefix_op.base; | |
| 444 | continue; | |
| 445 | }, | |
| 446 | else => unreachable, | |
| 663 | stack.append(State{ .ContainerDecl = container_decl }) catch unreachable; | |
| 664 | try stack.append(State { | |
| 665 | .TopLevelExtern = TopLevelDeclCtx { | |
| 666 | .decls = &container_decl.fields_and_decls, | |
| 667 | .visib_token = null, | |
| 668 | .extern_token = null, | |
| 669 | .lib_name = null, | |
| 447 | 670 | } |
| 448 | } | |
| 671 | }); | |
| 449 | 672 | continue; |
| 450 | }, | |
| 673 | } | |
| 451 | 674 | } |
| 452 | 675 | }, |
| 453 | 676 | |
| 454 | State.ExprListItemOrEnd => |params| { | |
| 455 | var token = self.getNextToken(); | |
| 456 | switch (token.id) { | |
| 457 | Token.Id.RParen => continue, | |
| 458 | else => { | |
| 459 | self.putBackToken(token); | |
| 460 | stack.append(State { .ExprListCommaOrEnd = params }) catch unreachable; | |
| 461 | try stack.append(State { .Expression = DestPtr{.List = params} }); | |
| 462 | }, | |
| 677 | State.ExpectToken => |token_id| { | |
| 678 | _ = (try self.eatToken(&stack, token_id)) ?? continue; | |
| 679 | continue; | |
| 680 | }, | |
| 681 | ||
| 682 | State.ExpectTokenSave => |expect_token_save| { | |
| 683 | *expect_token_save.ptr = (try self.eatToken(&stack, expect_token_save.id)) ?? continue; | |
| 684 | continue; | |
| 685 | }, | |
| 686 | ||
| 687 | State.IfToken => |token_id| { | |
| 688 | const token = self.getNextToken(); | |
| 689 | if (@TagType(Token.Id)(token.id) != token_id) { | |
| 690 | self.putBackToken(token); | |
| 691 | _ = stack.pop(); | |
| 692 | continue; | |
| 463 | 693 | } |
| 694 | continue; | |
| 464 | 695 | }, |
| 465 | 696 | |
| 466 | State.ExprListCommaOrEnd => |params| { | |
| 467 | var token = self.getNextToken(); | |
| 468 | switch (token.id) { | |
| 469 | Token.Id.Comma => { | |
| 470 | stack.append(State { .ExprListItemOrEnd = params }) catch unreachable; | |
| 471 | }, | |
| 472 | Token.Id.RParen => continue, | |
| 473 | else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)), | |
| 697 | State.IfTokenSave => |if_token_save| { | |
| 698 | const token = self.getNextToken(); | |
| 699 | if (@TagType(Token.Id)(token.id) != if_token_save.id) { | |
| 700 | self.putBackToken(token); | |
| 701 | _ = stack.pop(); | |
| 702 | continue; | |
| 474 | 703 | } |
| 704 | ||
| 705 | *if_token_save.ptr = token; | |
| 706 | continue; | |
| 475 | 707 | }, |
| 476 | 708 | |
| 477 | State.AddrOfModifiers => |addr_of_info| { | |
| 478 | var token = self.getNextToken(); | |
| 479 | switch (token.id) { | |
| 480 | Token.Id.Keyword_align => { | |
| 481 | stack.append(state) catch unreachable; | |
| 482 | if (addr_of_info.align_expr != null) return self.parseError(token, "multiple align qualifiers"); | |
| 483 | _ = try self.eatToken(Token.Id.LParen); | |
| 709 | State.Optional => { }, | |
| 710 | ||
| 711 | State.Expression => |dest_ptr| { | |
| 712 | const token = self.getNextToken(); | |
| 713 | switch (token.id) { | |
| 714 | Token.Id.Keyword_try => { | |
| 715 | const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Try); | |
| 716 | dest_ptr.store(&node.base); | |
| 717 | ||
| 718 | stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable; | |
| 719 | continue; | |
| 720 | }, | |
| 721 | Token.Id.Keyword_return => { | |
| 722 | const node = try self.createControlFlowExpr(arena, token, ast.NodeControlFlowExpression.Kind.Return); | |
| 723 | dest_ptr.store(&node.base); | |
| 724 | ||
| 725 | stack.append(State { | |
| 726 | .Optional = RevertState { | |
| 727 | .parser = *self, | |
| 728 | .tokenizer = *self.tokenizer, | |
| 729 | .ptr = &node.rhs, | |
| 730 | } | |
| 731 | }) catch unreachable; | |
| 732 | try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } }); | |
| 733 | continue; | |
| 734 | }, | |
| 735 | Token.Id.Keyword_break => { | |
| 736 | const label = blk: { | |
| 737 | const colon = self.getNextToken(); | |
| 738 | if (colon.id != Token.Id.Colon) { | |
| 739 | self.putBackToken(colon); | |
| 740 | break :blk null; | |
| 741 | } | |
| 742 | ||
| 743 | break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 744 | }; | |
| 745 | ||
| 746 | const node = try self.createControlFlowExpr(arena, token, | |
| 747 | ast.NodeControlFlowExpression.Kind { | |
| 748 | .Break = label, | |
| 749 | } | |
| 750 | ); | |
| 751 | dest_ptr.store(&node.base); | |
| 752 | ||
| 753 | stack.append(State { | |
| 754 | .Optional = RevertState { | |
| 755 | .parser = *self, | |
| 756 | .tokenizer = *self.tokenizer, | |
| 757 | .ptr = &node.rhs, | |
| 758 | } | |
| 759 | }) catch unreachable; | |
| 760 | try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } }); | |
| 761 | continue; | |
| 762 | }, | |
| 763 | Token.Id.Keyword_continue => { | |
| 764 | const label = blk: { | |
| 765 | const colon = self.getNextToken(); | |
| 766 | if (colon.id != Token.Id.Colon) { | |
| 767 | self.putBackToken(colon); | |
| 768 | break :blk null; | |
| 769 | } | |
| 770 | ||
| 771 | break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 772 | }; | |
| 773 | ||
| 774 | const node = try self.createControlFlowExpr(arena, token, | |
| 775 | ast.NodeControlFlowExpression.Kind { | |
| 776 | .Continue = label, | |
| 777 | } | |
| 778 | ); | |
| 779 | dest_ptr.store(&node.base); | |
| 780 | continue; | |
| 781 | }, | |
| 782 | Token.Id.Keyword_cancel => { | |
| 783 | const cancel_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Cancel); | |
| 784 | dest_ptr.store(&cancel_node.base); | |
| 785 | stack.append(State { .Expression = DestPtr { .Field = &cancel_node.rhs } }) catch unreachable; | |
| 786 | }, | |
| 787 | Token.Id.Keyword_resume => { | |
| 788 | const resume_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Resume); | |
| 789 | dest_ptr.store(&resume_node.base); | |
| 790 | stack.append(State { .Expression = DestPtr { .Field = &resume_node.rhs } }) catch unreachable; | |
| 791 | }, | |
| 792 | Token.Id.Keyword_suspend => { | |
| 793 | const node = try arena.create(ast.NodeSuspend); | |
| 794 | *node = ast.NodeSuspend { | |
| 795 | .base = self.initNode(ast.Node.Id.Suspend), | |
| 796 | .suspend_token = token, | |
| 797 | .payload = null, | |
| 798 | .body = null, | |
| 799 | }; | |
| 800 | dest_ptr.store(&node.base); | |
| 801 | stack.append(State { .SuspendBody = node }) catch unreachable; | |
| 802 | try stack.append(State { .Payload = &node.payload }); | |
| 803 | continue; | |
| 804 | }, | |
| 805 | Token.Id.Keyword_if => { | |
| 806 | const node = try arena.create(ast.NodeIf); | |
| 807 | *node = ast.NodeIf { | |
| 808 | .base = self.initNode(ast.Node.Id.If), | |
| 809 | .if_token = token, | |
| 810 | .condition = undefined, | |
| 811 | .payload = null, | |
| 812 | .body = undefined, | |
| 813 | .@"else" = null, | |
| 814 | }; | |
| 815 | dest_ptr.store(&node.base); | |
| 816 | ||
| 817 | stack.append(State { .Else = &node.@"else" }) catch unreachable; | |
| 818 | try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); | |
| 819 | try stack.append(State { .PointerPayload = &node.payload }); | |
| 484 | 820 | try stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 485 | try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} }); | |
| 821 | try stack.append(State { .Expression = DestPtr { .Field = &node.condition } }); | |
| 822 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 486 | 823 | continue; |
| 487 | 824 | }, |
| 488 | Token.Id.Keyword_const => { | |
| 489 | stack.append(state) catch unreachable; | |
| 490 | if (addr_of_info.const_token != null) return self.parseError(token, "duplicate qualifier: const"); | |
| 491 | addr_of_info.const_token = token; | |
| 825 | Token.Id.Keyword_while => { | |
| 826 | stack.append(State { | |
| 827 | .While = LoopCtx { | |
| 828 | .label = null, | |
| 829 | .inline_token = null, | |
| 830 | .loop_token = token, | |
| 831 | .dest_ptr = dest_ptr, | |
| 832 | } | |
| 833 | }) catch unreachable; | |
| 492 | 834 | continue; |
| 493 | 835 | }, |
| 494 | Token.Id.Keyword_volatile => { | |
| 495 | stack.append(state) catch unreachable; | |
| 496 | if (addr_of_info.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile"); | |
| 497 | addr_of_info.volatile_token = token; | |
| 836 | Token.Id.Keyword_for => { | |
| 837 | stack.append(State { | |
| 838 | .For = LoopCtx { | |
| 839 | .label = null, | |
| 840 | .inline_token = null, | |
| 841 | .loop_token = token, | |
| 842 | .dest_ptr = dest_ptr, | |
| 843 | } | |
| 844 | }) catch unreachable; | |
| 845 | continue; | |
| 846 | }, | |
| 847 | Token.Id.Keyword_switch => { | |
| 848 | const node = try arena.create(ast.NodeSwitch); | |
| 849 | *node = ast.NodeSwitch { | |
| 850 | .base = self.initNode(ast.Node.Id.Switch), | |
| 851 | .switch_token = token, | |
| 852 | .expr = undefined, | |
| 853 | .cases = ArrayList(&ast.NodeSwitchCase).init(arena), | |
| 854 | .rbrace = undefined, | |
| 855 | }; | |
| 856 | dest_ptr.store(&node.base); | |
| 857 | ||
| 858 | stack.append(State { | |
| 859 | .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) { | |
| 860 | .list = &node.cases, | |
| 861 | .ptr = &node.rbrace, | |
| 862 | }, | |
| 863 | }) catch unreachable; | |
| 864 | try stack.append(State { .ExpectToken = Token.Id.LBrace }); | |
| 865 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 866 | try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); | |
| 867 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 868 | }, | |
| 869 | Token.Id.Keyword_comptime => { | |
| 870 | const node = try arena.create(ast.NodeComptime); | |
| 871 | *node = ast.NodeComptime { | |
| 872 | .base = self.initNode(ast.Node.Id.Comptime), | |
| 873 | .comptime_token = token, | |
| 874 | .expr = undefined, | |
| 875 | }; | |
| 876 | dest_ptr.store(&node.base); | |
| 877 | try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); | |
| 878 | continue; | |
| 879 | }, | |
| 880 | Token.Id.LBrace => { | |
| 881 | const block = try self.createBlock(arena, (?Token)(null), token); | |
| 882 | dest_ptr.store(&block.base); | |
| 883 | ||
| 884 | stack.append(State { .Block = block }) catch unreachable; | |
| 498 | 885 | continue; |
| 499 | 886 | }, |
| 500 | 887 | else => { |
| 501 | 888 | self.putBackToken(token); |
| 889 | stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable; | |
| 502 | 890 | continue; |
| 503 | }, | |
| 891 | } | |
| 504 | 892 | } |
| 505 | 893 | }, |
| 506 | 894 | |
| 507 | State.TypeExpr => |dest_ptr| { | |
| 895 | State.RangeExpressionBegin => |dest_ptr| { | |
| 896 | stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable; | |
| 897 | try stack.append(State { .Expression = dest_ptr }); | |
| 898 | continue; | |
| 899 | }, | |
| 900 | ||
| 901 | State.RangeExpressionEnd => |dest_ptr| { | |
| 508 | 902 | const token = self.getNextToken(); |
| 509 | if (token.id == Token.Id.Keyword_var) { | |
| 510 | @panic("TODO param with type var"); | |
| 903 | if (token.id == Token.Id.Ellipsis3) { | |
| 904 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Range); | |
| 905 | node.lhs = dest_ptr.get(); | |
| 906 | dest_ptr.store(&node.base); | |
| 907 | ||
| 908 | stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable; | |
| 909 | continue; | |
| 910 | } else { | |
| 911 | self.putBackToken(token); | |
| 912 | continue; | |
| 511 | 913 | } |
| 512 | self.putBackToken(token); | |
| 914 | }, | |
| 513 | 915 | |
| 514 | stack.append(State { .Expression = dest_ptr }) catch unreachable; | |
| 916 | State.AssignmentExpressionBegin => |dest_ptr| { | |
| 917 | stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable; | |
| 918 | try stack.append(State { .Expression = dest_ptr }); | |
| 515 | 919 | continue; |
| 516 | 920 | }, |
| 517 | 921 | |
| 518 | State.FnProto => |fn_proto| { | |
| 519 | stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable; | |
| 520 | try stack.append(State { .ParamDecl = fn_proto }); | |
| 521 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 922 | State.AssignmentExpressionEnd => |dest_ptr| { | |
| 923 | const token = self.getNextToken(); | |
| 924 | if (tokenIdToAssignment(token.id)) |ass_id| { | |
| 925 | const node = try self.createInfixOp(arena, token, ass_id); | |
| 926 | node.lhs = dest_ptr.get(); | |
| 927 | dest_ptr.store(&node.base); | |
| 522 | 928 | |
| 523 | const next_token = self.getNextToken(); | |
| 524 | if (next_token.id == Token.Id.Identifier) { | |
| 525 | fn_proto.name_token = next_token; | |
| 929 | stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable; | |
| 930 | try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }); | |
| 931 | continue; | |
| 932 | } else { | |
| 933 | self.putBackToken(token); | |
| 526 | 934 | continue; |
| 527 | 935 | } |
| 528 | self.putBackToken(next_token); | |
| 936 | }, | |
| 937 | ||
| 938 | State.UnwrapExpressionBegin => |dest_ptr| { | |
| 939 | stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable; | |
| 940 | try stack.append(State { .BoolOrExpressionBegin = dest_ptr }); | |
| 529 | 941 | continue; |
| 530 | 942 | }, |
| 531 | 943 | |
| 532 | State.FnProtoAlign => |fn_proto| { | |
| 944 | State.UnwrapExpressionEnd => |dest_ptr| { | |
| 533 | 945 | const token = self.getNextToken(); |
| 534 | if (token.id == Token.Id.Keyword_align) { | |
| 535 | @panic("TODO fn proto align"); | |
| 946 | switch (token.id) { | |
| 947 | Token.Id.Keyword_catch => { | |
| 948 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp { .Catch = null }); | |
| 949 | node.lhs = dest_ptr.get(); | |
| 950 | dest_ptr.store(&node.base); | |
| 951 | ||
| 952 | stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable; | |
| 953 | try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }); | |
| 954 | try stack.append(State { .Payload = &node.op.Catch }); | |
| 955 | continue; | |
| 956 | }, | |
| 957 | Token.Id.QuestionMarkQuestionMark => { | |
| 958 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.UnwrapMaybe); | |
| 959 | node.lhs = dest_ptr.get(); | |
| 960 | dest_ptr.store(&node.base); | |
| 961 | ||
| 962 | stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable; | |
| 963 | try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }); | |
| 964 | continue; | |
| 965 | }, | |
| 966 | else => { | |
| 967 | self.putBackToken(token); | |
| 968 | continue; | |
| 969 | }, | |
| 536 | 970 | } |
| 537 | self.putBackToken(token); | |
| 538 | stack.append(State { | |
| 539 | .FnProtoReturnType = fn_proto, | |
| 540 | }) catch unreachable; | |
| 971 | }, | |
| 972 | ||
| 973 | State.BoolOrExpressionBegin => |dest_ptr| { | |
| 974 | stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable; | |
| 975 | try stack.append(State { .BoolAndExpressionBegin = dest_ptr }); | |
| 541 | 976 | continue; |
| 542 | 977 | }, |
| 543 | 978 | |
| 544 | State.FnProtoReturnType => |fn_proto| { | |
| 979 | State.BoolOrExpressionEnd => |dest_ptr| { | |
| 545 | 980 | const token = self.getNextToken(); |
| 546 | 981 | switch (token.id) { |
| 547 | Token.Id.Keyword_var => { | |
| 548 | fn_proto.return_type = ast.NodeFnProto.ReturnType { .Infer = token }; | |
| 549 | }, | |
| 550 | Token.Id.Bang => { | |
| 551 | fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined }; | |
| 552 | stack.append(State { | |
| 553 | .TypeExpr = DestPtr {.Field = &fn_proto.return_type.InferErrorSet}, | |
| 554 | }) catch unreachable; | |
| 982 | Token.Id.Keyword_or => { | |
| 983 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolOr); | |
| 984 | node.lhs = dest_ptr.get(); | |
| 985 | dest_ptr.store(&node.base); | |
| 986 | ||
| 987 | stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable; | |
| 988 | try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 989 | continue; | |
| 555 | 990 | }, |
| 556 | 991 | else => { |
| 557 | 992 | self.putBackToken(token); |
| 558 | fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined }; | |
| 559 | stack.append(State { | |
| 560 | .TypeExpr = DestPtr {.Field = &fn_proto.return_type.Explicit}, | |
| 561 | }) catch unreachable; | |
| 993 | continue; | |
| 562 | 994 | }, |
| 563 | 995 | } |
| 564 | if (token.id == Token.Id.Keyword_align) { | |
| 565 | @panic("TODO fn proto align"); | |
| 566 | } | |
| 996 | }, | |
| 997 | ||
| 998 | State.BoolAndExpressionBegin => |dest_ptr| { | |
| 999 | stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable; | |
| 1000 | try stack.append(State { .ComparisonExpressionBegin = dest_ptr }); | |
| 567 | 1001 | continue; |
| 568 | 1002 | }, |
| 569 | 1003 | |
| 570 | State.ParamDecl => |fn_proto| { | |
| 571 | var token = self.getNextToken(); | |
| 572 | if (token.id == Token.Id.RParen) { | |
| 573 | continue; | |
| 574 | } | |
| 575 | const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params); | |
| 576 | if (token.id == Token.Id.Keyword_comptime) { | |
| 577 | param_decl.comptime_token = token; | |
| 578 | token = self.getNextToken(); | |
| 579 | } else if (token.id == Token.Id.Keyword_noalias) { | |
| 580 | param_decl.noalias_token = token; | |
| 581 | token = self.getNextToken(); | |
| 582 | } | |
| 583 | if (token.id == Token.Id.Identifier) { | |
| 584 | const next_token = self.getNextToken(); | |
| 585 | if (next_token.id == Token.Id.Colon) { | |
| 586 | param_decl.name_token = token; | |
| 587 | token = self.getNextToken(); | |
| 588 | } else { | |
| 589 | self.putBackToken(next_token); | |
| 590 | } | |
| 1004 | State.BoolAndExpressionEnd => |dest_ptr| { | |
| 1005 | const token = self.getNextToken(); | |
| 1006 | switch (token.id) { | |
| 1007 | Token.Id.Keyword_and => { | |
| 1008 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolAnd); | |
| 1009 | node.lhs = dest_ptr.get(); | |
| 1010 | dest_ptr.store(&node.base); | |
| 1011 | ||
| 1012 | stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable; | |
| 1013 | try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 1014 | continue; | |
| 1015 | }, | |
| 1016 | else => { | |
| 1017 | self.putBackToken(token); | |
| 1018 | continue; | |
| 1019 | }, | |
| 591 | 1020 | } |
| 592 | if (token.id == Token.Id.Ellipsis3) { | |
| 593 | param_decl.var_args_token = token; | |
| 594 | stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable; | |
| 1021 | }, | |
| 1022 | ||
| 1023 | State.ComparisonExpressionBegin => |dest_ptr| { | |
| 1024 | stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable; | |
| 1025 | try stack.append(State { .BinaryOrExpressionBegin = dest_ptr }); | |
| 1026 | continue; | |
| 1027 | }, | |
| 1028 | ||
| 1029 | State.ComparisonExpressionEnd => |dest_ptr| { | |
| 1030 | const token = self.getNextToken(); | |
| 1031 | if (tokenIdToComparison(token.id)) |comp_id| { | |
| 1032 | const node = try self.createInfixOp(arena, token, comp_id); | |
| 1033 | node.lhs = dest_ptr.get(); | |
| 1034 | dest_ptr.store(&node.base); | |
| 1035 | ||
| 1036 | stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable; | |
| 1037 | try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 595 | 1038 | continue; |
| 596 | 1039 | } else { |
| 597 | 1040 | self.putBackToken(token); |
| 1041 | continue; | |
| 598 | 1042 | } |
| 1043 | }, | |
| 599 | 1044 | |
| 600 | stack.append(State { .ParamDecl = fn_proto }) catch unreachable; | |
| 601 | try stack.append(State.ParamDeclComma); | |
| 602 | try stack.append(State { | |
| 603 | .TypeExpr = DestPtr {.Field = &param_decl.type_node} | |
| 604 | }); | |
| 1045 | State.BinaryOrExpressionBegin => |dest_ptr| { | |
| 1046 | stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable; | |
| 1047 | try stack.append(State { .BinaryXorExpressionBegin = dest_ptr }); | |
| 605 | 1048 | continue; |
| 606 | 1049 | }, |
| 607 | 1050 | |
| 608 | State.ParamDeclComma => { | |
| 1051 | State.BinaryOrExpressionEnd => |dest_ptr| { | |
| 609 | 1052 | const token = self.getNextToken(); |
| 610 | 1053 | switch (token.id) { |
| 611 | Token.Id.RParen => { | |
| 612 | _ = stack.pop(); // pop off the ParamDecl | |
| 1054 | Token.Id.Pipe => { | |
| 1055 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitOr); | |
| 1056 | node.lhs = dest_ptr.get(); | |
| 1057 | dest_ptr.store(&node.base); | |
| 1058 | ||
| 1059 | stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable; | |
| 1060 | try stack.append(State { .BinaryXorExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 1061 | continue; | |
| 1062 | }, | |
| 1063 | else => { | |
| 1064 | self.putBackToken(token); | |
| 613 | 1065 | continue; |
| 614 | 1066 | }, |
| 615 | Token.Id.Comma => continue, | |
| 616 | else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)), | |
| 617 | 1067 | } |
| 618 | 1068 | }, |
| 619 | 1069 | |
| 620 | State.FnDef => |fn_proto| { | |
| 1070 | State.BinaryXorExpressionBegin => |dest_ptr| { | |
| 1071 | stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable; | |
| 1072 | try stack.append(State { .BinaryAndExpressionBegin = dest_ptr }); | |
| 1073 | continue; | |
| 1074 | }, | |
| 1075 | ||
| 1076 | State.BinaryXorExpressionEnd => |dest_ptr| { | |
| 621 | 1077 | const token = self.getNextToken(); |
| 622 | switch(token.id) { | |
| 623 | Token.Id.LBrace => { | |
| 624 | const block = try self.createBlock(arena, token); | |
| 625 | fn_proto.body_node = &block.base; | |
| 626 | stack.append(State { .Block = block }) catch unreachable; | |
| 1078 | switch (token.id) { | |
| 1079 | Token.Id.Caret => { | |
| 1080 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitXor); | |
| 1081 | node.lhs = dest_ptr.get(); | |
| 1082 | dest_ptr.store(&node.base); | |
| 1083 | ||
| 1084 | stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable; | |
| 1085 | try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 1086 | continue; | |
| 1087 | }, | |
| 1088 | else => { | |
| 1089 | self.putBackToken(token); | |
| 627 | 1090 | continue; |
| 628 | 1091 | }, |
| 629 | Token.Id.Semicolon => continue, | |
| 630 | else => return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id)), | |
| 631 | 1092 | } |
| 632 | 1093 | }, |
| 633 | 1094 | |
| 634 | State.Block => |block| { | |
| 1095 | State.BinaryAndExpressionBegin => |dest_ptr| { | |
| 1096 | stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable; | |
| 1097 | try stack.append(State { .BitShiftExpressionBegin = dest_ptr }); | |
| 1098 | continue; | |
| 1099 | }, | |
| 1100 | ||
| 1101 | State.BinaryAndExpressionEnd => |dest_ptr| { | |
| 635 | 1102 | const token = self.getNextToken(); |
| 636 | 1103 | switch (token.id) { |
| 637 | Token.Id.RBrace => { | |
| 638 | block.end_token = token; | |
| 1104 | Token.Id.Ampersand => { | |
| 1105 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitAnd); | |
| 1106 | node.lhs = dest_ptr.get(); | |
| 1107 | dest_ptr.store(&node.base); | |
| 1108 | ||
| 1109 | stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable; | |
| 1110 | try stack.append(State { .BitShiftExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 639 | 1111 | continue; |
| 640 | 1112 | }, |
| 641 | 1113 | else => { |
| 642 | 1114 | self.putBackToken(token); |
| 643 | stack.append(State { .Block = block }) catch unreachable; | |
| 644 | try stack.append(State { .Statement = block }); | |
| 645 | 1115 | continue; |
| 646 | 1116 | }, |
| 647 | 1117 | } |
| 648 | 1118 | }, |
| 649 | 1119 | |
| 650 | State.Statement => |block| { | |
| 651 | { | |
| 652 | // Look for comptime var, comptime const | |
| 653 | const comptime_token = self.getNextToken(); | |
| 654 | if (comptime_token.id == Token.Id.Keyword_comptime) { | |
| 655 | const mut_token = self.getNextToken(); | |
| 656 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { | |
| 657 | // TODO shouldn't need these casts | |
| 658 | const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null), | |
| 659 | mut_token, (?Token)(comptime_token), (?Token)(null)); | |
| 660 | try stack.append(State { .VarDecl = var_decl }); | |
| 661 | continue; | |
| 662 | } | |
| 663 | self.putBackToken(mut_token); | |
| 664 | } | |
| 665 | self.putBackToken(comptime_token); | |
| 666 | } | |
| 667 | { | |
| 668 | // Look for const, var | |
| 669 | const mut_token = self.getNextToken(); | |
| 670 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { | |
| 671 | // TODO shouldn't need these casts | |
| 672 | const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null), | |
| 673 | mut_token, (?Token)(null), (?Token)(null)); | |
| 674 | try stack.append(State { .VarDecl = var_decl }); | |
| 675 | continue; | |
| 676 | } | |
| 677 | self.putBackToken(mut_token); | |
| 1120 | State.BitShiftExpressionBegin => |dest_ptr| { | |
| 1121 | stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable; | |
| 1122 | try stack.append(State { .AdditionExpressionBegin = dest_ptr }); | |
| 1123 | continue; | |
| 1124 | }, | |
| 1125 | ||
| 1126 | State.BitShiftExpressionEnd => |dest_ptr| { | |
| 1127 | const token = self.getNextToken(); | |
| 1128 | if (tokenIdToBitShift(token.id)) |bitshift_id| { | |
| 1129 | const node = try self.createInfixOp(arena, token, bitshift_id); | |
| 1130 | node.lhs = dest_ptr.get(); | |
| 1131 | dest_ptr.store(&node.base); | |
| 1132 | ||
| 1133 | stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable; | |
| 1134 | try stack.append(State { .AdditionExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 1135 | continue; | |
| 1136 | } else { | |
| 1137 | self.putBackToken(token); | |
| 1138 | continue; | |
| 678 | 1139 | } |
| 1140 | }, | |
| 679 | 1141 | |
| 680 | stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable; | |
| 681 | try stack.append(State { .Expression = DestPtr{.List = &block.statements} }); | |
| 1142 | State.AdditionExpressionBegin => |dest_ptr| { | |
| 1143 | stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable; | |
| 1144 | try stack.append(State { .MultiplyExpressionBegin = dest_ptr }); | |
| 682 | 1145 | continue; |
| 683 | 1146 | }, |
| 684 | 1147 | |
| 685 | // These are data, not control flow. | |
| 686 | State.InfixOp => unreachable, | |
| 687 | State.PrefixOp => unreachable, | |
| 688 | State.Operand => unreachable, | |
| 689 | } | |
| 690 | } | |
| 691 | } | |
| 692 | ||
| 693 | fn initNode(self: &Parser, id: ast.Node.Id) ast.Node { | |
| 694 | if (self.pending_line_comment_node) |comment_node| { | |
| 695 | self.pending_line_comment_node = null; | |
| 696 | return ast.Node {.id = id, .comment = comment_node}; | |
| 697 | } | |
| 698 | return ast.Node {.id = id, .comment = null }; | |
| 699 | } | |
| 1148 | State.AdditionExpressionEnd => |dest_ptr| { | |
| 1149 | const token = self.getNextToken(); | |
| 1150 | if (tokenIdToAddition(token.id)) |add_id| { | |
| 1151 | const node = try self.createInfixOp(arena, token, add_id); | |
| 1152 | node.lhs = dest_ptr.get(); | |
| 1153 | dest_ptr.store(&node.base); | |
| 700 | 1154 | |
| 701 | fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot { | |
| 702 | const node = try arena.create(ast.NodeRoot); | |
| 1155 | stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable; | |
| 1156 | try stack.append(State { .MultiplyExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 1157 | continue; | |
| 1158 | } else { | |
| 1159 | self.putBackToken(token); | |
| 1160 | continue; | |
| 1161 | } | |
| 1162 | }, | |
| 1163 | ||
| 1164 | State.MultiplyExpressionBegin => |dest_ptr| { | |
| 1165 | stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable; | |
| 1166 | try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr }); | |
| 1167 | continue; | |
| 1168 | }, | |
| 1169 | ||
| 1170 | State.MultiplyExpressionEnd => |dest_ptr| { | |
| 1171 | const token = self.getNextToken(); | |
| 1172 | if (tokenIdToMultiply(token.id)) |mult_id| { | |
| 1173 | const node = try self.createInfixOp(arena, token, mult_id); | |
| 1174 | node.lhs = dest_ptr.get(); | |
| 1175 | dest_ptr.store(&node.base); | |
| 1176 | ||
| 1177 | stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable; | |
| 1178 | try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } }); | |
| 1179 | continue; | |
| 1180 | } else { | |
| 1181 | self.putBackToken(token); | |
| 1182 | continue; | |
| 1183 | } | |
| 1184 | }, | |
| 1185 | ||
| 1186 | State.CurlySuffixExpressionBegin => |dest_ptr| { | |
| 1187 | stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable; | |
| 1188 | try stack.append(State { .TypeExprBegin = dest_ptr }); | |
| 1189 | continue; | |
| 1190 | }, | |
| 1191 | ||
| 1192 | State.CurlySuffixExpressionEnd => |dest_ptr| { | |
| 1193 | const token = self.getNextToken(); | |
| 1194 | if (token.id != Token.Id.LBrace) { | |
| 1195 | self.putBackToken(token); | |
| 1196 | continue; | |
| 1197 | } | |
| 1198 | ||
| 1199 | const next = self.getNextToken(); | |
| 1200 | switch (next.id) { | |
| 1201 | Token.Id.Period => { | |
| 1202 | const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp { | |
| 1203 | .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena), | |
| 1204 | }); | |
| 1205 | node.lhs = dest_ptr.get(); | |
| 1206 | dest_ptr.store(&node.base); | |
| 1207 | ||
| 1208 | stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable; | |
| 1209 | try stack.append(State { | |
| 1210 | .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) { | |
| 1211 | .list = &node.op.StructInitializer, | |
| 1212 | .ptr = &node.rtoken, | |
| 1213 | } | |
| 1214 | }); | |
| 1215 | self.putBackToken(next); | |
| 1216 | continue; | |
| 1217 | }, | |
| 1218 | else => { | |
| 1219 | const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp { | |
| 1220 | .ArrayInitializer = ArrayList(&ast.Node).init(arena), | |
| 1221 | }); | |
| 1222 | node.lhs = dest_ptr.get(); | |
| 1223 | dest_ptr.store(&node.base); | |
| 1224 | ||
| 1225 | stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable; | |
| 1226 | try stack.append(State { | |
| 1227 | .ExprListItemOrEnd = ExprListCtx { | |
| 1228 | .list = &node.op.ArrayInitializer, | |
| 1229 | .end = Token.Id.RBrace, | |
| 1230 | .ptr = &node.rtoken, | |
| 1231 | } | |
| 1232 | }); | |
| 1233 | self.putBackToken(next); | |
| 1234 | continue; | |
| 1235 | }, | |
| 1236 | } | |
| 1237 | }, | |
| 1238 | ||
| 1239 | State.TypeExprBegin => |dest_ptr| { | |
| 1240 | stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable; | |
| 1241 | try stack.append(State { .PrefixOpExpression = dest_ptr }); | |
| 1242 | continue; | |
| 1243 | }, | |
| 1244 | ||
| 1245 | State.TypeExprEnd => |dest_ptr| { | |
| 1246 | const token = self.getNextToken(); | |
| 1247 | switch (token.id) { | |
| 1248 | Token.Id.Bang => { | |
| 1249 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.ErrorUnion); | |
| 1250 | node.lhs = dest_ptr.get(); | |
| 1251 | dest_ptr.store(&node.base); | |
| 1252 | ||
| 1253 | stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable; | |
| 1254 | try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } }); | |
| 1255 | continue; | |
| 1256 | }, | |
| 1257 | else => { | |
| 1258 | self.putBackToken(token); | |
| 1259 | continue; | |
| 1260 | }, | |
| 1261 | } | |
| 1262 | }, | |
| 1263 | ||
| 1264 | State.PrefixOpExpression => |dest_ptr| { | |
| 1265 | const token = self.getNextToken(); | |
| 1266 | if (tokenIdToPrefixOp(token.id)) |prefix_id| { | |
| 1267 | const node = try self.createPrefixOp(arena, token, prefix_id); | |
| 1268 | dest_ptr.store(&node.base); | |
| 1269 | ||
| 1270 | stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable; | |
| 1271 | if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) { | |
| 1272 | try stack.append(State { .AddrOfModifiers = &node.op.AddrOf }); | |
| 1273 | } | |
| 1274 | continue; | |
| 1275 | } else { | |
| 1276 | self.putBackToken(token); | |
| 1277 | stack.append(State { .SuffixOpExpressionBegin = dest_ptr }) catch unreachable; | |
| 1278 | continue; | |
| 1279 | } | |
| 1280 | }, | |
| 1281 | ||
| 1282 | State.SuffixOpExpressionBegin => |dest_ptr| { | |
| 1283 | const token = self.getNextToken(); | |
| 1284 | switch (token.id) { | |
| 1285 | Token.Id.Keyword_async => { | |
| 1286 | const async_node = try arena.create(ast.NodeAsyncAttribute); | |
| 1287 | *async_node = ast.NodeAsyncAttribute { | |
| 1288 | .base = self.initNode(ast.Node.Id.AsyncAttribute), | |
| 1289 | .async_token = token, | |
| 1290 | .allocator_type = null, | |
| 1291 | .rangle_bracket = null, | |
| 1292 | }; | |
| 1293 | ||
| 1294 | stack.append(State { | |
| 1295 | .AsyncEnd = AsyncEndCtx { | |
| 1296 | .dest_ptr = dest_ptr, | |
| 1297 | .attribute = async_node, | |
| 1298 | } | |
| 1299 | }) catch unreachable; | |
| 1300 | try stack.append(State { .SuffixOpExpressionEnd = dest_ptr }); | |
| 1301 | try stack.append(State { .PrimaryExpression = dest_ptr }); | |
| 1302 | ||
| 1303 | const langle_bracket = self.getNextToken(); | |
| 1304 | if (langle_bracket.id != Token.Id.AngleBracketLeft) { | |
| 1305 | self.putBackToken(langle_bracket); | |
| 1306 | continue; | |
| 1307 | } | |
| 1308 | ||
| 1309 | async_node.rangle_bracket = Token(undefined); | |
| 1310 | try stack.append(State { | |
| 1311 | .ExpectTokenSave = ExpectTokenSave { | |
| 1312 | .id = Token.Id.AngleBracketRight, | |
| 1313 | .ptr = &??async_node.rangle_bracket, | |
| 1314 | } | |
| 1315 | }); | |
| 1316 | try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } }); | |
| 1317 | continue; | |
| 1318 | }, | |
| 1319 | else => { | |
| 1320 | self.putBackToken(token); | |
| 1321 | stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable; | |
| 1322 | try stack.append(State { .PrimaryExpression = dest_ptr }); | |
| 1323 | continue; | |
| 1324 | } | |
| 1325 | } | |
| 1326 | }, | |
| 1327 | ||
| 1328 | State.SuffixOpExpressionEnd => |dest_ptr| { | |
| 1329 | const token = self.getNextToken(); | |
| 1330 | switch (token.id) { | |
| 1331 | Token.Id.LParen => { | |
| 1332 | const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp { | |
| 1333 | .Call = ast.NodeSuffixOp.CallInfo { | |
| 1334 | .params = ArrayList(&ast.Node).init(arena), | |
| 1335 | .async_attr = null, | |
| 1336 | } | |
| 1337 | }); | |
| 1338 | node.lhs = dest_ptr.get(); | |
| 1339 | dest_ptr.store(&node.base); | |
| 1340 | ||
| 1341 | stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable; | |
| 1342 | try stack.append(State { | |
| 1343 | .ExprListItemOrEnd = ExprListCtx { | |
| 1344 | .list = &node.op.Call.params, | |
| 1345 | .end = Token.Id.RParen, | |
| 1346 | .ptr = &node.rtoken, | |
| 1347 | } | |
| 1348 | }); | |
| 1349 | continue; | |
| 1350 | }, | |
| 1351 | Token.Id.LBracket => { | |
| 1352 | const node = try arena.create(ast.NodeSuffixOp); | |
| 1353 | *node = ast.NodeSuffixOp { | |
| 1354 | .base = self.initNode(ast.Node.Id.SuffixOp), | |
| 1355 | .lhs = undefined, | |
| 1356 | .op = ast.NodeSuffixOp.SuffixOp { | |
| 1357 | .ArrayAccess = undefined, | |
| 1358 | }, | |
| 1359 | .rtoken = undefined, | |
| 1360 | }; | |
| 1361 | node.lhs = dest_ptr.get(); | |
| 1362 | dest_ptr.store(&node.base); | |
| 1363 | ||
| 1364 | stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable; | |
| 1365 | try stack.append(State { .SliceOrArrayAccess = node }); | |
| 1366 | try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }}); | |
| 1367 | continue; | |
| 1368 | }, | |
| 1369 | Token.Id.Period => { | |
| 1370 | const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period); | |
| 1371 | node.lhs = dest_ptr.get(); | |
| 1372 | dest_ptr.store(&node.base); | |
| 1373 | ||
| 1374 | stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable; | |
| 1375 | try stack.append(State { .SuffixOpExpressionBegin = DestPtr { .Field = &node.rhs }}); | |
| 1376 | continue; | |
| 1377 | }, | |
| 1378 | else => { | |
| 1379 | self.putBackToken(token); | |
| 1380 | continue; | |
| 1381 | }, | |
| 1382 | } | |
| 1383 | }, | |
| 1384 | ||
| 1385 | State.PrimaryExpression => |dest_ptr| { | |
| 1386 | const token = self.getNextToken(); | |
| 1387 | switch (token.id) { | |
| 1388 | Token.Id.IntegerLiteral => { | |
| 1389 | dest_ptr.store(&(try self.createIntegerLiteral(arena, token)).base); | |
| 1390 | continue; | |
| 1391 | }, | |
| 1392 | Token.Id.FloatLiteral => { | |
| 1393 | dest_ptr.store(&(try self.createFloatLiteral(arena, token)).base); | |
| 1394 | continue; | |
| 1395 | }, | |
| 1396 | Token.Id.StringLiteral => { | |
| 1397 | dest_ptr.store(&(try self.createStringLiteral(arena, token)).base); | |
| 1398 | continue; | |
| 1399 | }, | |
| 1400 | Token.Id.CharLiteral => { | |
| 1401 | const node = try arena.create(ast.NodeCharLiteral); | |
| 1402 | *node = ast.NodeCharLiteral { | |
| 1403 | .base = self.initNode(ast.Node.Id.CharLiteral), | |
| 1404 | .token = token, | |
| 1405 | }; | |
| 1406 | dest_ptr.store(&node.base); | |
| 1407 | continue; | |
| 1408 | }, | |
| 1409 | Token.Id.Keyword_undefined => { | |
| 1410 | dest_ptr.store(&(try self.createUndefined(arena, token)).base); | |
| 1411 | continue; | |
| 1412 | }, | |
| 1413 | Token.Id.Keyword_true, Token.Id.Keyword_false => { | |
| 1414 | const node = try arena.create(ast.NodeBoolLiteral); | |
| 1415 | *node = ast.NodeBoolLiteral { | |
| 1416 | .base = self.initNode(ast.Node.Id.BoolLiteral), | |
| 1417 | .token = token, | |
| 1418 | }; | |
| 1419 | dest_ptr.store(&node.base); | |
| 1420 | continue; | |
| 1421 | }, | |
| 1422 | Token.Id.Keyword_null => { | |
| 1423 | const node = try arena.create(ast.NodeNullLiteral); | |
| 1424 | *node = ast.NodeNullLiteral { | |
| 1425 | .base = self.initNode(ast.Node.Id.NullLiteral), | |
| 1426 | .token = token, | |
| 1427 | }; | |
| 1428 | dest_ptr.store(&node.base); | |
| 1429 | continue; | |
| 1430 | }, | |
| 1431 | Token.Id.Keyword_this => { | |
| 1432 | const node = try arena.create(ast.NodeThisLiteral); | |
| 1433 | *node = ast.NodeThisLiteral { | |
| 1434 | .base = self.initNode(ast.Node.Id.ThisLiteral), | |
| 1435 | .token = token, | |
| 1436 | }; | |
| 1437 | dest_ptr.store(&node.base); | |
| 1438 | continue; | |
| 1439 | }, | |
| 1440 | Token.Id.Keyword_var => { | |
| 1441 | const node = try arena.create(ast.NodeVarType); | |
| 1442 | *node = ast.NodeVarType { | |
| 1443 | .base = self.initNode(ast.Node.Id.VarType), | |
| 1444 | .token = token, | |
| 1445 | }; | |
| 1446 | dest_ptr.store(&node.base); | |
| 1447 | }, | |
| 1448 | Token.Id.Keyword_unreachable => { | |
| 1449 | const node = try arena.create(ast.NodeUnreachable); | |
| 1450 | *node = ast.NodeUnreachable { | |
| 1451 | .base = self.initNode(ast.Node.Id.Unreachable), | |
| 1452 | .token = token, | |
| 1453 | }; | |
| 1454 | dest_ptr.store(&node.base); | |
| 1455 | continue; | |
| 1456 | }, | |
| 1457 | Token.Id.MultilineStringLiteralLine => { | |
| 1458 | const node = try arena.create(ast.NodeMultilineStringLiteral); | |
| 1459 | *node = ast.NodeMultilineStringLiteral { | |
| 1460 | .base = self.initNode(ast.Node.Id.MultilineStringLiteral), | |
| 1461 | .tokens = ArrayList(Token).init(arena), | |
| 1462 | }; | |
| 1463 | dest_ptr.store(&node.base); | |
| 1464 | try node.tokens.append(token); | |
| 1465 | ||
| 1466 | while (true) { | |
| 1467 | const multiline_str = self.getNextToken(); | |
| 1468 | if (multiline_str.id != Token.Id.MultilineStringLiteralLine) { | |
| 1469 | self.putBackToken(multiline_str); | |
| 1470 | break; | |
| 1471 | } | |
| 1472 | ||
| 1473 | try node.tokens.append(multiline_str); | |
| 1474 | } | |
| 1475 | continue; | |
| 1476 | }, | |
| 1477 | Token.Id.LParen => { | |
| 1478 | const node = try arena.create(ast.NodeGroupedExpression); | |
| 1479 | *node = ast.NodeGroupedExpression { | |
| 1480 | .base = self.initNode(ast.Node.Id.GroupedExpression), | |
| 1481 | .lparen = token, | |
| 1482 | .expr = undefined, | |
| 1483 | .rparen = undefined, | |
| 1484 | }; | |
| 1485 | dest_ptr.store(&node.base); | |
| 1486 | stack.append(State { | |
| 1487 | .ExpectTokenSave = ExpectTokenSave { | |
| 1488 | .id = Token.Id.RParen, | |
| 1489 | .ptr = &node.rparen, | |
| 1490 | } | |
| 1491 | }) catch unreachable; | |
| 1492 | try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); | |
| 1493 | continue; | |
| 1494 | }, | |
| 1495 | Token.Id.Builtin => { | |
| 1496 | const node = try arena.create(ast.NodeBuiltinCall); | |
| 1497 | *node = ast.NodeBuiltinCall { | |
| 1498 | .base = self.initNode(ast.Node.Id.BuiltinCall), | |
| 1499 | .builtin_token = token, | |
| 1500 | .params = ArrayList(&ast.Node).init(arena), | |
| 1501 | .rparen_token = undefined, | |
| 1502 | }; | |
| 1503 | dest_ptr.store(&node.base); | |
| 1504 | stack.append(State { | |
| 1505 | .ExprListItemOrEnd = ExprListCtx { | |
| 1506 | .list = &node.params, | |
| 1507 | .end = Token.Id.RParen, | |
| 1508 | .ptr = &node.rparen_token, | |
| 1509 | } | |
| 1510 | }) catch unreachable; | |
| 1511 | try stack.append(State { .ExpectToken = Token.Id.LParen, }); | |
| 1512 | continue; | |
| 1513 | }, | |
| 1514 | Token.Id.LBracket => { | |
| 1515 | const rbracket_token = self.getNextToken(); | |
| 1516 | if (rbracket_token.id == Token.Id.RBracket) { | |
| 1517 | const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{ | |
| 1518 | .SliceType = ast.NodePrefixOp.AddrOfInfo { | |
| 1519 | .align_expr = null, | |
| 1520 | .bit_offset_start_token = null, | |
| 1521 | .bit_offset_end_token = null, | |
| 1522 | .const_token = null, | |
| 1523 | .volatile_token = null, | |
| 1524 | } | |
| 1525 | }); | |
| 1526 | dest_ptr.store(&node.base); | |
| 1527 | stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable; | |
| 1528 | try stack.append(State { .AddrOfModifiers = &node.op.SliceType }); | |
| 1529 | continue; | |
| 1530 | } | |
| 1531 | ||
| 1532 | self.putBackToken(rbracket_token); | |
| 1533 | ||
| 1534 | const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{ | |
| 1535 | .ArrayType = undefined, | |
| 1536 | }); | |
| 1537 | dest_ptr.store(&node.base); | |
| 1538 | stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable; | |
| 1539 | try stack.append(State { .ExpectToken = Token.Id.RBracket }); | |
| 1540 | try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayType } }); | |
| 1541 | ||
| 1542 | }, | |
| 1543 | Token.Id.Keyword_error => { | |
| 1544 | const next = self.getNextToken(); | |
| 1545 | ||
| 1546 | if (next.id != Token.Id.LBrace) { | |
| 1547 | self.putBackToken(next); | |
| 1548 | const node = try arena.create(ast.NodeErrorType); | |
| 1549 | *node = ast.NodeErrorType { | |
| 1550 | .base = self.initNode(ast.Node.Id.ErrorType), | |
| 1551 | .token = token, | |
| 1552 | }; | |
| 1553 | dest_ptr.store(&node.base); | |
| 1554 | continue; | |
| 1555 | } | |
| 1556 | ||
| 1557 | const node = try arena.create(ast.NodeErrorSetDecl); | |
| 1558 | *node = ast.NodeErrorSetDecl { | |
| 1559 | .base = self.initNode(ast.Node.Id.ErrorSetDecl), | |
| 1560 | .error_token = token, | |
| 1561 | .decls = ArrayList(&ast.NodeIdentifier).init(arena), | |
| 1562 | .rbrace_token = undefined, | |
| 1563 | }; | |
| 1564 | dest_ptr.store(&node.base); | |
| 1565 | ||
| 1566 | while (true) { | |
| 1567 | const t = self.getNextToken(); | |
| 1568 | switch (t.id) { | |
| 1569 | Token.Id.RBrace => { | |
| 1570 | node.rbrace_token = t; | |
| 1571 | break; | |
| 1572 | }, | |
| 1573 | Token.Id.Identifier => { | |
| 1574 | try node.decls.append( | |
| 1575 | try self.createIdentifier(arena, t) | |
| 1576 | ); | |
| 1577 | }, | |
| 1578 | else => { | |
| 1579 | try self.parseError(&stack, token, "expected {} or {}, found {}", | |
| 1580 | @tagName(Token.Id.RBrace), | |
| 1581 | @tagName(Token.Id.Identifier), | |
| 1582 | @tagName(token.id)); | |
| 1583 | continue; | |
| 1584 | } | |
| 1585 | } | |
| 1586 | ||
| 1587 | const t2 = self.getNextToken(); | |
| 1588 | switch (t2.id) { | |
| 1589 | Token.Id.RBrace => { | |
| 1590 | node.rbrace_token = t; | |
| 1591 | break; | |
| 1592 | }, | |
| 1593 | Token.Id.Comma => continue, | |
| 1594 | else => { | |
| 1595 | try self.parseError(&stack, token, "expected {} or {}, found {}", | |
| 1596 | @tagName(Token.Id.RBrace), | |
| 1597 | @tagName(Token.Id.Comma), | |
| 1598 | @tagName(token.id)); | |
| 1599 | continue; | |
| 1600 | } | |
| 1601 | } | |
| 1602 | } | |
| 1603 | continue; | |
| 1604 | }, | |
| 1605 | Token.Id.Keyword_packed => { | |
| 1606 | stack.append(State { | |
| 1607 | .ContainerExtern = ContainerExternCtx { | |
| 1608 | .dest_ptr = dest_ptr, | |
| 1609 | .ltoken = token, | |
| 1610 | .layout = ast.NodeContainerDecl.Layout.Packed, | |
| 1611 | }, | |
| 1612 | }) catch unreachable; | |
| 1613 | }, | |
| 1614 | Token.Id.Keyword_extern => { | |
| 1615 | const next = self.getNextToken(); | |
| 1616 | if (next.id == Token.Id.Keyword_fn) { | |
| 1617 | // TODO shouldn't need this cast | |
| 1618 | const fn_proto = try self.createFnProto(arena, next, | |
| 1619 | (?Token)(token), (?&ast.Node)(null), (?Token)(null), (?Token)(null), (?Token)(null)); | |
| 1620 | dest_ptr.store(&fn_proto.base); | |
| 1621 | stack.append(State { .FnProto = fn_proto }) catch unreachable; | |
| 1622 | continue; | |
| 1623 | } | |
| 1624 | ||
| 1625 | self.putBackToken(next); | |
| 1626 | stack.append(State { | |
| 1627 | .ContainerExtern = ContainerExternCtx { | |
| 1628 | .dest_ptr = dest_ptr, | |
| 1629 | .ltoken = token, | |
| 1630 | .layout = ast.NodeContainerDecl.Layout.Extern, | |
| 1631 | }, | |
| 1632 | }) catch unreachable; | |
| 1633 | }, | |
| 1634 | Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => { | |
| 1635 | self.putBackToken(token); | |
| 1636 | stack.append(State { | |
| 1637 | .ContainerExtern = ContainerExternCtx { | |
| 1638 | .dest_ptr = dest_ptr, | |
| 1639 | .ltoken = token, | |
| 1640 | .layout = ast.NodeContainerDecl.Layout.Auto, | |
| 1641 | }, | |
| 1642 | }) catch unreachable; | |
| 1643 | }, | |
| 1644 | Token.Id.Identifier => { | |
| 1645 | const next = self.getNextToken(); | |
| 1646 | if (next.id != Token.Id.Colon) { | |
| 1647 | self.putBackToken(next); | |
| 1648 | dest_ptr.store(&(try self.createIdentifier(arena, token)).base); | |
| 1649 | continue; | |
| 1650 | } | |
| 1651 | ||
| 1652 | stack.append(State { | |
| 1653 | .LabeledExpression = LabelCtx { | |
| 1654 | .label = token, | |
| 1655 | .dest_ptr = dest_ptr | |
| 1656 | } | |
| 1657 | }) catch unreachable; | |
| 1658 | continue; | |
| 1659 | }, | |
| 1660 | Token.Id.Keyword_fn => { | |
| 1661 | // TODO shouldn't need these casts | |
| 1662 | const fn_proto = try self.createFnProto(arena, token, | |
| 1663 | (?Token)(null), (?&ast.Node)(null), (?Token)(null), (?Token)(null), (?Token)(null)); | |
| 1664 | dest_ptr.store(&fn_proto.base); | |
| 1665 | stack.append(State { .FnProto = fn_proto }) catch unreachable; | |
| 1666 | continue; | |
| 1667 | }, | |
| 1668 | Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { | |
| 1669 | const fn_token = (try self.eatToken(&stack, Token.Id.Keyword_fn)) ?? continue; | |
| 1670 | // TODO shouldn't need this cast | |
| 1671 | const fn_proto = try self.createFnProto(arena, fn_token, | |
| 1672 | (?Token)(null), (?&ast.Node)(null), (?Token)(token), (?Token)(null), (?Token)(null)); | |
| 1673 | dest_ptr.store(&fn_proto.base); | |
| 1674 | stack.append(State { .FnProto = fn_proto }) catch unreachable; | |
| 1675 | continue; | |
| 1676 | }, | |
| 1677 | Token.Id.Keyword_asm => { | |
| 1678 | const is_volatile = blk: { | |
| 1679 | const volatile_token = self.getNextToken(); | |
| 1680 | if (volatile_token.id != Token.Id.Keyword_volatile) { | |
| 1681 | self.putBackToken(volatile_token); | |
| 1682 | break :blk false; | |
| 1683 | } | |
| 1684 | break :blk true; | |
| 1685 | }; | |
| 1686 | _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue; | |
| 1687 | const template = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue; | |
| 1688 | // TODO parse template | |
| 1689 | ||
| 1690 | const node = try arena.create(ast.NodeAsm); | |
| 1691 | *node = ast.NodeAsm { | |
| 1692 | .base = self.initNode(ast.Node.Id.Asm), | |
| 1693 | .asm_token = token, | |
| 1694 | .is_volatile = is_volatile, | |
| 1695 | .template = template, | |
| 1696 | //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena), | |
| 1697 | .outputs = ArrayList(&ast.NodeAsmOutput).init(arena), | |
| 1698 | .inputs = ArrayList(&ast.NodeAsmInput).init(arena), | |
| 1699 | .cloppers = ArrayList(&ast.NodeStringLiteral).init(arena), | |
| 1700 | .rparen = undefined, | |
| 1701 | }; | |
| 1702 | dest_ptr.store(&node.base); | |
| 1703 | ||
| 1704 | stack.append(State { | |
| 1705 | .ExpectTokenSave = ExpectTokenSave { | |
| 1706 | .id = Token.Id.RParen, | |
| 1707 | .ptr = &node.rparen, | |
| 1708 | } | |
| 1709 | }) catch unreachable; | |
| 1710 | try stack.append(State { .AsmClopperItems = &node.cloppers }); | |
| 1711 | try stack.append(State { .IfToken = Token.Id.Colon }); | |
| 1712 | try stack.append(State { .AsmInputItems = &node.inputs }); | |
| 1713 | try stack.append(State { .IfToken = Token.Id.Colon }); | |
| 1714 | try stack.append(State { .AsmOutputItems = &node.outputs }); | |
| 1715 | try stack.append(State { .IfToken = Token.Id.Colon }); | |
| 1716 | }, | |
| 1717 | Token.Id.Keyword_inline => { | |
| 1718 | stack.append(State { | |
| 1719 | .Inline = InlineCtx { | |
| 1720 | .label = null, | |
| 1721 | .inline_token = token, | |
| 1722 | .dest_ptr = dest_ptr, | |
| 1723 | } | |
| 1724 | }) catch unreachable; | |
| 1725 | continue; | |
| 1726 | }, | |
| 1727 | else => { | |
| 1728 | try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id)); | |
| 1729 | continue; | |
| 1730 | } | |
| 1731 | } | |
| 1732 | }, | |
| 1733 | ||
| 1734 | State.SliceOrArrayAccess => |node| { | |
| 1735 | var token = self.getNextToken(); | |
| 1736 | ||
| 1737 | switch (token.id) { | |
| 1738 | Token.Id.Ellipsis2 => { | |
| 1739 | const start = node.op.ArrayAccess; | |
| 1740 | node.op = ast.NodeSuffixOp.SuffixOp { | |
| 1741 | .Slice = ast.NodeSuffixOp.SliceRange { | |
| 1742 | .start = start, | |
| 1743 | .end = undefined, | |
| 1744 | } | |
| 1745 | }; | |
| 1746 | ||
| 1747 | const rbracket_token = self.getNextToken(); | |
| 1748 | if (rbracket_token.id != Token.Id.RBracket) { | |
| 1749 | self.putBackToken(rbracket_token); | |
| 1750 | stack.append(State { | |
| 1751 | .ExpectTokenSave = ExpectTokenSave { | |
| 1752 | .id = Token.Id.RBracket, | |
| 1753 | .ptr = &node.rtoken, | |
| 1754 | } | |
| 1755 | }) catch unreachable; | |
| 1756 | try stack.append(State { .Expression = DestPtr { .NullableField = &node.op.Slice.end } }); | |
| 1757 | } else { | |
| 1758 | node.rtoken = rbracket_token; | |
| 1759 | } | |
| 1760 | continue; | |
| 1761 | }, | |
| 1762 | Token.Id.RBracket => { | |
| 1763 | node.rtoken = token; | |
| 1764 | continue; | |
| 1765 | }, | |
| 1766 | else => { | |
| 1767 | try self.parseError(&stack, token, "expected ']' or '..', found {}", @tagName(token.id)); | |
| 1768 | continue; | |
| 1769 | } | |
| 1770 | } | |
| 1771 | }, | |
| 1772 | ||
| 1773 | ||
| 1774 | State.AsmOutputItems => |items| { | |
| 1775 | const lbracket = self.getNextToken(); | |
| 1776 | if (lbracket.id != Token.Id.LBracket) { | |
| 1777 | self.putBackToken(lbracket); | |
| 1778 | continue; | |
| 1779 | } | |
| 1780 | ||
| 1781 | stack.append(State { .AsmOutputItems = items }) catch unreachable; | |
| 1782 | try stack.append(State { .IfToken = Token.Id.Comma }); | |
| 1783 | ||
| 1784 | const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 1785 | _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue; | |
| 1786 | const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue; | |
| 1787 | ||
| 1788 | _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue; | |
| 1789 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 1790 | ||
| 1791 | const node = try arena.create(ast.NodeAsmOutput); | |
| 1792 | *node = ast.NodeAsmOutput { | |
| 1793 | .base = self.initNode(ast.Node.Id.AsmOutput), | |
| 1794 | .symbolic_name = try self.createIdentifier(arena, symbolic_name), | |
| 1795 | .constraint = try self.createStringLiteral(arena, constraint), | |
| 1796 | .kind = undefined, | |
| 1797 | }; | |
| 1798 | try items.append(node); | |
| 1799 | ||
| 1800 | const symbol_or_arrow = self.getNextToken(); | |
| 1801 | switch (symbol_or_arrow.id) { | |
| 1802 | Token.Id.Identifier => { | |
| 1803 | node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createIdentifier(arena, symbol_or_arrow) }; | |
| 1804 | }, | |
| 1805 | Token.Id.Arrow => { | |
| 1806 | node.kind = ast.NodeAsmOutput.Kind { .Return = undefined }; | |
| 1807 | try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } }); | |
| 1808 | }, | |
| 1809 | else => { | |
| 1810 | try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}", | |
| 1811 | @tagName(Token.Id.Identifier), | |
| 1812 | @tagName(symbol_or_arrow.id)); | |
| 1813 | continue; | |
| 1814 | }, | |
| 1815 | } | |
| 1816 | }, | |
| 1817 | ||
| 1818 | State.AsmInputItems => |items| { | |
| 1819 | const lbracket = self.getNextToken(); | |
| 1820 | if (lbracket.id != Token.Id.LBracket) { | |
| 1821 | self.putBackToken(lbracket); | |
| 1822 | continue; | |
| 1823 | } | |
| 1824 | ||
| 1825 | stack.append(State { .AsmInputItems = items }) catch unreachable; | |
| 1826 | try stack.append(State { .IfToken = Token.Id.Comma }); | |
| 1827 | ||
| 1828 | const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 1829 | _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue; | |
| 1830 | const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue; | |
| 1831 | ||
| 1832 | _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue; | |
| 1833 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 1834 | ||
| 1835 | const node = try arena.create(ast.NodeAsmInput); | |
| 1836 | *node = ast.NodeAsmInput { | |
| 1837 | .base = self.initNode(ast.Node.Id.AsmInput), | |
| 1838 | .symbolic_name = try self.createIdentifier(arena, symbolic_name), | |
| 1839 | .constraint = try self.createStringLiteral(arena, constraint), | |
| 1840 | .expr = undefined, | |
| 1841 | }; | |
| 1842 | try items.append(node); | |
| 1843 | try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); | |
| 1844 | }, | |
| 1845 | ||
| 1846 | State.AsmClopperItems => |items| { | |
| 1847 | const string = self.getNextToken(); | |
| 1848 | if (string.id != Token.Id.StringLiteral) { | |
| 1849 | self.putBackToken(string); | |
| 1850 | continue; | |
| 1851 | } | |
| 1852 | ||
| 1853 | try items.append(try self.createStringLiteral(arena, string)); | |
| 1854 | stack.append(State { .AsmClopperItems = items }) catch unreachable; | |
| 1855 | try stack.append(State { .IfToken = Token.Id.Comma }); | |
| 1856 | }, | |
| 1857 | ||
| 1858 | State.ExprListItemOrEnd => |list_state| { | |
| 1859 | var token = self.getNextToken(); | |
| 1860 | ||
| 1861 | const IdTag = @TagType(Token.Id); | |
| 1862 | if (IdTag(list_state.end) == token.id) { | |
| 1863 | *list_state.ptr = token; | |
| 1864 | continue; | |
| 1865 | } | |
| 1866 | ||
| 1867 | self.putBackToken(token); | |
| 1868 | stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable; | |
| 1869 | try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } }); | |
| 1870 | }, | |
| 1871 | ||
| 1872 | State.FieldInitListItemOrEnd => |list_state| { | |
| 1873 | var token = self.getNextToken(); | |
| 1874 | ||
| 1875 | if (token.id == Token.Id.RBrace){ | |
| 1876 | *list_state.ptr = token; | |
| 1877 | continue; | |
| 1878 | } | |
| 1879 | ||
| 1880 | self.putBackToken(token); | |
| 1881 | ||
| 1882 | const node = try arena.create(ast.NodeFieldInitializer); | |
| 1883 | *node = ast.NodeFieldInitializer { | |
| 1884 | .base = self.initNode(ast.Node.Id.FieldInitializer), | |
| 1885 | .period_token = undefined, | |
| 1886 | .name_token = undefined, | |
| 1887 | .expr = undefined, | |
| 1888 | }; | |
| 1889 | try list_state.list.append(node); | |
| 1890 | ||
| 1891 | stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable; | |
| 1892 | try stack.append(State { .Expression = DestPtr{.Field = &node.expr} }); | |
| 1893 | try stack.append(State { .ExpectToken = Token.Id.Equal }); | |
| 1894 | try stack.append(State { | |
| 1895 | .ExpectTokenSave = ExpectTokenSave { | |
| 1896 | .id = Token.Id.Identifier, | |
| 1897 | .ptr = &node.name_token, | |
| 1898 | } | |
| 1899 | }); | |
| 1900 | try stack.append(State { | |
| 1901 | .ExpectTokenSave = ExpectTokenSave { | |
| 1902 | .id = Token.Id.Period, | |
| 1903 | .ptr = &node.period_token, | |
| 1904 | } | |
| 1905 | }); | |
| 1906 | }, | |
| 1907 | ||
| 1908 | State.SwitchCaseOrEnd => |list_state| { | |
| 1909 | var token = self.getNextToken(); | |
| 1910 | ||
| 1911 | if (token.id == Token.Id.RBrace){ | |
| 1912 | *list_state.ptr = token; | |
| 1913 | continue; | |
| 1914 | } | |
| 1915 | ||
| 1916 | self.putBackToken(token); | |
| 1917 | ||
| 1918 | const node = try arena.create(ast.NodeSwitchCase); | |
| 1919 | *node = ast.NodeSwitchCase { | |
| 1920 | .base = self.initNode(ast.Node.Id.SwitchCase), | |
| 1921 | .items = ArrayList(&ast.Node).init(arena), | |
| 1922 | .payload = null, | |
| 1923 | .expr = undefined, | |
| 1924 | }; | |
| 1925 | try list_state.list.append(node); | |
| 1926 | stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable; | |
| 1927 | try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } }); | |
| 1928 | try stack.append(State { .PointerPayload = &node.payload }); | |
| 1929 | ||
| 1930 | const maybe_else = self.getNextToken(); | |
| 1931 | if (maybe_else.id == Token.Id.Keyword_else) { | |
| 1932 | const else_node = try arena.create(ast.NodeSwitchElse); | |
| 1933 | *else_node = ast.NodeSwitchElse { | |
| 1934 | .base = self.initNode(ast.Node.Id.SwitchElse), | |
| 1935 | .token = maybe_else, | |
| 1936 | }; | |
| 1937 | try node.items.append(&else_node.base); | |
| 1938 | try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight }); | |
| 1939 | continue; | |
| 1940 | } else { | |
| 1941 | self.putBackToken(maybe_else); | |
| 1942 | try stack.append(State { .SwitchCaseItem = &node.items }); | |
| 1943 | continue; | |
| 1944 | } | |
| 1945 | }, | |
| 1946 | ||
| 1947 | State.SwitchCaseItem => |case_items| { | |
| 1948 | stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable; | |
| 1949 | try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } }); | |
| 1950 | }, | |
| 1951 | ||
| 1952 | State.ExprListCommaOrEnd => |list_state| { | |
| 1953 | try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state }); | |
| 1954 | continue; | |
| 1955 | }, | |
| 1956 | ||
| 1957 | State.FieldInitListCommaOrEnd => |list_state| { | |
| 1958 | try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state }); | |
| 1959 | continue; | |
| 1960 | }, | |
| 1961 | ||
| 1962 | State.FieldListCommaOrEnd => |container_decl| { | |
| 1963 | try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token, | |
| 1964 | State { .ContainerDecl = container_decl }); | |
| 1965 | continue; | |
| 1966 | }, | |
| 1967 | ||
| 1968 | State.SwitchCaseCommaOrEnd => |list_state| { | |
| 1969 | try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state }); | |
| 1970 | continue; | |
| 1971 | }, | |
| 1972 | ||
| 1973 | State.SwitchCaseItemCommaOrEnd => |case_items| { | |
| 1974 | try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items }); | |
| 1975 | continue; | |
| 1976 | }, | |
| 1977 | ||
| 1978 | State.Else => |dest| { | |
| 1979 | const else_token = self.getNextToken(); | |
| 1980 | if (else_token.id != Token.Id.Keyword_else) { | |
| 1981 | self.putBackToken(else_token); | |
| 1982 | continue; | |
| 1983 | } | |
| 1984 | ||
| 1985 | const node = try arena.create(ast.NodeElse); | |
| 1986 | *node = ast.NodeElse { | |
| 1987 | .base = self.initNode(ast.Node.Id.Else), | |
| 1988 | .else_token = else_token, | |
| 1989 | .payload = null, | |
| 1990 | .body = undefined, | |
| 1991 | }; | |
| 1992 | *dest = node; | |
| 1993 | ||
| 1994 | stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable; | |
| 1995 | try stack.append(State { .Payload = &node.payload }); | |
| 1996 | }, | |
| 1997 | ||
| 1998 | State.WhileContinueExpr => |dest| { | |
| 1999 | const colon = self.getNextToken(); | |
| 2000 | if (colon.id != Token.Id.Colon) { | |
| 2001 | self.putBackToken(colon); | |
| 2002 | continue; | |
| 2003 | } | |
| 2004 | ||
| 2005 | _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue; | |
| 2006 | stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable; | |
| 2007 | try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = dest } }); | |
| 2008 | }, | |
| 2009 | ||
| 2010 | State.SuspendBody => |suspend_node| { | |
| 2011 | if (suspend_node.payload != null) { | |
| 2012 | try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } }); | |
| 2013 | } | |
| 2014 | continue; | |
| 2015 | }, | |
| 2016 | ||
| 2017 | State.AsyncEnd => |ctx| { | |
| 2018 | const node = ctx.dest_ptr.get(); | |
| 2019 | ||
| 2020 | switch (node.id) { | |
| 2021 | ast.Node.Id.FnProto => { | |
| 2022 | const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node); | |
| 2023 | fn_proto.async_attr = ctx.attribute; | |
| 2024 | }, | |
| 2025 | ast.Node.Id.SuffixOp => { | |
| 2026 | const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node); | |
| 2027 | if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) { | |
| 2028 | suffix_op.op.Call.async_attr = ctx.attribute; | |
| 2029 | continue; | |
| 2030 | } | |
| 2031 | ||
| 2032 | try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.", | |
| 2033 | @tagName(suffix_op.op)); | |
| 2034 | continue; | |
| 2035 | }, | |
| 2036 | else => { | |
| 2037 | try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.", | |
| 2038 | @tagName(node.id)); | |
| 2039 | continue; | |
| 2040 | } | |
| 2041 | } | |
| 2042 | }, | |
| 2043 | ||
| 2044 | State.Payload => |dest| { | |
| 2045 | const lpipe = self.getNextToken(); | |
| 2046 | if (lpipe.id != Token.Id.Pipe) { | |
| 2047 | self.putBackToken(lpipe); | |
| 2048 | continue; | |
| 2049 | } | |
| 2050 | ||
| 2051 | const error_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 2052 | const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; | |
| 2053 | const node = try arena.create(ast.NodePayload); | |
| 2054 | *node = ast.NodePayload { | |
| 2055 | .base = self.initNode(ast.Node.Id.Payload), | |
| 2056 | .lpipe = lpipe, | |
| 2057 | .error_symbol = try self.createIdentifier(arena, error_symbol), | |
| 2058 | .rpipe = rpipe | |
| 2059 | }; | |
| 2060 | *dest = node; | |
| 2061 | }, | |
| 2062 | ||
| 2063 | State.PointerPayload => |dest| { | |
| 2064 | const lpipe = self.getNextToken(); | |
| 2065 | if (lpipe.id != Token.Id.Pipe) { | |
| 2066 | self.putBackToken(lpipe); | |
| 2067 | continue; | |
| 2068 | } | |
| 2069 | ||
| 2070 | const is_ptr = blk: { | |
| 2071 | const asterik = self.getNextToken(); | |
| 2072 | if (asterik.id == Token.Id.Asterisk) { | |
| 2073 | break :blk true; | |
| 2074 | } else { | |
| 2075 | self.putBackToken(asterik); | |
| 2076 | break :blk false; | |
| 2077 | } | |
| 2078 | }; | |
| 2079 | ||
| 2080 | const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 2081 | const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; | |
| 2082 | const node = try arena.create(ast.NodePointerPayload); | |
| 2083 | *node = ast.NodePointerPayload { | |
| 2084 | .base = self.initNode(ast.Node.Id.PointerPayload), | |
| 2085 | .lpipe = lpipe, | |
| 2086 | .is_ptr = is_ptr, | |
| 2087 | .value_symbol = try self.createIdentifier(arena, value_symbol), | |
| 2088 | .rpipe = rpipe | |
| 2089 | }; | |
| 2090 | *dest = node; | |
| 2091 | }, | |
| 2092 | ||
| 2093 | State.PointerIndexPayload => |dest| { | |
| 2094 | const lpipe = self.getNextToken(); | |
| 2095 | if (lpipe.id != Token.Id.Pipe) { | |
| 2096 | self.putBackToken(lpipe); | |
| 2097 | continue; | |
| 2098 | } | |
| 2099 | ||
| 2100 | const is_ptr = blk: { | |
| 2101 | const asterik = self.getNextToken(); | |
| 2102 | if (asterik.id == Token.Id.Asterisk) { | |
| 2103 | break :blk true; | |
| 2104 | } else { | |
| 2105 | self.putBackToken(asterik); | |
| 2106 | break :blk false; | |
| 2107 | } | |
| 2108 | }; | |
| 2109 | ||
| 2110 | const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 2111 | const index_symbol = blk: { | |
| 2112 | const comma = self.getNextToken(); | |
| 2113 | if (comma.id != Token.Id.Comma) { | |
| 2114 | self.putBackToken(comma); | |
| 2115 | break :blk null; | |
| 2116 | } | |
| 2117 | ||
| 2118 | const symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue; | |
| 2119 | break :blk try self.createIdentifier(arena, symbol); | |
| 2120 | }; | |
| 2121 | ||
| 2122 | const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue; | |
| 2123 | const node = try arena.create(ast.NodePointerIndexPayload); | |
| 2124 | *node = ast.NodePointerIndexPayload { | |
| 2125 | .base = self.initNode(ast.Node.Id.PointerIndexPayload), | |
| 2126 | .lpipe = lpipe, | |
| 2127 | .is_ptr = is_ptr, | |
| 2128 | .value_symbol = try self.createIdentifier(arena, value_symbol), | |
| 2129 | .index_symbol = index_symbol, | |
| 2130 | .rpipe = rpipe | |
| 2131 | }; | |
| 2132 | *dest = node; | |
| 2133 | }, | |
| 2134 | ||
| 2135 | State.AddrOfModifiers => |addr_of_info| { | |
| 2136 | var token = self.getNextToken(); | |
| 2137 | switch (token.id) { | |
| 2138 | Token.Id.Keyword_align => { | |
| 2139 | stack.append(state) catch unreachable; | |
| 2140 | if (addr_of_info.align_expr != null) { | |
| 2141 | try self.parseError(&stack, token, "multiple align qualifiers"); | |
| 2142 | continue; | |
| 2143 | } | |
| 2144 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 2145 | try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} }); | |
| 2146 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 2147 | continue; | |
| 2148 | }, | |
| 2149 | Token.Id.Keyword_const => { | |
| 2150 | stack.append(state) catch unreachable; | |
| 2151 | if (addr_of_info.const_token != null) { | |
| 2152 | try self.parseError(&stack, token, "duplicate qualifier: const"); | |
| 2153 | continue; | |
| 2154 | } | |
| 2155 | addr_of_info.const_token = token; | |
| 2156 | continue; | |
| 2157 | }, | |
| 2158 | Token.Id.Keyword_volatile => { | |
| 2159 | stack.append(state) catch unreachable; | |
| 2160 | if (addr_of_info.volatile_token != null) { | |
| 2161 | try self.parseError(&stack, token, "duplicate qualifier: volatile"); | |
| 2162 | continue; | |
| 2163 | } | |
| 2164 | addr_of_info.volatile_token = token; | |
| 2165 | continue; | |
| 2166 | }, | |
| 2167 | else => { | |
| 2168 | self.putBackToken(token); | |
| 2169 | continue; | |
| 2170 | }, | |
| 2171 | } | |
| 2172 | }, | |
| 2173 | ||
| 2174 | State.FnProto => |fn_proto| { | |
| 2175 | stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable; | |
| 2176 | try stack.append(State { .ParamDecl = fn_proto }); | |
| 2177 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 2178 | ||
| 2179 | const next_token = self.getNextToken(); | |
| 2180 | if (next_token.id == Token.Id.Identifier) { | |
| 2181 | fn_proto.name_token = next_token; | |
| 2182 | continue; | |
| 2183 | } | |
| 2184 | self.putBackToken(next_token); | |
| 2185 | continue; | |
| 2186 | }, | |
| 2187 | ||
| 2188 | State.FnProtoAlign => |fn_proto| { | |
| 2189 | const token = self.getNextToken(); | |
| 2190 | if (token.id == Token.Id.Keyword_align) { | |
| 2191 | @panic("TODO fn proto align"); | |
| 2192 | } | |
| 2193 | self.putBackToken(token); | |
| 2194 | stack.append(State { | |
| 2195 | .FnProtoReturnType = fn_proto, | |
| 2196 | }) catch unreachable; | |
| 2197 | continue; | |
| 2198 | }, | |
| 2199 | ||
| 2200 | State.FnProtoReturnType => |fn_proto| { | |
| 2201 | const token = self.getNextToken(); | |
| 2202 | switch (token.id) { | |
| 2203 | Token.Id.Bang => { | |
| 2204 | fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined }; | |
| 2205 | stack.append(State { | |
| 2206 | .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.InferErrorSet}, | |
| 2207 | }) catch unreachable; | |
| 2208 | }, | |
| 2209 | else => { | |
| 2210 | self.putBackToken(token); | |
| 2211 | fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined }; | |
| 2212 | stack.append(State { | |
| 2213 | .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.Explicit}, | |
| 2214 | }) catch unreachable; | |
| 2215 | }, | |
| 2216 | } | |
| 2217 | if (token.id == Token.Id.Keyword_align) { | |
| 2218 | @panic("TODO fn proto align"); | |
| 2219 | } | |
| 2220 | continue; | |
| 2221 | }, | |
| 2222 | ||
| 2223 | State.ParamDecl => |fn_proto| { | |
| 2224 | var token = self.getNextToken(); | |
| 2225 | if (token.id == Token.Id.RParen) { | |
| 2226 | continue; | |
| 2227 | } | |
| 2228 | const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params); | |
| 2229 | if (token.id == Token.Id.Keyword_comptime) { | |
| 2230 | param_decl.comptime_token = token; | |
| 2231 | token = self.getNextToken(); | |
| 2232 | } else if (token.id == Token.Id.Keyword_noalias) { | |
| 2233 | param_decl.noalias_token = token; | |
| 2234 | token = self.getNextToken(); | |
| 2235 | } | |
| 2236 | if (token.id == Token.Id.Identifier) { | |
| 2237 | const next_token = self.getNextToken(); | |
| 2238 | if (next_token.id == Token.Id.Colon) { | |
| 2239 | param_decl.name_token = token; | |
| 2240 | token = self.getNextToken(); | |
| 2241 | } else { | |
| 2242 | self.putBackToken(next_token); | |
| 2243 | } | |
| 2244 | } | |
| 2245 | if (token.id == Token.Id.Ellipsis3) { | |
| 2246 | param_decl.var_args_token = token; | |
| 2247 | stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable; | |
| 2248 | continue; | |
| 2249 | } else { | |
| 2250 | self.putBackToken(token); | |
| 2251 | } | |
| 2252 | ||
| 2253 | stack.append(State { .ParamDecl = fn_proto }) catch unreachable; | |
| 2254 | try stack.append(State.ParamDeclComma); | |
| 2255 | try stack.append(State { | |
| 2256 | .TypeExprBegin = DestPtr {.Field = &param_decl.type_node} | |
| 2257 | }); | |
| 2258 | continue; | |
| 2259 | }, | |
| 2260 | ||
| 2261 | State.ParamDeclComma => { | |
| 2262 | const token = self.getNextToken(); | |
| 2263 | switch (token.id) { | |
| 2264 | Token.Id.RParen => { | |
| 2265 | _ = stack.pop(); // pop off the ParamDecl | |
| 2266 | continue; | |
| 2267 | }, | |
| 2268 | Token.Id.Comma => continue, | |
| 2269 | else => { | |
| 2270 | try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id)); | |
| 2271 | continue; | |
| 2272 | }, | |
| 2273 | } | |
| 2274 | }, | |
| 2275 | ||
| 2276 | State.FnDef => |fn_proto| { | |
| 2277 | const token = self.getNextToken(); | |
| 2278 | switch(token.id) { | |
| 2279 | Token.Id.LBrace => { | |
| 2280 | const block = try self.createBlock(arena, (?Token)(null), token); | |
| 2281 | fn_proto.body_node = &block.base; | |
| 2282 | stack.append(State { .Block = block }) catch unreachable; | |
| 2283 | continue; | |
| 2284 | }, | |
| 2285 | Token.Id.Semicolon => continue, | |
| 2286 | else => { | |
| 2287 | try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id)); | |
| 2288 | continue; | |
| 2289 | }, | |
| 2290 | } | |
| 2291 | }, | |
| 2292 | ||
| 2293 | State.LabeledExpression => |ctx| { | |
| 2294 | const token = self.getNextToken(); | |
| 2295 | switch (token.id) { | |
| 2296 | Token.Id.LBrace => { | |
| 2297 | const block = try self.createBlock(arena, (?Token)(ctx.label), token); | |
| 2298 | ctx.dest_ptr.store(&block.base); | |
| 2299 | ||
| 2300 | stack.append(State { .Block = block }) catch unreachable; | |
| 2301 | continue; | |
| 2302 | }, | |
| 2303 | Token.Id.Keyword_while => { | |
| 2304 | stack.append(State { | |
| 2305 | .While = LoopCtx { | |
| 2306 | .label = ctx.label, | |
| 2307 | .inline_token = null, | |
| 2308 | .loop_token = token, | |
| 2309 | .dest_ptr = ctx.dest_ptr, | |
| 2310 | } | |
| 2311 | }) catch unreachable; | |
| 2312 | continue; | |
| 2313 | }, | |
| 2314 | Token.Id.Keyword_for => { | |
| 2315 | stack.append(State { | |
| 2316 | .For = LoopCtx { | |
| 2317 | .label = ctx.label, | |
| 2318 | .inline_token = null, | |
| 2319 | .loop_token = token, | |
| 2320 | .dest_ptr = ctx.dest_ptr, | |
| 2321 | } | |
| 2322 | }) catch unreachable; | |
| 2323 | continue; | |
| 2324 | }, | |
| 2325 | Token.Id.Keyword_inline => { | |
| 2326 | stack.append(State { | |
| 2327 | .Inline = InlineCtx { | |
| 2328 | .label = ctx.label, | |
| 2329 | .inline_token = token, | |
| 2330 | .dest_ptr = ctx.dest_ptr, | |
| 2331 | } | |
| 2332 | }) catch unreachable; | |
| 2333 | continue; | |
| 2334 | }, | |
| 2335 | else => { | |
| 2336 | try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id)); | |
| 2337 | continue; | |
| 2338 | }, | |
| 2339 | } | |
| 2340 | }, | |
| 2341 | ||
| 2342 | State.Inline => |ctx| { | |
| 2343 | const token = self.getNextToken(); | |
| 2344 | switch (token.id) { | |
| 2345 | Token.Id.Keyword_while => { | |
| 2346 | stack.append(State { | |
| 2347 | .While = LoopCtx { | |
| 2348 | .inline_token = ctx.inline_token, | |
| 2349 | .label = ctx.label, | |
| 2350 | .loop_token = token, | |
| 2351 | .dest_ptr = ctx.dest_ptr, | |
| 2352 | } | |
| 2353 | }) catch unreachable; | |
| 2354 | continue; | |
| 2355 | }, | |
| 2356 | Token.Id.Keyword_for => { | |
| 2357 | stack.append(State { | |
| 2358 | .For = LoopCtx { | |
| 2359 | .inline_token = ctx.inline_token, | |
| 2360 | .label = ctx.label, | |
| 2361 | .loop_token = token, | |
| 2362 | .dest_ptr = ctx.dest_ptr, | |
| 2363 | } | |
| 2364 | }) catch unreachable; | |
| 2365 | continue; | |
| 2366 | }, | |
| 2367 | else => { | |
| 2368 | try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id)); | |
| 2369 | continue; | |
| 2370 | }, | |
| 2371 | } | |
| 2372 | }, | |
| 2373 | ||
| 2374 | State.While => |ctx| { | |
| 2375 | const node = try arena.create(ast.NodeWhile); | |
| 2376 | *node = ast.NodeWhile { | |
| 2377 | .base = self.initNode(ast.Node.Id.While), | |
| 2378 | .label = ctx.label, | |
| 2379 | .inline_token = ctx.inline_token, | |
| 2380 | .while_token = ctx.loop_token, | |
| 2381 | .condition = undefined, | |
| 2382 | .payload = null, | |
| 2383 | .continue_expr = null, | |
| 2384 | .body = undefined, | |
| 2385 | .@"else" = null, | |
| 2386 | }; | |
| 2387 | ctx.dest_ptr.store(&node.base); | |
| 2388 | ||
| 2389 | stack.append(State { .Else = &node.@"else" }) catch unreachable; | |
| 2390 | try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); | |
| 2391 | try stack.append(State { .WhileContinueExpr = &node.continue_expr }); | |
| 2392 | try stack.append(State { .PointerPayload = &node.payload }); | |
| 2393 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 2394 | try stack.append(State { .Expression = DestPtr { .Field = &node.condition } }); | |
| 2395 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 2396 | }, | |
| 2397 | ||
| 2398 | State.For => |ctx| { | |
| 2399 | const node = try arena.create(ast.NodeFor); | |
| 2400 | *node = ast.NodeFor { | |
| 2401 | .base = self.initNode(ast.Node.Id.For), | |
| 2402 | .label = ctx.label, | |
| 2403 | .inline_token = ctx.inline_token, | |
| 2404 | .for_token = ctx.loop_token, | |
| 2405 | .array_expr = undefined, | |
| 2406 | .payload = null, | |
| 2407 | .body = undefined, | |
| 2408 | .@"else" = null, | |
| 2409 | }; | |
| 2410 | ctx.dest_ptr.store(&node.base); | |
| 2411 | ||
| 2412 | stack.append(State { .Else = &node.@"else" }) catch unreachable; | |
| 2413 | try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); | |
| 2414 | try stack.append(State { .PointerIndexPayload = &node.payload }); | |
| 2415 | try stack.append(State { .ExpectToken = Token.Id.RParen }); | |
| 2416 | try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } }); | |
| 2417 | try stack.append(State { .ExpectToken = Token.Id.LParen }); | |
| 2418 | }, | |
| 2419 | ||
| 2420 | State.Block => |block| { | |
| 2421 | const token = self.getNextToken(); | |
| 2422 | switch (token.id) { | |
| 2423 | Token.Id.RBrace => { | |
| 2424 | block.rbrace = token; | |
| 2425 | continue; | |
| 2426 | }, | |
| 2427 | else => { | |
| 2428 | self.putBackToken(token); | |
| 2429 | stack.append(State { .Block = block }) catch unreachable; | |
| 2430 | try stack.append(State { .Statement = block }); | |
| 2431 | continue; | |
| 2432 | }, | |
| 2433 | } | |
| 2434 | }, | |
| 2435 | ||
| 2436 | State.Statement => |block| { | |
| 2437 | const next = self.getNextToken(); | |
| 2438 | switch (next.id) { | |
| 2439 | Token.Id.Keyword_comptime => { | |
| 2440 | const mut_token = self.getNextToken(); | |
| 2441 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { | |
| 2442 | // TODO shouldn't need these casts | |
| 2443 | const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null), | |
| 2444 | mut_token, (?Token)(next), (?Token)(null), null); | |
| 2445 | stack.append(State { .VarDecl = var_decl }) catch unreachable; | |
| 2446 | continue; | |
| 2447 | } else { | |
| 2448 | self.putBackToken(mut_token); | |
| 2449 | self.putBackToken(next); | |
| 2450 | const statememt = try block.statements.addOne(); | |
| 2451 | stack.append(State { .Semicolon = statememt }) catch unreachable; | |
| 2452 | try stack.append(State { .Expression = DestPtr{.Field = statememt } }); | |
| 2453 | } | |
| 2454 | }, | |
| 2455 | Token.Id.Keyword_var, Token.Id.Keyword_const => { | |
| 2456 | const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null), | |
| 2457 | next, (?Token)(null), (?Token)(null), null); | |
| 2458 | stack.append(State { .VarDecl = var_decl }) catch unreachable; | |
| 2459 | continue; | |
| 2460 | }, | |
| 2461 | Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => { | |
| 2462 | const node = try arena.create(ast.NodeDefer); | |
| 2463 | *node = ast.NodeDefer { | |
| 2464 | .base = self.initNode(ast.Node.Id.Defer), | |
| 2465 | .defer_token = next, | |
| 2466 | .kind = switch (next.id) { | |
| 2467 | Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional, | |
| 2468 | Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error, | |
| 2469 | else => unreachable, | |
| 2470 | }, | |
| 2471 | .expr = undefined, | |
| 2472 | }; | |
| 2473 | try block.statements.append(&node.base); | |
| 2474 | ||
| 2475 | stack.append(State { .Semicolon = &node.base }) catch unreachable; | |
| 2476 | try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = &node.expr } }); | |
| 2477 | continue; | |
| 2478 | }, | |
| 2479 | Token.Id.LBrace => { | |
| 2480 | const inner_block = try self.createBlock(arena, (?Token)(null), next); | |
| 2481 | try block.statements.append(&inner_block.base); | |
| 2482 | ||
| 2483 | stack.append(State { .Block = inner_block }) catch unreachable; | |
| 2484 | continue; | |
| 2485 | }, | |
| 2486 | else => { | |
| 2487 | self.putBackToken(next); | |
| 2488 | const statememt = try block.statements.addOne(); | |
| 2489 | stack.append(State { .Semicolon = statememt }) catch unreachable; | |
| 2490 | try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } }); | |
| 2491 | continue; | |
| 2492 | } | |
| 2493 | } | |
| 2494 | ||
| 2495 | }, | |
| 2496 | ||
| 2497 | State.Semicolon => |node_ptr| { | |
| 2498 | const node = *node_ptr; | |
| 2499 | if (requireSemiColon(node)) { | |
| 2500 | _ = (try self.eatToken(&stack, Token.Id.Semicolon)) ?? continue; | |
| 2501 | } | |
| 2502 | } | |
| 2503 | } | |
| 2504 | } | |
| 2505 | } | |
| 2506 | ||
| 2507 | fn requireSemiColon(node: &const ast.Node) bool { | |
| 2508 | var n = node; | |
| 2509 | while (true) { | |
| 2510 | switch (n.id) { | |
| 2511 | ast.Node.Id.Root, | |
| 2512 | ast.Node.Id.StructField, | |
| 2513 | ast.Node.Id.UnionTag, | |
| 2514 | ast.Node.Id.EnumTag, | |
| 2515 | ast.Node.Id.ParamDecl, | |
| 2516 | ast.Node.Id.Block, | |
| 2517 | ast.Node.Id.Payload, | |
| 2518 | ast.Node.Id.PointerPayload, | |
| 2519 | ast.Node.Id.PointerIndexPayload, | |
| 2520 | ast.Node.Id.Switch, | |
| 2521 | ast.Node.Id.SwitchCase, | |
| 2522 | ast.Node.Id.SwitchElse, | |
| 2523 | ast.Node.Id.FieldInitializer, | |
| 2524 | ast.Node.Id.LineComment, | |
| 2525 | ast.Node.Id.TestDecl => return false, | |
| 2526 | ast.Node.Id.While => { | |
| 2527 | const while_node = @fieldParentPtr(ast.NodeWhile, "base", n); | |
| 2528 | if (while_node.@"else") |@"else"| { | |
| 2529 | n = @"else".base; | |
| 2530 | continue; | |
| 2531 | } | |
| 2532 | ||
| 2533 | n = while_node.body; | |
| 2534 | }, | |
| 2535 | ast.Node.Id.For => { | |
| 2536 | const for_node = @fieldParentPtr(ast.NodeFor, "base", n); | |
| 2537 | if (for_node.@"else") |@"else"| { | |
| 2538 | n = @"else".base; | |
| 2539 | continue; | |
| 2540 | } | |
| 2541 | ||
| 2542 | n = for_node.body; | |
| 2543 | }, | |
| 2544 | ast.Node.Id.If => { | |
| 2545 | const if_node = @fieldParentPtr(ast.NodeIf, "base", n); | |
| 2546 | if (if_node.@"else") |@"else"| { | |
| 2547 | n = @"else".base; | |
| 2548 | continue; | |
| 2549 | } | |
| 2550 | ||
| 2551 | n = if_node.body; | |
| 2552 | }, | |
| 2553 | ast.Node.Id.Else => { | |
| 2554 | const else_node = @fieldParentPtr(ast.NodeElse, "base", n); | |
| 2555 | n = else_node.body; | |
| 2556 | }, | |
| 2557 | ast.Node.Id.Defer => { | |
| 2558 | const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n); | |
| 2559 | n = defer_node.expr; | |
| 2560 | }, | |
| 2561 | ast.Node.Id.Comptime => { | |
| 2562 | const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n); | |
| 2563 | n = comptime_node.expr; | |
| 2564 | }, | |
| 2565 | ast.Node.Id.Suspend => { | |
| 2566 | const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n); | |
| 2567 | if (suspend_node.body) |body| { | |
| 2568 | n = body; | |
| 2569 | continue; | |
| 2570 | } | |
| 2571 | ||
| 2572 | return true; | |
| 2573 | }, | |
| 2574 | else => return true, | |
| 2575 | } | |
| 2576 | } | |
| 2577 | } | |
| 2578 | ||
| 2579 | fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void { | |
| 2580 | var token = self.getNextToken(); | |
| 2581 | switch (token.id) { | |
| 2582 | Token.Id.Comma => { | |
| 2583 | stack.append(state_after_comma) catch unreachable; | |
| 2584 | }, | |
| 2585 | else => { | |
| 2586 | const IdTag = @TagType(Token.Id); | |
| 2587 | if (IdTag(*end) == token.id) { | |
| 2588 | if (maybe_ptr) |ptr| { | |
| 2589 | *ptr = token; | |
| 2590 | } | |
| 2591 | return; | |
| 2592 | } | |
| 2593 | ||
| 2594 | try self.parseError(stack, token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id)); | |
| 2595 | }, | |
| 2596 | } | |
| 2597 | } | |
| 2598 | ||
| 2599 | fn tokenIdToAssignment(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp { | |
| 2600 | // TODO: We have to cast all cases because of this: | |
| 2601 | // error: expected type '?InfixOp', found '?@TagType(InfixOp)' | |
| 2602 | return switch (*id) { | |
| 2603 | Token.Id.AmpersandEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitAnd), | |
| 2604 | Token.Id.AngleBracketAngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftLeft), | |
| 2605 | Token.Id.AngleBracketAngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftRight), | |
| 2606 | Token.Id.AsteriskEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimes), | |
| 2607 | Token.Id.AsteriskPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimesWarp), | |
| 2608 | Token.Id.CaretEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitXor), | |
| 2609 | Token.Id.Equal => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Assign), | |
| 2610 | Token.Id.MinusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinus), | |
| 2611 | Token.Id.MinusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinusWrap), | |
| 2612 | Token.Id.PercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMod), | |
| 2613 | Token.Id.PipeEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitOr), | |
| 2614 | Token.Id.PlusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlus), | |
| 2615 | Token.Id.PlusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlusWrap), | |
| 2616 | Token.Id.SlashEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignDiv), | |
| 2617 | else => null, | |
| 2618 | }; | |
| 2619 | } | |
| 2620 | ||
| 2621 | fn tokenIdToComparison(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp { | |
| 2622 | // TODO: We have to cast all cases because of this: | |
| 2623 | // error: expected type '?InfixOp', found '?@TagType(InfixOp)' | |
| 2624 | return switch (*id) { | |
| 2625 | Token.Id.BangEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BangEqual), | |
| 2626 | Token.Id.EqualEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.EqualEqual), | |
| 2627 | Token.Id.AngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.LessThan), | |
| 2628 | Token.Id.AngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.LessOrEqual), | |
| 2629 | Token.Id.AngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.GreaterThan), | |
| 2630 | Token.Id.AngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.GreaterOrEqual), | |
| 2631 | else => null, | |
| 2632 | }; | |
| 2633 | } | |
| 2634 | ||
| 2635 | fn tokenIdToBitShift(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp { | |
| 2636 | // TODO: We have to cast all cases because of this: | |
| 2637 | // error: expected type '?InfixOp', found '?@TagType(InfixOp)' | |
| 2638 | return switch (*id) { | |
| 2639 | Token.Id.AngleBracketAngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftLeft), | |
| 2640 | Token.Id.AngleBracketAngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftRight), | |
| 2641 | else => null, | |
| 2642 | }; | |
| 2643 | } | |
| 2644 | ||
| 2645 | fn tokenIdToAddition(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp { | |
| 2646 | // TODO: We have to cast all cases because of this: | |
| 2647 | // error: expected type '?InfixOp', found '?@TagType(InfixOp)' | |
| 2648 | return switch (*id) { | |
| 2649 | Token.Id.Minus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Sub), | |
| 2650 | Token.Id.MinusPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.SubWrap), | |
| 2651 | Token.Id.Plus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Add), | |
| 2652 | Token.Id.PlusPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AddWrap), | |
| 2653 | Token.Id.PlusPlus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayCat), | |
| 2654 | else => null, | |
| 2655 | }; | |
| 2656 | } | |
| 2657 | ||
| 2658 | fn tokenIdToMultiply(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp { | |
| 2659 | // TODO: We have to cast all cases because of this: | |
| 2660 | // error: expected type '?InfixOp', found '?@TagType(InfixOp)' | |
| 2661 | return switch (*id) { | |
| 2662 | Token.Id.Slash => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Div), | |
| 2663 | Token.Id.Asterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mult), | |
| 2664 | Token.Id.AsteriskAsterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayMult), | |
| 2665 | Token.Id.AsteriskPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.MultWrap), | |
| 2666 | Token.Id.Percent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mod), | |
| 2667 | Token.Id.PipePipe => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.MergeErrorSets), | |
| 2668 | else => null, | |
| 2669 | }; | |
| 2670 | } | |
| 2671 | ||
| 2672 | fn tokenIdToPrefixOp(id: &const Token.Id) ?ast.NodePrefixOp.PrefixOp { | |
| 2673 | // TODO: We have to cast all cases because of this: | |
| 2674 | // error: expected type '?InfixOp', found '?@TagType(InfixOp)' | |
| 2675 | return switch (*id) { | |
| 2676 | Token.Id.Bang => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BoolNot), | |
| 2677 | Token.Id.Tilde => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BitNot), | |
| 2678 | Token.Id.Minus => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Negation), | |
| 2679 | Token.Id.MinusPercent => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.NegationWrap), | |
| 2680 | Token.Id.Asterisk => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Deref), | |
| 2681 | Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp { | |
| 2682 | .AddrOf = ast.NodePrefixOp.AddrOfInfo { | |
| 2683 | .align_expr = null, | |
| 2684 | .bit_offset_start_token = null, | |
| 2685 | .bit_offset_end_token = null, | |
| 2686 | .const_token = null, | |
| 2687 | .volatile_token = null, | |
| 2688 | }, | |
| 2689 | }, | |
| 2690 | Token.Id.QuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.MaybeType), | |
| 2691 | Token.Id.QuestionMarkQuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.UnwrapMaybe), | |
| 2692 | Token.Id.Keyword_await => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Await), | |
| 2693 | else => null, | |
| 2694 | }; | |
| 2695 | } | |
| 2696 | ||
| 2697 | fn initNode(self: &Parser, id: ast.Node.Id) ast.Node { | |
| 2698 | if (self.pending_line_comment_node) |comment_node| { | |
| 2699 | self.pending_line_comment_node = null; | |
| 2700 | return ast.Node {.id = id, .comment = comment_node}; | |
| 2701 | } | |
| 2702 | return ast.Node {.id = id, .comment = null }; | |
| 2703 | } | |
| 2704 | ||
| 2705 | fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot { | |
| 2706 | const node = try arena.create(ast.NodeRoot); | |
| 703 | 2707 | |
| 704 | 2708 | *node = ast.NodeRoot { |
| 705 | 2709 | .base = self.initNode(ast.Node.Id.Root), |
| ... | ... | @@ -711,7 +2715,7 @@ pub const Parser = struct { |
| 711 | 2715 | } |
| 712 | 2716 | |
| 713 | 2717 | fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token, |
| 714 | comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl | |
| 2718 | comptime_token: &const ?Token, extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl | |
| 715 | 2719 | { |
| 716 | 2720 | const node = try arena.create(ast.NodeVarDecl); |
| 717 | 2721 | |
| ... | ... | @@ -724,7 +2728,7 @@ pub const Parser = struct { |
| 724 | 2728 | .type_node = null, |
| 725 | 2729 | .align_node = null, |
| 726 | 2730 | .init_node = null, |
| 727 | .lib_name = null, | |
| 2731 | .lib_name = lib_name, | |
| 728 | 2732 | // initialized later |
| 729 | 2733 | .name_token = undefined, |
| 730 | 2734 | .eq_token = undefined, |
| ... | ... | @@ -733,8 +2737,33 @@ pub const Parser = struct { |
| 733 | 2737 | return node; |
| 734 | 2738 | } |
| 735 | 2739 | |
| 2740 | fn createStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeStringLiteral { | |
| 2741 | const node = try arena.create(ast.NodeStringLiteral); | |
| 2742 | ||
| 2743 | assert(token.id == Token.Id.StringLiteral); | |
| 2744 | *node = ast.NodeStringLiteral { | |
| 2745 | .base = self.initNode(ast.Node.Id.StringLiteral), | |
| 2746 | .token = *token, | |
| 2747 | }; | |
| 2748 | return node; | |
| 2749 | } | |
| 2750 | ||
| 2751 | fn createTestDecl(self: &Parser, arena: &mem.Allocator, test_token: &const Token, name: &ast.Node, | |
| 2752 | block: &ast.NodeBlock) !&ast.NodeTestDecl | |
| 2753 | { | |
| 2754 | const node = try arena.create(ast.NodeTestDecl); | |
| 2755 | ||
| 2756 | *node = ast.NodeTestDecl { | |
| 2757 | .base = self.initNode(ast.Node.Id.TestDecl), | |
| 2758 | .test_token = *test_token, | |
| 2759 | .name = name, | |
| 2760 | .body_node = &block.base, | |
| 2761 | }; | |
| 2762 | return node; | |
| 2763 | } | |
| 2764 | ||
| 736 | 2765 | fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token, |
| 737 | cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto | |
| 2766 | lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto | |
| 738 | 2767 | { |
| 739 | 2768 | const node = try arena.create(ast.NodeFnProto); |
| 740 | 2769 | |
| ... | ... | @@ -749,8 +2778,9 @@ pub const Parser = struct { |
| 749 | 2778 | .extern_token = *extern_token, |
| 750 | 2779 | .inline_token = *inline_token, |
| 751 | 2780 | .cc_token = *cc_token, |
| 2781 | .async_attr = null, | |
| 752 | 2782 | .body_node = null, |
| 753 | .lib_name = null, | |
| 2783 | .lib_name = lib_name, | |
| 754 | 2784 | .align_expr = null, |
| 755 | 2785 | }; |
| 756 | 2786 | return node; |
| ... | ... | @@ -770,14 +2800,28 @@ pub const Parser = struct { |
| 770 | 2800 | return node; |
| 771 | 2801 | } |
| 772 | 2802 | |
| 773 | fn createBlock(self: &Parser, arena: &mem.Allocator, begin_token: &const Token) !&ast.NodeBlock { | |
| 2803 | fn createBlock(self: &Parser, arena: &mem.Allocator, label: &const ?Token, lbrace: &const Token) !&ast.NodeBlock { | |
| 774 | 2804 | const node = try arena.create(ast.NodeBlock); |
| 775 | 2805 | |
| 776 | 2806 | *node = ast.NodeBlock { |
| 777 | 2807 | .base = self.initNode(ast.Node.Id.Block), |
| 778 | .begin_token = *begin_token, | |
| 779 | .end_token = undefined, | |
| 2808 | .label = *label, | |
| 2809 | .lbrace = *lbrace, | |
| 780 | 2810 | .statements = ArrayList(&ast.Node).init(arena), |
| 2811 | .rbrace = undefined, | |
| 2812 | }; | |
| 2813 | return node; | |
| 2814 | } | |
| 2815 | ||
| 2816 | fn createControlFlowExpr(self: &Parser, arena: &mem.Allocator, ltoken: &const Token, | |
| 2817 | kind: &const ast.NodeControlFlowExpression.Kind) !&ast.NodeControlFlowExpression | |
| 2818 | { | |
| 2819 | const node = try arena.create(ast.NodeControlFlowExpression); | |
| 2820 | *node = ast.NodeControlFlowExpression { | |
| 2821 | .base = self.initNode(ast.Node.Id.ControlFlowExpression), | |
| 2822 | .ltoken = *ltoken, | |
| 2823 | .kind = *kind, | |
| 2824 | .rhs = null, | |
| 781 | 2825 | }; |
| 782 | 2826 | return node; |
| 783 | 2827 | } |
| ... | ... | @@ -807,6 +2851,18 @@ pub const Parser = struct { |
| 807 | 2851 | return node; |
| 808 | 2852 | } |
| 809 | 2853 | |
| 2854 | fn createSuffixOp(self: &Parser, arena: &mem.Allocator, op: &const ast.NodeSuffixOp.SuffixOp) !&ast.NodeSuffixOp { | |
| 2855 | const node = try arena.create(ast.NodeSuffixOp); | |
| 2856 | ||
| 2857 | *node = ast.NodeSuffixOp { | |
| 2858 | .base = self.initNode(ast.Node.Id.SuffixOp), | |
| 2859 | .lhs = undefined, | |
| 2860 | .op = *op, | |
| 2861 | .rtoken = undefined, | |
| 2862 | }; | |
| 2863 | return node; | |
| 2864 | } | |
| 2865 | ||
| 810 | 2866 | fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier { |
| 811 | 2867 | const node = try arena.create(ast.NodeIdentifier); |
| 812 | 2868 | |
| ... | ... | @@ -837,6 +2893,16 @@ pub const Parser = struct { |
| 837 | 2893 | return node; |
| 838 | 2894 | } |
| 839 | 2895 | |
| 2896 | fn createUndefined(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeUndefinedLiteral { | |
| 2897 | const node = try arena.create(ast.NodeUndefinedLiteral); | |
| 2898 | ||
| 2899 | *node = ast.NodeUndefinedLiteral { | |
| 2900 | .base = self.initNode(ast.Node.Id.UndefinedLiteral), | |
| 2901 | .token = *token, | |
| 2902 | }; | |
| 2903 | return node; | |
| 2904 | } | |
| 2905 | ||
| 840 | 2906 | fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier { |
| 841 | 2907 | const node = try self.createIdentifier(arena, name_token); |
| 842 | 2908 | try dest_ptr.store(&node.base); |
| ... | ... | @@ -850,54 +2916,78 @@ pub const Parser = struct { |
| 850 | 2916 | } |
| 851 | 2917 | |
| 852 | 2918 | fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token, |
| 853 | extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token, | |
| 2919 | extern_token: &const ?Token, lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token, | |
| 854 | 2920 | inline_token: &const ?Token) !&ast.NodeFnProto |
| 855 | 2921 | { |
| 856 | const node = try self.createFnProto(arena, fn_token, extern_token, cc_token, visib_token, inline_token); | |
| 2922 | const node = try self.createFnProto(arena, fn_token, extern_token, lib_name, cc_token, visib_token, inline_token); | |
| 857 | 2923 | try list.append(&node.base); |
| 858 | 2924 | return node; |
| 859 | 2925 | } |
| 860 | 2926 | |
| 861 | 2927 | fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), |
| 862 | 2928 | visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token, |
| 863 | extern_token: &const ?Token) !&ast.NodeVarDecl | |
| 2929 | extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl | |
| 864 | 2930 | { |
| 865 | const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token); | |
| 2931 | const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token, lib_name); | |
| 866 | 2932 | try list.append(&node.base); |
| 867 | 2933 | return node; |
| 868 | 2934 | } |
| 869 | 2935 | |
| 870 | fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) { | |
| 871 | const loc = self.tokenizer.getTokenLocation(token); | |
| 872 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args); | |
| 873 | warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]); | |
| 874 | { | |
| 875 | var i: usize = 0; | |
| 876 | while (i < token.column) : (i += 1) { | |
| 877 | warn(" "); | |
| 2936 | fn createAttachTestDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), | |
| 2937 | test_token: &const Token, name: &ast.Node, block: &ast.NodeBlock) !&ast.NodeTestDecl | |
| 2938 | { | |
| 2939 | const node = try self.createTestDecl(arena, test_token, name, block); | |
| 2940 | try list.append(&node.base); | |
| 2941 | return node; | |
| 2942 | } | |
| 2943 | ||
| 2944 | fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void { | |
| 2945 | // Before reporting an error. We pop the stack to see if our state was optional | |
| 2946 | self.revertIfOptional(stack) catch { | |
| 2947 | const loc = self.tokenizer.getTokenLocation(0, token); | |
| 2948 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args); | |
| 2949 | warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]); | |
| 2950 | { | |
| 2951 | var i: usize = 0; | |
| 2952 | while (i < loc.column) : (i += 1) { | |
| 2953 | warn(" "); | |
| 2954 | } | |
| 878 | 2955 | } |
| 879 | } | |
| 880 | { | |
| 881 | const caret_count = token.end - token.start; | |
| 882 | var i: usize = 0; | |
| 883 | while (i < caret_count) : (i += 1) { | |
| 884 | warn("~"); | |
| 2956 | { | |
| 2957 | const caret_count = token.end - token.start; | |
| 2958 | var i: usize = 0; | |
| 2959 | while (i < caret_count) : (i += 1) { | |
| 2960 | warn("~"); | |
| 2961 | } | |
| 885 | 2962 | } |
| 886 | } | |
| 887 | warn("\n"); | |
| 888 | return error.ParseError; | |
| 2963 | warn("\n"); | |
| 2964 | return error.ParseError; | |
| 2965 | }; | |
| 889 | 2966 | } |
| 890 | 2967 | |
| 891 | fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) !void { | |
| 2968 | fn eatToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token { | |
| 2969 | const token = self.getNextToken(); | |
| 892 | 2970 | if (token.id != id) { |
| 893 | return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id)); | |
| 2971 | try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id)); | |
| 2972 | return null; | |
| 894 | 2973 | } |
| 2974 | return token; | |
| 895 | 2975 | } |
| 896 | 2976 | |
| 897 | fn eatToken(self: &Parser, id: @TagType(Token.Id)) !Token { | |
| 898 | const token = self.getNextToken(); | |
| 899 | try self.expectToken(token, id); | |
| 900 | return token; | |
| 2977 | fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void { | |
| 2978 | while (stack.popOrNull()) |state| { | |
| 2979 | switch (state) { | |
| 2980 | State.Optional => |revert| { | |
| 2981 | *self = revert.parser; | |
| 2982 | *self.tokenizer = revert.tokenizer; | |
| 2983 | *revert.ptr = null; | |
| 2984 | return; | |
| 2985 | }, | |
| 2986 | else => { } | |
| 2987 | } | |
| 2988 | } | |
| 2989 | ||
| 2990 | return error.NoOptionalStateFound; | |
| 901 | 2991 | } |
| 902 | 2992 | |
| 903 | 2993 | fn putBackToken(self: &Parser, token: &const Token) void { |
| ... | ... | @@ -956,6 +3046,7 @@ pub const Parser = struct { |
| 956 | 3046 | Expression: &ast.Node, |
| 957 | 3047 | VarDecl: &ast.NodeVarDecl, |
| 958 | 3048 | Statement: &ast.Node, |
| 3049 | FieldInitializer: &ast.NodeFieldInitializer, | |
| 959 | 3050 | PrintIndent, |
| 960 | 3051 | Indent: usize, |
| 961 | 3052 | }; |
| ... | ... | @@ -976,9 +3067,8 @@ pub const Parser = struct { |
| 976 | 3067 | try stack.append(RenderState { |
| 977 | 3068 | .Text = blk: { |
| 978 | 3069 | const prev_node = root_node.decls.at(i - 1); |
| 979 | const prev_line_index = prev_node.lastToken().line; | |
| 980 | const this_line_index = decl.firstToken().line; | |
| 981 | if (this_line_index - prev_line_index >= 2) { | |
| 3070 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken()); | |
| 3071 | if (loc.line >= 2) { | |
| 982 | 3072 | break :blk "\n\n"; |
| 983 | 3073 | } |
| 984 | 3074 | break :blk "\n"; |
| ... | ... | @@ -996,64 +3086,76 @@ pub const Parser = struct { |
| 996 | 3086 | switch (decl.id) { |
| 997 | 3087 | ast.Node.Id.FnProto => { |
| 998 | 3088 | const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl); |
| 999 | if (fn_proto.visib_token) |visib_token| { | |
| 1000 | switch (visib_token.id) { | |
| 1001 | Token.Id.Keyword_pub => try stream.print("pub "), | |
| 1002 | Token.Id.Keyword_export => try stream.print("export "), | |
| 1003 | else => unreachable, | |
| 1004 | } | |
| 1005 | } | |
| 1006 | if (fn_proto.extern_token) |extern_token| { | |
| 1007 | try stream.print("{} ", self.tokenizer.getTokenSlice(extern_token)); | |
| 1008 | } | |
| 1009 | try stream.print("fn"); | |
| 1010 | ||
| 1011 | if (fn_proto.name_token) |name_token| { | |
| 1012 | try stream.print(" {}", self.tokenizer.getTokenSlice(name_token)); | |
| 1013 | } | |
| 1014 | 3089 | |
| 1015 | try stream.print("("); | |
| 1016 | ||
| 1017 | if (fn_proto.body_node == null) { | |
| 1018 | try stack.append(RenderState { .Text = ";" }); | |
| 3090 | if (fn_proto.body_node) |body_node| { | |
| 3091 | stack.append(RenderState { .Expression = body_node}) catch unreachable; | |
| 3092 | try stack.append(RenderState { .Text = " "}); | |
| 3093 | } else { | |
| 3094 | stack.append(RenderState { .Text = ";" }) catch unreachable; | |
| 1019 | 3095 | } |
| 1020 | 3096 | |
| 1021 | try stack.append(RenderState { .FnProtoRParen = fn_proto}); | |
| 1022 | var i = fn_proto.params.len; | |
| 1023 | while (i != 0) { | |
| 1024 | i -= 1; | |
| 1025 | const param_decl_node = fn_proto.params.items[i]; | |
| 1026 | try stack.append(RenderState { .ParamDecl = param_decl_node}); | |
| 1027 | if (i != 0) { | |
| 1028 | try stack.append(RenderState { .Text = ", " }); | |
| 1029 | } | |
| 3097 | try stack.append(RenderState { .Expression = decl }); | |
| 3098 | }, | |
| 3099 | ast.Node.Id.Use => { | |
| 3100 | const use_decl = @fieldParentPtr(ast.NodeUse, "base", decl); | |
| 3101 | if (use_decl.visib_token) |visib_token| { | |
| 3102 | try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token)); | |
| 1030 | 3103 | } |
| 3104 | try stream.print("use "); | |
| 3105 | try stack.append(RenderState { .Text = ";" }); | |
| 3106 | try stack.append(RenderState { .Expression = use_decl.expr }); | |
| 1031 | 3107 | }, |
| 1032 | 3108 | ast.Node.Id.VarDecl => { |
| 1033 | 3109 | const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl); |
| 1034 | 3110 | try stack.append(RenderState { .VarDecl = var_decl}); |
| 3111 | }, | |
| 3112 | ast.Node.Id.TestDecl => { | |
| 3113 | const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl); | |
| 3114 | try stream.print("test "); | |
| 3115 | try stack.append(RenderState { .Expression = test_decl.body_node }); | |
| 3116 | try stack.append(RenderState { .Text = " " }); | |
| 3117 | try stack.append(RenderState { .Expression = test_decl.name }); | |
| 3118 | }, | |
| 3119 | ast.Node.Id.StructField => { | |
| 3120 | const field = @fieldParentPtr(ast.NodeStructField, "base", decl); | |
| 3121 | try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token)); | |
| 3122 | try stack.append(RenderState { .Expression = field.type_expr}); | |
| 3123 | }, | |
| 3124 | ast.Node.Id.UnionTag => { | |
| 3125 | const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl); | |
| 3126 | try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token)); | |
| 3127 | ||
| 3128 | if (tag.type_expr) |type_expr| { | |
| 3129 | try stream.print(": "); | |
| 3130 | try stack.append(RenderState { .Expression = type_expr}); | |
| 3131 | } | |
| 3132 | }, | |
| 3133 | ast.Node.Id.EnumTag => { | |
| 3134 | const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl); | |
| 3135 | try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token)); | |
| 1035 | 3136 | |
| 3137 | if (tag.value) |value| { | |
| 3138 | try stream.print(" = "); | |
| 3139 | try stack.append(RenderState { .Expression = value}); | |
| 3140 | } | |
| 3141 | }, | |
| 3142 | ast.Node.Id.Comptime => { | |
| 3143 | if (requireSemiColon(decl)) { | |
| 3144 | try stack.append(RenderState { .Text = ";" }); | |
| 3145 | } | |
| 3146 | try stack.append(RenderState { .Expression = decl }); | |
| 1036 | 3147 | }, |
| 1037 | 3148 | else => unreachable, |
| 1038 | 3149 | } |
| 1039 | 3150 | }, |
| 1040 | 3151 | |
| 1041 | RenderState.VarDecl => |var_decl| { | |
| 1042 | if (var_decl.visib_token) |visib_token| { | |
| 1043 | try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token)); | |
| 1044 | } | |
| 1045 | if (var_decl.extern_token) |extern_token| { | |
| 1046 | try stream.print("{} ", self.tokenizer.getTokenSlice(extern_token)); | |
| 1047 | if (var_decl.lib_name != null) { | |
| 1048 | @panic("TODO"); | |
| 1049 | } | |
| 1050 | } | |
| 1051 | if (var_decl.comptime_token) |comptime_token| { | |
| 1052 | try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token)); | |
| 1053 | } | |
| 1054 | try stream.print("{} ", self.tokenizer.getTokenSlice(var_decl.mut_token)); | |
| 1055 | try stream.print("{}", self.tokenizer.getTokenSlice(var_decl.name_token)); | |
| 3152 | RenderState.FieldInitializer => |field_init| { | |
| 3153 | try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token)); | |
| 3154 | try stream.print(" = "); | |
| 3155 | try stack.append(RenderState { .Expression = field_init.expr }); | |
| 3156 | }, | |
| 1056 | 3157 | |
| 3158 | RenderState.VarDecl => |var_decl| { | |
| 1057 | 3159 | try stack.append(RenderState { .Text = ";" }); |
| 1058 | 3160 | if (var_decl.init_node) |init_node| { |
| 1059 | 3161 | try stack.append(RenderState { .Expression = init_node }); |
| ... | ... | @@ -1065,8 +3167,30 @@ pub const Parser = struct { |
| 1065 | 3167 | try stack.append(RenderState { .Text = " align(" }); |
| 1066 | 3168 | } |
| 1067 | 3169 | if (var_decl.type_node) |type_node| { |
| 1068 | try stream.print(": "); | |
| 1069 | 3170 | try stack.append(RenderState { .Expression = type_node }); |
| 3171 | try stack.append(RenderState { .Text = ": " }); | |
| 3172 | } | |
| 3173 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) }); | |
| 3174 | try stack.append(RenderState { .Text = " " }); | |
| 3175 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) }); | |
| 3176 | ||
| 3177 | if (var_decl.comptime_token) |comptime_token| { | |
| 3178 | try stack.append(RenderState { .Text = " " }); | |
| 3179 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) }); | |
| 3180 | } | |
| 3181 | ||
| 3182 | if (var_decl.extern_token) |extern_token| { | |
| 3183 | if (var_decl.lib_name != null) { | |
| 3184 | try stack.append(RenderState { .Text = " " }); | |
| 3185 | try stack.append(RenderState { .Expression = ??var_decl.lib_name }); | |
| 3186 | } | |
| 3187 | try stack.append(RenderState { .Text = " " }); | |
| 3188 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) }); | |
| 3189 | } | |
| 3190 | ||
| 3191 | if (var_decl.visib_token) |visib_token| { | |
| 3192 | try stack.append(RenderState { .Text = " " }); | |
| 3193 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) }); | |
| 1070 | 3194 | } |
| 1071 | 3195 | }, |
| 1072 | 3196 | |
| ... | ... | @@ -1097,6 +3221,10 @@ pub const Parser = struct { |
| 1097 | 3221 | }, |
| 1098 | 3222 | ast.Node.Id.Block => { |
| 1099 | 3223 | const block = @fieldParentPtr(ast.NodeBlock, "base", base); |
| 3224 | if (block.label) |label| { | |
| 3225 | try stream.print("{}: ", self.tokenizer.getTokenSlice(label)); | |
| 3226 | } | |
| 3227 | ||
| 1100 | 3228 | if (block.statements.len == 0) { |
| 1101 | 3229 | try stream.write("{}"); |
| 1102 | 3230 | } else { |
| ... | ... | @@ -1115,10 +3243,9 @@ pub const Parser = struct { |
| 1115 | 3243 | try stack.append(RenderState { |
| 1116 | 3244 | .Text = blk: { |
| 1117 | 3245 | if (i != 0) { |
| 1118 | const prev_statement_node = block.statements.items[i - 1]; | |
| 1119 | const prev_line_index = prev_statement_node.lastToken().line; | |
| 1120 | const this_line_index = statement_node.firstToken().line; | |
| 1121 | if (this_line_index - prev_line_index >= 2) { | |
| 3246 | const prev_node = block.statements.items[i - 1]; | |
| 3247 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken()); | |
| 3248 | if (loc.line >= 2) { | |
| 1122 | 3249 | break :blk "\n\n"; |
| 1123 | 3250 | } |
| 1124 | 3251 | } |
| ... | ... | @@ -1128,19 +3255,98 @@ pub const Parser = struct { |
| 1128 | 3255 | } |
| 1129 | 3256 | } |
| 1130 | 3257 | }, |
| 3258 | ast.Node.Id.Defer => { | |
| 3259 | const defer_node = @fieldParentPtr(ast.NodeDefer, "base", base); | |
| 3260 | try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token)); | |
| 3261 | try stack.append(RenderState { .Expression = defer_node.expr }); | |
| 3262 | }, | |
| 3263 | ast.Node.Id.Comptime => { | |
| 3264 | const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", base); | |
| 3265 | try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token)); | |
| 3266 | try stack.append(RenderState { .Expression = comptime_node.expr }); | |
| 3267 | }, | |
| 3268 | ast.Node.Id.AsyncAttribute => { | |
| 3269 | const async_attr = @fieldParentPtr(ast.NodeAsyncAttribute, "base", base); | |
| 3270 | try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token)); | |
| 3271 | ||
| 3272 | if (async_attr.allocator_type) |allocator_type| { | |
| 3273 | try stack.append(RenderState { .Text = ">" }); | |
| 3274 | try stack.append(RenderState { .Expression = allocator_type }); | |
| 3275 | try stack.append(RenderState { .Text = "<" }); | |
| 3276 | } | |
| 3277 | }, | |
| 3278 | ast.Node.Id.Suspend => { | |
| 3279 | const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", base); | |
| 3280 | try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token)); | |
| 3281 | ||
| 3282 | if (suspend_node.body) |body| { | |
| 3283 | try stack.append(RenderState { .Expression = body }); | |
| 3284 | try stack.append(RenderState { .Text = " " }); | |
| 3285 | } | |
| 3286 | ||
| 3287 | if (suspend_node.payload) |payload| { | |
| 3288 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3289 | try stack.append(RenderState { .Text = " " }); | |
| 3290 | } | |
| 3291 | }, | |
| 1131 | 3292 | ast.Node.Id.InfixOp => { |
| 1132 | 3293 | const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base); |
| 1133 | 3294 | try stack.append(RenderState { .Expression = prefix_op_node.rhs }); |
| 1134 | switch (prefix_op_node.op) { | |
| 1135 | ast.NodeInfixOp.InfixOp.EqualEqual => { | |
| 1136 | try stack.append(RenderState { .Text = " == "}); | |
| 1137 | }, | |
| 1138 | ast.NodeInfixOp.InfixOp.BangEqual => { | |
| 1139 | try stack.append(RenderState { .Text = " != "}); | |
| 1140 | }, | |
| 1141 | ast.NodeInfixOp.InfixOp.Period => { | |
| 1142 | try stack.append(RenderState { .Text = "."}); | |
| 1143 | }, | |
| 3295 | ||
| 3296 | if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) { | |
| 3297 | if (prefix_op_node.op.Catch) |payload| { | |
| 3298 | try stack.append(RenderState { .Text = " " }); | |
| 3299 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3300 | } | |
| 3301 | try stack.append(RenderState { .Text = " catch " }); | |
| 3302 | } else { | |
| 3303 | const text = switch (prefix_op_node.op) { | |
| 3304 | ast.NodeInfixOp.InfixOp.Add => " + ", | |
| 3305 | ast.NodeInfixOp.InfixOp.AddWrap => " +% ", | |
| 3306 | ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ", | |
| 3307 | ast.NodeInfixOp.InfixOp.ArrayMult => " ** ", | |
| 3308 | ast.NodeInfixOp.InfixOp.Assign => " = ", | |
| 3309 | ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ", | |
| 3310 | ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ", | |
| 3311 | ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ", | |
| 3312 | ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ", | |
| 3313 | ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ", | |
| 3314 | ast.NodeInfixOp.InfixOp.AssignDiv => " /= ", | |
| 3315 | ast.NodeInfixOp.InfixOp.AssignMinus => " -= ", | |
| 3316 | ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ", | |
| 3317 | ast.NodeInfixOp.InfixOp.AssignMod => " %= ", | |
| 3318 | ast.NodeInfixOp.InfixOp.AssignPlus => " += ", | |
| 3319 | ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ", | |
| 3320 | ast.NodeInfixOp.InfixOp.AssignTimes => " *= ", | |
| 3321 | ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ", | |
| 3322 | ast.NodeInfixOp.InfixOp.BangEqual => " != ", | |
| 3323 | ast.NodeInfixOp.InfixOp.BitAnd => " & ", | |
| 3324 | ast.NodeInfixOp.InfixOp.BitOr => " | ", | |
| 3325 | ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ", | |
| 3326 | ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ", | |
| 3327 | ast.NodeInfixOp.InfixOp.BitXor => " ^ ", | |
| 3328 | ast.NodeInfixOp.InfixOp.BoolAnd => " and ", | |
| 3329 | ast.NodeInfixOp.InfixOp.BoolOr => " or ", | |
| 3330 | ast.NodeInfixOp.InfixOp.Div => " / ", | |
| 3331 | ast.NodeInfixOp.InfixOp.EqualEqual => " == ", | |
| 3332 | ast.NodeInfixOp.InfixOp.ErrorUnion => "!", | |
| 3333 | ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ", | |
| 3334 | ast.NodeInfixOp.InfixOp.GreaterThan => " > ", | |
| 3335 | ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ", | |
| 3336 | ast.NodeInfixOp.InfixOp.LessThan => " < ", | |
| 3337 | ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ", | |
| 3338 | ast.NodeInfixOp.InfixOp.Mod => " % ", | |
| 3339 | ast.NodeInfixOp.InfixOp.Mult => " * ", | |
| 3340 | ast.NodeInfixOp.InfixOp.MultWrap => " *% ", | |
| 3341 | ast.NodeInfixOp.InfixOp.Period => ".", | |
| 3342 | ast.NodeInfixOp.InfixOp.Sub => " - ", | |
| 3343 | ast.NodeInfixOp.InfixOp.SubWrap => " -% ", | |
| 3344 | ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ", | |
| 3345 | ast.NodeInfixOp.InfixOp.Range => " ... ", | |
| 3346 | ast.NodeInfixOp.InfixOp.Catch => unreachable, | |
| 3347 | }; | |
| 3348 | ||
| 3349 | try stack.append(RenderState { .Text = text }); | |
| 1144 | 3350 | } |
| 1145 | 3351 | try stack.append(RenderState { .Expression = prefix_op_node.lhs }); |
| 1146 | 3352 | }, |
| ... | ... | @@ -1148,12 +3354,6 @@ pub const Parser = struct { |
| 1148 | 3354 | const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base); |
| 1149 | 3355 | try stack.append(RenderState { .Expression = prefix_op_node.rhs }); |
| 1150 | 3356 | switch (prefix_op_node.op) { |
| 1151 | ast.NodePrefixOp.PrefixOp.Return => { | |
| 1152 | try stream.write("return "); | |
| 1153 | }, | |
| 1154 | ast.NodePrefixOp.PrefixOp.Try => { | |
| 1155 | try stream.write("try "); | |
| 1156 | }, | |
| 1157 | 3357 | ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| { |
| 1158 | 3358 | try stream.write("&"); |
| 1159 | 3359 | if (addr_of_info.volatile_token != null) { |
| ... | ... | @@ -1168,7 +3368,179 @@ pub const Parser = struct { |
| 1168 | 3368 | try stack.append(RenderState { .Expression = align_expr}); |
| 1169 | 3369 | } |
| 1170 | 3370 | }, |
| 3371 | ast.NodePrefixOp.PrefixOp.SliceType => |addr_of_info| { | |
| 3372 | try stream.write("[]"); | |
| 3373 | if (addr_of_info.volatile_token != null) { | |
| 3374 | try stack.append(RenderState { .Text = "volatile "}); | |
| 3375 | } | |
| 3376 | if (addr_of_info.const_token != null) { | |
| 3377 | try stack.append(RenderState { .Text = "const "}); | |
| 3378 | } | |
| 3379 | if (addr_of_info.align_expr) |align_expr| { | |
| 3380 | try stream.print("align("); | |
| 3381 | try stack.append(RenderState { .Text = ") "}); | |
| 3382 | try stack.append(RenderState { .Expression = align_expr}); | |
| 3383 | } | |
| 3384 | }, | |
| 3385 | ast.NodePrefixOp.PrefixOp.ArrayType => |array_index| { | |
| 3386 | try stack.append(RenderState { .Text = "]"}); | |
| 3387 | try stack.append(RenderState { .Expression = array_index}); | |
| 3388 | try stack.append(RenderState { .Text = "["}); | |
| 3389 | }, | |
| 3390 | ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"), | |
| 3391 | ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"), | |
| 3392 | ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"), | |
| 3393 | ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"), | |
| 3394 | ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"), | |
| 3395 | ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "), | |
| 3396 | ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"), | |
| 3397 | ast.NodePrefixOp.PrefixOp.MaybeType => try stream.write("?"), | |
| 3398 | ast.NodePrefixOp.PrefixOp.Await => try stream.write("await "), | |
| 3399 | ast.NodePrefixOp.PrefixOp.Cancel => try stream.write("cancel "), | |
| 3400 | ast.NodePrefixOp.PrefixOp.Resume => try stream.write("resume "), | |
| 3401 | } | |
| 3402 | }, | |
| 3403 | ast.Node.Id.SuffixOp => { | |
| 3404 | const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", base); | |
| 3405 | ||
| 3406 | switch (suffix_op.op) { | |
| 3407 | ast.NodeSuffixOp.SuffixOp.Call => |call_info| { | |
| 3408 | try stack.append(RenderState { .Text = ")"}); | |
| 3409 | var i = call_info.params.len; | |
| 3410 | while (i != 0) { | |
| 3411 | i -= 1; | |
| 3412 | const param_node = call_info.params.at(i); | |
| 3413 | try stack.append(RenderState { .Expression = param_node}); | |
| 3414 | if (i != 0) { | |
| 3415 | try stack.append(RenderState { .Text = ", " }); | |
| 3416 | } | |
| 3417 | } | |
| 3418 | try stack.append(RenderState { .Text = "("}); | |
| 3419 | try stack.append(RenderState { .Expression = suffix_op.lhs }); | |
| 3420 | ||
| 3421 | if (call_info.async_attr) |async_attr| { | |
| 3422 | try stack.append(RenderState { .Text = " "}); | |
| 3423 | try stack.append(RenderState { .Expression = &async_attr.base }); | |
| 3424 | } | |
| 3425 | }, | |
| 3426 | ast.NodeSuffixOp.SuffixOp.ArrayAccess => |index_expr| { | |
| 3427 | try stack.append(RenderState { .Text = "]"}); | |
| 3428 | try stack.append(RenderState { .Expression = index_expr}); | |
| 3429 | try stack.append(RenderState { .Text = "["}); | |
| 3430 | try stack.append(RenderState { .Expression = suffix_op.lhs }); | |
| 3431 | }, | |
| 3432 | ast.NodeSuffixOp.SuffixOp.Slice => |range| { | |
| 3433 | try stack.append(RenderState { .Text = "]"}); | |
| 3434 | if (range.end) |end| { | |
| 3435 | try stack.append(RenderState { .Expression = end}); | |
| 3436 | } | |
| 3437 | try stack.append(RenderState { .Text = ".."}); | |
| 3438 | try stack.append(RenderState { .Expression = range.start}); | |
| 3439 | try stack.append(RenderState { .Text = "["}); | |
| 3440 | try stack.append(RenderState { .Expression = suffix_op.lhs }); | |
| 3441 | }, | |
| 3442 | ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| { | |
| 3443 | try stack.append(RenderState { .Text = " }"}); | |
| 3444 | var i = field_inits.len; | |
| 3445 | while (i != 0) { | |
| 3446 | i -= 1; | |
| 3447 | const field_init = field_inits.at(i); | |
| 3448 | try stack.append(RenderState { .FieldInitializer = field_init }); | |
| 3449 | try stack.append(RenderState { .Text = " " }); | |
| 3450 | if (i != 0) { | |
| 3451 | try stack.append(RenderState { .Text = "," }); | |
| 3452 | } | |
| 3453 | } | |
| 3454 | try stack.append(RenderState { .Text = "{"}); | |
| 3455 | try stack.append(RenderState { .Expression = suffix_op.lhs }); | |
| 3456 | }, | |
| 3457 | ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| { | |
| 3458 | try stack.append(RenderState { .Text = " }"}); | |
| 3459 | var i = exprs.len; | |
| 3460 | while (i != 0) { | |
| 3461 | i -= 1; | |
| 3462 | const expr = exprs.at(i); | |
| 3463 | try stack.append(RenderState { .Expression = expr }); | |
| 3464 | try stack.append(RenderState { .Text = " " }); | |
| 3465 | if (i != 0) { | |
| 3466 | try stack.append(RenderState { .Text = "," }); | |
| 3467 | } | |
| 3468 | } | |
| 3469 | try stack.append(RenderState { .Text = "{"}); | |
| 3470 | try stack.append(RenderState { .Expression = suffix_op.lhs }); | |
| 3471 | }, | |
| 3472 | } | |
| 3473 | }, | |
| 3474 | ast.Node.Id.ControlFlowExpression => { | |
| 3475 | const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base); | |
| 3476 | switch (flow_expr.kind) { | |
| 3477 | ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| { | |
| 3478 | try stream.print("break"); | |
| 3479 | if (maybe_blk_token) |blk_token| { | |
| 3480 | try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token)); | |
| 3481 | } | |
| 3482 | }, | |
| 3483 | ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| { | |
| 3484 | try stream.print("continue"); | |
| 3485 | if (maybe_blk_token) |blk_token| { | |
| 3486 | try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token)); | |
| 3487 | } | |
| 3488 | }, | |
| 3489 | ast.NodeControlFlowExpression.Kind.Return => { | |
| 3490 | try stream.print("return"); | |
| 3491 | }, | |
| 3492 | ||
| 1171 | 3493 | } |
| 3494 | ||
| 3495 | if (flow_expr.rhs) |rhs| { | |
| 3496 | try stream.print(" "); | |
| 3497 | try stack.append(RenderState { .Expression = rhs }); | |
| 3498 | } | |
| 3499 | }, | |
| 3500 | ast.Node.Id.Payload => { | |
| 3501 | const payload = @fieldParentPtr(ast.NodePayload, "base", base); | |
| 3502 | try stack.append(RenderState { .Text = "|"}); | |
| 3503 | try stack.append(RenderState { .Expression = &payload.error_symbol.base }); | |
| 3504 | try stack.append(RenderState { .Text = "|"}); | |
| 3505 | }, | |
| 3506 | ast.Node.Id.PointerPayload => { | |
| 3507 | const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base); | |
| 3508 | try stack.append(RenderState { .Text = "|"}); | |
| 3509 | try stack.append(RenderState { .Expression = &payload.value_symbol.base }); | |
| 3510 | ||
| 3511 | if (payload.is_ptr) { | |
| 3512 | try stack.append(RenderState { .Text = "*"}); | |
| 3513 | } | |
| 3514 | ||
| 3515 | try stack.append(RenderState { .Text = "|"}); | |
| 3516 | }, | |
| 3517 | ast.Node.Id.PointerIndexPayload => { | |
| 3518 | const payload = @fieldParentPtr(ast.NodePointerIndexPayload, "base", base); | |
| 3519 | try stack.append(RenderState { .Text = "|"}); | |
| 3520 | ||
| 3521 | if (payload.index_symbol) |index_symbol| { | |
| 3522 | try stack.append(RenderState { .Expression = &index_symbol.base }); | |
| 3523 | try stack.append(RenderState { .Text = ", "}); | |
| 3524 | } | |
| 3525 | ||
| 3526 | try stack.append(RenderState { .Expression = &payload.value_symbol.base }); | |
| 3527 | ||
| 3528 | if (payload.is_ptr) { | |
| 3529 | try stack.append(RenderState { .Text = "*"}); | |
| 3530 | } | |
| 3531 | ||
| 3532 | try stack.append(RenderState { .Text = "|"}); | |
| 3533 | }, | |
| 3534 | ast.Node.Id.GroupedExpression => { | |
| 3535 | const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base); | |
| 3536 | try stack.append(RenderState { .Text = ")"}); | |
| 3537 | try stack.append(RenderState { .Expression = grouped_expr.expr }); | |
| 3538 | try stack.append(RenderState { .Text = "("}); | |
| 3539 | }, | |
| 3540 | ast.Node.Id.FieldInitializer => { | |
| 3541 | const field_init = @fieldParentPtr(ast.NodeFieldInitializer, "base", base); | |
| 3542 | try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token)); | |
| 3543 | try stack.append(RenderState { .Expression = field_init.expr }); | |
| 1172 | 3544 | }, |
| 1173 | 3545 | ast.Node.Id.IntegerLiteral => { |
| 1174 | 3546 | const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base); |
| ... | ... | @@ -1182,6 +3554,151 @@ pub const Parser = struct { |
| 1182 | 3554 | const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base); |
| 1183 | 3555 | try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token)); |
| 1184 | 3556 | }, |
| 3557 | ast.Node.Id.CharLiteral => { | |
| 3558 | const char_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base); | |
| 3559 | try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token)); | |
| 3560 | }, | |
| 3561 | ast.Node.Id.BoolLiteral => { | |
| 3562 | const bool_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base); | |
| 3563 | try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token)); | |
| 3564 | }, | |
| 3565 | ast.Node.Id.NullLiteral => { | |
| 3566 | const null_literal = @fieldParentPtr(ast.NodeNullLiteral, "base", base); | |
| 3567 | try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token)); | |
| 3568 | }, | |
| 3569 | ast.Node.Id.ThisLiteral => { | |
| 3570 | const this_literal = @fieldParentPtr(ast.NodeThisLiteral, "base", base); | |
| 3571 | try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token)); | |
| 3572 | }, | |
| 3573 | ast.Node.Id.Unreachable => { | |
| 3574 | const unreachable_node = @fieldParentPtr(ast.NodeUnreachable, "base", base); | |
| 3575 | try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token)); | |
| 3576 | }, | |
| 3577 | ast.Node.Id.ErrorType => { | |
| 3578 | const error_type = @fieldParentPtr(ast.NodeErrorType, "base", base); | |
| 3579 | try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token)); | |
| 3580 | }, | |
| 3581 | ast.Node.Id.VarType => { | |
| 3582 | const var_type = @fieldParentPtr(ast.NodeVarType, "base", base); | |
| 3583 | try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token)); | |
| 3584 | }, | |
| 3585 | ast.Node.Id.ContainerDecl => { | |
| 3586 | const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base); | |
| 3587 | ||
| 3588 | switch (container_decl.layout) { | |
| 3589 | ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "), | |
| 3590 | ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "), | |
| 3591 | ast.NodeContainerDecl.Layout.Auto => { }, | |
| 3592 | } | |
| 3593 | ||
| 3594 | switch (container_decl.kind) { | |
| 3595 | ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"), | |
| 3596 | ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"), | |
| 3597 | ast.NodeContainerDecl.Kind.Union => try stream.print("union"), | |
| 3598 | } | |
| 3599 | ||
| 3600 | try stack.append(RenderState { .Text = "}"}); | |
| 3601 | try stack.append(RenderState.PrintIndent); | |
| 3602 | try stack.append(RenderState { .Indent = indent }); | |
| 3603 | try stack.append(RenderState { .Text = "\n"}); | |
| 3604 | ||
| 3605 | const fields_and_decls = container_decl.fields_and_decls.toSliceConst(); | |
| 3606 | var i = fields_and_decls.len; | |
| 3607 | while (i != 0) { | |
| 3608 | i -= 1; | |
| 3609 | const node = fields_and_decls[i]; | |
| 3610 | try stack.append(RenderState { .TopLevelDecl = node}); | |
| 3611 | try stack.append(RenderState.PrintIndent); | |
| 3612 | try stack.append(RenderState { | |
| 3613 | .Text = blk: { | |
| 3614 | if (i != 0) { | |
| 3615 | const prev_node = fields_and_decls[i - 1]; | |
| 3616 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken()); | |
| 3617 | if (loc.line >= 2) { | |
| 3618 | break :blk "\n\n"; | |
| 3619 | } | |
| 3620 | } | |
| 3621 | break :blk "\n"; | |
| 3622 | }, | |
| 3623 | }); | |
| 3624 | ||
| 3625 | if (i != 0) { | |
| 3626 | const prev_node = fields_and_decls[i - 1]; | |
| 3627 | switch (prev_node.id) { | |
| 3628 | ast.Node.Id.StructField, | |
| 3629 | ast.Node.Id.UnionTag, | |
| 3630 | ast.Node.Id.EnumTag => { | |
| 3631 | try stack.append(RenderState { .Text = "," }); | |
| 3632 | }, | |
| 3633 | else => { } | |
| 3634 | } | |
| 3635 | } | |
| 3636 | } | |
| 3637 | try stack.append(RenderState { .Indent = indent + indent_delta}); | |
| 3638 | try stack.append(RenderState { .Text = "{"}); | |
| 3639 | ||
| 3640 | switch (container_decl.init_arg_expr) { | |
| 3641 | ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}), | |
| 3642 | ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}), | |
| 3643 | ast.NodeContainerDecl.InitArg.Type => |type_expr| { | |
| 3644 | try stack.append(RenderState { .Text = ") "}); | |
| 3645 | try stack.append(RenderState { .Expression = type_expr}); | |
| 3646 | try stack.append(RenderState { .Text = "("}); | |
| 3647 | }, | |
| 3648 | } | |
| 3649 | }, | |
| 3650 | ast.Node.Id.ErrorSetDecl => { | |
| 3651 | const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base); | |
| 3652 | try stream.print("error "); | |
| 3653 | ||
| 3654 | try stack.append(RenderState { .Text = "}"}); | |
| 3655 | try stack.append(RenderState.PrintIndent); | |
| 3656 | try stack.append(RenderState { .Indent = indent }); | |
| 3657 | try stack.append(RenderState { .Text = "\n"}); | |
| 3658 | ||
| 3659 | const decls = err_set_decl.decls.toSliceConst(); | |
| 3660 | var i = decls.len; | |
| 3661 | while (i != 0) { | |
| 3662 | i -= 1; | |
| 3663 | const node = decls[i]; | |
| 3664 | try stack.append(RenderState { .Expression = &node.base}); | |
| 3665 | try stack.append(RenderState.PrintIndent); | |
| 3666 | try stack.append(RenderState { | |
| 3667 | .Text = blk: { | |
| 3668 | if (i != 0) { | |
| 3669 | const prev_node = decls[i - 1]; | |
| 3670 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken()); | |
| 3671 | if (loc.line >= 2) { | |
| 3672 | break :blk "\n\n"; | |
| 3673 | } | |
| 3674 | } | |
| 3675 | break :blk "\n"; | |
| 3676 | }, | |
| 3677 | }); | |
| 3678 | ||
| 3679 | if (i != 0) { | |
| 3680 | try stack.append(RenderState { .Text = "," }); | |
| 3681 | } | |
| 3682 | } | |
| 3683 | try stack.append(RenderState { .Indent = indent + indent_delta}); | |
| 3684 | try stack.append(RenderState { .Text = "{"}); | |
| 3685 | }, | |
| 3686 | ast.Node.Id.MultilineStringLiteral => { | |
| 3687 | const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base); | |
| 3688 | try stream.print("\n"); | |
| 3689 | ||
| 3690 | var i : usize = 0; | |
| 3691 | while (i < multiline_str_literal.tokens.len) : (i += 1) { | |
| 3692 | const t = multiline_str_literal.tokens.at(i); | |
| 3693 | try stream.writeByteNTimes(' ', indent + indent_delta); | |
| 3694 | try stream.print("{}", self.tokenizer.getTokenSlice(t)); | |
| 3695 | } | |
| 3696 | try stream.writeByteNTimes(' ', indent + indent_delta); | |
| 3697 | }, | |
| 3698 | ast.Node.Id.UndefinedLiteral => { | |
| 3699 | const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base); | |
| 3700 | try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token)); | |
| 3701 | }, | |
| 1185 | 3702 | ast.Node.Id.BuiltinCall => { |
| 1186 | 3703 | const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base); |
| 1187 | 3704 | try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token)); |
| ... | ... | @@ -1196,11 +3713,420 @@ pub const Parser = struct { |
| 1196 | 3713 | } |
| 1197 | 3714 | } |
| 1198 | 3715 | }, |
| 1199 | ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"), | |
| 1200 | ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"), | |
| 3716 | ast.Node.Id.FnProto => { | |
| 3717 | const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", base); | |
| 3718 | ||
| 3719 | switch (fn_proto.return_type) { | |
| 3720 | ast.NodeFnProto.ReturnType.Explicit => |node| { | |
| 3721 | try stack.append(RenderState { .Expression = node}); | |
| 3722 | }, | |
| 3723 | ast.NodeFnProto.ReturnType.InferErrorSet => |node| { | |
| 3724 | try stack.append(RenderState { .Expression = node}); | |
| 3725 | try stack.append(RenderState { .Text = "!"}); | |
| 3726 | }, | |
| 3727 | } | |
| 3728 | ||
| 3729 | if (fn_proto.align_expr != null) { | |
| 3730 | @panic("TODO"); | |
| 3731 | } | |
| 3732 | ||
| 3733 | try stack.append(RenderState { .Text = ") " }); | |
| 3734 | var i = fn_proto.params.len; | |
| 3735 | while (i != 0) { | |
| 3736 | i -= 1; | |
| 3737 | const param_decl_node = fn_proto.params.items[i]; | |
| 3738 | try stack.append(RenderState { .ParamDecl = param_decl_node}); | |
| 3739 | if (i != 0) { | |
| 3740 | try stack.append(RenderState { .Text = ", " }); | |
| 3741 | } | |
| 3742 | } | |
| 3743 | ||
| 3744 | try stack.append(RenderState { .Text = "(" }); | |
| 3745 | if (fn_proto.name_token) |name_token| { | |
| 3746 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) }); | |
| 3747 | try stack.append(RenderState { .Text = " " }); | |
| 3748 | } | |
| 3749 | ||
| 3750 | try stack.append(RenderState { .Text = "fn" }); | |
| 3751 | ||
| 3752 | if (fn_proto.async_attr) |async_attr| { | |
| 3753 | try stack.append(RenderState { .Text = " " }); | |
| 3754 | try stack.append(RenderState { .Expression = &async_attr.base }); | |
| 3755 | } | |
| 3756 | ||
| 3757 | if (fn_proto.cc_token) |cc_token| { | |
| 3758 | try stack.append(RenderState { .Text = " " }); | |
| 3759 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) }); | |
| 3760 | } | |
| 3761 | ||
| 3762 | if (fn_proto.lib_name) |lib_name| { | |
| 3763 | try stack.append(RenderState { .Text = " " }); | |
| 3764 | try stack.append(RenderState { .Expression = lib_name }); | |
| 3765 | } | |
| 3766 | if (fn_proto.extern_token) |extern_token| { | |
| 3767 | try stack.append(RenderState { .Text = " " }); | |
| 3768 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) }); | |
| 3769 | } | |
| 3770 | ||
| 3771 | if (fn_proto.visib_token) |visib_token| { | |
| 3772 | assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export); | |
| 3773 | try stack.append(RenderState { .Text = " " }); | |
| 3774 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) }); | |
| 3775 | } | |
| 3776 | }, | |
| 3777 | ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"), | |
| 3778 | ast.Node.Id.Switch => { | |
| 3779 | const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base); | |
| 3780 | try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token)); | |
| 3781 | ||
| 3782 | try stack.append(RenderState { .Text = "}"}); | |
| 3783 | try stack.append(RenderState.PrintIndent); | |
| 3784 | try stack.append(RenderState { .Indent = indent }); | |
| 3785 | try stack.append(RenderState { .Text = "\n"}); | |
| 3786 | ||
| 3787 | const cases = switch_node.cases.toSliceConst(); | |
| 3788 | var i = cases.len; | |
| 3789 | while (i != 0) { | |
| 3790 | i -= 1; | |
| 3791 | const node = cases[i]; | |
| 3792 | try stack.append(RenderState { .Expression = &node.base}); | |
| 3793 | try stack.append(RenderState.PrintIndent); | |
| 3794 | try stack.append(RenderState { | |
| 3795 | .Text = blk: { | |
| 3796 | if (i != 0) { | |
| 3797 | const prev_node = cases[i - 1]; | |
| 3798 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken()); | |
| 3799 | if (loc.line >= 2) { | |
| 3800 | break :blk "\n\n"; | |
| 3801 | } | |
| 3802 | } | |
| 3803 | break :blk "\n"; | |
| 3804 | }, | |
| 3805 | }); | |
| 3806 | ||
| 3807 | if (i != 0) { | |
| 3808 | try stack.append(RenderState { .Text = "," }); | |
| 3809 | } | |
| 3810 | } | |
| 3811 | try stack.append(RenderState { .Indent = indent + indent_delta}); | |
| 3812 | try stack.append(RenderState { .Text = ") {"}); | |
| 3813 | try stack.append(RenderState { .Expression = switch_node.expr }); | |
| 3814 | }, | |
| 3815 | ast.Node.Id.SwitchCase => { | |
| 3816 | const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base); | |
| 3817 | ||
| 3818 | try stack.append(RenderState { .Expression = switch_case.expr }); | |
| 3819 | if (switch_case.payload) |payload| { | |
| 3820 | try stack.append(RenderState { .Text = " " }); | |
| 3821 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3822 | } | |
| 3823 | try stack.append(RenderState { .Text = " => "}); | |
| 3824 | ||
| 3825 | const items = switch_case.items.toSliceConst(); | |
| 3826 | var i = items.len; | |
| 3827 | while (i != 0) { | |
| 3828 | i -= 1; | |
| 3829 | try stack.append(RenderState { .Expression = items[i] }); | |
| 3830 | ||
| 3831 | if (i != 0) { | |
| 3832 | try stack.append(RenderState { .Text = ", " }); | |
| 3833 | } | |
| 3834 | } | |
| 3835 | }, | |
| 3836 | ast.Node.Id.SwitchElse => { | |
| 3837 | const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base); | |
| 3838 | try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token)); | |
| 3839 | }, | |
| 3840 | ast.Node.Id.Else => { | |
| 3841 | const else_node = @fieldParentPtr(ast.NodeElse, "base", base); | |
| 3842 | try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token)); | |
| 3843 | ||
| 3844 | switch (else_node.body.id) { | |
| 3845 | ast.Node.Id.Block, ast.Node.Id.If, | |
| 3846 | ast.Node.Id.For, ast.Node.Id.While, | |
| 3847 | ast.Node.Id.Switch => { | |
| 3848 | try stream.print(" "); | |
| 3849 | try stack.append(RenderState { .Expression = else_node.body }); | |
| 3850 | }, | |
| 3851 | else => { | |
| 3852 | try stack.append(RenderState { .Indent = indent }); | |
| 3853 | try stack.append(RenderState { .Expression = else_node.body }); | |
| 3854 | try stack.append(RenderState.PrintIndent); | |
| 3855 | try stack.append(RenderState { .Indent = indent + indent_delta }); | |
| 3856 | try stack.append(RenderState { .Text = "\n" }); | |
| 3857 | } | |
| 3858 | } | |
| 3859 | ||
| 3860 | if (else_node.payload) |payload| { | |
| 3861 | try stack.append(RenderState { .Text = " " }); | |
| 3862 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3863 | } | |
| 3864 | }, | |
| 3865 | ast.Node.Id.While => { | |
| 3866 | const while_node = @fieldParentPtr(ast.NodeWhile, "base", base); | |
| 3867 | if (while_node.label) |label| { | |
| 3868 | try stream.print("{}: ", self.tokenizer.getTokenSlice(label)); | |
| 3869 | } | |
| 3870 | ||
| 3871 | if (while_node.inline_token) |inline_token| { | |
| 3872 | try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token)); | |
| 3873 | } | |
| 3874 | ||
| 3875 | try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token)); | |
| 3876 | ||
| 3877 | if (while_node.@"else") |@"else"| { | |
| 3878 | try stack.append(RenderState { .Expression = &@"else".base }); | |
| 3879 | ||
| 3880 | if (while_node.body.id == ast.Node.Id.Block) { | |
| 3881 | try stack.append(RenderState { .Text = " " }); | |
| 3882 | } else { | |
| 3883 | try stack.append(RenderState.PrintIndent); | |
| 3884 | try stack.append(RenderState { .Text = "\n" }); | |
| 3885 | } | |
| 3886 | } | |
| 3887 | ||
| 3888 | if (while_node.body.id == ast.Node.Id.Block) { | |
| 3889 | try stack.append(RenderState { .Expression = while_node.body }); | |
| 3890 | try stack.append(RenderState { .Text = " " }); | |
| 3891 | } else { | |
| 3892 | try stack.append(RenderState { .Indent = indent }); | |
| 3893 | try stack.append(RenderState { .Expression = while_node.body }); | |
| 3894 | try stack.append(RenderState.PrintIndent); | |
| 3895 | try stack.append(RenderState { .Indent = indent + indent_delta }); | |
| 3896 | try stack.append(RenderState { .Text = "\n" }); | |
| 3897 | } | |
| 3898 | ||
| 3899 | if (while_node.continue_expr) |continue_expr| { | |
| 3900 | try stack.append(RenderState { .Text = ")" }); | |
| 3901 | try stack.append(RenderState { .Expression = continue_expr }); | |
| 3902 | try stack.append(RenderState { .Text = ": (" }); | |
| 3903 | try stack.append(RenderState { .Text = " " }); | |
| 3904 | } | |
| 3905 | ||
| 3906 | if (while_node.payload) |payload| { | |
| 3907 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3908 | try stack.append(RenderState { .Text = " " }); | |
| 3909 | } | |
| 3910 | ||
| 3911 | try stack.append(RenderState { .Text = ")" }); | |
| 3912 | try stack.append(RenderState { .Expression = while_node.condition }); | |
| 3913 | try stack.append(RenderState { .Text = "(" }); | |
| 3914 | }, | |
| 3915 | ast.Node.Id.For => { | |
| 3916 | const for_node = @fieldParentPtr(ast.NodeFor, "base", base); | |
| 3917 | if (for_node.label) |label| { | |
| 3918 | try stream.print("{}: ", self.tokenizer.getTokenSlice(label)); | |
| 3919 | } | |
| 3920 | ||
| 3921 | if (for_node.inline_token) |inline_token| { | |
| 3922 | try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token)); | |
| 3923 | } | |
| 3924 | ||
| 3925 | try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token)); | |
| 3926 | ||
| 3927 | if (for_node.@"else") |@"else"| { | |
| 3928 | try stack.append(RenderState { .Expression = &@"else".base }); | |
| 3929 | ||
| 3930 | if (for_node.body.id == ast.Node.Id.Block) { | |
| 3931 | try stack.append(RenderState { .Text = " " }); | |
| 3932 | } else { | |
| 3933 | try stack.append(RenderState.PrintIndent); | |
| 3934 | try stack.append(RenderState { .Text = "\n" }); | |
| 3935 | } | |
| 3936 | } | |
| 3937 | ||
| 3938 | if (for_node.body.id == ast.Node.Id.Block) { | |
| 3939 | try stack.append(RenderState { .Expression = for_node.body }); | |
| 3940 | try stack.append(RenderState { .Text = " " }); | |
| 3941 | } else { | |
| 3942 | try stack.append(RenderState { .Indent = indent }); | |
| 3943 | try stack.append(RenderState { .Expression = for_node.body }); | |
| 3944 | try stack.append(RenderState.PrintIndent); | |
| 3945 | try stack.append(RenderState { .Indent = indent + indent_delta }); | |
| 3946 | try stack.append(RenderState { .Text = "\n" }); | |
| 3947 | } | |
| 3948 | ||
| 3949 | if (for_node.payload) |payload| { | |
| 3950 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3951 | try stack.append(RenderState { .Text = " " }); | |
| 3952 | } | |
| 3953 | ||
| 3954 | try stack.append(RenderState { .Text = ")" }); | |
| 3955 | try stack.append(RenderState { .Expression = for_node.array_expr }); | |
| 3956 | try stack.append(RenderState { .Text = "(" }); | |
| 3957 | }, | |
| 3958 | ast.Node.Id.If => { | |
| 3959 | const if_node = @fieldParentPtr(ast.NodeIf, "base", base); | |
| 3960 | try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token)); | |
| 3961 | ||
| 3962 | switch (if_node.body.id) { | |
| 3963 | ast.Node.Id.Block, ast.Node.Id.If, | |
| 3964 | ast.Node.Id.For, ast.Node.Id.While, | |
| 3965 | ast.Node.Id.Switch => { | |
| 3966 | if (if_node.@"else") |@"else"| { | |
| 3967 | try stack.append(RenderState { .Expression = &@"else".base }); | |
| 3968 | ||
| 3969 | if (if_node.body.id == ast.Node.Id.Block) { | |
| 3970 | try stack.append(RenderState { .Text = " " }); | |
| 3971 | } else { | |
| 3972 | try stack.append(RenderState.PrintIndent); | |
| 3973 | try stack.append(RenderState { .Text = "\n" }); | |
| 3974 | } | |
| 3975 | } | |
| 3976 | }, | |
| 3977 | else => { | |
| 3978 | if (if_node.@"else") |@"else"| { | |
| 3979 | try stack.append(RenderState { .Expression = @"else".body }); | |
| 3980 | ||
| 3981 | if (@"else".payload) |payload| { | |
| 3982 | try stack.append(RenderState { .Text = " " }); | |
| 3983 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3984 | } | |
| 3985 | ||
| 3986 | try stack.append(RenderState { .Text = " " }); | |
| 3987 | try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) }); | |
| 3988 | try stack.append(RenderState { .Text = " " }); | |
| 3989 | } | |
| 3990 | } | |
| 3991 | } | |
| 3992 | ||
| 3993 | try stack.append(RenderState { .Expression = if_node.body }); | |
| 3994 | try stack.append(RenderState { .Text = " " }); | |
| 3995 | ||
| 3996 | if (if_node.payload) |payload| { | |
| 3997 | try stack.append(RenderState { .Expression = &payload.base }); | |
| 3998 | try stack.append(RenderState { .Text = " " }); | |
| 3999 | } | |
| 4000 | ||
| 4001 | try stack.append(RenderState { .Text = ")" }); | |
| 4002 | try stack.append(RenderState { .Expression = if_node.condition }); | |
| 4003 | try stack.append(RenderState { .Text = "(" }); | |
| 4004 | }, | |
| 4005 | ast.Node.Id.Asm => { | |
| 4006 | const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base); | |
| 4007 | try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token)); | |
| 4008 | ||
| 4009 | if (asm_node.is_volatile) { | |
| 4010 | try stream.write("volatile "); | |
| 4011 | } | |
| 4012 | ||
| 4013 | try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template)); | |
| 4014 | ||
| 4015 | try stack.append(RenderState { .Indent = indent }); | |
| 4016 | try stack.append(RenderState { .Text = ")" }); | |
| 4017 | { | |
| 4018 | const cloppers = asm_node.cloppers.toSliceConst(); | |
| 4019 | var i = cloppers.len; | |
| 4020 | while (i != 0) { | |
| 4021 | i -= 1; | |
| 4022 | try stack.append(RenderState { .Expression = &cloppers[i].base }); | |
| 4023 | ||
| 4024 | if (i != 0) { | |
| 4025 | try stack.append(RenderState { .Text = ", " }); | |
| 4026 | } | |
| 4027 | } | |
| 4028 | } | |
| 4029 | try stack.append(RenderState { .Text = ": " }); | |
| 4030 | try stack.append(RenderState.PrintIndent); | |
| 4031 | try stack.append(RenderState { .Indent = indent + indent_delta }); | |
| 4032 | try stack.append(RenderState { .Text = "\n" }); | |
| 4033 | { | |
| 4034 | const inputs = asm_node.inputs.toSliceConst(); | |
| 4035 | var i = inputs.len; | |
| 4036 | while (i != 0) { | |
| 4037 | i -= 1; | |
| 4038 | const node = inputs[i]; | |
| 4039 | try stack.append(RenderState { .Expression = &node.base}); | |
| 4040 | ||
| 4041 | if (i != 0) { | |
| 4042 | try stack.append(RenderState.PrintIndent); | |
| 4043 | try stack.append(RenderState { | |
| 4044 | .Text = blk: { | |
| 4045 | const prev_node = inputs[i - 1]; | |
| 4046 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken()); | |
| 4047 | if (loc.line >= 2) { | |
| 4048 | break :blk "\n\n"; | |
| 4049 | } | |
| 4050 | break :blk "\n"; | |
| 4051 | }, | |
| 4052 | }); | |
| 4053 | try stack.append(RenderState { .Text = "," }); | |
| 4054 | } | |
| 4055 | } | |
| 4056 | } | |
| 4057 | try stack.append(RenderState { .Indent = indent + indent_delta + 2}); | |
| 4058 | try stack.append(RenderState { .Text = ": "}); | |
| 4059 | try stack.append(RenderState.PrintIndent); | |
| 4060 | try stack.append(RenderState { .Indent = indent + indent_delta}); | |
| 4061 | try stack.append(RenderState { .Text = "\n" }); | |
| 4062 | { | |
| 4063 | const outputs = asm_node.outputs.toSliceConst(); | |
| 4064 | var i = outputs.len; | |
| 4065 | while (i != 0) { | |
| 4066 | i -= 1; | |
| 4067 | const node = outputs[i]; | |
| 4068 | try stack.append(RenderState { .Expression = &node.base}); | |
| 4069 | ||
| 4070 | if (i != 0) { | |
| 4071 | try stack.append(RenderState.PrintIndent); | |
| 4072 | try stack.append(RenderState { | |
| 4073 | .Text = blk: { | |
| 4074 | const prev_node = outputs[i - 1]; | |
| 4075 | const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken()); | |
| 4076 | if (loc.line >= 2) { | |
| 4077 | break :blk "\n\n"; | |
| 4078 | } | |
| 4079 | break :blk "\n"; | |
| 4080 | }, | |
| 4081 | }); | |
| 4082 | try stack.append(RenderState { .Text = "," }); | |
| 4083 | } | |
| 4084 | } | |
| 4085 | } | |
| 4086 | try stack.append(RenderState { .Indent = indent + indent_delta + 2}); | |
| 4087 | try stack.append(RenderState { .Text = ": "}); | |
| 4088 | try stack.append(RenderState.PrintIndent); | |
| 4089 | try stack.append(RenderState { .Indent = indent + indent_delta}); | |
| 4090 | try stack.append(RenderState { .Text = "\n" }); | |
| 4091 | }, | |
| 4092 | ast.Node.Id.AsmInput => { | |
| 4093 | const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base); | |
| 4094 | ||
| 4095 | try stack.append(RenderState { .Text = ")"}); | |
| 4096 | try stack.append(RenderState { .Expression = asm_input.expr}); | |
| 4097 | try stack.append(RenderState { .Text = " ("}); | |
| 4098 | try stack.append(RenderState { .Expression = &asm_input.constraint.base}); | |
| 4099 | try stack.append(RenderState { .Text = "] "}); | |
| 4100 | try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base}); | |
| 4101 | try stack.append(RenderState { .Text = "["}); | |
| 4102 | }, | |
| 4103 | ast.Node.Id.AsmOutput => { | |
| 4104 | const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base); | |
| 4105 | ||
| 4106 | try stack.append(RenderState { .Text = ")"}); | |
| 4107 | switch (asm_output.kind) { | |
| 4108 | ast.NodeAsmOutput.Kind.Variable => |variable_name| { | |
| 4109 | try stack.append(RenderState { .Expression = &variable_name.base}); | |
| 4110 | }, | |
| 4111 | ast.NodeAsmOutput.Kind.Return => |return_type| { | |
| 4112 | try stack.append(RenderState { .Expression = return_type}); | |
| 4113 | try stack.append(RenderState { .Text = "-> "}); | |
| 4114 | }, | |
| 4115 | } | |
| 4116 | try stack.append(RenderState { .Text = " ("}); | |
| 4117 | try stack.append(RenderState { .Expression = &asm_output.constraint.base}); | |
| 4118 | try stack.append(RenderState { .Text = "] "}); | |
| 4119 | try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base}); | |
| 4120 | try stack.append(RenderState { .Text = "["}); | |
| 4121 | }, | |
| 1201 | 4122 | |
| 4123 | ast.Node.Id.StructField, | |
| 4124 | ast.Node.Id.UnionTag, | |
| 4125 | ast.Node.Id.EnumTag, | |
| 1202 | 4126 | ast.Node.Id.Root, |
| 1203 | 4127 | ast.Node.Id.VarDecl, |
| 4128 | ast.Node.Id.Use, | |
| 4129 | ast.Node.Id.TestDecl, | |
| 1204 | 4130 | ast.Node.Id.ParamDecl => unreachable, |
| 1205 | 4131 | }, |
| 1206 | 4132 | RenderState.FnProtoRParen => |fn_proto| { |
| ... | ... | @@ -1217,9 +4143,6 @@ pub const Parser = struct { |
| 1217 | 4143 | ast.NodeFnProto.ReturnType.Explicit => |node| { |
| 1218 | 4144 | try stack.append(RenderState { .Expression = node}); |
| 1219 | 4145 | }, |
| 1220 | ast.NodeFnProto.ReturnType.Infer => { | |
| 1221 | try stream.print("var"); | |
| 1222 | }, | |
| 1223 | 4146 | ast.NodeFnProto.ReturnType.InferErrorSet => |node| { |
| 1224 | 4147 | try stream.print("!"); |
| 1225 | 4148 | try stack.append(RenderState { .Expression = node}); |
| ... | ... | @@ -1239,8 +4162,10 @@ pub const Parser = struct { |
| 1239 | 4162 | try stack.append(RenderState { .VarDecl = var_decl}); |
| 1240 | 4163 | }, |
| 1241 | 4164 | else => { |
| 1242 | try stack.append(RenderState { .Text = ";"}); | |
| 1243 | try stack.append(RenderState { .Expression = base}); | |
| 4165 | if (requireSemiColon(base)) { | |
| 4166 | try stack.append(RenderState { .Text = ";" }); | |
| 4167 | } | |
| 4168 | try stack.append(RenderState { .Expression = base }); | |
| 1244 | 4169 | }, |
| 1245 | 4170 | } |
| 1246 | 4171 | }, |
| ... | ... | @@ -1324,7 +4249,7 @@ fn testCanonical(source: []const u8) !void { |
| 1324 | 4249 | } |
| 1325 | 4250 | } |
| 1326 | 4251 | |
| 1327 | test "zig fmt" { | |
| 4252 | test "zig fmt: get stdout or fail" { | |
| 1328 | 4253 | try testCanonical( |
| 1329 | 4254 | \\const std = @import("std"); |
| 1330 | 4255 | \\ |
| ... | ... | @@ -1335,7 +4260,9 @@ test "zig fmt" { |
| 1335 | 4260 | \\} |
| 1336 | 4261 | \\ |
| 1337 | 4262 | ); |
| 4263 | } | |
| 1338 | 4264 | |
| 4265 | test "zig fmt: preserve spacing" { | |
| 1339 | 4266 | try testCanonical( |
| 1340 | 4267 | \\const std = @import("std"); |
| 1341 | 4268 | \\ |
| ... | ... | @@ -1348,25 +4275,26 @@ test "zig fmt" { |
| 1348 | 4275 | \\} |
| 1349 | 4276 | \\ |
| 1350 | 4277 | ); |
| 4278 | } | |
| 1351 | 4279 | |
| 4280 | test "zig fmt: return types" { | |
| 1352 | 4281 | try testCanonical( |
| 1353 | 4282 | \\pub fn main() !void {} |
| 1354 | 4283 | \\pub fn main() var {} |
| 1355 | 4284 | \\pub fn main() i32 {} |
| 1356 | 4285 | \\ |
| 1357 | 4286 | ); |
| 4287 | } | |
| 1358 | 4288 | |
| 4289 | test "zig fmt: imports" { | |
| 1359 | 4290 | try testCanonical( |
| 1360 | 4291 | \\const std = @import("std"); |
| 1361 | 4292 | \\const std = @import(); |
| 1362 | 4293 | \\ |
| 1363 | 4294 | ); |
| 4295 | } | |
| 1364 | 4296 | |
| 1365 | try testCanonical( | |
| 1366 | \\extern fn puts(s: &const u8) c_int; | |
| 1367 | \\ | |
| 1368 | ); | |
| 1369 | ||
| 4297 | test "zig fmt: global declarations" { | |
| 1370 | 4298 | try testCanonical( |
| 1371 | 4299 | \\const a = b; |
| 1372 | 4300 | \\pub const a = b; |
| ... | ... | @@ -1376,50 +4304,746 @@ test "zig fmt" { |
| 1376 | 4304 | \\pub const a: i32 = b; |
| 1377 | 4305 | \\var a: i32 = b; |
| 1378 | 4306 | \\pub var a: i32 = b; |
| 4307 | \\extern const a: i32 = b; | |
| 4308 | \\pub extern const a: i32 = b; | |
| 4309 | \\extern var a: i32 = b; | |
| 4310 | \\pub extern var a: i32 = b; | |
| 4311 | \\extern "a" const a: i32 = b; | |
| 4312 | \\pub extern "a" const a: i32 = b; | |
| 4313 | \\extern "a" var a: i32 = b; | |
| 4314 | \\pub extern "a" var a: i32 = b; | |
| 1379 | 4315 | \\ |
| 1380 | 4316 | ); |
| 4317 | } | |
| 1381 | 4318 | |
| 4319 | test "zig fmt: extern declaration" { | |
| 1382 | 4320 | try testCanonical( |
| 1383 | 4321 | \\extern var foo: c_int; |
| 1384 | 4322 | \\ |
| 1385 | 4323 | ); |
| 4324 | } | |
| 1386 | 4325 | |
| 1387 | try testCanonical( | |
| 4326 | test "zig fmt: alignment" { | |
| 4327 | try testCanonical( | |
| 1388 | 4328 | \\var foo: c_int align(1); |
| 1389 | 4329 | \\ |
| 1390 | 4330 | ); |
| 4331 | } | |
| 1391 | 4332 | |
| 4333 | test "zig fmt: C main" { | |
| 1392 | 4334 | try testCanonical( |
| 1393 | 4335 | \\fn main(argc: c_int, argv: &&u8) c_int { |
| 1394 | 4336 | \\ const a = b; |
| 1395 | 4337 | \\} |
| 1396 | 4338 | \\ |
| 1397 | 4339 | ); |
| 4340 | } | |
| 1398 | 4341 | |
| 4342 | test "zig fmt: return" { | |
| 1399 | 4343 | try testCanonical( |
| 1400 | 4344 | \\fn foo(argc: c_int, argv: &&u8) c_int { |
| 1401 | 4345 | \\ return 0; |
| 1402 | 4346 | \\} |
| 1403 | 4347 | \\ |
| 4348 | \\fn bar() void { | |
| 4349 | \\ return; | |
| 4350 | \\} | |
| 4351 | \\ | |
| 4352 | ); | |
| 4353 | } | |
| 4354 | ||
| 4355 | test "zig fmt: pointer attributes" { | |
| 4356 | try testCanonical( | |
| 4357 | \\extern fn f1(s: &align(&u8) u8) c_int; | |
| 4358 | \\extern fn f2(s: &&align(1) &const &volatile u8) c_int; | |
| 4359 | \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int; | |
| 4360 | \\extern fn f4(s: &align(1) const volatile u8) c_int; | |
| 4361 | \\ | |
| 1404 | 4362 | ); |
| 4363 | } | |
| 1405 | 4364 | |
| 4365 | test "zig fmt: slice attributes" { | |
| 1406 | 4366 | try testCanonical( |
| 1407 | 4367 | \\extern fn f1(s: &align(&u8) u8) c_int; |
| 4368 | \\extern fn f2(s: &&align(1) &const &volatile u8) c_int; | |
| 4369 | \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int; | |
| 4370 | \\extern fn f4(s: &align(1) const volatile u8) c_int; | |
| 4371 | \\ | |
| 4372 | ); | |
| 4373 | } | |
| 4374 | ||
| 4375 | test "zig fmt: test declaration" { | |
| 4376 | try testCanonical( | |
| 4377 | \\test "test name" { | |
| 4378 | \\ const a = 1; | |
| 4379 | \\ var b = 1; | |
| 4380 | \\} | |
| 4381 | \\ | |
| 4382 | ); | |
| 4383 | } | |
| 4384 | ||
| 4385 | test "zig fmt: infix operators" { | |
| 4386 | try testCanonical( | |
| 4387 | \\test "infix operators" { | |
| 4388 | \\ var i = undefined; | |
| 4389 | \\ i = 2; | |
| 4390 | \\ i *= 2; | |
| 4391 | \\ i |= 2; | |
| 4392 | \\ i ^= 2; | |
| 4393 | \\ i <<= 2; | |
| 4394 | \\ i >>= 2; | |
| 4395 | \\ i &= 2; | |
| 4396 | \\ i *= 2; | |
| 4397 | \\ i *%= 2; | |
| 4398 | \\ i -= 2; | |
| 4399 | \\ i -%= 2; | |
| 4400 | \\ i += 2; | |
| 4401 | \\ i +%= 2; | |
| 4402 | \\ i /= 2; | |
| 4403 | \\ i %= 2; | |
| 4404 | \\ _ = i == i; | |
| 4405 | \\ _ = i != i; | |
| 4406 | \\ _ = i != i; | |
| 4407 | \\ _ = i.i; | |
| 4408 | \\ _ = i || i; | |
| 4409 | \\ _ = i!i; | |
| 4410 | \\ _ = i ** i; | |
| 4411 | \\ _ = i ++ i; | |
| 4412 | \\ _ = i ?? i; | |
| 4413 | \\ _ = i % i; | |
| 4414 | \\ _ = i / i; | |
| 4415 | \\ _ = i *% i; | |
| 4416 | \\ _ = i * i; | |
| 4417 | \\ _ = i -% i; | |
| 4418 | \\ _ = i - i; | |
| 4419 | \\ _ = i +% i; | |
| 4420 | \\ _ = i + i; | |
| 4421 | \\ _ = i << i; | |
| 4422 | \\ _ = i >> i; | |
| 4423 | \\ _ = i & i; | |
| 4424 | \\ _ = i ^ i; | |
| 4425 | \\ _ = i | i; | |
| 4426 | \\ _ = i >= i; | |
| 4427 | \\ _ = i <= i; | |
| 4428 | \\ _ = i > i; | |
| 4429 | \\ _ = i < i; | |
| 4430 | \\ _ = i and i; | |
| 4431 | \\ _ = i or i; | |
| 4432 | \\} | |
| 4433 | \\ | |
| 4434 | ); | |
| 4435 | } | |
| 4436 | ||
| 4437 | test "zig fmt: precedence" { | |
| 4438 | try testCanonical( | |
| 4439 | \\test "precedence" { | |
| 4440 | \\ a!b(); | |
| 4441 | \\ (a!b)(); | |
| 4442 | \\ !a!b; | |
| 4443 | \\ !(a!b); | |
| 4444 | \\ !a{ }; | |
| 4445 | \\ !(a{ }); | |
| 4446 | \\ a + b{ }; | |
| 4447 | \\ (a + b){ }; | |
| 4448 | \\ a << b + c; | |
| 4449 | \\ (a << b) + c; | |
| 4450 | \\ a & b << c; | |
| 4451 | \\ (a & b) << c; | |
| 4452 | \\ a ^ b & c; | |
| 4453 | \\ (a ^ b) & c; | |
| 4454 | \\ a | b ^ c; | |
| 4455 | \\ (a | b) ^ c; | |
| 4456 | \\ a == b | c; | |
| 4457 | \\ (a == b) | c; | |
| 4458 | \\ a and b == c; | |
| 4459 | \\ (a and b) == c; | |
| 4460 | \\ a or b and c; | |
| 4461 | \\ (a or b) and c; | |
| 4462 | \\ (a or b) and c; | |
| 4463 | \\} | |
| 4464 | \\ | |
| 4465 | ); | |
| 4466 | } | |
| 4467 | ||
| 4468 | test "zig fmt: prefix operators" { | |
| 4469 | try testCanonical( | |
| 4470 | \\test "prefix operators" { | |
| 4471 | \\ try return --%~??!*&0; | |
| 4472 | \\} | |
| 4473 | \\ | |
| 4474 | ); | |
| 4475 | } | |
| 4476 | ||
| 4477 | test "zig fmt: call expression" { | |
| 4478 | try testCanonical( | |
| 4479 | \\test "test calls" { | |
| 4480 | \\ a(); | |
| 4481 | \\ a(1); | |
| 4482 | \\ a(1, 2); | |
| 4483 | \\ a(1, 2) + a(1, 2); | |
| 4484 | \\} | |
| 4485 | \\ | |
| 4486 | ); | |
| 4487 | } | |
| 4488 | ||
| 4489 | test "zig fmt: var args" { | |
| 4490 | try testCanonical( | |
| 4491 | \\fn print(args: ...) void {} | |
| 4492 | \\ | |
| 4493 | ); | |
| 4494 | } | |
| 4495 | ||
| 4496 | test "zig fmt: var type" { | |
| 4497 | try testCanonical( | |
| 4498 | \\fn print(args: var) var {} | |
| 4499 | \\const Var = var; | |
| 4500 | \\const i: var = 0; | |
| 4501 | \\ | |
| 4502 | ); | |
| 4503 | } | |
| 4504 | ||
| 4505 | test "zig fmt: extern function" { | |
| 4506 | try testCanonical( | |
| 4507 | \\extern fn puts(s: &const u8) c_int; | |
| 4508 | \\extern "c" fn puts(s: &const u8) c_int; | |
| 4509 | \\ | |
| 4510 | ); | |
| 4511 | } | |
| 4512 | ||
| 4513 | test "zig fmt: multiline string" { | |
| 4514 | try testCanonical( | |
| 4515 | \\const s = | |
| 4516 | \\ \\ something | |
| 4517 | \\ \\ something else | |
| 4518 | \\ ; | |
| 4519 | \\ | |
| 4520 | ); | |
| 4521 | } | |
| 4522 | ||
| 4523 | test "zig fmt: values" { | |
| 4524 | try testCanonical( | |
| 4525 | \\test "values" { | |
| 4526 | \\ 1; | |
| 4527 | \\ 1.0; | |
| 4528 | \\ "string"; | |
| 4529 | \\ c"cstring"; | |
| 4530 | \\ 'c'; | |
| 4531 | \\ true; | |
| 4532 | \\ false; | |
| 4533 | \\ null; | |
| 4534 | \\ undefined; | |
| 4535 | \\ error; | |
| 4536 | \\ this; | |
| 4537 | \\ unreachable; | |
| 4538 | \\} | |
| 4539 | \\ | |
| 4540 | ); | |
| 4541 | } | |
| 4542 | ||
| 4543 | test "zig fmt: indexing" { | |
| 4544 | try testCanonical( | |
| 4545 | \\test "test index" { | |
| 4546 | \\ a[0]; | |
| 4547 | \\ a[0 + 5]; | |
| 4548 | \\ a[0..]; | |
| 4549 | \\ a[0..5]; | |
| 4550 | \\ a[a[0]]; | |
| 4551 | \\ a[a[0..]]; | |
| 4552 | \\ a[a[0..5]]; | |
| 4553 | \\ a[a[0]..]; | |
| 4554 | \\ a[a[0..5]..]; | |
| 4555 | \\ a[a[0]..a[0]]; | |
| 4556 | \\ a[a[0..5]..a[0]]; | |
| 4557 | \\ a[a[0..5]..a[0..5]]; | |
| 4558 | \\} | |
| 4559 | \\ | |
| 4560 | ); | |
| 4561 | } | |
| 4562 | ||
| 4563 | test "zig fmt: struct declaration" { | |
| 4564 | try testCanonical( | |
| 4565 | \\const S = struct { | |
| 4566 | \\ const Self = this; | |
| 4567 | \\ f1: u8, | |
| 4568 | \\ | |
| 4569 | \\ fn method(self: &Self) Self { | |
| 4570 | \\ return *self; | |
| 4571 | \\ } | |
| 4572 | \\ | |
| 4573 | \\ f2: u8 | |
| 4574 | \\}; | |
| 4575 | \\ | |
| 4576 | \\const Ps = packed struct { | |
| 4577 | \\ a: u8, | |
| 4578 | \\ b: u8, | |
| 4579 | \\ | |
| 4580 | \\ c: u8 | |
| 4581 | \\}; | |
| 4582 | \\ | |
| 4583 | \\const Es = extern struct { | |
| 4584 | \\ a: u8, | |
| 4585 | \\ b: u8, | |
| 4586 | \\ | |
| 4587 | \\ c: u8 | |
| 4588 | \\}; | |
| 4589 | \\ | |
| 4590 | ); | |
| 4591 | } | |
| 4592 | ||
| 4593 | test "zig fmt: enum declaration" { | |
| 4594 | try testCanonical( | |
| 4595 | \\const E = enum { | |
| 4596 | \\ Ok, | |
| 4597 | \\ SomethingElse = 0 | |
| 4598 | \\}; | |
| 4599 | \\ | |
| 4600 | \\const E2 = enum(u8) { | |
| 4601 | \\ Ok, | |
| 4602 | \\ SomethingElse = 255, | |
| 4603 | \\ SomethingThird | |
| 4604 | \\}; | |
| 4605 | \\ | |
| 4606 | \\const Ee = extern enum { | |
| 4607 | \\ Ok, | |
| 4608 | \\ SomethingElse, | |
| 4609 | \\ SomethingThird | |
| 4610 | \\}; | |
| 4611 | \\ | |
| 4612 | \\const Ep = packed enum { | |
| 4613 | \\ Ok, | |
| 4614 | \\ SomethingElse, | |
| 4615 | \\ SomethingThird | |
| 4616 | \\}; | |
| 4617 | \\ | |
| 4618 | ); | |
| 4619 | } | |
| 4620 | ||
| 4621 | test "zig fmt: union declaration" { | |
| 4622 | try testCanonical( | |
| 4623 | \\const U = union { | |
| 4624 | \\ Int: u8, | |
| 4625 | \\ Float: f32, | |
| 4626 | \\ None, | |
| 4627 | \\ Bool: bool | |
| 4628 | \\}; | |
| 4629 | \\ | |
| 4630 | \\const Ue = union(enum) { | |
| 4631 | \\ Int: u8, | |
| 4632 | \\ Float: f32, | |
| 4633 | \\ None, | |
| 4634 | \\ Bool: bool | |
| 4635 | \\}; | |
| 4636 | \\ | |
| 4637 | \\const E = enum { | |
| 4638 | \\ Int, | |
| 4639 | \\ Float, | |
| 4640 | \\ None, | |
| 4641 | \\ Bool | |
| 4642 | \\}; | |
| 4643 | \\ | |
| 4644 | \\const Ue2 = union(E) { | |
| 4645 | \\ Int: u8, | |
| 4646 | \\ Float: f32, | |
| 4647 | \\ None, | |
| 4648 | \\ Bool: bool | |
| 4649 | \\}; | |
| 4650 | \\ | |
| 4651 | \\const Eu = extern union { | |
| 4652 | \\ Int: u8, | |
| 4653 | \\ Float: f32, | |
| 4654 | \\ None, | |
| 4655 | \\ Bool: bool | |
| 4656 | \\}; | |
| 4657 | \\ | |
| 4658 | ); | |
| 4659 | } | |
| 4660 | ||
| 4661 | test "zig fmt: error set declaration" { | |
| 4662 | try testCanonical( | |
| 4663 | \\const E = error { | |
| 4664 | \\ A, | |
| 4665 | \\ B, | |
| 4666 | \\ | |
| 4667 | \\ C | |
| 4668 | \\}; | |
| 4669 | \\ | |
| 4670 | ); | |
| 4671 | } | |
| 4672 | ||
| 4673 | test "zig fmt: arrays" { | |
| 4674 | try testCanonical( | |
| 4675 | \\test "test array" { | |
| 4676 | \\ const a: [2]u8 = [2]u8{ 1, 2 }; | |
| 4677 | \\ const a: [2]u8 = []u8{ 1, 2 }; | |
| 4678 | \\ const a: [0]u8 = []u8{ }; | |
| 4679 | \\} | |
| 4680 | \\ | |
| 4681 | ); | |
| 4682 | } | |
| 4683 | ||
| 4684 | test "zig fmt: container initializers" { | |
| 4685 | try testCanonical( | |
| 4686 | \\const a1 = []u8{ }; | |
| 4687 | \\const a2 = []u8{ 1, 2, 3, 4 }; | |
| 4688 | \\const s1 = S{ }; | |
| 4689 | \\const s2 = S{ .a = 1, .b = 2 }; | |
| 4690 | \\ | |
| 4691 | ); | |
| 4692 | } | |
| 4693 | ||
| 4694 | test "zig fmt: catch" { | |
| 4695 | try testCanonical( | |
| 4696 | \\test "catch" { | |
| 4697 | \\ const a: error!u8 = 0; | |
| 4698 | \\ _ = a catch return; | |
| 4699 | \\ _ = a catch |err| return; | |
| 4700 | \\} | |
| 4701 | \\ | |
| 4702 | ); | |
| 4703 | } | |
| 4704 | ||
| 4705 | test "zig fmt: blocks" { | |
| 4706 | try testCanonical( | |
| 4707 | \\test "blocks" { | |
| 4708 | \\ { | |
| 4709 | \\ const a = 0; | |
| 4710 | \\ const b = 0; | |
| 4711 | \\ } | |
| 4712 | \\ | |
| 4713 | \\ blk: { | |
| 4714 | \\ const a = 0; | |
| 4715 | \\ const b = 0; | |
| 4716 | \\ } | |
| 4717 | \\ | |
| 4718 | \\ const r = blk: { | |
| 4719 | \\ const a = 0; | |
| 4720 | \\ const b = 0; | |
| 4721 | \\ }; | |
| 4722 | \\} | |
| 4723 | \\ | |
| 4724 | ); | |
| 4725 | } | |
| 4726 | ||
| 4727 | test "zig fmt: switch" { | |
| 4728 | try testCanonical( | |
| 4729 | \\test "switch" { | |
| 4730 | \\ switch (0) { | |
| 4731 | \\ 0 => {}, | |
| 4732 | \\ 1 => unreachable, | |
| 4733 | \\ 2, 3 => {}, | |
| 4734 | \\ 4 ... 7 => {}, | |
| 4735 | \\ 1 + 4 * 3 + 22 => {}, | |
| 4736 | \\ else => { | |
| 4737 | \\ const a = 1; | |
| 4738 | \\ const b = a; | |
| 4739 | \\ } | |
| 4740 | \\ } | |
| 4741 | \\ | |
| 4742 | \\ const res = switch (0) { | |
| 4743 | \\ 0 => 0, | |
| 4744 | \\ 1 => 2, | |
| 4745 | \\ else => 4 | |
| 4746 | \\ }; | |
| 4747 | \\ | |
| 4748 | \\ const Union = union(enum) { | |
| 4749 | \\ Int: i64, | |
| 4750 | \\ Float: f64 | |
| 4751 | \\ }; | |
| 4752 | \\ | |
| 4753 | \\ const u = Union{ .Int = 0 }; | |
| 4754 | \\ switch (u) { | |
| 4755 | \\ Union.Int => |int| {}, | |
| 4756 | \\ Union.Float => |*float| unreachable | |
| 4757 | \\ } | |
| 4758 | \\} | |
| 4759 | \\ | |
| 4760 | ); | |
| 4761 | } | |
| 4762 | ||
| 4763 | test "zig fmt: while" { | |
| 4764 | try testCanonical( | |
| 4765 | \\test "while" { | |
| 4766 | \\ while (10 < 1) { | |
| 4767 | \\ unreachable; | |
| 4768 | \\ } | |
| 4769 | \\ | |
| 4770 | \\ while (10 < 1) | |
| 4771 | \\ unreachable; | |
| 4772 | \\ | |
| 4773 | \\ var i: usize = 0; | |
| 4774 | \\ while (i < 10) : (i += 1) { | |
| 4775 | \\ continue; | |
| 4776 | \\ } | |
| 4777 | \\ | |
| 4778 | \\ i = 0; | |
| 4779 | \\ while (i < 10) : (i += 1) | |
| 4780 | \\ continue; | |
| 4781 | \\ | |
| 4782 | \\ i = 0; | |
| 4783 | \\ var j: usize = 0; | |
| 4784 | \\ while (i < 10) : ({ | |
| 4785 | \\ i += 1; | |
| 4786 | \\ j += 1; | |
| 4787 | \\ }) { | |
| 4788 | \\ continue; | |
| 4789 | \\ } | |
| 4790 | \\ | |
| 4791 | \\ var a: ?u8 = 2; | |
| 4792 | \\ while (a) |v| : (a = null) { | |
| 4793 | \\ continue; | |
| 4794 | \\ } | |
| 4795 | \\ | |
| 4796 | \\ while (a) |v| : (a = null) | |
| 4797 | \\ unreachable; | |
| 4798 | \\ | |
| 4799 | \\ label: while (10 < 0) { | |
| 4800 | \\ unreachable; | |
| 4801 | \\ } | |
| 4802 | \\ | |
| 4803 | \\ const res = while (0 < 10) { | |
| 4804 | \\ break 7; | |
| 4805 | \\ } else { | |
| 4806 | \\ unreachable; | |
| 4807 | \\ }; | |
| 4808 | \\ | |
| 4809 | \\ const res = while (0 < 10) | |
| 4810 | \\ break 7 | |
| 4811 | \\ else | |
| 4812 | \\ unreachable; | |
| 4813 | \\ | |
| 4814 | \\ var a: error!u8 = 0; | |
| 4815 | \\ while (a) |v| { | |
| 4816 | \\ a = error.Err; | |
| 4817 | \\ } else |err| { | |
| 4818 | \\ i = 1; | |
| 4819 | \\ } | |
| 4820 | \\ | |
| 4821 | \\ comptime var k: usize = 0; | |
| 4822 | \\ inline while (i < 10) : (i += 1) | |
| 4823 | \\ j += 2; | |
| 4824 | \\} | |
| 4825 | \\ | |
| 4826 | ); | |
| 4827 | } | |
| 4828 | ||
| 4829 | test "zig fmt: for" { | |
| 4830 | try testCanonical( | |
| 4831 | \\test "for" { | |
| 4832 | \\ const a = []u8{ 1, 2, 3 }; | |
| 4833 | \\ for (a) |v| { | |
| 4834 | \\ continue; | |
| 4835 | \\ } | |
| 4836 | \\ | |
| 4837 | \\ for (a) |v| | |
| 4838 | \\ continue; | |
| 4839 | \\ | |
| 4840 | \\ for (a) |*v| | |
| 4841 | \\ continue; | |
| 4842 | \\ | |
| 4843 | \\ for (a) |v, i| { | |
| 4844 | \\ continue; | |
| 4845 | \\ } | |
| 4846 | \\ | |
| 4847 | \\ for (a) |v, i| | |
| 4848 | \\ continue; | |
| 4849 | \\ | |
| 4850 | \\ const res = for (a) |v, i| { | |
| 4851 | \\ break v; | |
| 4852 | \\ } else { | |
| 4853 | \\ unreachable; | |
| 4854 | \\ }; | |
| 4855 | \\ | |
| 4856 | \\ var num: usize = 0; | |
| 4857 | \\ inline for (a) |v, i| { | |
| 4858 | \\ num += v; | |
| 4859 | \\ num += i; | |
| 4860 | \\ } | |
| 4861 | \\} | |
| 4862 | \\ | |
| 4863 | ); | |
| 4864 | } | |
| 4865 | ||
| 4866 | test "zig fmt: if" { | |
| 4867 | try testCanonical( | |
| 4868 | \\test "if" { | |
| 4869 | \\ if (10 < 0) { | |
| 4870 | \\ unreachable; | |
| 4871 | \\ } | |
| 4872 | \\ | |
| 4873 | \\ if (10 < 0) unreachable; | |
| 4874 | \\ | |
| 4875 | \\ if (10 < 0) { | |
| 4876 | \\ unreachable; | |
| 4877 | \\ } else { | |
| 4878 | \\ const a = 20; | |
| 4879 | \\ } | |
| 4880 | \\ | |
| 4881 | \\ if (10 < 0) { | |
| 4882 | \\ unreachable; | |
| 4883 | \\ } else if (5 < 0) { | |
| 4884 | \\ unreachable; | |
| 4885 | \\ } else { | |
| 4886 | \\ const a = 20; | |
| 4887 | \\ } | |
| 4888 | \\ | |
| 4889 | \\ const is_world_broken = if (10 < 0) true else false; | |
| 4890 | \\ | |
| 4891 | \\ const a: ?u8 = 10; | |
| 4892 | \\ const b: ?u8 = null; | |
| 4893 | \\ if (a) |v| { | |
| 4894 | \\ const some = v; | |
| 4895 | \\ } else if (b) |*v| { | |
| 4896 | \\ unreachable; | |
| 4897 | \\ } else { | |
| 4898 | \\ const some = 10; | |
| 4899 | \\ } | |
| 4900 | \\ | |
| 4901 | \\ const non_null_a = if (a) |v| v else 0; | |
| 4902 | \\ | |
| 4903 | \\ const a_err: error!u8 = 0; | |
| 4904 | \\ if (a_err) |v| { | |
| 4905 | \\ const p = v; | |
| 4906 | \\ } else |err| { | |
| 4907 | \\ unreachable; | |
| 4908 | \\ } | |
| 4909 | \\} | |
| 4910 | \\ | |
| 4911 | ); | |
| 4912 | } | |
| 4913 | ||
| 4914 | test "zig fmt: defer" { | |
| 4915 | try testCanonical( | |
| 4916 | \\test "defer" { | |
| 4917 | \\ var i: usize = 0; | |
| 4918 | \\ defer i = 1; | |
| 4919 | \\ defer { | |
| 4920 | \\ i += 2; | |
| 4921 | \\ i *= i; | |
| 4922 | \\ } | |
| 4923 | \\ | |
| 4924 | \\ errdefer i += 3; | |
| 4925 | \\ errdefer { | |
| 4926 | \\ i += 2; | |
| 4927 | \\ i /= i; | |
| 4928 | \\ } | |
| 4929 | \\} | |
| 4930 | \\ | |
| 4931 | ); | |
| 4932 | } | |
| 4933 | ||
| 4934 | test "zig fmt: comptime" { | |
| 4935 | try testCanonical( | |
| 4936 | \\fn a() u8 { | |
| 4937 | \\ return 5; | |
| 4938 | \\} | |
| 4939 | \\ | |
| 4940 | \\fn b(comptime i: u8) u8 { | |
| 4941 | \\ return i; | |
| 4942 | \\} | |
| 4943 | \\ | |
| 4944 | \\const av = comptime a(); | |
| 4945 | \\const av2 = comptime blk: { | |
| 4946 | \\ var res = a(); | |
| 4947 | \\ res *= b(2); | |
| 4948 | \\ break :blk res; | |
| 4949 | \\}; | |
| 4950 | \\ | |
| 4951 | \\comptime { | |
| 4952 | \\ _ = a(); | |
| 4953 | \\} | |
| 4954 | \\ | |
| 4955 | \\test "comptime" { | |
| 4956 | \\ const av3 = comptime a(); | |
| 4957 | \\ const av4 = comptime blk: { | |
| 4958 | \\ var res = a(); | |
| 4959 | \\ res *= a(); | |
| 4960 | \\ break :blk res; | |
| 4961 | \\ }; | |
| 4962 | \\ | |
| 4963 | \\ comptime var i = 0; | |
| 4964 | \\ comptime { | |
| 4965 | \\ i = a(); | |
| 4966 | \\ i += b(i); | |
| 4967 | \\ } | |
| 4968 | \\} | |
| 4969 | \\ | |
| 4970 | ); | |
| 4971 | } | |
| 4972 | ||
| 4973 | test "zig fmt: fn type" { | |
| 4974 | try testCanonical( | |
| 4975 | \\fn a(i: u8) u8 { | |
| 4976 | \\ return i + 1; | |
| 4977 | \\} | |
| 4978 | \\ | |
| 4979 | \\const a: fn(u8) u8 = undefined; | |
| 4980 | \\const b: extern fn(u8) u8 = undefined; | |
| 4981 | \\const c: nakedcc fn(u8) u8 = undefined; | |
| 4982 | \\const ap: fn(u8) u8 = a; | |
| 4983 | \\ | |
| 4984 | ); | |
| 4985 | } | |
| 4986 | ||
| 4987 | test "zig fmt: inline asm" { | |
| 4988 | try testCanonical( | |
| 4989 | \\pub fn syscall1(number: usize, arg1: usize) usize { | |
| 4990 | \\ return asm volatile ("syscall" | |
| 4991 | \\ : [ret] "={rax}" (-> usize) | |
| 4992 | \\ : [number] "{rax}" (number), | |
| 4993 | \\ [arg1] "{rdi}" (arg1) | |
| 4994 | \\ : "rcx", "r11"); | |
| 4995 | \\} | |
| 1408 | 4996 | \\ |
| 1409 | 4997 | ); |
| 4998 | } | |
| 1410 | 4999 | |
| 5000 | test "zig fmt: coroutines" { | |
| 1411 | 5001 | try testCanonical( |
| 1412 | \\extern fn f1(s: &&align(1) &const &volatile u8) c_int; | |
| 1413 | \\extern fn f2(s: &align(1) const &align(1) volatile &const volatile u8) c_int; | |
| 1414 | \\extern fn f3(s: &align(1) const volatile u8) c_int; | |
| 5002 | \\async fn simpleAsyncFn() void { | |
| 5003 | \\ x += 1; | |
| 5004 | \\ suspend; | |
| 5005 | \\ x += 1; | |
| 5006 | \\ suspend |p| {} | |
| 5007 | \\ const p = async simpleAsyncFn() catch unreachable; | |
| 5008 | \\ await p; | |
| 5009 | \\} | |
| 5010 | \\ | |
| 5011 | \\test "coroutine suspend, resume, cancel" { | |
| 5012 | \\ const p = try async<std.debug.global_allocator> testAsyncSeq(); | |
| 5013 | \\ resume p; | |
| 5014 | \\ cancel p; | |
| 5015 | \\} | |
| 1415 | 5016 | \\ |
| 1416 | 5017 | ); |
| 5018 | } | |
| 1417 | 5019 | |
| 5020 | test "zig fmt: Block after if" { | |
| 1418 | 5021 | try testCanonical( |
| 1419 | \\fn f1(a: bool, b: bool) bool { | |
| 1420 | \\ a != b; | |
| 1421 | \\ return a == b; | |
| 5022 | \\test "Block after if" { | |
| 5023 | \\ if (true) { | |
| 5024 | \\ const a = 0; | |
| 5025 | \\ } | |
| 5026 | \\ | |
| 5027 | \\ { | |
| 5028 | \\ const a = 0; | |
| 5029 | \\ } | |
| 1422 | 5030 | \\} |
| 1423 | 5031 | \\ |
| 1424 | 5032 | ); |
| 1425 | 5033 | } |
| 5034 | ||
| 5035 | test "zig fmt: use" { | |
| 5036 | try testCanonical( | |
| 5037 | \\use @import("std"); | |
| 5038 | \\pub use @import("std"); | |
| 5039 | \\ | |
| 5040 | ); | |
| 5041 | } | |
| 5042 | ||
| 5043 | test "zig fmt: string identifier" { | |
| 5044 | try testCanonical( | |
| 5045 | \\const @"a b" = @"c d".@"e f"; | |
| 5046 | \\fn @"g h"() void {} | |
| 5047 | \\ | |
| 5048 | ); | |
| 5049 | } |
std/zig/tokenizer.zig+434-38| ... | ... | @@ -5,8 +5,6 @@ pub const Token = struct { |
| 5 | 5 | id: Id, |
| 6 | 6 | start: usize, |
| 7 | 7 | end: usize, |
| 8 | line: usize, | |
| 9 | column: usize, | |
| 10 | 8 | |
| 11 | 9 | const KeywordId = struct { |
| 12 | 10 | bytes: []const u8, |
| ... | ... | @@ -17,14 +15,18 @@ pub const Token = struct { |
| 17 | 15 | KeywordId{.bytes="align", .id = Id.Keyword_align}, |
| 18 | 16 | KeywordId{.bytes="and", .id = Id.Keyword_and}, |
| 19 | 17 | KeywordId{.bytes="asm", .id = Id.Keyword_asm}, |
| 18 | KeywordId{.bytes="async", .id = Id.Keyword_async}, | |
| 19 | KeywordId{.bytes="await", .id = Id.Keyword_await}, | |
| 20 | 20 | KeywordId{.bytes="break", .id = Id.Keyword_break}, |
| 21 | 21 | KeywordId{.bytes="catch", .id = Id.Keyword_catch}, |
| 22 | KeywordId{.bytes="cancel", .id = Id.Keyword_cancel}, | |
| 22 | 23 | KeywordId{.bytes="comptime", .id = Id.Keyword_comptime}, |
| 23 | 24 | KeywordId{.bytes="const", .id = Id.Keyword_const}, |
| 24 | 25 | KeywordId{.bytes="continue", .id = Id.Keyword_continue}, |
| 25 | 26 | KeywordId{.bytes="defer", .id = Id.Keyword_defer}, |
| 26 | 27 | KeywordId{.bytes="else", .id = Id.Keyword_else}, |
| 27 | 28 | KeywordId{.bytes="enum", .id = Id.Keyword_enum}, |
| 29 | KeywordId{.bytes="errdefer", .id = Id.Keyword_errdefer}, | |
| 28 | 30 | KeywordId{.bytes="error", .id = Id.Keyword_error}, |
| 29 | 31 | KeywordId{.bytes="export", .id = Id.Keyword_export}, |
| 30 | 32 | KeywordId{.bytes="extern", .id = Id.Keyword_extern}, |
| ... | ... | @@ -39,10 +41,12 @@ pub const Token = struct { |
| 39 | 41 | KeywordId{.bytes="or", .id = Id.Keyword_or}, |
| 40 | 42 | KeywordId{.bytes="packed", .id = Id.Keyword_packed}, |
| 41 | 43 | KeywordId{.bytes="pub", .id = Id.Keyword_pub}, |
| 44 | KeywordId{.bytes="resume", .id = Id.Keyword_resume}, | |
| 42 | 45 | KeywordId{.bytes="return", .id = Id.Keyword_return}, |
| 43 | 46 | KeywordId{.bytes="section", .id = Id.Keyword_section}, |
| 44 | 47 | KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc}, |
| 45 | 48 | KeywordId{.bytes="struct", .id = Id.Keyword_struct}, |
| 49 | KeywordId{.bytes="suspend", .id = Id.Keyword_suspend}, | |
| 46 | 50 | KeywordId{.bytes="switch", .id = Id.Keyword_switch}, |
| 47 | 51 | KeywordId{.bytes="test", .id = Id.Keyword_test}, |
| 48 | 52 | KeywordId{.bytes="this", .id = Id.Keyword_this}, |
| ... | ... | @@ -72,38 +76,74 @@ pub const Token = struct { |
| 72 | 76 | Invalid, |
| 73 | 77 | Identifier, |
| 74 | 78 | StringLiteral: StrLitKind, |
| 75 | StringIdentifier, | |
| 79 | MultilineStringLiteralLine: StrLitKind, | |
| 80 | CharLiteral, | |
| 76 | 81 | Eof, |
| 77 | 82 | Builtin, |
| 78 | 83 | Bang, |
| 79 | 84 | Pipe, |
| 85 | PipePipe, | |
| 80 | 86 | PipeEqual, |
| 81 | 87 | Equal, |
| 82 | 88 | EqualEqual, |
| 89 | EqualAngleBracketRight, | |
| 83 | 90 | BangEqual, |
| 84 | 91 | LParen, |
| 85 | 92 | RParen, |
| 86 | 93 | Semicolon, |
| 87 | 94 | Percent, |
| 95 | PercentEqual, | |
| 88 | 96 | LBrace, |
| 89 | 97 | RBrace, |
| 98 | LBracket, | |
| 99 | RBracket, | |
| 90 | 100 | Period, |
| 91 | 101 | Ellipsis2, |
| 92 | 102 | Ellipsis3, |
| 103 | Caret, | |
| 104 | CaretEqual, | |
| 105 | Plus, | |
| 106 | PlusPlus, | |
| 107 | PlusEqual, | |
| 108 | PlusPercent, | |
| 109 | PlusPercentEqual, | |
| 93 | 110 | Minus, |
| 111 | MinusEqual, | |
| 112 | MinusPercent, | |
| 113 | MinusPercentEqual, | |
| 114 | Asterisk, | |
| 115 | AsteriskEqual, | |
| 116 | AsteriskAsterisk, | |
| 117 | AsteriskPercent, | |
| 118 | AsteriskPercentEqual, | |
| 94 | 119 | Arrow, |
| 95 | 120 | Colon, |
| 96 | 121 | Slash, |
| 122 | SlashEqual, | |
| 97 | 123 | Comma, |
| 98 | 124 | Ampersand, |
| 99 | 125 | AmpersandEqual, |
| 126 | QuestionMark, | |
| 127 | QuestionMarkQuestionMark, | |
| 128 | AngleBracketLeft, | |
| 129 | AngleBracketLeftEqual, | |
| 130 | AngleBracketAngleBracketLeft, | |
| 131 | AngleBracketAngleBracketLeftEqual, | |
| 132 | AngleBracketRight, | |
| 133 | AngleBracketRightEqual, | |
| 134 | AngleBracketAngleBracketRight, | |
| 135 | AngleBracketAngleBracketRightEqual, | |
| 136 | Tilde, | |
| 100 | 137 | IntegerLiteral, |
| 101 | 138 | FloatLiteral, |
| 102 | 139 | LineComment, |
| 103 | 140 | Keyword_align, |
| 104 | 141 | Keyword_and, |
| 105 | 142 | Keyword_asm, |
| 143 | Keyword_async, | |
| 144 | Keyword_await, | |
| 106 | 145 | Keyword_break, |
| 146 | Keyword_cancel, | |
| 107 | 147 | Keyword_catch, |
| 108 | 148 | Keyword_comptime, |
| 109 | 149 | Keyword_const, |
| ... | ... | @@ -111,6 +151,7 @@ pub const Token = struct { |
| 111 | 151 | Keyword_defer, |
| 112 | 152 | Keyword_else, |
| 113 | 153 | Keyword_enum, |
| 154 | Keyword_errdefer, | |
| 114 | 155 | Keyword_error, |
| 115 | 156 | Keyword_export, |
| 116 | 157 | Keyword_extern, |
| ... | ... | @@ -125,10 +166,12 @@ pub const Token = struct { |
| 125 | 166 | Keyword_or, |
| 126 | 167 | Keyword_packed, |
| 127 | 168 | Keyword_pub, |
| 169 | Keyword_resume, | |
| 128 | 170 | Keyword_return, |
| 129 | 171 | Keyword_section, |
| 130 | 172 | Keyword_stdcallcc, |
| 131 | 173 | Keyword_struct, |
| 174 | Keyword_suspend, | |
| 132 | 175 | Keyword_switch, |
| 133 | 176 | Keyword_test, |
| 134 | 177 | Keyword_this, |
| ... | ... | @@ -147,28 +190,34 @@ pub const Token = struct { |
| 147 | 190 | pub const Tokenizer = struct { |
| 148 | 191 | buffer: []const u8, |
| 149 | 192 | index: usize, |
| 150 | line: usize, | |
| 151 | column: usize, | |
| 152 | 193 | pending_invalid_token: ?Token, |
| 153 | 194 | |
| 154 | pub const LineLocation = struct { | |
| 195 | pub const Location = struct { | |
| 196 | line: usize, | |
| 197 | column: usize, | |
| 155 | 198 | line_start: usize, |
| 156 | 199 | line_end: usize, |
| 157 | 200 | }; |
| 158 | 201 | |
| 159 | pub fn getTokenLocation(self: &Tokenizer, token: &const Token) LineLocation { | |
| 160 | var loc = LineLocation { | |
| 161 | .line_start = 0, | |
| 202 | pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location { | |
| 203 | var loc = Location { | |
| 204 | .line = 0, | |
| 205 | .column = 0, | |
| 206 | .line_start = start_index, | |
| 162 | 207 | .line_end = self.buffer.len, |
| 163 | 208 | }; |
| 164 | for (self.buffer) |c, i| { | |
| 165 | if (i == token.start) { | |
| 166 | loc.line_end = i; | |
| 209 | for (self.buffer[start_index..]) |c, i| { | |
| 210 | if (i + start_index == token.start) { | |
| 211 | loc.line_end = i + start_index; | |
| 167 | 212 | while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {} |
| 168 | 213 | return loc; |
| 169 | 214 | } |
| 170 | 215 | if (c == '\n') { |
| 216 | loc.line += 1; | |
| 217 | loc.column = 0; | |
| 171 | 218 | loc.line_start = i + 1; |
| 219 | } else { | |
| 220 | loc.column += 1; | |
| 172 | 221 | } |
| 173 | 222 | } |
| 174 | 223 | return loc; |
| ... | ... | @@ -183,8 +232,6 @@ pub const Tokenizer = struct { |
| 183 | 232 | return Tokenizer { |
| 184 | 233 | .buffer = buffer, |
| 185 | 234 | .index = 0, |
| 186 | .line = 0, | |
| 187 | .column = 0, | |
| 188 | 235 | .pending_invalid_token = null, |
| 189 | 236 | }; |
| 190 | 237 | } |
| ... | ... | @@ -196,10 +243,19 @@ pub const Tokenizer = struct { |
| 196 | 243 | C, |
| 197 | 244 | StringLiteral, |
| 198 | 245 | StringLiteralBackslash, |
| 246 | MultilineStringLiteralLine, | |
| 247 | MultilineStringLiteralLineBackslash, | |
| 248 | CharLiteral, | |
| 249 | CharLiteralBackslash, | |
| 250 | CharLiteralEnd, | |
| 251 | Backslash, | |
| 199 | 252 | Equal, |
| 200 | 253 | Bang, |
| 201 | 254 | Pipe, |
| 202 | 255 | Minus, |
| 256 | MinusPercent, | |
| 257 | Asterisk, | |
| 258 | AsteriskPercent, | |
| 203 | 259 | Slash, |
| 204 | 260 | LineComment, |
| 205 | 261 | Zero, |
| ... | ... | @@ -210,6 +266,15 @@ pub const Tokenizer = struct { |
| 210 | 266 | FloatExponentUnsigned, |
| 211 | 267 | FloatExponentNumber, |
| 212 | 268 | Ampersand, |
| 269 | Caret, | |
| 270 | Percent, | |
| 271 | QuestionMark, | |
| 272 | Plus, | |
| 273 | PlusPercent, | |
| 274 | AngleBracketLeft, | |
| 275 | AngleBracketAngleBracketLeft, | |
| 276 | AngleBracketRight, | |
| 277 | AngleBracketAngleBracketRight, | |
| 213 | 278 | Period, |
| 214 | 279 | Period2, |
| 215 | 280 | SawAtSign, |
| ... | ... | @@ -220,26 +285,22 @@ pub const Tokenizer = struct { |
| 220 | 285 | self.pending_invalid_token = null; |
| 221 | 286 | return token; |
| 222 | 287 | } |
| 288 | const start_index = self.index; | |
| 223 | 289 | var state = State.Start; |
| 224 | 290 | var result = Token { |
| 225 | 291 | .id = Token.Id.Eof, |
| 226 | 292 | .start = self.index, |
| 227 | 293 | .end = undefined, |
| 228 | .line = self.line, | |
| 229 | .column = self.column, | |
| 230 | 294 | }; |
| 231 | while (self.index < self.buffer.len) { | |
| 295 | while (self.index < self.buffer.len) : (self.index += 1) { | |
| 232 | 296 | const c = self.buffer[self.index]; |
| 233 | 297 | switch (state) { |
| 234 | 298 | State.Start => switch (c) { |
| 235 | 299 | ' ' => { |
| 236 | 300 | result.start = self.index + 1; |
| 237 | result.column += 1; | |
| 238 | 301 | }, |
| 239 | 302 | '\n' => { |
| 240 | 303 | result.start = self.index + 1; |
| 241 | result.line += 1; | |
| 242 | result.column = 0; | |
| 243 | 304 | }, |
| 244 | 305 | 'c' => { |
| 245 | 306 | state = State.C; |
| ... | ... | @@ -249,6 +310,9 @@ pub const Tokenizer = struct { |
| 249 | 310 | state = State.StringLiteral; |
| 250 | 311 | result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal }; |
| 251 | 312 | }, |
| 313 | '\'' => { | |
| 314 | state = State.CharLiteral; | |
| 315 | }, | |
| 252 | 316 | 'a'...'b', 'd'...'z', 'A'...'Z', '_' => { |
| 253 | 317 | state = State.Identifier; |
| 254 | 318 | result.id = Token.Id.Identifier; |
| ... | ... | @@ -275,6 +339,16 @@ pub const Tokenizer = struct { |
| 275 | 339 | self.index += 1; |
| 276 | 340 | break; |
| 277 | 341 | }, |
| 342 | '[' => { | |
| 343 | result.id = Token.Id.LBracket; | |
| 344 | self.index += 1; | |
| 345 | break; | |
| 346 | }, | |
| 347 | ']' => { | |
| 348 | result.id = Token.Id.RBracket; | |
| 349 | self.index += 1; | |
| 350 | break; | |
| 351 | }, | |
| 278 | 352 | ';' => { |
| 279 | 353 | result.id = Token.Id.Semicolon; |
| 280 | 354 | self.index += 1; |
| ... | ... | @@ -291,9 +365,29 @@ pub const Tokenizer = struct { |
| 291 | 365 | break; |
| 292 | 366 | }, |
| 293 | 367 | '%' => { |
| 294 | result.id = Token.Id.Percent; | |
| 295 | self.index += 1; | |
| 296 | break; | |
| 368 | state = State.Percent; | |
| 369 | }, | |
| 370 | '*' => { | |
| 371 | state = State.Asterisk; | |
| 372 | }, | |
| 373 | '+' => { | |
| 374 | state = State.Plus; | |
| 375 | }, | |
| 376 | '?' => { | |
| 377 | state = State.QuestionMark; | |
| 378 | }, | |
| 379 | '<' => { | |
| 380 | state = State.AngleBracketLeft; | |
| 381 | }, | |
| 382 | '>' => { | |
| 383 | state = State.AngleBracketRight; | |
| 384 | }, | |
| 385 | '^' => { | |
| 386 | state = State.Caret; | |
| 387 | }, | |
| 388 | '\\' => { | |
| 389 | state = State.Backslash; | |
| 390 | result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.Normal }; | |
| 297 | 391 | }, |
| 298 | 392 | '{' => { |
| 299 | 393 | result.id = Token.Id.LBrace; |
| ... | ... | @@ -305,6 +399,11 @@ pub const Tokenizer = struct { |
| 305 | 399 | self.index += 1; |
| 306 | 400 | break; |
| 307 | 401 | }, |
| 402 | '~' => { | |
| 403 | result.id = Token.Id.Tilde; | |
| 404 | self.index += 1; | |
| 405 | break; | |
| 406 | }, | |
| 308 | 407 | '.' => { |
| 309 | 408 | state = State.Period; |
| 310 | 409 | }, |
| ... | ... | @@ -334,7 +433,7 @@ pub const Tokenizer = struct { |
| 334 | 433 | |
| 335 | 434 | State.SawAtSign => switch (c) { |
| 336 | 435 | '"' => { |
| 337 | result.id = Token.Id.StringIdentifier; | |
| 436 | result.id = Token.Id.Identifier; | |
| 338 | 437 | state = State.StringLiteral; |
| 339 | 438 | }, |
| 340 | 439 | else => { |
| ... | ... | @@ -356,6 +455,107 @@ pub const Tokenizer = struct { |
| 356 | 455 | break; |
| 357 | 456 | }, |
| 358 | 457 | }, |
| 458 | ||
| 459 | State.Asterisk => switch (c) { | |
| 460 | '=' => { | |
| 461 | result.id = Token.Id.AsteriskEqual; | |
| 462 | self.index += 1; | |
| 463 | break; | |
| 464 | }, | |
| 465 | '*' => { | |
| 466 | result.id = Token.Id.AsteriskAsterisk; | |
| 467 | self.index += 1; | |
| 468 | break; | |
| 469 | }, | |
| 470 | '%' => { | |
| 471 | state = State.AsteriskPercent; | |
| 472 | }, | |
| 473 | else => { | |
| 474 | result.id = Token.Id.Asterisk; | |
| 475 | break; | |
| 476 | } | |
| 477 | }, | |
| 478 | ||
| 479 | State.AsteriskPercent => switch (c) { | |
| 480 | '=' => { | |
| 481 | result.id = Token.Id.AsteriskPercentEqual; | |
| 482 | self.index += 1; | |
| 483 | break; | |
| 484 | }, | |
| 485 | else => { | |
| 486 | result.id = Token.Id.AsteriskPercent; | |
| 487 | break; | |
| 488 | } | |
| 489 | }, | |
| 490 | ||
| 491 | State.QuestionMark => switch (c) { | |
| 492 | '?' => { | |
| 493 | result.id = Token.Id.QuestionMarkQuestionMark; | |
| 494 | self.index += 1; | |
| 495 | break; | |
| 496 | }, | |
| 497 | else => { | |
| 498 | result.id = Token.Id.QuestionMark; | |
| 499 | break; | |
| 500 | }, | |
| 501 | }, | |
| 502 | ||
| 503 | State.Percent => switch (c) { | |
| 504 | '=' => { | |
| 505 | result.id = Token.Id.PercentEqual; | |
| 506 | self.index += 1; | |
| 507 | break; | |
| 508 | }, | |
| 509 | else => { | |
| 510 | result.id = Token.Id.Percent; | |
| 511 | break; | |
| 512 | }, | |
| 513 | }, | |
| 514 | ||
| 515 | State.Plus => switch (c) { | |
| 516 | '=' => { | |
| 517 | result.id = Token.Id.PlusEqual; | |
| 518 | self.index += 1; | |
| 519 | break; | |
| 520 | }, | |
| 521 | '+' => { | |
| 522 | result.id = Token.Id.PlusPlus; | |
| 523 | self.index += 1; | |
| 524 | break; | |
| 525 | }, | |
| 526 | '%' => { | |
| 527 | state = State.PlusPercent; | |
| 528 | }, | |
| 529 | else => { | |
| 530 | result.id = Token.Id.Plus; | |
| 531 | break; | |
| 532 | }, | |
| 533 | }, | |
| 534 | ||
| 535 | State.PlusPercent => switch (c) { | |
| 536 | '=' => { | |
| 537 | result.id = Token.Id.PlusPercentEqual; | |
| 538 | self.index += 1; | |
| 539 | break; | |
| 540 | }, | |
| 541 | else => { | |
| 542 | result.id = Token.Id.PlusPercent; | |
| 543 | break; | |
| 544 | }, | |
| 545 | }, | |
| 546 | ||
| 547 | State.Caret => switch (c) { | |
| 548 | '=' => { | |
| 549 | result.id = Token.Id.CaretEqual; | |
| 550 | self.index += 1; | |
| 551 | break; | |
| 552 | }, | |
| 553 | else => { | |
| 554 | result.id = Token.Id.Caret; | |
| 555 | break; | |
| 556 | } | |
| 557 | }, | |
| 558 | ||
| 359 | 559 | State.Identifier => switch (c) { |
| 360 | 560 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, |
| 361 | 561 | else => { |
| ... | ... | @@ -369,8 +569,17 @@ pub const Tokenizer = struct { |
| 369 | 569 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, |
| 370 | 570 | else => break, |
| 371 | 571 | }, |
| 572 | State.Backslash => switch (c) { | |
| 573 | '\\' => { | |
| 574 | state = State.MultilineStringLiteralLine; | |
| 575 | }, | |
| 576 | else => break, | |
| 577 | }, | |
| 372 | 578 | State.C => switch (c) { |
| 373 | '\\' => @panic("TODO"), | |
| 579 | '\\' => { | |
| 580 | state = State.Backslash; | |
| 581 | result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.C }; | |
| 582 | }, | |
| 374 | 583 | '"' => { |
| 375 | 584 | state = State.StringLiteral; |
| 376 | 585 | result.id = Token.Id { .StringLiteral = Token.StrLitKind.C }; |
| ... | ... | @@ -399,6 +608,64 @@ pub const Tokenizer = struct { |
| 399 | 608 | }, |
| 400 | 609 | }, |
| 401 | 610 | |
| 611 | State.CharLiteral => switch (c) { | |
| 612 | '\\' => { | |
| 613 | state = State.CharLiteralBackslash; | |
| 614 | }, | |
| 615 | '\'' => { | |
| 616 | result.id = Token.Id.Invalid; | |
| 617 | break; | |
| 618 | }, | |
| 619 | else => { | |
| 620 | if (c < 0x20 or c == 0x7f) { | |
| 621 | result.id = Token.Id.Invalid; | |
| 622 | break; | |
| 623 | } | |
| 624 | ||
| 625 | state = State.CharLiteralEnd; | |
| 626 | } | |
| 627 | }, | |
| 628 | ||
| 629 | State.CharLiteralBackslash => switch (c) { | |
| 630 | '\n' => { | |
| 631 | result.id = Token.Id.Invalid; | |
| 632 | break; | |
| 633 | }, | |
| 634 | else => { | |
| 635 | state = State.CharLiteralEnd; | |
| 636 | }, | |
| 637 | }, | |
| 638 | ||
| 639 | State.CharLiteralEnd => switch (c) { | |
| 640 | '\'' => { | |
| 641 | result.id = Token.Id.CharLiteral; | |
| 642 | self.index += 1; | |
| 643 | break; | |
| 644 | }, | |
| 645 | else => { | |
| 646 | result.id = Token.Id.Invalid; | |
| 647 | break; | |
| 648 | }, | |
| 649 | }, | |
| 650 | ||
| 651 | State.MultilineStringLiteralLine => switch (c) { | |
| 652 | '\\' => { | |
| 653 | state = State.MultilineStringLiteralLineBackslash; | |
| 654 | }, | |
| 655 | '\n' => { | |
| 656 | self.index += 1; | |
| 657 | break; | |
| 658 | }, | |
| 659 | else => self.checkLiteralCharacter(), | |
| 660 | }, | |
| 661 | ||
| 662 | State.MultilineStringLiteralLineBackslash => switch (c) { | |
| 663 | '\n' => break, // Look for this error later. | |
| 664 | else => { | |
| 665 | state = State.MultilineStringLiteralLine; | |
| 666 | }, | |
| 667 | }, | |
| 668 | ||
| 402 | 669 | State.Bang => switch (c) { |
| 403 | 670 | '=' => { |
| 404 | 671 | result.id = Token.Id.BangEqual; |
| ... | ... | @@ -417,6 +684,11 @@ pub const Tokenizer = struct { |
| 417 | 684 | self.index += 1; |
| 418 | 685 | break; |
| 419 | 686 | }, |
| 687 | '|' => { | |
| 688 | result.id = Token.Id.PipePipe; | |
| 689 | self.index += 1; | |
| 690 | break; | |
| 691 | }, | |
| 420 | 692 | else => { |
| 421 | 693 | result.id = Token.Id.Pipe; |
| 422 | 694 | break; |
| ... | ... | @@ -429,6 +701,11 @@ pub const Tokenizer = struct { |
| 429 | 701 | self.index += 1; |
| 430 | 702 | break; |
| 431 | 703 | }, |
| 704 | '>' => { | |
| 705 | result.id = Token.Id.EqualAngleBracketRight; | |
| 706 | self.index += 1; | |
| 707 | break; | |
| 708 | }, | |
| 432 | 709 | else => { |
| 433 | 710 | result.id = Token.Id.Equal; |
| 434 | 711 | break; |
| ... | ... | @@ -441,12 +718,86 @@ pub const Tokenizer = struct { |
| 441 | 718 | self.index += 1; |
| 442 | 719 | break; |
| 443 | 720 | }, |
| 721 | '=' => { | |
| 722 | result.id = Token.Id.MinusEqual; | |
| 723 | self.index += 1; | |
| 724 | break; | |
| 725 | }, | |
| 726 | '%' => { | |
| 727 | state = State.MinusPercent; | |
| 728 | }, | |
| 444 | 729 | else => { |
| 445 | 730 | result.id = Token.Id.Minus; |
| 446 | 731 | break; |
| 447 | 732 | }, |
| 448 | 733 | }, |
| 449 | 734 | |
| 735 | State.MinusPercent => switch (c) { | |
| 736 | '=' => { | |
| 737 | result.id = Token.Id.MinusPercentEqual; | |
| 738 | self.index += 1; | |
| 739 | break; | |
| 740 | }, | |
| 741 | else => { | |
| 742 | result.id = Token.Id.MinusPercent; | |
| 743 | break; | |
| 744 | } | |
| 745 | }, | |
| 746 | ||
| 747 | State.AngleBracketLeft => switch (c) { | |
| 748 | '<' => { | |
| 749 | state = State.AngleBracketAngleBracketLeft; | |
| 750 | }, | |
| 751 | '=' => { | |
| 752 | result.id = Token.Id.AngleBracketLeftEqual; | |
| 753 | self.index += 1; | |
| 754 | break; | |
| 755 | }, | |
| 756 | else => { | |
| 757 | result.id = Token.Id.AngleBracketLeft; | |
| 758 | break; | |
| 759 | }, | |
| 760 | }, | |
| 761 | ||
| 762 | State.AngleBracketAngleBracketLeft => switch (c) { | |
| 763 | '=' => { | |
| 764 | result.id = Token.Id.AngleBracketAngleBracketLeftEqual; | |
| 765 | self.index += 1; | |
| 766 | break; | |
| 767 | }, | |
| 768 | else => { | |
| 769 | result.id = Token.Id.AngleBracketAngleBracketLeft; | |
| 770 | break; | |
| 771 | }, | |
| 772 | }, | |
| 773 | ||
| 774 | State.AngleBracketRight => switch (c) { | |
| 775 | '>' => { | |
| 776 | state = State.AngleBracketAngleBracketRight; | |
| 777 | }, | |
| 778 | '=' => { | |
| 779 | result.id = Token.Id.AngleBracketRightEqual; | |
| 780 | self.index += 1; | |
| 781 | break; | |
| 782 | }, | |
| 783 | else => { | |
| 784 | result.id = Token.Id.AngleBracketRight; | |
| 785 | break; | |
| 786 | }, | |
| 787 | }, | |
| 788 | ||
| 789 | State.AngleBracketAngleBracketRight => switch (c) { | |
| 790 | '=' => { | |
| 791 | result.id = Token.Id.AngleBracketAngleBracketRightEqual; | |
| 792 | self.index += 1; | |
| 793 | break; | |
| 794 | }, | |
| 795 | else => { | |
| 796 | result.id = Token.Id.AngleBracketAngleBracketRight; | |
| 797 | break; | |
| 798 | }, | |
| 799 | }, | |
| 800 | ||
| 450 | 801 | State.Period => switch (c) { |
| 451 | 802 | '.' => { |
| 452 | 803 | state = State.Period2; |
| ... | ... | @@ -474,6 +825,11 @@ pub const Tokenizer = struct { |
| 474 | 825 | result.id = Token.Id.LineComment; |
| 475 | 826 | state = State.LineComment; |
| 476 | 827 | }, |
| 828 | '=' => { | |
| 829 | result.id = Token.Id.SlashEqual; | |
| 830 | self.index += 1; | |
| 831 | break; | |
| 832 | }, | |
| 477 | 833 | else => { |
| 478 | 834 | result.id = Token.Id.Slash; |
| 479 | 835 | break; |
| ... | ... | @@ -547,14 +903,6 @@ pub const Tokenizer = struct { |
| 547 | 903 | else => break, |
| 548 | 904 | }, |
| 549 | 905 | } |
| 550 | ||
| 551 | self.index += 1; | |
| 552 | if (c == '\n') { | |
| 553 | self.line += 1; | |
| 554 | self.column = 0; | |
| 555 | } else { | |
| 556 | self.column += 1; | |
| 557 | } | |
| 558 | 906 | } else if (self.index == self.buffer.len) { |
| 559 | 907 | switch (state) { |
| 560 | 908 | State.Start, |
| ... | ... | @@ -564,6 +912,7 @@ pub const Tokenizer = struct { |
| 564 | 912 | State.FloatFraction, |
| 565 | 913 | State.FloatExponentNumber, |
| 566 | 914 | State.StringLiteral, // find this error later |
| 915 | State.MultilineStringLiteralLine, | |
| 567 | 916 | State.Builtin => {}, |
| 568 | 917 | |
| 569 | 918 | State.Identifier => { |
| ... | ... | @@ -578,6 +927,11 @@ pub const Tokenizer = struct { |
| 578 | 927 | State.NumberDot, |
| 579 | 928 | State.FloatExponentUnsigned, |
| 580 | 929 | State.SawAtSign, |
| 930 | State.Backslash, | |
| 931 | State.MultilineStringLiteralLineBackslash, | |
| 932 | State.CharLiteral, | |
| 933 | State.CharLiteralBackslash, | |
| 934 | State.CharLiteralEnd, | |
| 581 | 935 | State.StringLiteralBackslash => { |
| 582 | 936 | result.id = Token.Id.Invalid; |
| 583 | 937 | }, |
| ... | ... | @@ -609,8 +963,45 @@ pub const Tokenizer = struct { |
| 609 | 963 | State.Pipe => { |
| 610 | 964 | result.id = Token.Id.Pipe; |
| 611 | 965 | }, |
| 966 | State.AngleBracketAngleBracketRight => { | |
| 967 | result.id = Token.Id.AngleBracketAngleBracketRight; | |
| 968 | }, | |
| 969 | State.AngleBracketRight => { | |
| 970 | result.id = Token.Id.AngleBracketRight; | |
| 971 | }, | |
| 972 | State.AngleBracketAngleBracketLeft => { | |
| 973 | result.id = Token.Id.AngleBracketAngleBracketLeft; | |
| 974 | }, | |
| 975 | State.AngleBracketLeft => { | |
| 976 | result.id = Token.Id.AngleBracketLeft; | |
| 977 | }, | |
| 978 | State.PlusPercent => { | |
| 979 | result.id = Token.Id.PlusPercent; | |
| 980 | }, | |
| 981 | State.Plus => { | |
| 982 | result.id = Token.Id.Plus; | |
| 983 | }, | |
| 984 | State.QuestionMark => { | |
| 985 | result.id = Token.Id.QuestionMark; | |
| 986 | }, | |
| 987 | State.Percent => { | |
| 988 | result.id = Token.Id.Percent; | |
| 989 | }, | |
| 990 | State.Caret => { | |
| 991 | result.id = Token.Id.Caret; | |
| 992 | }, | |
| 993 | State.AsteriskPercent => { | |
| 994 | result.id = Token.Id.AsteriskPercent; | |
| 995 | }, | |
| 996 | State.Asterisk => { | |
| 997 | result.id = Token.Id.Asterisk; | |
| 998 | }, | |
| 999 | State.MinusPercent => { | |
| 1000 | result.id = Token.Id.MinusPercent; | |
| 1001 | }, | |
| 612 | 1002 | } |
| 613 | 1003 | } |
| 1004 | ||
| 614 | 1005 | if (result.id == Token.Id.Eof) { |
| 615 | 1006 | if (self.pending_invalid_token) |token| { |
| 616 | 1007 | self.pending_invalid_token = null; |
| ... | ... | @@ -634,8 +1025,6 @@ pub const Tokenizer = struct { |
| 634 | 1025 | .id = Token.Id.Invalid, |
| 635 | 1026 | .start = self.index, |
| 636 | 1027 | .end = self.index + invalid_length, |
| 637 | .line = self.line, | |
| 638 | .column = self.column, | |
| 639 | 1028 | }; |
| 640 | 1029 | } |
| 641 | 1030 | |
| ... | ... | @@ -685,9 +1074,16 @@ test "tokenizer" { |
| 685 | 1074 | }); |
| 686 | 1075 | } |
| 687 | 1076 | |
| 1077 | test "tokenizer - chars" { | |
| 1078 | testTokenize("'c'", []Token.Id {Token.Id.CharLiteral}); | |
| 1079 | } | |
| 1080 | ||
| 688 | 1081 | test "tokenizer - invalid token characters" { |
| 689 | 1082 | testTokenize("#", []Token.Id{Token.Id.Invalid}); |
| 690 | 1083 | testTokenize("`", []Token.Id{Token.Id.Invalid}); |
| 1084 | testTokenize("'c", []Token.Id {Token.Id.Invalid}); | |
| 1085 | testTokenize("'", []Token.Id {Token.Id.Invalid}); | |
| 1086 | testTokenize("''", []Token.Id {Token.Id.Invalid, Token.Id.Invalid}); | |
| 691 | 1087 | } |
| 692 | 1088 | |
| 693 | 1089 | test "tokenizer - invalid literal/comment characters" { |
| ... | ... | @@ -739,7 +1135,7 @@ test "tokenizer - string identifier and builtin fns" { |
| 739 | 1135 | , |
| 740 | 1136 | []Token.Id{ |
| 741 | 1137 | Token.Id.Keyword_const, |
| 742 | Token.Id.StringIdentifier, | |
| 1138 | Token.Id.Identifier, | |
| 743 | 1139 | Token.Id.Equal, |
| 744 | 1140 | Token.Id.Builtin, |
| 745 | 1141 | Token.Id.LParen, |
| ... | ... | @@ -752,8 +1148,8 @@ test "tokenizer - string identifier and builtin fns" { |
| 752 | 1148 | |
| 753 | 1149 | test "tokenizer - pipe and then invalid" { |
| 754 | 1150 | testTokenize("||=", []Token.Id{ |
| 755 | Token.Id.Pipe, | |
| 756 | Token.Id.PipeEqual, | |
| 1151 | Token.Id.PipePipe, | |
| 1152 | Token.Id.Equal, | |
| 757 | 1153 | }); |
| 758 | 1154 | } |
| 759 | 1155 |
test/build_examples.zig+1| ... | ... | @@ -14,6 +14,7 @@ pub fn addCases(cases: &tests.BuildExamplesContext) void { |
| 14 | 14 | cases.addBuildFile("example/mix_o_files/build.zig"); |
| 15 | 15 | } |
| 16 | 16 | cases.addBuildFile("test/standalone/issue_339/build.zig"); |
| 17 | cases.addBuildFile("test/standalone/issue_794/build.zig"); | |
| 17 | 18 | cases.addBuildFile("test/standalone/pkg_import/build.zig"); |
| 18 | 19 | cases.addBuildFile("test/standalone/use_alias/build.zig"); |
| 19 | 20 | cases.addBuildFile("test/standalone/brace_expansion/build.zig"); |
test/cases/coroutines.zig+87-6| ... | ... | @@ -1,10 +1,12 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const assert = std.debug.assert; |
| 3 | 4 | |
| 4 | 5 | var x: i32 = 1; |
| 5 | 6 | |
| 6 | 7 | test "create a coroutine and cancel it" { |
| 7 | const p = try async(std.debug.global_allocator) simpleAsyncFn(); | |
| 8 | const p = try async<std.debug.global_allocator> simpleAsyncFn(); | |
| 9 | comptime assert(@typeOf(p) == promise->void); | |
| 8 | 10 | cancel p; |
| 9 | 11 | assert(x == 2); |
| 10 | 12 | } |
| ... | ... | @@ -17,7 +19,7 @@ async fn simpleAsyncFn() void { |
| 17 | 19 | |
| 18 | 20 | test "coroutine suspend, resume, cancel" { |
| 19 | 21 | seq('a'); |
| 20 | const p = try async(std.debug.global_allocator) testAsyncSeq(); | |
| 22 | const p = try async<std.debug.global_allocator> testAsyncSeq(); | |
| 21 | 23 | seq('c'); |
| 22 | 24 | resume p; |
| 23 | 25 | seq('f'); |
| ... | ... | @@ -43,7 +45,7 @@ fn seq(c: u8) void { |
| 43 | 45 | } |
| 44 | 46 | |
| 45 | 47 | test "coroutine suspend with block" { |
| 46 | const p = try async(std.debug.global_allocator) testSuspendBlock(); | |
| 48 | const p = try async<std.debug.global_allocator> testSuspendBlock(); | |
| 47 | 49 | std.debug.assert(!result); |
| 48 | 50 | resume a_promise; |
| 49 | 51 | std.debug.assert(result); |
| ... | ... | @@ -55,6 +57,7 @@ var result = false; |
| 55 | 57 | |
| 56 | 58 | async fn testSuspendBlock() void { |
| 57 | 59 | suspend |p| { |
| 60 | comptime assert(@typeOf(p) == promise->void); | |
| 58 | 61 | a_promise = p; |
| 59 | 62 | } |
| 60 | 63 | result = true; |
| ... | ... | @@ -65,7 +68,7 @@ var await_final_result: i32 = 0; |
| 65 | 68 | |
| 66 | 69 | test "coroutine await" { |
| 67 | 70 | await_seq('a'); |
| 68 | const p = async(std.debug.global_allocator) await_amain() catch unreachable; | |
| 71 | const p = async<std.debug.global_allocator> await_amain() catch unreachable; | |
| 69 | 72 | await_seq('f'); |
| 70 | 73 | resume await_a_promise; |
| 71 | 74 | await_seq('i'); |
| ... | ... | @@ -104,7 +107,7 @@ var early_final_result: i32 = 0; |
| 104 | 107 | |
| 105 | 108 | test "coroutine await early return" { |
| 106 | 109 | early_seq('a'); |
| 107 | const p = async(std.debug.global_allocator) early_amain() catch unreachable; | |
| 110 | const p = async<std.debug.global_allocator> early_amain() catch unreachable; | |
| 108 | 111 | early_seq('f'); |
| 109 | 112 | assert(early_final_result == 1234); |
| 110 | 113 | assert(std.mem.eql(u8, early_points, "abcdef")); |
| ... | ... | @@ -133,7 +136,7 @@ fn early_seq(c: u8) void { |
| 133 | 136 | |
| 134 | 137 | test "coro allocation failure" { |
| 135 | 138 | var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); |
| 136 | if (async(&failing_allocator.allocator) asyncFuncThatNeverGetsRun()) { | |
| 139 | if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { | |
| 137 | 140 | @panic("expected allocation failure"); |
| 138 | 141 | } else |err| switch (err) { |
| 139 | 142 | error.OutOfMemory => {}, |
| ... | ... | @@ -143,3 +146,81 @@ test "coro allocation failure" { |
| 143 | 146 | async fn asyncFuncThatNeverGetsRun() void { |
| 144 | 147 | @panic("coro frame allocation should fail"); |
| 145 | 148 | } |
| 149 | ||
| 150 | test "async function with dot syntax" { | |
| 151 | const S = struct { | |
| 152 | var y: i32 = 1; | |
| 153 | async fn foo() void { | |
| 154 | y += 1; | |
| 155 | suspend; | |
| 156 | } | |
| 157 | }; | |
| 158 | const p = try async<std.debug.global_allocator> S.foo(); | |
| 159 | cancel p; | |
| 160 | assert(S.y == 2); | |
| 161 | } | |
| 162 | ||
| 163 | test "async fn pointer in a struct field" { | |
| 164 | var data: i32 = 1; | |
| 165 | const Foo = struct { | |
| 166 | bar: async<&std.mem.Allocator> fn(&i32) void, | |
| 167 | }; | |
| 168 | var foo = Foo { | |
| 169 | .bar = simpleAsyncFn2, | |
| 170 | }; | |
| 171 | const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable; | |
| 172 | assert(data == 2); | |
| 173 | cancel p; | |
| 174 | assert(data == 4); | |
| 175 | } | |
| 176 | ||
| 177 | async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void { | |
| 178 | defer *y += 2; | |
| 179 | *y += 1; | |
| 180 | suspend; | |
| 181 | } | |
| 182 | ||
| 183 | test "async fn with inferred error set" { | |
| 184 | const p = (async<std.debug.global_allocator> failing()) catch unreachable; | |
| 185 | resume p; | |
| 186 | cancel p; | |
| 187 | } | |
| 188 | ||
| 189 | async fn failing() !void { | |
| 190 | suspend; | |
| 191 | return error.Fail; | |
| 192 | } | |
| 193 | ||
| 194 | test "error return trace across suspend points - early return" { | |
| 195 | const p = nonFailing(); | |
| 196 | resume p; | |
| 197 | const p2 = try async<std.debug.global_allocator> printTrace(p); | |
| 198 | cancel p2; | |
| 199 | } | |
| 200 | ||
| 201 | test "error return trace across suspend points - async return" { | |
| 202 | const p = nonFailing(); | |
| 203 | const p2 = try async<std.debug.global_allocator> printTrace(p); | |
| 204 | resume p; | |
| 205 | cancel p2; | |
| 206 | } | |
| 207 | ||
| 208 | fn nonFailing() promise->error!void { | |
| 209 | return async<std.debug.global_allocator> suspendThenFail() catch unreachable; | |
| 210 | } | |
| 211 | ||
| 212 | async fn suspendThenFail() error!void { | |
| 213 | suspend; | |
| 214 | return error.Fail; | |
| 215 | } | |
| 216 | ||
| 217 | async fn printTrace(p: promise->error!void) void { | |
| 218 | (await p) catch |e| { | |
| 219 | std.debug.assert(e == error.Fail); | |
| 220 | if (@errorReturnTrace()) |trace| { | |
| 221 | assert(trace.index == 1); | |
| 222 | } else if (builtin.mode != builtin.Mode.ReleaseFast) { | |
| 223 | @panic("expected return trace"); | |
| 224 | } | |
| 225 | }; | |
| 226 | } |
test/cases/eval.zig+11-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 2 | 3 | const builtin = @import("builtin"); |
| 3 | 4 | |
| 4 | 5 | test "compile time recursion" { |
| ... | ... | @@ -503,3 +504,12 @@ test "const ptr to comptime mutable data is not memoized" { |
| 503 | 504 | assert(foo.read_x() == 2); |
| 504 | 505 | } |
| 505 | 506 | } |
| 507 | ||
| 508 | test "array concat of slices gives slice" { | |
| 509 | comptime { | |
| 510 | var a: []const u8 = "aoeu"; | |
| 511 | var b: []const u8 = "asdf"; | |
| 512 | const c = a ++ b; | |
| 513 | assert(std.mem.eql(u8, c, "aoeuasdf")); | |
| 514 | } | |
| 515 | } |
test/compile_errors.zig+10-1| ... | ... | @@ -1,6 +1,15 @@ |
| 1 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 4 | cases.add("wrong type passed to @panic", | |
| 5 | \\export fn entry() void { | |
| 6 | \\ var e = error.Foo; | |
| 7 | \\ @panic(e); | |
| 8 | \\} | |
| 9 | , | |
| 10 | ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'"); | |
| 11 | ||
| 12 | ||
| 4 | 13 | cases.add("@tagName used on union with no associated enum tag", |
| 5 | 14 | \\const FloatInt = extern union { |
| 6 | 15 | \\ Float: f32, |
| ... | ... | @@ -17,7 +26,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { |
| 17 | 26 | cases.add("returning error from void async function", |
| 18 | 27 | \\const std = @import("std"); |
| 19 | 28 | \\export fn entry() void { |
| 20 | \\ const p = async(std.debug.global_allocator) amain() catch unreachable; | |
| 29 | \\ const p = async<std.debug.global_allocator> amain() catch unreachable; | |
| 21 | 30 | \\} |
| 22 | 31 | \\async fn amain() void { |
| 23 | 32 | \\ return error.ShouldBeCompileError; |
test/gen_h.zig+11| ... | ... | @@ -51,6 +51,16 @@ pub fn addCases(cases: &tests.GenHContext) void { |
| 51 | 51 | \\ |
| 52 | 52 | ); |
| 53 | 53 | |
| 54 | cases.add("declare opaque type", | |
| 55 | \\export const Foo = @OpaqueType(); | |
| 56 | \\ | |
| 57 | \\export fn entry(foo: ?&Foo) void { } | |
| 58 | , | |
| 59 | \\struct Foo; | |
| 60 | \\ | |
| 61 | \\TEST_EXPORT void entry(struct Foo * foo); | |
| 62 | ); | |
| 63 | ||
| 54 | 64 | cases.add("array field-type", |
| 55 | 65 | \\const Foo = extern struct { |
| 56 | 66 | \\ A: [2]i32, |
| ... | ... | @@ -66,4 +76,5 @@ pub fn addCases(cases: &tests.GenHContext) void { |
| 66 | 76 | \\TEST_EXPORT void entry(struct Foo foo, uint8_t bar[]); |
| 67 | 77 | \\ |
| 68 | 78 | ); |
| 79 | ||
| 69 | 80 | } |
test/runtime_safety.zig+30| ... | ... | @@ -281,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 281 | 281 | \\ f.float = 12.34; |
| 282 | 282 | \\} |
| 283 | 283 | ); |
| 284 | ||
| 285 | // This case makes sure that the code compiles and runs. There is not actually a special | |
| 286 | // runtime safety check having to do specifically with error return traces across suspend points. | |
| 287 | cases.addRuntimeSafety("error return trace across suspend points", | |
| 288 | \\const std = @import("std"); | |
| 289 | \\ | |
| 290 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | |
| 291 | \\ std.os.exit(126); | |
| 292 | \\} | |
| 293 | \\ | |
| 294 | \\pub fn main() void { | |
| 295 | \\ const p = nonFailing(); | |
| 296 | \\ resume p; | |
| 297 | \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable; | |
| 298 | \\ cancel p2; | |
| 299 | \\} | |
| 300 | \\ | |
| 301 | \\fn nonFailing() promise->error!void { | |
| 302 | \\ return async<std.debug.global_allocator> failing() catch unreachable; | |
| 303 | \\} | |
| 304 | \\ | |
| 305 | \\async fn failing() error!void { | |
| 306 | \\ suspend; | |
| 307 | \\ return error.Fail; | |
| 308 | \\} | |
| 309 | \\ | |
| 310 | \\async fn printTrace(p: promise->error!void) void { | |
| 311 | \\ (await p) catch unreachable; | |
| 312 | \\} | |
| 313 | ); | |
| 284 | 314 | } |
test/standalone/issue_794/a_directory/foo.h created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | #define NUMBER 1234 |
test/standalone/issue_794/build.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | const Builder = @import("std").build.Builder; | |
| 2 | ||
| 3 | pub fn build(b: &Builder) void { | |
| 4 | const test_artifact = b.addTest("main.zig"); | |
| 5 | test_artifact.addIncludeDir("a_directory"); | |
| 6 | ||
| 7 | b.default_step.dependOn(&test_artifact.step); | |
| 8 | ||
| 9 | const test_step = b.step("test", "Test the program"); | |
| 10 | test_step.dependOn(&test_artifact.step); | |
| 11 | } |
test/standalone/issue_794/main.zig created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | const c = @cImport(@cInclude("foo.h")); | |
| 2 | const std = @import("std"); | |
| 3 | const assert = std.debug.assert; | |
| 4 | ||
| 5 | test "c import" { | |
| 6 | comptime assert(c.NUMBER == 1234); | |
| 7 | } |