| author | |
| committer | |
| log | cca93908e6d57f18054d153ca01d6869739306f2 |
| tree | b7316e13386963e5b08aebc1f5707498b64a9ebb |
| parent | c541ac240c3ad17dda964f9de085a5e8f5472c7a |
| parent | 8938429ea12ff2857ace5380932a7cd68d3b4ab1 |
61 files changed, 3135 insertions(+), 1368 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+5-6| ... | ... | @@ -30,11 +30,7 @@ if(GIT_EXE) |
| 30 | 30 | endif() |
| 31 | 31 | message("Configuring zig version ${ZIG_VERSION}") |
| 32 | 32 | |
| 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") | |
| 33 | set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") | |
| 38 | 34 | |
| 39 | 35 | string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}") |
| 40 | 36 | string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}") |
| ... | ... | @@ -429,6 +425,7 @@ set(ZIG_STD_FILES |
| 429 | 425 | "crypto/sha2.zig" |
| 430 | 426 | "crypto/sha3.zig" |
| 431 | 427 | "crypto/blake2.zig" |
| 428 | "crypto/hmac.zig" | |
| 432 | 429 | "cstr.zig" |
| 433 | 430 | "debug/failing_allocator.zig" |
| 434 | 431 | "debug/index.zig" |
| ... | ... | @@ -509,7 +506,7 @@ set(ZIG_STD_FILES |
| 509 | 506 | "os/windows/index.zig" |
| 510 | 507 | "os/windows/util.zig" |
| 511 | 508 | "os/zen.zig" |
| 512 | "rand.zig" | |
| 509 | "rand/index.zig" | |
| 513 | 510 | "sort.zig" |
| 514 | 511 | "special/bootstrap.zig" |
| 515 | 512 | "special/bootstrap_lib.zig" |
| ... | ... | @@ -698,6 +695,8 @@ if(MINGW) |
| 698 | 695 | set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++") |
| 699 | 696 | elseif(MSVC) |
| 700 | 697 | set(EXE_LDFLAGS "/STACK:16777216") |
| 698 | elseif(ZIG_STATIC) | |
| 699 | set(EXE_LDFLAGS "-static") | |
| 701 | 700 | else() |
| 702 | 701 | set(EXE_LDFLAGS " ") |
| 703 | 702 | endif() |
README.md+1-7| ... | ... | @@ -138,14 +138,10 @@ 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 .. -DCMAKE_INSTALL_PREFIX=$(pwd) | |
| 149 | 145 | make |
| 150 | 146 | make install |
| 151 | 147 | ./zig build --build-file ../build.zig test |
| ... | ... | @@ -153,8 +149,6 @@ make install |
| 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@7 |
| 160 | 154 | brew outdated llvm@7 || brew upgrade llvm@7 |
build.zig+5| ... | ... | @@ -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"); |
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-7.0 libclang-7.0 libclang-7.0-dev llvm-7.0 llvm-7.0-dev liblld-7.0 liblld-7.0-dev cmake wine1.6-amd64 | |
| 7 | sudo apt-get install -y clang-7.0 libclang-7.0 libclang-7.0-dev llvm-7.0 llvm-7.0-dev liblld-7.0 liblld-7.0-dev cmake s3cmd |
ci/travis_linux_script+11-20| ... | ... | @@ -8,25 +8,16 @@ export CXX=clang++-7.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/Findllvm.cmake+1-1| ... | ... | @@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE |
| 15 | 15 | "c:/msys64/mingw64/bin" |
| 16 | 16 | "C:/Libraries/llvm-7.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 |
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+11-10| ... | ... | @@ -2864,18 +2864,18 @@ const err = (error {FileNotFound}).FileNotFound; |
| 2864 | 2864 | assert to make sure the error value is in fact in the destination error set. |
| 2865 | 2865 | </p> |
| 2866 | 2866 | <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#}. | |
| 2867 | The global error set should generally be avoided because it prevents the | |
| 2868 | compiler from knowing what errors are possible at compile-time. Knowing | |
| 2869 | the error set at compile-time is better for generated documentation and | |
| 2870 | helpful error messages, such as forgetting a possible error value in a {#link|switch#}. | |
| 2871 | 2871 | </p> |
| 2872 | 2872 | {#header_close#} |
| 2873 | 2873 | {#header_close#} |
| 2874 | 2874 | {#header_open|Error Union Type#} |
| 2875 | 2875 | <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. | |
| 2876 | An error set type and normal type can be combined with the <code>!</code> | |
| 2877 | binary operator to form an error union type. You are likely to use an | |
| 2878 | error union type more often than an error set type by itself. | |
| 2879 | 2879 | </p> |
| 2880 | 2880 | <p> |
| 2881 | 2881 | Here is a function to parse a string into a 64-bit integer: |
| ... | ... | @@ -5739,7 +5739,7 @@ UseDecl = "use" Expression ";" |
| 5739 | 5739 | |
| 5740 | 5740 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" |
| 5741 | 5741 | |
| 5742 | FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var") | |
| 5742 | FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("&lt;" Expression "&gt;"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var") | |
| 5743 | 5743 | |
| 5744 | 5744 | FnDef = option("inline" | "export") FnProto Block |
| 5745 | 5745 | |
| ... | ... | @@ -5863,7 +5863,9 @@ StructLiteralField = "." Symbol "=" Expression |
| 5863 | 5863 | |
| 5864 | 5864 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" |
| 5865 | 5865 | |
| 5866 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | |
| 5866 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType | |
| 5867 | ||
| 5868 | PromiseType = "promise" option("-&gt;" TypeExpr) | |
| 5867 | 5869 | |
| 5868 | 5870 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr |
| 5869 | 5871 | |
| ... | ... | @@ -6031,4 +6033,3 @@ hljs.registerLanguage("zig", function(t) { |
| 6031 | 6033 | </script> |
| 6032 | 6034 | </body> |
| 6033 | 6035 | </html> |
| 6034 |
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+159| ... | ... | @@ -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); |
src/all_types.hpp+39-2| ... | ... | @@ -409,6 +409,7 @@ enum NodeType { |
| 409 | 409 | NodeTypeResume, |
| 410 | 410 | NodeTypeAwaitExpr, |
| 411 | 411 | NodeTypeSuspend, |
| 412 | NodeTypePromiseType, | |
| 412 | 413 | }; |
| 413 | 414 | |
| 414 | 415 | struct AstNodeRoot { |
| ... | ... | @@ -879,6 +880,10 @@ struct AstNodeSuspend { |
| 879 | 880 | AstNode *promise_symbol; |
| 880 | 881 | }; |
| 881 | 882 | |
| 883 | struct AstNodePromiseType { | |
| 884 | AstNode *payload_type; // can be NULL | |
| 885 | }; | |
| 886 | ||
| 882 | 887 | struct AstNode { |
| 883 | 888 | enum NodeType type; |
| 884 | 889 | size_t line; |
| ... | ... | @@ -939,6 +944,7 @@ struct AstNode { |
| 939 | 944 | AstNodeResumeExpr resume_expr; |
| 940 | 945 | AstNodeAwaitExpr await_expr; |
| 941 | 946 | AstNodeSuspend suspend; |
| 947 | AstNodePromiseType promise_type; | |
| 942 | 948 | } data; |
| 943 | 949 | }; |
| 944 | 950 | |
| ... | ... | @@ -1251,7 +1257,10 @@ struct FnTableEntry { |
| 1251 | 1257 | ScopeBlock *def_scope; // parent is child_scope |
| 1252 | 1258 | Buf symbol_name; |
| 1253 | 1259 | TypeTableEntry *type_entry; // function type |
| 1254 | TypeTableEntry *implicit_return_type; | |
| 1260 | // in the case of normal functions this is the implicit return type | |
| 1261 | // in the case of async functions this is the implicit return type according to the | |
| 1262 | // zig source code, not according to zig ir | |
| 1263 | TypeTableEntry *src_implicit_return_type; | |
| 1255 | 1264 | bool is_test; |
| 1256 | 1265 | FnInline fn_inline; |
| 1257 | 1266 | FnAnalState anal_state; |
| ... | ... | @@ -1612,7 +1621,8 @@ struct CodeGen { |
| 1612 | 1621 | FnTableEntry *panic_fn; |
| 1613 | 1622 | LLVMValueRef cur_ret_ptr; |
| 1614 | 1623 | LLVMValueRef cur_fn_val; |
| 1615 | LLVMValueRef cur_err_ret_trace_val; | |
| 1624 | LLVMValueRef cur_err_ret_trace_val_arg; | |
| 1625 | LLVMValueRef cur_err_ret_trace_val_stack; | |
| 1616 | 1626 | bool c_want_stdint; |
| 1617 | 1627 | bool c_want_stdbool; |
| 1618 | 1628 | AstNode *root_export_decl; |
| ... | ... | @@ -1749,6 +1759,7 @@ enum ScopeId { |
| 1749 | 1759 | ScopeIdLoop, |
| 1750 | 1760 | ScopeIdFnDef, |
| 1751 | 1761 | ScopeIdCompTime, |
| 1762 | ScopeIdCoroPrelude, | |
| 1752 | 1763 | }; |
| 1753 | 1764 | |
| 1754 | 1765 | struct Scope { |
| ... | ... | @@ -1856,6 +1867,12 @@ struct ScopeFnDef { |
| 1856 | 1867 | FnTableEntry *fn_entry; |
| 1857 | 1868 | }; |
| 1858 | 1869 | |
| 1870 | // This scope is created to indicate that the code in the scope | |
| 1871 | // is auto-generated coroutine prelude stuff. | |
| 1872 | struct ScopeCoroPrelude { | |
| 1873 | Scope base; | |
| 1874 | }; | |
| 1875 | ||
| 1859 | 1876 | // synchronized with code in define_builtin_compile_vars |
| 1860 | 1877 | enum AtomicOrder { |
| 1861 | 1878 | AtomicOrderUnordered, |
| ... | ... | @@ -1942,6 +1959,7 @@ enum IrInstructionId { |
| 1942 | 1959 | IrInstructionIdSetRuntimeSafety, |
| 1943 | 1960 | IrInstructionIdSetFloatMode, |
| 1944 | 1961 | IrInstructionIdArrayType, |
| 1962 | IrInstructionIdPromiseType, | |
| 1945 | 1963 | IrInstructionIdSliceType, |
| 1946 | 1964 | IrInstructionIdAsm, |
| 1947 | 1965 | IrInstructionIdSizeOf, |
| ... | ... | @@ -2032,6 +2050,8 @@ enum IrInstructionId { |
| 2032 | 2050 | IrInstructionIdAtomicRmw, |
| 2033 | 2051 | IrInstructionIdPromiseResultType, |
| 2034 | 2052 | IrInstructionIdAwaitBookkeeping, |
| 2053 | IrInstructionIdSaveErrRetAddr, | |
| 2054 | IrInstructionIdAddImplicitReturnType, | |
| 2035 | 2055 | }; |
| 2036 | 2056 | |
| 2037 | 2057 | struct IrInstruction { |
| ... | ... | @@ -2358,6 +2378,12 @@ struct IrInstructionArrayType { |
| 2358 | 2378 | IrInstruction *child_type; |
| 2359 | 2379 | }; |
| 2360 | 2380 | |
| 2381 | struct IrInstructionPromiseType { | |
| 2382 | IrInstruction base; | |
| 2383 | ||
| 2384 | IrInstruction *payload_type; | |
| 2385 | }; | |
| 2386 | ||
| 2361 | 2387 | struct IrInstructionSliceType { |
| 2362 | 2388 | IrInstruction base; |
| 2363 | 2389 | |
| ... | ... | @@ -2671,6 +2697,7 @@ struct IrInstructionFnProto { |
| 2671 | 2697 | IrInstruction **param_types; |
| 2672 | 2698 | IrInstruction *align_value; |
| 2673 | 2699 | IrInstruction *return_type; |
| 2700 | IrInstruction *async_allocator_type_value; | |
| 2674 | 2701 | bool is_var_args; |
| 2675 | 2702 | }; |
| 2676 | 2703 | |
| ... | ... | @@ -2985,6 +3012,16 @@ struct IrInstructionAwaitBookkeeping { |
| 2985 | 3012 | IrInstruction *promise_result_type; |
| 2986 | 3013 | }; |
| 2987 | 3014 | |
| 3015 | struct IrInstructionSaveErrRetAddr { | |
| 3016 | IrInstruction base; | |
| 3017 | }; | |
| 3018 | ||
| 3019 | struct IrInstructionAddImplicitReturnType { | |
| 3020 | IrInstruction base; | |
| 3021 | ||
| 3022 | IrInstruction *value; | |
| 3023 | }; | |
| 3024 | ||
| 2988 | 3025 | static const size_t slice_ptr_index = 0; |
| 2989 | 3026 | static const size_t slice_len_index = 1; |
| 2990 | 3027 |
src/analyze.cpp+125-17| ... | ... | @@ -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) { |
| ... | ... | @@ -985,7 +991,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 985 | 991 | // populate the name of the type |
| 986 | 992 | buf_resize(&fn_type->name, 0); |
| 987 | 993 | 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)); | |
| 994 | assert(fn_type_id->async_allocator_type != nullptr); | |
| 995 | buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name)); | |
| 989 | 996 | } else { |
| 990 | 997 | const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc); |
| 991 | 998 | buf_appendf(&fn_type->name, "%s", cc_str); |
| ... | ... | @@ -3253,6 +3260,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3253 | 3260 | case NodeTypeResume: |
| 3254 | 3261 | case NodeTypeAwaitExpr: |
| 3255 | 3262 | case NodeTypeSuspend: |
| 3263 | case NodeTypePromiseType: | |
| 3256 | 3264 | zig_unreachable(); |
| 3257 | 3265 | } |
| 3258 | 3266 | } |
| ... | ... | @@ -3590,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { |
| 3590 | 3598 | case ScopeIdCImport: |
| 3591 | 3599 | case ScopeIdLoop: |
| 3592 | 3600 | case ScopeIdCompTime: |
| 3601 | case ScopeIdCoroPrelude: | |
| 3593 | 3602 | scope = scope->parent; |
| 3594 | 3603 | continue; |
| 3595 | 3604 | case ScopeIdFnDef: |
| ... | ... | @@ -3864,7 +3873,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3864 | 3873 | |
| 3865 | 3874 | TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, |
| 3866 | 3875 | &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3867 | fn_table_entry->implicit_return_type = block_return_type; | |
| 3876 | fn_table_entry->src_implicit_return_type = block_return_type; | |
| 3868 | 3877 | |
| 3869 | 3878 | if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) { |
| 3870 | 3879 | assert(g->errors.length > 0); |
| ... | ... | @@ -3876,10 +3885,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3876 | 3885 | TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; |
| 3877 | 3886 | if (return_err_set_type->data.error_set.infer_fn != nullptr) { |
| 3878 | 3887 | 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; | |
| 3888 | if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) { | |
| 3889 | inferred_err_set_type = fn_table_entry->src_implicit_return_type; | |
| 3890 | } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3891 | inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type; | |
| 3883 | 3892 | } else { |
| 3884 | 3893 | add_node_error(g, return_type_node, |
| 3885 | 3894 | buf_sprintf("function with inferred error set must return at least one possible error")); |
| ... | ... | @@ -4276,26 +4285,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) { |
| 4276 | 4285 | return g->win_sdk; |
| 4277 | 4286 | } |
| 4278 | 4287 | |
| 4288 | ||
| 4289 | Buf *get_linux_libc_lib_path(const char *o_file) { | |
| 4290 | const char *cc_exe = getenv("CC"); | |
| 4291 | cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; | |
| 4292 | ZigList<const char *> args = {}; | |
| 4293 | args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file))); | |
| 4294 | Termination term; | |
| 4295 | Buf *out_stderr = buf_alloc(); | |
| 4296 | Buf *out_stdout = buf_alloc(); | |
| 4297 | int err; | |
| 4298 | if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { | |
| 4299 | zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err)); | |
| 4300 | } | |
| 4301 | if (term.how != TerminationIdClean || term.code != 0) { | |
| 4302 | zig_panic("unable to determine libc lib path: executing C compiler command failed"); | |
| 4303 | } | |
| 4304 | if (buf_ends_with_str(out_stdout, "\n")) { | |
| 4305 | buf_resize(out_stdout, buf_len(out_stdout) - 1); | |
| 4306 | } | |
| 4307 | if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) { | |
| 4308 | zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file); | |
| 4309 | } | |
| 4310 | Buf *result = buf_alloc(); | |
| 4311 | os_path_dirname(out_stdout, result); | |
| 4312 | return result; | |
| 4313 | } | |
| 4314 | ||
| 4315 | Buf *get_linux_libc_include_path(void) { | |
| 4316 | const char *cc_exe = getenv("CC"); | |
| 4317 | cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; | |
| 4318 | ZigList<const char *> args = {}; | |
| 4319 | args.append("-E"); | |
| 4320 | args.append("-Wp,-v"); | |
| 4321 | args.append("-xc"); | |
| 4322 | args.append("/dev/null"); | |
| 4323 | Termination term; | |
| 4324 | Buf *out_stderr = buf_alloc(); | |
| 4325 | Buf *out_stdout = buf_alloc(); | |
| 4326 | int err; | |
| 4327 | if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { | |
| 4328 | zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err)); | |
| 4329 | } | |
| 4330 | if (term.how != TerminationIdClean || term.code != 0) { | |
| 4331 | zig_panic("unable to determine libc include path: executing C compiler command failed"); | |
| 4332 | } | |
| 4333 | char *prev_newline = buf_ptr(out_stderr); | |
| 4334 | ZigList<const char *> search_paths = {}; | |
| 4335 | bool found_search_paths = false; | |
| 4336 | for (;;) { | |
| 4337 | char *newline = strchr(prev_newline, '\n'); | |
| 4338 | if (newline == nullptr) { | |
| 4339 | zig_panic("unable to determine libc include path: bad output from C compiler command"); | |
| 4340 | } | |
| 4341 | *newline = 0; | |
| 4342 | if (found_search_paths) { | |
| 4343 | if (strcmp(prev_newline, "End of search list.") == 0) { | |
| 4344 | break; | |
| 4345 | } | |
| 4346 | search_paths.append(prev_newline); | |
| 4347 | } else { | |
| 4348 | if (strcmp(prev_newline, "#include <...> search starts here:") == 0) { | |
| 4349 | found_search_paths = true; | |
| 4350 | } | |
| 4351 | } | |
| 4352 | prev_newline = newline + 1; | |
| 4353 | } | |
| 4354 | if (search_paths.length == 0) { | |
| 4355 | zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are"); | |
| 4356 | } | |
| 4357 | for (size_t i = 0; i < search_paths.length; i += 1) { | |
| 4358 | // search in reverse order | |
| 4359 | const char *search_path = search_paths.items[search_paths.length - i - 1]; | |
| 4360 | // cut off spaces | |
| 4361 | while (*search_path == ' ') { | |
| 4362 | search_path += 1; | |
| 4363 | } | |
| 4364 | Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path); | |
| 4365 | bool exists; | |
| 4366 | if ((err = os_file_exists(stdlib_path, &exists))) { | |
| 4367 | exists = false; | |
| 4368 | } | |
| 4369 | if (exists) { | |
| 4370 | return buf_create_from_str(search_path); | |
| 4371 | } | |
| 4372 | } | |
| 4373 | zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths"); | |
| 4374 | } | |
| 4375 | ||
| 4279 | 4376 | 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); | |
| 4377 | if (g->libc_include_dir == nullptr) { | |
| 4282 | 4378 | |
| 4283 | 4379 | if (g->zig_target.os == OsWindows) { |
| 4380 | ZigWindowsSDK *sdk = get_windows_sdk(g); | |
| 4381 | g->libc_include_dir = buf_alloc(); | |
| 4284 | 4382 | if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) { |
| 4285 | 4383 | zig_panic("Unable to determine libc include path."); |
| 4286 | 4384 | } |
| 4385 | } else if (g->zig_target.os == OsLinux) { | |
| 4386 | g->libc_include_dir = get_linux_libc_include_path(); | |
| 4387 | } else if (g->zig_target.os == OsMacOSX) { | |
| 4388 | g->libc_include_dir = buf_create_from_str("/usr/include"); | |
| 4389 | } else { | |
| 4390 | // TODO find libc at runtime for other operating systems | |
| 4391 | zig_panic("Unable to determine libc include path."); | |
| 4287 | 4392 | } |
| 4288 | 4393 | } |
| 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 | } | |
| 4394 | assert(buf_len(g->libc_include_dir) != 0); | |
| 4294 | 4395 | } |
| 4295 | 4396 | |
| 4296 | 4397 | void find_libc_lib_path(CodeGen *g) { |
| 4297 | 4398 | // 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 || | |
| 4399 | if (g->libc_lib_dir == nullptr || | |
| 4299 | 4400 | (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr))) |
| 4300 | 4401 | { |
| 4301 | 4402 | if (g->zig_target.os == OsWindows) { |
| ... | ... | @@ -4319,18 +4420,25 @@ void find_libc_lib_path(CodeGen *g) { |
| 4319 | 4420 | g->msvc_lib_dir = vc_lib_dir; |
| 4320 | 4421 | g->libc_lib_dir = ucrt_lib_path; |
| 4321 | 4422 | g->kernel32_lib_dir = kern_lib_path; |
| 4423 | } else if (g->zig_target.os == OsLinux) { | |
| 4424 | g->libc_lib_dir = get_linux_libc_lib_path("crt1.o"); | |
| 4322 | 4425 | } else { |
| 4323 | 4426 | zig_panic("Unable to determine libc lib path."); |
| 4324 | 4427 | } |
| 4428 | } else { | |
| 4429 | assert(buf_len(g->libc_lib_dir) != 0); | |
| 4325 | 4430 | } |
| 4326 | 4431 | |
| 4327 | if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) { | |
| 4432 | if (g->libc_static_lib_dir == nullptr) { | |
| 4328 | 4433 | if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) { |
| 4329 | 4434 | return; |
| 4330 | } | |
| 4331 | else { | |
| 4435 | } else if (g->zig_target.os == OsLinux) { | |
| 4436 | g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o"); | |
| 4437 | } else { | |
| 4332 | 4438 | zig_panic("Unable to determine libc static lib path."); |
| 4333 | 4439 | } |
| 4440 | } else { | |
| 4441 | assert(buf_len(g->libc_static_lib_dir) != 0); | |
| 4334 | 4442 | } |
| 4335 | 4443 | } |
| 4336 | 4444 |
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-1| ... | ... | @@ -250,6 +250,8 @@ static const char *node_type_str(NodeType node_type) { |
| 250 | 250 | return "AwaitExpr"; |
| 251 | 251 | case NodeTypeSuspend: |
| 252 | 252 | return "Suspend"; |
| 253 | case NodeTypePromiseType: | |
| 254 | return "PromiseType"; | |
| 253 | 255 | } |
| 254 | 256 | zig_unreachable(); |
| 255 | 257 | } |
| ... | ... | @@ -658,6 +660,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 658 | 660 | if (node->data.fn_call_expr.is_builtin) { |
| 659 | 661 | fprintf(ar->f, "@"); |
| 660 | 662 | } |
| 663 | if (node->data.fn_call_expr.is_async) { | |
| 664 | fprintf(ar->f, "async"); | |
| 665 | if (node->data.fn_call_expr.async_allocator != nullptr) { | |
| 666 | fprintf(ar->f, "<"); | |
| 667 | render_node_extra(ar, node->data.fn_call_expr.async_allocator, true); | |
| 668 | fprintf(ar->f, ">"); | |
| 669 | } | |
| 670 | fprintf(ar->f, " "); | |
| 671 | } | |
| 661 | 672 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 662 | 673 | bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); |
| 663 | 674 | render_node_extra(ar, fn_ref_node, grouped); |
| ... | ... | @@ -772,6 +783,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 772 | 783 | render_node_ungrouped(ar, node->data.array_type.child_type); |
| 773 | 784 | break; |
| 774 | 785 | } |
| 786 | case NodeTypePromiseType: | |
| 787 | { | |
| 788 | fprintf(ar->f, "promise"); | |
| 789 | if (node->data.promise_type.payload_type != nullptr) { | |
| 790 | fprintf(ar->f, "->"); | |
| 791 | render_node_grouped(ar, node->data.promise_type.payload_type); | |
| 792 | } | |
| 793 | break; | |
| 794 | } | |
| 775 | 795 | case NodeTypeErrorType: |
| 776 | 796 | fprintf(ar->f, "error"); |
| 777 | 797 | break; |
| ... | ... | @@ -1023,7 +1043,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1023 | 1043 | case NodeTypeUnwrapErrorExpr: |
| 1024 | 1044 | { |
| 1025 | 1045 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); |
| 1026 | fprintf(ar->f, " %%%% "); | |
| 1046 | fprintf(ar->f, " catch "); | |
| 1027 | 1047 | if (node->data.unwrap_err_expr.symbol) { |
| 1028 | 1048 | Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol; |
| 1029 | 1049 | fprintf(ar->f, "|%s| ", buf_ptr(var_name)); |
src/codegen.cpp+80-55| ... | ... | @@ -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) |
| ... | ... | @@ -657,6 +654,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 657 | 654 | case ScopeIdDeferExpr: |
| 658 | 655 | case ScopeIdLoop: |
| 659 | 656 | case ScopeIdCompTime: |
| 657 | case ScopeIdCoroPrelude: | |
| 660 | 658 | return get_di_scope(g, scope->parent); |
| 661 | 659 | } |
| 662 | 660 | zig_unreachable(); |
| ... | ... | @@ -1295,9 +1293,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1295 | 1293 | return fn_val; |
| 1296 | 1294 | } |
| 1297 | 1295 | |
| 1298 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | |
| 1296 | static bool is_coro_prelude_scope(Scope *scope) { | |
| 1297 | while (scope != nullptr) { | |
| 1298 | if (scope->id == ScopeIdCoroPrelude) { | |
| 1299 | return true; | |
| 1300 | } else if (scope->id == ScopeIdFnDef) { | |
| 1301 | break; | |
| 1302 | } | |
| 1303 | scope = scope->parent; | |
| 1304 | } | |
| 1305 | return false; | |
| 1306 | } | |
| 1307 | ||
| 1308 | static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) { | |
| 1309 | if (!g->have_err_ret_tracing) { | |
| 1310 | return nullptr; | |
| 1311 | } | |
| 1312 | if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { | |
| 1313 | return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack; | |
| 1314 | } | |
| 1315 | if (g->cur_err_ret_trace_val_stack != nullptr) { | |
| 1316 | return g->cur_err_ret_trace_val_stack; | |
| 1317 | } | |
| 1318 | return g->cur_err_ret_trace_val_arg; | |
| 1319 | } | |
| 1320 | ||
| 1321 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { | |
| 1299 | 1322 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); |
| 1300 | LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val; | |
| 1323 | LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); | |
| 1301 | 1324 | if (err_ret_trace_val == nullptr) { |
| 1302 | 1325 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 1303 | 1326 | err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref); |
| ... | ... | @@ -1574,32 +1597,25 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1574 | 1597 | return instruction->llvm_value; |
| 1575 | 1598 | } |
| 1576 | 1599 | |
| 1600 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, | |
| 1601 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) | |
| 1602 | { | |
| 1603 | assert(g->have_err_ret_tracing); | |
| 1604 | ||
| 1605 | LLVMValueRef return_err_fn = get_return_err_fn(g); | |
| 1606 | LLVMValueRef args[] = { | |
| 1607 | get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope), | |
| 1608 | }; | |
| 1609 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | |
| 1610 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1611 | LLVMSetTailCall(call_instruction, true); | |
| 1612 | return call_instruction; | |
| 1613 | } | |
| 1614 | ||
| 1577 | 1615 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { |
| 1578 | 1616 | LLVMValueRef value = ir_llvm_value(g, return_instruction->value); |
| 1579 | 1617 | TypeTableEntry *return_type = return_instruction->value->value.type; |
| 1580 | 1618 | |
| 1581 | if (g->have_err_ret_tracing) { | |
| 1582 | bool is_err_return = false; | |
| 1583 | if (return_type->id == TypeTableEntryIdErrorUnion) { | |
| 1584 | if (return_instruction->value->value.special == ConstValSpecialStatic) { | |
| 1585 | is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr; | |
| 1586 | } else if (return_instruction->value->value.special == ConstValSpecialRuntime) { | |
| 1587 | is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; | |
| 1588 | // TODO: emit a branch to check if the return value is an error | |
| 1589 | } | |
| 1590 | } else if (return_type->id == TypeTableEntryIdErrorSet) { | |
| 1591 | is_err_return = true; | |
| 1592 | } | |
| 1593 | if (is_err_return) { | |
| 1594 | LLVMValueRef return_err_fn = get_return_err_fn(g); | |
| 1595 | LLVMValueRef args[] = { | |
| 1596 | g->cur_err_ret_trace_val, | |
| 1597 | }; | |
| 1598 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | |
| 1599 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1600 | LLVMSetTailCall(call_instruction, true); | |
| 1601 | } | |
| 1602 | } | |
| 1603 | 1619 | if (handle_is_ptr(return_type)) { |
| 1604 | 1620 | if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { |
| 1605 | 1621 | assert(g->cur_ret_ptr); |
| ... | ... | @@ -2671,7 +2687,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2671 | 2687 | gen_param_index += 1; |
| 2672 | 2688 | } |
| 2673 | 2689 | if (prefix_arg_err_ret_stack) { |
| 2674 | gen_param_values[gen_param_index] = g->cur_err_ret_trace_val; | |
| 2690 | gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 2675 | 2691 | gen_param_index += 1; |
| 2676 | 2692 | } |
| 2677 | 2693 | if (instruction->is_async) { |
| ... | ... | @@ -3238,11 +3254,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I |
| 3238 | 3254 | static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, |
| 3239 | 3255 | IrInstructionErrorReturnTrace *instruction) |
| 3240 | 3256 | { |
| 3241 | if (g->cur_err_ret_trace_val == nullptr) { | |
| 3257 | LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 3258 | if (cur_err_ret_trace_val == nullptr) { | |
| 3242 | 3259 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 3243 | 3260 | return LLVMConstNull(ptr_to_stack_trace_type->type_ref); |
| 3244 | 3261 | } |
| 3245 | return g->cur_err_ret_trace_val; | |
| 3262 | return cur_err_ret_trace_val; | |
| 3246 | 3263 | } |
| 3247 | 3264 | |
| 3248 | 3265 | static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) { |
| ... | ... | @@ -3648,7 +3665,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3648 | 3665 | LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); |
| 3649 | 3666 | |
| 3650 | 3667 | LLVMPositionBuilderAtEnd(g->builder, err_block); |
| 3651 | gen_safety_crash_for_err(g, err_val); | |
| 3668 | gen_safety_crash_for_err(g, err_val, instruction->base.scope); | |
| 3652 | 3669 | |
| 3653 | 3670 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3654 | 3671 | } |
| ... | ... | @@ -3840,7 +3857,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec |
| 3840 | 3857 | } |
| 3841 | 3858 | |
| 3842 | 3859 | static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { |
| 3843 | gen_panic(g, ir_llvm_value(g, instruction->msg), g->cur_err_ret_trace_val); | |
| 3860 | gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); | |
| 3844 | 3861 | return nullptr; |
| 3845 | 3862 | } |
| 3846 | 3863 | |
| ... | ... | @@ -4127,6 +4144,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4127 | 4144 | case IrInstructionIdSetRuntimeSafety: |
| 4128 | 4145 | case IrInstructionIdSetFloatMode: |
| 4129 | 4146 | case IrInstructionIdArrayType: |
| 4147 | case IrInstructionIdPromiseType: | |
| 4130 | 4148 | case IrInstructionIdSliceType: |
| 4131 | 4149 | case IrInstructionIdSizeOf: |
| 4132 | 4150 | case IrInstructionIdSwitchTarget: |
| ... | ... | @@ -4167,6 +4185,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4167 | 4185 | case IrInstructionIdErrorUnion: |
| 4168 | 4186 | case IrInstructionIdPromiseResultType: |
| 4169 | 4187 | case IrInstructionIdAwaitBookkeeping: |
| 4188 | case IrInstructionIdAddImplicitReturnType: | |
| 4170 | 4189 | zig_unreachable(); |
| 4171 | 4190 | |
| 4172 | 4191 | case IrInstructionIdReturn: |
| ... | ... | @@ -4315,6 +4334,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4315 | 4334 | return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction); |
| 4316 | 4335 | case IrInstructionIdAtomicRmw: |
| 4317 | 4336 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); |
| 4337 | case IrInstructionIdSaveErrRetAddr: | |
| 4338 | return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); | |
| 4318 | 4339 | } |
| 4319 | 4340 | zig_unreachable(); |
| 4320 | 4341 | } |
| ... | ... | @@ -5197,9 +5218,17 @@ static void do_code_gen(CodeGen *g) { |
| 5197 | 5218 | clear_debug_source_node(g); |
| 5198 | 5219 | |
| 5199 | 5220 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); |
| 5200 | if (err_ret_trace_arg_index != UINT32_MAX) { | |
| 5201 | g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 5202 | } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) { | |
| 5221 | bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; | |
| 5222 | if (have_err_ret_trace_arg) { | |
| 5223 | g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 5224 | } else { | |
| 5225 | g->cur_err_ret_trace_val_arg = nullptr; | |
| 5226 | } | |
| 5227 | ||
| 5228 | bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 5229 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && | |
| 5230 | (is_async || !have_err_ret_trace_arg); | |
| 5231 | if (have_err_ret_trace_stack) { | |
| 5203 | 5232 | // TODO call graph analysis to find out what this number needs to be for every function |
| 5204 | 5233 | static const size_t stack_trace_ptr_count = 30; |
| 5205 | 5234 | |
| ... | ... | @@ -5207,13 +5236,13 @@ static void do_code_gen(CodeGen *g) { |
| 5207 | 5236 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); |
| 5208 | 5237 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", |
| 5209 | 5238 | get_abi_alignment(g, array_type)); |
| 5210 | g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | |
| 5239 | 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)); | |
| 5211 | 5240 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| 5212 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, ""); | |
| 5241 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); | |
| 5213 | 5242 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); |
| 5214 | 5243 | |
| 5215 | 5244 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| 5216 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, ""); | |
| 5245 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); | |
| 5217 | 5246 | |
| 5218 | 5247 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; |
| 5219 | 5248 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; |
| ... | ... | @@ -5229,7 +5258,7 @@ static void do_code_gen(CodeGen *g) { |
| 5229 | 5258 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); |
| 5230 | 5259 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); |
| 5231 | 5260 | } else { |
| 5232 | g->cur_err_ret_trace_val = nullptr; | |
| 5261 | g->cur_err_ret_trace_val_stack = nullptr; | |
| 5233 | 5262 | } |
| 5234 | 5263 | |
| 5235 | 5264 | // allocate temporary stack data |
| ... | ... | @@ -6172,7 +6201,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package |
| 6172 | 6201 | zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); |
| 6173 | 6202 | } |
| 6174 | 6203 | Buf *import_code = buf_alloc(); |
| 6175 | if ((err = os_fetch_file_path(abs_full_path, import_code))) { | |
| 6204 | if ((err = os_fetch_file_path(abs_full_path, import_code, false))) { | |
| 6176 | 6205 | zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); |
| 6177 | 6206 | } |
| 6178 | 6207 | |
| ... | ... | @@ -6260,7 +6289,7 @@ static void gen_root_source(CodeGen *g) { |
| 6260 | 6289 | } |
| 6261 | 6290 | |
| 6262 | 6291 | Buf *source_code = buf_alloc(); |
| 6263 | if ((err = os_fetch_file_path(rel_full_path, source_code))) { | |
| 6292 | if ((err = os_fetch_file_path(rel_full_path, source_code, true))) { | |
| 6264 | 6293 | zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err)); |
| 6265 | 6294 | } |
| 6266 | 6295 | |
| ... | ... | @@ -6325,7 +6354,7 @@ static void gen_global_asm(CodeGen *g) { |
| 6325 | 6354 | int err; |
| 6326 | 6355 | for (size_t i = 0; i < g->assembly_files.length; i += 1) { |
| 6327 | 6356 | Buf *asm_file = g->assembly_files.at(i); |
| 6328 | if ((err = os_fetch_file_path(asm_file, &contents))) { | |
| 6357 | if ((err = os_fetch_file_path(asm_file, &contents, false))) { | |
| 6329 | 6358 | zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); |
| 6330 | 6359 | } |
| 6331 | 6360 | buf_append_buf(&g->global_asm, &contents); |
| ... | ... | @@ -6507,6 +6536,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf |
| 6507 | 6536 | } |
| 6508 | 6537 | } |
| 6509 | 6538 | case TypeTableEntryIdStruct: |
| 6539 | case TypeTableEntryIdOpaque: | |
| 6510 | 6540 | { |
| 6511 | 6541 | buf_init_from_str(out_buf, "struct "); |
| 6512 | 6542 | buf_append_buf(out_buf, &type_entry->name); |
| ... | ... | @@ -6524,11 +6554,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf |
| 6524 | 6554 | buf_append_buf(out_buf, &type_entry->name); |
| 6525 | 6555 | return; |
| 6526 | 6556 | } |
| 6527 | case TypeTableEntryIdOpaque: | |
| 6528 | { | |
| 6529 | buf_init_from_buf(out_buf, &type_entry->name); | |
| 6530 | return; | |
| 6531 | } | |
| 6532 | 6557 | case TypeTableEntryIdArray: |
| 6533 | 6558 | { |
| 6534 | 6559 | 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+234-70| ... | ... | @@ -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,14 @@ 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 | ||
| 716 | 728 | template<typename T> |
| 717 | 729 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 718 | 730 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1461,6 +1473,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode |
| 1461 | 1473 | return &instruction->base; |
| 1462 | 1474 | } |
| 1463 | 1475 | |
| 1476 | static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1477 | IrInstruction *payload_type) | |
| 1478 | { | |
| 1479 | IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node); | |
| 1480 | instruction->payload_type = payload_type; | |
| 1481 | ||
| 1482 | if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block); | |
| 1483 | ||
| 1484 | return &instruction->base; | |
| 1485 | } | |
| 1486 | ||
| 1464 | 1487 | static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1465 | 1488 | IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value) |
| 1466 | 1489 | { |
| ... | ... | @@ -2141,12 +2164,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc |
| 2141 | 2164 | } |
| 2142 | 2165 | |
| 2143 | 2166 | 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) | |
| 2167 | IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, | |
| 2168 | IrInstruction *async_allocator_type_value, bool is_var_args) | |
| 2145 | 2169 | { |
| 2146 | 2170 | IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node); |
| 2147 | 2171 | instruction->param_types = param_types; |
| 2148 | 2172 | instruction->align_value = align_value; |
| 2149 | 2173 | instruction->return_type = return_type; |
| 2174 | instruction->async_allocator_type_value = async_allocator_type_value; | |
| 2150 | 2175 | instruction->is_var_args = is_var_args; |
| 2151 | 2176 | |
| 2152 | 2177 | assert(source_node->type == NodeTypeFnProto); |
| ... | ... | @@ -2156,6 +2181,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s |
| 2156 | 2181 | if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block); |
| 2157 | 2182 | } |
| 2158 | 2183 | if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); |
| 2184 | if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block); | |
| 2159 | 2185 | ir_ref_instruction(return_type, irb->current_basic_block); |
| 2160 | 2186 | |
| 2161 | 2187 | return &instruction->base; |
| ... | ... | @@ -2675,6 +2701,22 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A |
| 2675 | 2701 | return &instruction->base; |
| 2676 | 2702 | } |
| 2677 | 2703 | |
| 2704 | static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) { | |
| 2705 | IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node); | |
| 2706 | return &instruction->base; | |
| 2707 | } | |
| 2708 | ||
| 2709 | static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2710 | IrInstruction *value) | |
| 2711 | { | |
| 2712 | IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node); | |
| 2713 | instruction->value = value; | |
| 2714 | ||
| 2715 | ir_ref_instruction(value, irb->current_basic_block); | |
| 2716 | ||
| 2717 | return &instruction->base; | |
| 2718 | } | |
| 2719 | ||
| 2678 | 2720 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2679 | 2721 | results[ReturnKindUnconditional] = 0; |
| 2680 | 2722 | results[ReturnKindError] = 0; |
| ... | ... | @@ -2747,16 +2789,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { |
| 2747 | 2789 | return nullptr; |
| 2748 | 2790 | } |
| 2749 | 2791 | |
| 2792 | static bool exec_is_async(IrExecutable *exec) { | |
| 2793 | FnTableEntry *fn_entry = exec_fn_entry(exec); | |
| 2794 | return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 2795 | } | |
| 2796 | ||
| 2750 | 2797 | static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value, |
| 2751 | 2798 | bool is_generated_code) |
| 2752 | 2799 | { |
| 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; | |
| 2800 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value)); | |
| 2801 | ||
| 2802 | bool is_async = exec_is_async(irb->exec); | |
| 2755 | 2803 | 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 | 2804 | IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value); |
| 2761 | 2805 | return_inst->is_gen = is_generated_code; |
| 2762 | 2806 | return return_inst; |
| ... | ... | @@ -2778,21 +2822,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode |
| 2778 | 2822 | // the above blocks are rendered by ir_gen after the rest of codegen |
| 2779 | 2823 | } |
| 2780 | 2824 | |
| 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 | //} | |
| 2825 | static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) { | |
| 2826 | if (!g->have_err_ret_tracing) | |
| 2827 | return false; | |
| 2828 | FnTableEntry *fn_entry = exec_fn_entry(exec); | |
| 2829 | if (fn_entry == nullptr) | |
| 2830 | return false; | |
| 2831 | if (exec->is_inline) | |
| 2832 | return false; | |
| 2833 | return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type); | |
| 2834 | } | |
| 2835 | ||
| 2836 | static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 2837 | if (!exec_have_err_ret_trace(irb->codegen, irb->exec)) | |
| 2838 | return; | |
| 2839 | ||
| 2840 | bool is_async = exec_is_async(irb->exec); | |
| 2841 | ||
| 2842 | if (is_async) { | |
| 2843 | //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr); | |
| 2844 | //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node); | |
| 2845 | //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr); | |
| 2846 | //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize); | |
| 2847 | return; | |
| 2848 | } | |
| 2849 | ||
| 2850 | ir_build_save_err_ret_addr(irb, scope, node); | |
| 2851 | } | |
| 2796 | 2852 | |
| 2797 | 2853 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { |
| 2798 | 2854 | assert(node->type == NodeTypeReturnExpr); |
| ... | ... | @@ -2853,7 +2909,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2853 | 2909 | if (have_err_defers) { |
| 2854 | 2910 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2855 | 2911 | } |
| 2856 | //ir_gen_save_err_ret_addr(irb, scope, node, is_async); | |
| 2912 | ir_gen_save_err_ret_addr(irb, scope, node); | |
| 2857 | 2913 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 2858 | 2914 | |
| 2859 | 2915 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| ... | ... | @@ -2892,6 +2948,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2892 | 2948 | ir_set_cursor_at_end_and_append_block(irb, return_block); |
| 2893 | 2949 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2894 | 2950 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); |
| 2951 | ir_gen_save_err_ret_addr(irb, scope, node); | |
| 2895 | 2952 | ir_gen_async_return(irb, scope, node, err_val, false); |
| 2896 | 2953 | |
| 2897 | 2954 | ir_set_cursor_at_end_and_append_block(irb, continue_block); |
| ... | ... | @@ -5032,6 +5089,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n |
| 5032 | 5089 | } |
| 5033 | 5090 | } |
| 5034 | 5091 | |
| 5092 | static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 5093 | assert(node->type == NodeTypePromiseType); | |
| 5094 | ||
| 5095 | AstNode *payload_type_node = node->data.promise_type.payload_type; | |
| 5096 | IrInstruction *payload_type_value = nullptr; | |
| 5097 | ||
| 5098 | if (payload_type_node != nullptr) { | |
| 5099 | payload_type_value = ir_gen_node(irb, payload_type_node, scope); | |
| 5100 | if (payload_type_value == irb->codegen->invalid_instruction) | |
| 5101 | return payload_type_value; | |
| 5102 | ||
| 5103 | } | |
| 5104 | ||
| 5105 | return ir_build_promise_type(irb, scope, node, payload_type_value); | |
| 5106 | } | |
| 5107 | ||
| 5035 | 5108 | static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5036 | 5109 | assert(node->type == NodeTypeUndefinedLiteral); |
| 5037 | 5110 | return ir_build_const_undefined(irb, scope, node); |
| ... | ... | @@ -5989,7 +6062,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5989 | 6062 | return_type = nullptr; |
| 5990 | 6063 | } |
| 5991 | 6064 | |
| 5992 | return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args); | |
| 6065 | IrInstruction *async_allocator_type_value = nullptr; | |
| 6066 | if (node->data.fn_proto.async_allocator_type != nullptr) { | |
| 6067 | async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope); | |
| 6068 | if (async_allocator_type_value == irb->codegen->invalid_instruction) | |
| 6069 | return irb->codegen->invalid_instruction; | |
| 6070 | } | |
| 6071 | ||
| 6072 | return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, | |
| 6073 | async_allocator_type_value, is_var_args); | |
| 5993 | 6074 | } |
| 5994 | 6075 | |
| 5995 | 6076 | static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| ... | ... | @@ -6232,6 +6313,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6232 | 6313 | return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); |
| 6233 | 6314 | case NodeTypeArrayType: |
| 6234 | 6315 | return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval); |
| 6316 | case NodeTypePromiseType: | |
| 6317 | return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval); | |
| 6235 | 6318 | case NodeTypeStringLiteral: |
| 6236 | 6319 | return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval); |
| 6237 | 6320 | case NodeTypeUndefinedLiteral: |
| ... | ... | @@ -6329,58 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6329 | 6412 | VariableTableEntry *coro_size_var; |
| 6330 | 6413 | if (is_async) { |
| 6331 | 6414 | // 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); | |
| 6415 | Scope *coro_scope = create_coro_prelude_scope(node, scope); | |
| 6416 | const_bool_false = ir_build_const_bool(irb, coro_scope, node, false); | |
| 6417 | VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6334 | 6418 | |
| 6335 | 6419 | 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); | |
| 6420 | IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type); | |
| 6421 | ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init); | |
| 6422 | IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false); | |
| 6339 | 6423 | |
| 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, | |
| 6424 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6425 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); | |
| 6426 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, | |
| 6343 | 6427 | 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, | |
| 6428 | ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); | |
| 6429 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, | |
| 6346 | 6430 | await_handle_var, false, false); |
| 6347 | 6431 | |
| 6348 | u8_ptr_type = ir_build_const_type(irb, scope, node, | |
| 6432 | u8_ptr_type = ir_build_const_type(irb, coro_scope, node, | |
| 6349 | 6433 | 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, | |
| 6434 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); | |
| 6435 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); | |
| 6436 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6437 | IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); | |
| 6438 | ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); | |
| 6439 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, | |
| 6356 | 6440 | 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); | |
| 6441 | irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); | |
| 6442 | ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); | |
| 6359 | 6443 | 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); | |
| 6444 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); | |
| 6445 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); | |
| 6446 | IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size); | |
| 6447 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); | |
| 6448 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError"); | |
| 6449 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk"); | |
| 6450 | ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); | |
| 6367 | 6451 | |
| 6368 | 6452 | 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); | |
| 6453 | // we can return undefined here, because the caller passes a pointer to the error struct field | |
| 6454 | // in the error union result, and we populate it in case of allocation failure. | |
| 6455 | IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); | |
| 6456 | ir_build_return(irb, coro_scope, node, undef); | |
| 6371 | 6457 | |
| 6372 | 6458 | 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); | |
| 6459 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); | |
| 6460 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); | |
| 6375 | 6461 | |
| 6376 | 6462 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6377 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, | |
| 6463 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, | |
| 6378 | 6464 | awaiter_handle_field_name); |
| 6379 | 6465 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6380 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); | |
| 6466 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name); | |
| 6381 | 6467 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6382 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); | |
| 6383 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); | |
| 6468 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name); | |
| 6469 | ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); | |
| 6384 | 6470 | |
| 6385 | 6471 | |
| 6386 | 6472 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
| ... | ... | @@ -6395,6 +6481,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6395 | 6481 | return false; |
| 6396 | 6482 | |
| 6397 | 6483 | if (!instr_is_unreachable(result)) { |
| 6484 | // no need for save_err_ret_addr because this cannot return error | |
| 6398 | 6485 | ir_gen_async_return(irb, scope, result->source_node, result, true); |
| 6399 | 6486 | } |
| 6400 | 6487 | |
| ... | ... | @@ -10074,13 +10161,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 10074 | 10161 | return result; |
| 10075 | 10162 | } |
| 10076 | 10163 | |
| 10164 | static TypeTableEntry *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira, | |
| 10165 | IrInstructionAddImplicitReturnType *instruction) | |
| 10166 | { | |
| 10167 | IrInstruction *value = instruction->value->other; | |
| 10168 | if (type_is_invalid(value->value.type)) | |
| 10169 | return ir_unreach_error(ira); | |
| 10170 | ||
| 10171 | ira->src_implicit_return_type_list.append(value); | |
| 10172 | ||
| 10173 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 10174 | out_val->type = ira->codegen->builtin_types.entry_void; | |
| 10175 | return out_val->type; | |
| 10176 | } | |
| 10177 | ||
| 10077 | 10178 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, |
| 10078 | 10179 | IrInstructionReturn *return_instruction) |
| 10079 | 10180 | { |
| 10080 | 10181 | IrInstruction *value = return_instruction->value->other; |
| 10081 | 10182 | if (type_is_invalid(value->value.type)) |
| 10082 | 10183 | return ir_unreach_error(ira); |
| 10083 | ira->implicit_return_type_list.append(value); | |
| 10084 | 10184 | |
| 10085 | 10185 | IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); |
| 10086 | 10186 | if (casted_value == ira->codegen->invalid_instruction) |
| ... | ... | @@ -10958,6 +11058,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * |
| 10958 | 11058 | result_type = get_array_type(ira->codegen, child_type, new_len); |
| 10959 | 11059 | |
| 10960 | 11060 | out_array_val = out_val; |
| 11061 | } else if (is_slice(op1_type) || is_slice(op2_type)) { | |
| 11062 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, child_type, true); | |
| 11063 | result_type = get_slice_type(ira->codegen, ptr_type); | |
| 11064 | out_array_val = create_const_vals(1); | |
| 11065 | out_array_val->special = ConstValSpecialStatic; | |
| 11066 | out_array_val->type = get_array_type(ira->codegen, child_type, new_len); | |
| 11067 | ||
| 11068 | out_val->data.x_struct.fields = create_const_vals(2); | |
| 11069 | ||
| 11070 | out_val->data.x_struct.fields[slice_ptr_index].type = ptr_type; | |
| 11071 | out_val->data.x_struct.fields[slice_ptr_index].special = ConstValSpecialStatic; | |
| 11072 | out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.special = ConstPtrSpecialBaseArray; | |
| 11073 | out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.data.base_array.array_val = out_array_val; | |
| 11074 | out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.data.base_array.elem_index = 0; | |
| 11075 | ||
| 11076 | out_val->data.x_struct.fields[slice_len_index].type = ira->codegen->builtin_types.entry_usize; | |
| 11077 | out_val->data.x_struct.fields[slice_len_index].special = ConstValSpecialStatic; | |
| 11078 | bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index].data.x_bigint, new_len); | |
| 10961 | 11079 | } else { |
| 10962 | 11080 | new_len += 1; // null byte |
| 10963 | 11081 | |
| ... | ... | @@ -11453,13 +11571,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 11453 | 11571 | return ira->codegen->builtin_types.entry_void; |
| 11454 | 11572 | } |
| 11455 | 11573 | |
| 11574 | static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { | |
| 11575 | FnTableEntry *fn_entry = exec_fn_entry(exec); | |
| 11576 | return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing; | |
| 11577 | } | |
| 11578 | ||
| 11456 | 11579 | static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 11457 | 11580 | IrInstructionErrorReturnTrace *instruction) |
| 11458 | 11581 | { |
| 11459 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 11460 | 11582 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); |
| 11461 | 11583 | 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) { | |
| 11584 | if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { | |
| 11463 | 11585 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 11464 | 11586 | out_val->data.x_maybe = nullptr; |
| 11465 | 11587 | return nullable_type; |
| ... | ... | @@ -13999,6 +14121,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 13999 | 14121 | zig_unreachable(); |
| 14000 | 14122 | } |
| 14001 | 14123 | |
| 14124 | static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) { | |
| 14125 | TypeTableEntry *promise_type; | |
| 14126 | ||
| 14127 | if (instruction->payload_type == nullptr) { | |
| 14128 | promise_type = ira->codegen->builtin_types.entry_promise; | |
| 14129 | } else { | |
| 14130 | TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload_type->other); | |
| 14131 | if (type_is_invalid(payload_type)) | |
| 14132 | return ira->codegen->builtin_types.entry_invalid; | |
| 14133 | ||
| 14134 | promise_type = get_promise_type(ira->codegen, payload_type); | |
| 14135 | } | |
| 14136 | ||
| 14137 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14138 | out_val->data.x_type = promise_type; | |
| 14139 | return ira->codegen->builtin_types.entry_type; | |
| 14140 | } | |
| 14141 | ||
| 14002 | 14142 | static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 14003 | 14143 | IrInstructionSizeOf *size_of_instruction) |
| 14004 | 14144 | { |
| ... | ... | @@ -14569,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi |
| 14569 | 14709 | return ira->codegen->builtin_types.entry_namespace; |
| 14570 | 14710 | } |
| 14571 | 14711 | |
| 14572 | if ((err = os_fetch_file_path(abs_full_path, import_code))) { | |
| 14712 | if ((err = os_fetch_file_path(abs_full_path, import_code, true))) { | |
| 14573 | 14713 | if (err == ErrorFileNotFound) { |
| 14574 | 14714 | ir_add_error_node(ira, source_node, |
| 14575 | 14715 | buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); |
| ... | ... | @@ -15430,7 +15570,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr |
| 15430 | 15570 | // load from file system into const expr |
| 15431 | 15571 | Buf *file_contents = buf_alloc(); |
| 15432 | 15572 | int err; |
| 15433 | if ((err = os_fetch_file_path(&file_path, file_contents))) { | |
| 15573 | if ((err = os_fetch_file_path(&file_path, file_contents, false))) { | |
| 15434 | 15574 | if (err == ErrorFileNotFound) { |
| 15435 | 15575 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); |
| 15436 | 15576 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -16561,6 +16701,13 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc |
| 16561 | 16701 | if (type_is_invalid(fn_type_id.return_type)) |
| 16562 | 16702 | return ira->codegen->builtin_types.entry_invalid; |
| 16563 | 16703 | |
| 16704 | if (fn_type_id.cc == CallingConventionAsync) { | |
| 16705 | IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other; | |
| 16706 | fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value); | |
| 16707 | if (type_is_invalid(fn_type_id.async_allocator_type)) | |
| 16708 | return ira->codegen->builtin_types.entry_invalid; | |
| 16709 | } | |
| 16710 | ||
| 16564 | 16711 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 16565 | 16712 | out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id); |
| 16566 | 16713 | return ira->codegen->builtin_types.entry_type; |
| ... | ... | @@ -16789,18 +16936,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira, |
| 16789 | 16936 | static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) { |
| 16790 | 16937 | IrInstruction *msg = instruction->msg->other; |
| 16791 | 16938 | if (type_is_invalid(msg->value.type)) |
| 16792 | return ira->codegen->builtin_types.entry_invalid; | |
| 16939 | return ir_unreach_error(ira); | |
| 16793 | 16940 | |
| 16794 | 16941 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) { |
| 16795 | 16942 | ir_add_error(ira, &instruction->base, buf_sprintf("encountered @panic at compile-time")); |
| 16796 | return ira->codegen->builtin_types.entry_invalid; | |
| 16943 | return ir_unreach_error(ira); | |
| 16797 | 16944 | } |
| 16798 | 16945 | |
| 16799 | 16946 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); |
| 16800 | 16947 | TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 16801 | 16948 | IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type); |
| 16802 | 16949 | if (type_is_invalid(casted_msg->value.type)) |
| 16803 | return ira->codegen->builtin_types.entry_invalid; | |
| 16950 | return ir_unreach_error(ira); | |
| 16804 | 16951 | |
| 16805 | 16952 | IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope, |
| 16806 | 16953 | instruction->base.source_node, casted_msg); |
| ... | ... | @@ -17757,6 +17904,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, |
| 17757 | 17904 | return out_val->type; |
| 17758 | 17905 | } |
| 17759 | 17906 | |
| 17907 | static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) { | |
| 17908 | IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope, | |
| 17909 | instruction->base.source_node); | |
| 17910 | ir_link_new_instruction(result, &instruction->base); | |
| 17911 | result->value.type = ira->codegen->builtin_types.entry_void; | |
| 17912 | return result->value.type; | |
| 17913 | } | |
| 17914 | ||
| 17760 | 17915 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 17761 | 17916 | switch (instruction->id) { |
| 17762 | 17917 | case IrInstructionIdInvalid: |
| ... | ... | @@ -17822,6 +17977,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17822 | 17977 | return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction); |
| 17823 | 17978 | case IrInstructionIdArrayType: |
| 17824 | 17979 | return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction); |
| 17980 | case IrInstructionIdPromiseType: | |
| 17981 | return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction); | |
| 17825 | 17982 | case IrInstructionIdSizeOf: |
| 17826 | 17983 | return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); |
| 17827 | 17984 | case IrInstructionIdTestNonNull: |
| ... | ... | @@ -17994,6 +18151,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17994 | 18151 | return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); |
| 17995 | 18152 | case IrInstructionIdAwaitBookkeeping: |
| 17996 | 18153 | return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction); |
| 18154 | case IrInstructionIdSaveErrRetAddr: | |
| 18155 | return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); | |
| 18156 | case IrInstructionIdAddImplicitReturnType: | |
| 18157 | return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction); | |
| 17997 | 18158 | } |
| 17998 | 18159 | zig_unreachable(); |
| 17999 | 18160 | } |
| ... | ... | @@ -18067,11 +18228,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl |
| 18067 | 18228 | |
| 18068 | 18229 | if (new_exec->invalid) { |
| 18069 | 18230 | return ira->codegen->builtin_types.entry_invalid; |
| 18070 | } else if (ira->implicit_return_type_list.length == 0) { | |
| 18231 | } else if (ira->src_implicit_return_type_list.length == 0) { | |
| 18071 | 18232 | return codegen->builtin_types.entry_unreachable; |
| 18072 | 18233 | } 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); | |
| 18234 | return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items, | |
| 18235 | ira->src_implicit_return_type_list.length); | |
| 18075 | 18236 | } |
| 18076 | 18237 | } |
| 18077 | 18238 | |
| ... | ... | @@ -18119,6 +18280,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18119 | 18280 | case IrInstructionIdCoroSave: |
| 18120 | 18281 | case IrInstructionIdCoroAllocHelper: |
| 18121 | 18282 | case IrInstructionIdAwaitBookkeeping: |
| 18283 | case IrInstructionIdSaveErrRetAddr: | |
| 18284 | case IrInstructionIdAddImplicitReturnType: | |
| 18122 | 18285 | return true; |
| 18123 | 18286 | |
| 18124 | 18287 | case IrInstructionIdPhi: |
| ... | ... | @@ -18141,6 +18304,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18141 | 18304 | case IrInstructionIdStructFieldPtr: |
| 18142 | 18305 | case IrInstructionIdUnionFieldPtr: |
| 18143 | 18306 | case IrInstructionIdArrayType: |
| 18307 | case IrInstructionIdPromiseType: | |
| 18144 | 18308 | case IrInstructionIdSliceType: |
| 18145 | 18309 | case IrInstructionIdSizeOf: |
| 18146 | 18310 | case IrInstructionIdTestNonNull: |
src/ir_print.cpp+29-2| ... | ... | @@ -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); |
| ... | ... | @@ -1161,6 +1169,16 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi |
| 1161 | 1169 | fprintf(irp->f, ")"); |
| 1162 | 1170 | } |
| 1163 | 1171 | |
| 1172 | static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) { | |
| 1173 | fprintf(irp->f, "@saveErrRetAddr()"); | |
| 1174 | } | |
| 1175 | ||
| 1176 | static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImplicitReturnType *instruction) { | |
| 1177 | fprintf(irp->f, "@addImplicitReturnType("); | |
| 1178 | ir_print_other_instruction(irp, instruction->value); | |
| 1179 | fprintf(irp->f, ")"); | |
| 1180 | } | |
| 1181 | ||
| 1164 | 1182 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1165 | 1183 | ir_print_prefix(irp, instruction); |
| 1166 | 1184 | switch (instruction->id) { |
| ... | ... | @@ -1253,6 +1271,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1253 | 1271 | case IrInstructionIdArrayType: |
| 1254 | 1272 | ir_print_array_type(irp, (IrInstructionArrayType *)instruction); |
| 1255 | 1273 | break; |
| 1274 | case IrInstructionIdPromiseType: | |
| 1275 | ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction); | |
| 1276 | break; | |
| 1256 | 1277 | case IrInstructionIdSliceType: |
| 1257 | 1278 | ir_print_slice_type(irp, (IrInstructionSliceType *)instruction); |
| 1258 | 1279 | break; |
| ... | ... | @@ -1532,6 +1553,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1532 | 1553 | case IrInstructionIdAwaitBookkeeping: |
| 1533 | 1554 | ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction); |
| 1534 | 1555 | break; |
| 1556 | case IrInstructionIdSaveErrRetAddr: | |
| 1557 | ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction); | |
| 1558 | break; | |
| 1559 | case IrInstructionIdAddImplicitReturnType: | |
| 1560 | ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction); | |
| 1561 | break; | |
| 1535 | 1562 | } |
| 1536 | 1563 | fprintf(irp->f, "\n"); |
| 1537 | 1564 | } |
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+82-58| ... | ... | @@ -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,6 +964,66 @@ 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 | 1028 | SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) |
| 960 | 1029 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| ... | ... | @@ -979,6 +1048,11 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 979 | 1048 | } |
| 980 | 1049 | |
| 981 | 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 | } | |
| 982 | 1056 | AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true); |
| 983 | 1057 | if (node->type != NodeTypeFnCallExpr) { |
| 984 | 1058 | ast_error(pc, fncall_token, "expected function call, found '%s'", token_name(fncall_token->id)); |
| ... | ... | @@ -2434,9 +2508,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2434 | 2508 | } else if (first_token->id == TokenIdKeywordAsync) { |
| 2435 | 2509 | *token_index += 1; |
| 2436 | 2510 | Token *next_token = &pc->tokens->at(*token_index); |
| 2437 | if (next_token->id == TokenIdLParen) { | |
| 2511 | if (next_token->id == TokenIdCmpLessThan) { | |
| 2512 | *token_index += 1; | |
| 2438 | 2513 | async_allocator_type_node = ast_parse_type_expr(pc, token_index, true); |
| 2439 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2514 | ast_eat_token(pc, token_index, TokenIdCmpGreaterThan); | |
| 2440 | 2515 | } |
| 2441 | 2516 | fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); |
| 2442 | 2517 | cc = CallingConventionAsync; |
| ... | ... | @@ -2470,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2470 | 2545 | return nullptr; |
| 2471 | 2546 | } |
| 2472 | 2547 | |
| 2473 | AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); | |
| 2474 | node->data.fn_proto.visib_mod = visib_mod; | |
| 2475 | node->data.fn_proto.cc = cc; | |
| 2476 | node->data.fn_proto.is_extern = is_extern; | |
| 2477 | node->data.fn_proto.async_allocator_type = async_allocator_type_node; | |
| 2478 | ||
| 2479 | Token *fn_name = &pc->tokens->at(*token_index); | |
| 2480 | ||
| 2481 | if (fn_name->id == TokenIdSymbol) { | |
| 2482 | *token_index += 1; | |
| 2483 | node->data.fn_proto.name = token_buf(fn_name); | |
| 2484 | } else { | |
| 2485 | node->data.fn_proto.name = nullptr; | |
| 2486 | } | |
| 2487 | ||
| 2488 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | |
| 2489 | ||
| 2490 | Token *next_token = &pc->tokens->at(*token_index); | |
| 2491 | if (next_token->id == TokenIdKeywordAlign) { | |
| 2492 | *token_index += 1; | |
| 2493 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 2494 | ||
| 2495 | node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true); | |
| 2496 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2497 | next_token = &pc->tokens->at(*token_index); | |
| 2498 | } | |
| 2499 | if (next_token->id == TokenIdKeywordSection) { | |
| 2500 | *token_index += 1; | |
| 2501 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 2502 | ||
| 2503 | node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true); | |
| 2504 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2505 | next_token = &pc->tokens->at(*token_index); | |
| 2506 | } | |
| 2507 | if (next_token->id == TokenIdKeywordVar) { | |
| 2508 | node->data.fn_proto.return_var_token = next_token; | |
| 2509 | *token_index += 1; | |
| 2510 | next_token = &pc->tokens->at(*token_index); | |
| 2511 | } else { | |
| 2512 | if (next_token->id == TokenIdKeywordError) { | |
| 2513 | Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1); | |
| 2514 | if (maybe_lbrace_tok->id == TokenIdLBrace) { | |
| 2515 | *token_index += 1; | |
| 2516 | node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token); | |
| 2517 | return node; | |
| 2518 | } | |
| 2519 | } else if (next_token->id == TokenIdBang) { | |
| 2520 | *token_index += 1; | |
| 2521 | node->data.fn_proto.auto_err_set = true; | |
| 2522 | next_token = &pc->tokens->at(*token_index); | |
| 2523 | } | |
| 2524 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true); | |
| 2525 | } | |
| 2526 | ||
| 2527 | return node; | |
| 2548 | return ast_parse_fn_proto_partial(pc, token_index, fn_token, async_allocator_type_node, cc, is_extern, visib_mod); | |
| 2528 | 2549 | } |
| 2529 | 2550 | |
| 2530 | 2551 | /* |
| ... | ... | @@ -3069,6 +3090,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3069 | 3090 | visit_field(&node->data.array_type.child_type, visit, context); |
| 3070 | 3091 | visit_field(&node->data.array_type.align_expr, visit, context); |
| 3071 | 3092 | break; |
| 3093 | case NodeTypePromiseType: | |
| 3094 | visit_field(&node->data.promise_type.payload_type, visit, context); | |
| 3095 | break; | |
| 3072 | 3096 | case NodeTypeErrorType: |
| 3073 | 3097 | // none |
| 3074 | 3098 | 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| ... | ... | @@ -862,6 +862,10 @@ Buf *target_dynamic_linker(ZigTarget *target) { |
| 862 | 862 | env == ZigLLVM_GNUX32) |
| 863 | 863 | { |
| 864 | 864 | return buf_create_from_str("/libx32/ld-linux-x32.so.2"); |
| 865 | } else if (arch == ZigLLVM_x86_64 && | |
| 866 | (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF)) | |
| 867 | { | |
| 868 | return buf_create_from_str("/lib/ld-musl-x86_64.so.1"); | |
| 865 | 869 | } else { |
| 866 | 870 | return buf_create_from_str("/lib64/ld-linux-x86-64.so.2"); |
| 867 | 871 | } |
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/c/darwin.zig+10| ... | ... | @@ -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,12 @@ 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 | }; |
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/index.zig+2-2| ... | ... | @@ -26,7 +26,7 @@ pub const math = @import("math/index.zig"); |
| 26 | 26 | pub const mem = @import("mem.zig"); |
| 27 | 27 | pub const net = @import("net.zig"); |
| 28 | 28 | pub const os = @import("os/index.zig"); |
| 29 | pub const rand = @import("rand.zig"); | |
| 29 | pub const rand = @import("rand/index.zig"); | |
| 30 | 30 | pub const sort = @import("sort.zig"); |
| 31 | 31 | pub const unicode = @import("unicode.zig"); |
| 32 | 32 | pub const zig = @import("zig/index.zig"); |
| ... | ... | @@ -58,7 +58,7 @@ test "std" { |
| 58 | 58 | _ = @import("heap.zig"); |
| 59 | 59 | _ = @import("net.zig"); |
| 60 | 60 | _ = @import("os/index.zig"); |
| 61 | _ = @import("rand.zig"); | |
| 61 | _ = @import("rand/index.zig"); | |
| 62 | 62 | _ = @import("sort.zig"); |
| 63 | 63 | _ = @import("unicode.zig"); |
| 64 | 64 | _ = @import("zig/index.zig"); |
std/io.zig+21-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,20 @@ 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 | '\n' => return index, | |
| 490 | else => { | |
| 491 | if (index == buf.len) return error.InputTooLong; | |
| 492 | buf[index] = byte; | |
| 493 | index += 1; | |
| 494 | }, | |
| 495 | } | |
| 496 | } | |
| 497 | } |
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/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/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+32| ... | ... | @@ -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,7 @@ 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; | |
| 271 | 303 | |
| 272 | 304 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 273 | 305 | 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+99-13| ... | ... | @@ -1050,15 +1050,16 @@ const DeleteTreeError = error { |
| 1050 | 1050 | }; |
| 1051 | 1051 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void { |
| 1052 | 1052 | start_over: while (true) { |
| 1053 | var got_access_denied = false; | |
| 1053 | 1054 | // First, try deleting the item as a file. This way we don't follow sym links. |
| 1054 | 1055 | if (deleteFile(allocator, full_path)) { |
| 1055 | 1056 | return; |
| 1056 | 1057 | } else |err| switch (err) { |
| 1057 | 1058 | error.FileNotFound => return, |
| 1058 | 1059 | error.IsDir => {}, |
| 1060 | error.AccessDenied => got_access_denied = true, | |
| 1059 | 1061 | |
| 1060 | 1062 | error.OutOfMemory, |
| 1061 | error.AccessDenied, | |
| 1062 | 1063 | error.SymLinkLoop, |
| 1063 | 1064 | error.NameTooLong, |
| 1064 | 1065 | error.SystemResources, |
| ... | ... | @@ -1071,7 +1072,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError! |
| 1071 | 1072 | } |
| 1072 | 1073 | { |
| 1073 | 1074 | var dir = Dir.open(allocator, full_path) catch |err| switch (err) { |
| 1074 | error.NotDir => continue :start_over, | |
| 1075 | error.NotDir => { | |
| 1076 | if (got_access_denied) { | |
| 1077 | return error.AccessDenied; | |
| 1078 | } | |
| 1079 | continue :start_over; | |
| 1080 | }, | |
| 1075 | 1081 | |
| 1076 | 1082 | error.OutOfMemory, |
| 1077 | 1083 | error.AccessDenied, |
| ... | ... | @@ -1109,18 +1115,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError! |
| 1109 | 1115 | } |
| 1110 | 1116 | |
| 1111 | 1117 | pub const Dir = struct { |
| 1112 | // See man getdents | |
| 1113 | 1118 | fd: i32, |
| 1119 | darwin_seek: darwin_seek_t, | |
| 1114 | 1120 | allocator: &Allocator, |
| 1115 | 1121 | buf: []u8, |
| 1116 | 1122 | index: usize, |
| 1117 | 1123 | end_index: usize, |
| 1118 | 1124 | |
| 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 | |
| 1125 | const darwin_seek_t = switch (builtin.os) { | |
| 1126 | Os.macosx, Os.ios => i64, | |
| 1127 | else => void, | |
| 1124 | 1128 | }; |
| 1125 | 1129 | |
| 1126 | 1130 | pub const Entry = struct { |
| ... | ... | @@ -1135,15 +1139,26 @@ pub const Dir = struct { |
| 1135 | 1139 | SymLink, |
| 1136 | 1140 | File, |
| 1137 | 1141 | UnixDomainSocket, |
| 1142 | Whiteout, | |
| 1138 | 1143 | Unknown, |
| 1139 | 1144 | }; |
| 1140 | 1145 | }; |
| 1141 | 1146 | |
| 1142 | 1147 | 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); | |
| 1148 | const fd = switch (builtin.os) { | |
| 1149 | Os.windows => @compileError("TODO support Dir.open for windows"), | |
| 1150 | Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0), | |
| 1151 | Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0), | |
| 1152 | else => @compileError("Dir.open is not supported for this platform"), | |
| 1153 | }; | |
| 1154 | const darwin_seek_init = switch (builtin.os) { | |
| 1155 | Os.macosx, Os.ios => 0, | |
| 1156 | else => {}, | |
| 1157 | }; | |
| 1144 | 1158 | return Dir { |
| 1145 | 1159 | .allocator = allocator, |
| 1146 | 1160 | .fd = fd, |
| 1161 | .darwin_seek = darwin_seek_init, | |
| 1147 | 1162 | .index = 0, |
| 1148 | 1163 | .end_index = 0, |
| 1149 | 1164 | .buf = []u8{}, |
| ... | ... | @@ -1158,6 +1173,76 @@ pub const Dir = struct { |
| 1158 | 1173 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 1159 | 1174 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. |
| 1160 | 1175 | pub fn next(self: &Dir) !?Entry { |
| 1176 | switch (builtin.os) { | |
| 1177 | Os.linux => return self.nextLinux(), | |
| 1178 | Os.macosx, Os.ios => return self.nextDarwin(), | |
| 1179 | Os.windows => return self.nextWindows(), | |
| 1180 | else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)), | |
| 1181 | } | |
| 1182 | } | |
| 1183 | ||
| 1184 | fn nextDarwin(self: &Dir) !?Entry { | |
| 1185 | start_over: while (true) { | |
| 1186 | if (self.index >= self.end_index) { | |
| 1187 | if (self.buf.len == 0) { | |
| 1188 | self.buf = try self.allocator.alloc(u8, page_size); | |
| 1189 | } | |
| 1190 | ||
| 1191 | while (true) { | |
| 1192 | const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len, | |
| 1193 | &self.darwin_seek); | |
| 1194 | const err = posix.getErrno(result); | |
| 1195 | if (err > 0) { | |
| 1196 | switch (err) { | |
| 1197 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, | |
| 1198 | posix.EINVAL => { | |
| 1199 | self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2); | |
| 1200 | continue; | |
| 1201 | }, | |
| 1202 | else => return unexpectedErrorPosix(err), | |
| 1203 | } | |
| 1204 | } | |
| 1205 | if (result == 0) | |
| 1206 | return null; | |
| 1207 | self.index = 0; | |
| 1208 | self.end_index = result; | |
| 1209 | break; | |
| 1210 | } | |
| 1211 | } | |
| 1212 | const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]); | |
| 1213 | const next_index = self.index + darwin_entry.d_reclen; | |
| 1214 | self.index = next_index; | |
| 1215 | ||
| 1216 | const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen]; | |
| 1217 | ||
| 1218 | // skip . and .. entries | |
| 1219 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { | |
| 1220 | continue :start_over; | |
| 1221 | } | |
| 1222 | ||
| 1223 | const entry_kind = switch (darwin_entry.d_type) { | |
| 1224 | posix.DT_BLK => Entry.Kind.BlockDevice, | |
| 1225 | posix.DT_CHR => Entry.Kind.CharacterDevice, | |
| 1226 | posix.DT_DIR => Entry.Kind.Directory, | |
| 1227 | posix.DT_FIFO => Entry.Kind.NamedPipe, | |
| 1228 | posix.DT_LNK => Entry.Kind.SymLink, | |
| 1229 | posix.DT_REG => Entry.Kind.File, | |
| 1230 | posix.DT_SOCK => Entry.Kind.UnixDomainSocket, | |
| 1231 | posix.DT_WHT => Entry.Kind.Whiteout, | |
| 1232 | else => Entry.Kind.Unknown, | |
| 1233 | }; | |
| 1234 | return Entry { | |
| 1235 | .name = name, | |
| 1236 | .kind = entry_kind, | |
| 1237 | }; | |
| 1238 | } | |
| 1239 | } | |
| 1240 | ||
| 1241 | fn nextWindows(self: &Dir) !?Entry { | |
| 1242 | @compileError("TODO support Dir.next for windows"); | |
| 1243 | } | |
| 1244 | ||
| 1245 | fn nextLinux(self: &Dir) !?Entry { | |
| 1161 | 1246 | start_over: while (true) { |
| 1162 | 1247 | if (self.index >= self.end_index) { |
| 1163 | 1248 | if (self.buf.len == 0) { |
| ... | ... | @@ -1166,7 +1251,7 @@ pub const Dir = struct { |
| 1166 | 1251 | |
| 1167 | 1252 | while (true) { |
| 1168 | 1253 | const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); |
| 1169 | const err = linux.getErrno(result); | |
| 1254 | const err = posix.getErrno(result); | |
| 1170 | 1255 | if (err > 0) { |
| 1171 | 1256 | switch (err) { |
| 1172 | 1257 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, |
| ... | ... | @@ -1184,7 +1269,7 @@ pub const Dir = struct { |
| 1184 | 1269 | break; |
| 1185 | 1270 | } |
| 1186 | 1271 | } |
| 1187 | const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); | |
| 1272 | const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]); | |
| 1188 | 1273 | const next_index = self.index + linux_entry.d_reclen; |
| 1189 | 1274 | self.index = next_index; |
| 1190 | 1275 | |
| ... | ... | @@ -1679,6 +1764,7 @@ test "std.os" { |
| 1679 | 1764 | _ = @import("linux/index.zig"); |
| 1680 | 1765 | _ = @import("path.zig"); |
| 1681 | 1766 | _ = @import("windows/index.zig"); |
| 1767 | _ = @import("test.zig"); | |
| 1682 | 1768 | } |
| 1683 | 1769 | |
| 1684 | 1770 | |
| ... | ... | @@ -1690,7 +1776,7 @@ const unexpected_error_tracing = false; |
| 1690 | 1776 | pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) { |
| 1691 | 1777 | if (unexpected_error_tracing) { |
| 1692 | 1778 | debug.warn("unexpected errno: {}\n", errno); |
| 1693 | debug.dumpStackTrace(); | |
| 1779 | debug.dumpCurrentStackTrace(null); | |
| 1694 | 1780 | } |
| 1695 | 1781 | return error.Unexpected; |
| 1696 | 1782 | } |
| ... | ... | @@ -1700,7 +1786,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) { |
| 1700 | 1786 | pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) { |
| 1701 | 1787 | if (unexpected_error_tracing) { |
| 1702 | 1788 | debug.warn("unexpected GetLastError(): {}\n", err); |
| 1703 | debug.dumpStackTrace(); | |
| 1789 | debug.dumpCurrentStackTrace(null); | |
| 1704 | 1790 | } |
| 1705 | 1791 | return error.Unexpected; |
| 1706 | 1792 | } |
std/os/linux/index.zig+67-91| ... | ... | @@ -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; |
| ... | ... | @@ -394,65 +373,65 @@ pub fn getErrno(r: usize) usize { |
| 394 | 373 | } |
| 395 | 374 | |
| 396 | 375 | pub fn dup2(old: i32, new: i32) usize { |
| 397 | return arch.syscall2(arch.SYS_dup2, usize(old), usize(new)); | |
| 376 | return syscall2(SYS_dup2, usize(old), usize(new)); | |
| 398 | 377 | } |
| 399 | 378 | |
| 400 | 379 | pub fn chdir(path: &const u8) usize { |
| 401 | return arch.syscall1(arch.SYS_chdir, @ptrToInt(path)); | |
| 380 | return syscall1(SYS_chdir, @ptrToInt(path)); | |
| 402 | 381 | } |
| 403 | 382 | |
| 404 | 383 | 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)); | |
| 384 | return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); | |
| 406 | 385 | } |
| 407 | 386 | |
| 408 | 387 | pub fn fork() usize { |
| 409 | return arch.syscall0(arch.SYS_fork); | |
| 388 | return syscall0(SYS_fork); | |
| 410 | 389 | } |
| 411 | 390 | |
| 412 | 391 | pub fn getcwd(buf: &u8, size: usize) usize { |
| 413 | return arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size); | |
| 392 | return syscall2(SYS_getcwd, @ptrToInt(buf), size); | |
| 414 | 393 | } |
| 415 | 394 | |
| 416 | 395 | pub fn getdents(fd: i32, dirp: &u8, count: usize) usize { |
| 417 | return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count); | |
| 396 | return syscall3(SYS_getdents, usize(fd), @ptrToInt(dirp), count); | |
| 418 | 397 | } |
| 419 | 398 | |
| 420 | 399 | pub fn isatty(fd: i32) bool { |
| 421 | 400 | var wsz: winsize = undefined; |
| 422 | return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; | |
| 401 | return syscall3(SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; | |
| 423 | 402 | } |
| 424 | 403 | |
| 425 | 404 | 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); | |
| 405 | return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 427 | 406 | } |
| 428 | 407 | |
| 429 | 408 | pub fn mkdir(path: &const u8, mode: u32) usize { |
| 430 | return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode); | |
| 409 | return syscall2(SYS_mkdir, @ptrToInt(path), mode); | |
| 431 | 410 | } |
| 432 | 411 | |
| 433 | 412 | 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), | |
| 413 | return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), | |
| 435 | 414 | @bitCast(usize, offset)); |
| 436 | 415 | } |
| 437 | 416 | |
| 438 | 417 | pub fn munmap(address: &u8, length: usize) usize { |
| 439 | return arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length); | |
| 418 | return syscall2(SYS_munmap, @ptrToInt(address), length); | |
| 440 | 419 | } |
| 441 | 420 | |
| 442 | 421 | pub fn read(fd: i32, buf: &u8, count: usize) usize { |
| 443 | return arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count); | |
| 422 | return syscall3(SYS_read, usize(fd), @ptrToInt(buf), count); | |
| 444 | 423 | } |
| 445 | 424 | |
| 446 | 425 | pub fn rmdir(path: &const u8) usize { |
| 447 | return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)); | |
| 426 | return syscall1(SYS_rmdir, @ptrToInt(path)); | |
| 448 | 427 | } |
| 449 | 428 | |
| 450 | 429 | pub fn symlink(existing: &const u8, new: &const u8) usize { |
| 451 | return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); | |
| 430 | return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); | |
| 452 | 431 | } |
| 453 | 432 | |
| 454 | 433 | 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); | |
| 434 | return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset); | |
| 456 | 435 | } |
| 457 | 436 | |
| 458 | 437 | pub fn pipe(fd: &[2]i32) usize { |
| ... | ... | @@ -460,84 +439,84 @@ pub fn pipe(fd: &[2]i32) usize { |
| 460 | 439 | } |
| 461 | 440 | |
| 462 | 441 | pub fn pipe2(fd: &[2]i32, flags: usize) usize { |
| 463 | return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags); | |
| 442 | return syscall2(SYS_pipe2, @ptrToInt(fd), flags); | |
| 464 | 443 | } |
| 465 | 444 | |
| 466 | 445 | pub fn write(fd: i32, buf: &const u8, count: usize) usize { |
| 467 | return arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count); | |
| 446 | return syscall3(SYS_write, usize(fd), @ptrToInt(buf), count); | |
| 468 | 447 | } |
| 469 | 448 | |
| 470 | 449 | 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); | |
| 450 | return syscall4(SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset); | |
| 472 | 451 | } |
| 473 | 452 | |
| 474 | 453 | pub fn rename(old: &const u8, new: &const u8) usize { |
| 475 | return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)); | |
| 454 | return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); | |
| 476 | 455 | } |
| 477 | 456 | |
| 478 | 457 | pub fn open(path: &const u8, flags: u32, perm: usize) usize { |
| 479 | return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm); | |
| 458 | return syscall3(SYS_open, @ptrToInt(path), flags, perm); | |
| 480 | 459 | } |
| 481 | 460 | |
| 482 | 461 | pub fn create(path: &const u8, perm: usize) usize { |
| 483 | return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm); | |
| 462 | return syscall2(SYS_creat, @ptrToInt(path), perm); | |
| 484 | 463 | } |
| 485 | 464 | |
| 486 | 465 | 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); | |
| 466 | return syscall4(SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode); | |
| 488 | 467 | } |
| 489 | 468 | |
| 490 | 469 | pub fn close(fd: i32) usize { |
| 491 | return arch.syscall1(arch.SYS_close, usize(fd)); | |
| 470 | return syscall1(SYS_close, usize(fd)); | |
| 492 | 471 | } |
| 493 | 472 | |
| 494 | 473 | 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); | |
| 474 | return syscall3(SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos); | |
| 496 | 475 | } |
| 497 | 476 | |
| 498 | 477 | pub fn exit(status: i32) noreturn { |
| 499 | _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); | |
| 478 | _ = syscall1(SYS_exit, @bitCast(usize, isize(status))); | |
| 500 | 479 | unreachable; |
| 501 | 480 | } |
| 502 | 481 | |
| 503 | 482 | pub fn getrandom(buf: &u8, count: usize, flags: u32) usize { |
| 504 | return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags)); | |
| 483 | return syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags)); | |
| 505 | 484 | } |
| 506 | 485 | |
| 507 | 486 | pub fn kill(pid: i32, sig: i32) usize { |
| 508 | return arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig)); | |
| 487 | return syscall2(SYS_kill, @bitCast(usize, isize(pid)), usize(sig)); | |
| 509 | 488 | } |
| 510 | 489 | |
| 511 | 490 | pub fn unlink(path: &const u8) usize { |
| 512 | return arch.syscall1(arch.SYS_unlink, @ptrToInt(path)); | |
| 491 | return syscall1(SYS_unlink, @ptrToInt(path)); | |
| 513 | 492 | } |
| 514 | 493 | |
| 515 | 494 | 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); | |
| 495 | return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); | |
| 517 | 496 | } |
| 518 | 497 | |
| 519 | 498 | pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize { |
| 520 | return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); | |
| 499 | return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); | |
| 521 | 500 | } |
| 522 | 501 | |
| 523 | 502 | pub fn setuid(uid: u32) usize { |
| 524 | return arch.syscall1(arch.SYS_setuid, uid); | |
| 503 | return syscall1(SYS_setuid, uid); | |
| 525 | 504 | } |
| 526 | 505 | |
| 527 | 506 | pub fn setgid(gid: u32) usize { |
| 528 | return arch.syscall1(arch.SYS_setgid, gid); | |
| 507 | return syscall1(SYS_setgid, gid); | |
| 529 | 508 | } |
| 530 | 509 | |
| 531 | 510 | pub fn setreuid(ruid: u32, euid: u32) usize { |
| 532 | return arch.syscall2(arch.SYS_setreuid, ruid, euid); | |
| 511 | return syscall2(SYS_setreuid, ruid, euid); | |
| 533 | 512 | } |
| 534 | 513 | |
| 535 | 514 | pub fn setregid(rgid: u32, egid: u32) usize { |
| 536 | return arch.syscall2(arch.SYS_setregid, rgid, egid); | |
| 515 | return syscall2(SYS_setregid, rgid, egid); | |
| 537 | 516 | } |
| 538 | 517 | |
| 539 | 518 | 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); | |
| 519 | return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8); | |
| 541 | 520 | } |
| 542 | 521 | |
| 543 | 522 | pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize { |
| ... | ... | @@ -548,11 +527,11 @@ pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigacti |
| 548 | 527 | .handler = act.handler, |
| 549 | 528 | .flags = act.flags | SA_RESTORER, |
| 550 | 529 | .mask = undefined, |
| 551 | .restorer = @ptrCast(extern fn()void, arch.restore_rt), | |
| 530 | .restorer = @ptrCast(extern fn()void, restore_rt), | |
| 552 | 531 | }; |
| 553 | 532 | var ksa_old: k_sigaction = undefined; |
| 554 | 533 | @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))); | |
| 534 | const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); | |
| 556 | 535 | const err = getErrno(result); |
| 557 | 536 | if (err != 0) { |
| 558 | 537 | return result; |
| ... | ... | @@ -592,22 +571,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len; |
| 592 | 571 | pub fn raise(sig: i32) usize { |
| 593 | 572 | var set: sigset_t = undefined; |
| 594 | 573 | blockAppSignals(&set); |
| 595 | const tid = i32(arch.syscall0(arch.SYS_gettid)); | |
| 596 | const ret = arch.syscall2(arch.SYS_tkill, usize(tid), usize(sig)); | |
| 574 | const tid = i32(syscall0(SYS_gettid)); | |
| 575 | const ret = syscall2(SYS_tkill, usize(tid), usize(sig)); | |
| 597 | 576 | restoreSignals(&set); |
| 598 | 577 | return ret; |
| 599 | 578 | } |
| 600 | 579 | |
| 601 | 580 | fn blockAllSignals(set: &sigset_t) void { |
| 602 | _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8); | |
| 581 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8); | |
| 603 | 582 | } |
| 604 | 583 | |
| 605 | 584 | fn blockAppSignals(set: &sigset_t) void { |
| 606 | _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8); | |
| 585 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8); | |
| 607 | 586 | } |
| 608 | 587 | |
| 609 | 588 | fn restoreSignals(set: &sigset_t) void { |
| 610 | _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8); | |
| 589 | _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8); | |
| 611 | 590 | } |
| 612 | 591 | |
| 613 | 592 | pub fn sigaddset(set: &sigset_t, sig: u6) void { |
| ... | ... | @@ -653,61 +632,61 @@ pub const iovec = extern struct { |
| 653 | 632 | }; |
| 654 | 633 | |
| 655 | 634 | 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)); | |
| 635 | return syscall3(SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)); | |
| 657 | 636 | } |
| 658 | 637 | |
| 659 | 638 | 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)); | |
| 639 | return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)); | |
| 661 | 640 | } |
| 662 | 641 | |
| 663 | 642 | 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)); | |
| 643 | return syscall3(SYS_socket, usize(domain), usize(socket_type), usize(protocol)); | |
| 665 | 644 | } |
| 666 | 645 | |
| 667 | 646 | 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)); | |
| 647 | return syscall5(SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen)); | |
| 669 | 648 | } |
| 670 | 649 | |
| 671 | 650 | 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)); | |
| 651 | return syscall5(SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen)); | |
| 673 | 652 | } |
| 674 | 653 | |
| 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); | |
| 654 | pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize { | |
| 655 | return syscall3(SYS_sendmsg, usize(fd), @ptrToInt(msg), flags); | |
| 677 | 656 | } |
| 678 | 657 | |
| 679 | 658 | 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)); | |
| 659 | return syscall3(SYS_connect, usize(fd), @ptrToInt(addr), usize(len)); | |
| 681 | 660 | } |
| 682 | 661 | |
| 683 | pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) usize { | |
| 684 | return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags); | |
| 662 | pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize { | |
| 663 | return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags); | |
| 685 | 664 | } |
| 686 | 665 | |
| 687 | 666 | pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, |
| 688 | 667 | noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize |
| 689 | 668 | { |
| 690 | return arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | |
| 669 | return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | |
| 691 | 670 | } |
| 692 | 671 | |
| 693 | 672 | pub fn shutdown(fd: i32, how: i32) usize { |
| 694 | return arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how)); | |
| 673 | return syscall2(SYS_shutdown, usize(fd), usize(how)); | |
| 695 | 674 | } |
| 696 | 675 | |
| 697 | 676 | 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)); | |
| 677 | return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len)); | |
| 699 | 678 | } |
| 700 | 679 | |
| 701 | 680 | pub fn listen(fd: i32, backlog: i32) usize { |
| 702 | return arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog)); | |
| 681 | return syscall2(SYS_listen, usize(fd), usize(backlog)); | |
| 703 | 682 | } |
| 704 | 683 | |
| 705 | 684 | 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)); | |
| 685 | return syscall6(SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)); | |
| 707 | 686 | } |
| 708 | 687 | |
| 709 | 688 | 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])); | |
| 689 | return syscall4(SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])); | |
| 711 | 690 | } |
| 712 | 691 | |
| 713 | 692 | pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize { |
| ... | ... | @@ -715,7 +694,7 @@ pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize { |
| 715 | 694 | } |
| 716 | 695 | |
| 717 | 696 | 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); | |
| 697 | return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags); | |
| 719 | 698 | } |
| 720 | 699 | |
| 721 | 700 | // error NameTooLong; |
| ... | ... | @@ -746,11 +725,8 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: |
| 746 | 725 | // return ifr.ifr_ifindex; |
| 747 | 726 | // } |
| 748 | 727 | |
| 749 | pub const Stat = arch.Stat; | |
| 750 | pub const timespec = arch.timespec; | |
| 751 | ||
| 752 | 728 | pub fn fstat(fd: i32, stat_buf: &Stat) usize { |
| 753 | return arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf)); | |
| 729 | return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf)); | |
| 754 | 730 | } |
| 755 | 731 | |
| 756 | 732 | pub const epoll_data = extern union { |
| ... | ... | @@ -770,19 +746,19 @@ pub fn epoll_create() usize { |
| 770 | 746 | } |
| 771 | 747 | |
| 772 | 748 | pub fn epoll_create1(flags: usize) usize { |
| 773 | return arch.syscall1(arch.SYS_epoll_create1, flags); | |
| 749 | return syscall1(SYS_epoll_create1, flags); | |
| 774 | 750 | } |
| 775 | 751 | |
| 776 | 752 | 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)); | |
| 753 | return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev)); | |
| 778 | 754 | } |
| 779 | 755 | |
| 780 | 756 | 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)); | |
| 757 | return syscall4(SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout)); | |
| 782 | 758 | } |
| 783 | 759 | |
| 784 | 760 | pub fn timerfd_create(clockid: i32, flags: u32) usize { |
| 785 | return arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags)); | |
| 761 | return syscall2(SYS_timerfd_create, usize(clockid), usize(flags)); | |
| 786 | 762 | } |
| 787 | 763 | |
| 788 | 764 | pub const itimerspec = extern struct { |
| ... | ... | @@ -791,11 +767,11 @@ pub const itimerspec = extern struct { |
| 791 | 767 | }; |
| 792 | 768 | |
| 793 | 769 | pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize { |
| 794 | return arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value)); | |
| 770 | return syscall2(SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value)); | |
| 795 | 771 | } |
| 796 | 772 | |
| 797 | 773 | 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)); | |
| 774 | return syscall4(SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value)); | |
| 799 | 775 | } |
| 800 | 776 | |
| 801 | 777 | 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/zig/ast.zig+175-6| ... | ... | @@ -20,8 +20,11 @@ pub const Node = struct { |
| 20 | 20 | IntegerLiteral, |
| 21 | 21 | FloatLiteral, |
| 22 | 22 | StringLiteral, |
| 23 | UndefinedLiteral, | |
| 23 | 24 | BuiltinCall, |
| 25 | Call, | |
| 24 | 26 | LineComment, |
| 27 | TestDecl, | |
| 25 | 28 | }; |
| 26 | 29 | |
| 27 | 30 | pub fn iterate(base: &Node, index: usize) ?&Node { |
| ... | ... | @@ -37,8 +40,11 @@ pub const Node = struct { |
| 37 | 40 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index), |
| 38 | 41 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index), |
| 39 | 42 | Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index), |
| 43 | Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index), | |
| 40 | 44 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index), |
| 45 | Id.Call => @fieldParentPtr(NodeCall, "base", base).iterate(index), | |
| 41 | 46 | Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index), |
| 47 | Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index), | |
| 42 | 48 | }; |
| 43 | 49 | } |
| 44 | 50 | |
| ... | ... | @@ -55,8 +61,11 @@ pub const Node = struct { |
| 55 | 61 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(), |
| 56 | 62 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(), |
| 57 | 63 | Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(), |
| 64 | Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(), | |
| 58 | 65 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(), |
| 66 | Id.Call => @fieldParentPtr(NodeCall, "base", base).firstToken(), | |
| 59 | 67 | Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(), |
| 68 | Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(), | |
| 60 | 69 | }; |
| 61 | 70 | } |
| 62 | 71 | |
| ... | ... | @@ -73,8 +82,11 @@ pub const Node = struct { |
| 73 | 82 | Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(), |
| 74 | 83 | Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(), |
| 75 | 84 | Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(), |
| 85 | Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(), | |
| 76 | 86 | Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(), |
| 87 | Id.Call => @fieldParentPtr(NodeCall, "base", base).lastToken(), | |
| 77 | 88 | Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(), |
| 89 | Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(), | |
| 78 | 90 | }; |
| 79 | 91 | } |
| 80 | 92 | }; |
| ... | ... | @@ -305,9 +317,47 @@ pub const NodeInfixOp = struct { |
| 305 | 317 | rhs: &Node, |
| 306 | 318 | |
| 307 | 319 | const InfixOp = enum { |
| 308 | EqualEqual, | |
| 320 | Add, | |
| 321 | AddWrap, | |
| 322 | ArrayCat, | |
| 323 | ArrayMult, | |
| 324 | Assign, | |
| 325 | AssignBitAnd, | |
| 326 | AssignBitOr, | |
| 327 | AssignBitShiftLeft, | |
| 328 | AssignBitShiftRight, | |
| 329 | AssignBitXor, | |
| 330 | AssignDiv, | |
| 331 | AssignMinus, | |
| 332 | AssignMinusWrap, | |
| 333 | AssignMod, | |
| 334 | AssignPlus, | |
| 335 | AssignPlusWrap, | |
| 336 | AssignTimes, | |
| 337 | AssignTimesWarp, | |
| 309 | 338 | BangEqual, |
| 339 | BitAnd, | |
| 340 | BitOr, | |
| 341 | BitShiftLeft, | |
| 342 | BitShiftRight, | |
| 343 | BitXor, | |
| 344 | BoolAnd, | |
| 345 | BoolOr, | |
| 346 | Div, | |
| 347 | EqualEqual, | |
| 348 | ErrorUnion, | |
| 349 | GreaterOrEqual, | |
| 350 | GreaterThan, | |
| 351 | LessOrEqual, | |
| 352 | LessThan, | |
| 353 | MergeErrorSets, | |
| 354 | Mod, | |
| 355 | Mult, | |
| 356 | MultWrap, | |
| 310 | 357 | Period, |
| 358 | Sub, | |
| 359 | SubWrap, | |
| 360 | UnwrapMaybe, | |
| 311 | 361 | }; |
| 312 | 362 | |
| 313 | 363 | pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node { |
| ... | ... | @@ -317,9 +367,47 @@ pub const NodeInfixOp = struct { |
| 317 | 367 | i -= 1; |
| 318 | 368 | |
| 319 | 369 | switch (self.op) { |
| 320 | InfixOp.EqualEqual, | |
| 370 | InfixOp.Add, | |
| 371 | InfixOp.AddWrap, | |
| 372 | InfixOp.ArrayCat, | |
| 373 | InfixOp.ArrayMult, | |
| 374 | InfixOp.Assign, | |
| 375 | InfixOp.AssignBitAnd, | |
| 376 | InfixOp.AssignBitOr, | |
| 377 | InfixOp.AssignBitShiftLeft, | |
| 378 | InfixOp.AssignBitShiftRight, | |
| 379 | InfixOp.AssignBitXor, | |
| 380 | InfixOp.AssignDiv, | |
| 381 | InfixOp.AssignMinus, | |
| 382 | InfixOp.AssignMinusWrap, | |
| 383 | InfixOp.AssignMod, | |
| 384 | InfixOp.AssignPlus, | |
| 385 | InfixOp.AssignPlusWrap, | |
| 386 | InfixOp.AssignTimes, | |
| 387 | InfixOp.AssignTimesWarp, | |
| 321 | 388 | InfixOp.BangEqual, |
| 322 | InfixOp.Period => {}, | |
| 389 | InfixOp.BitAnd, | |
| 390 | InfixOp.BitOr, | |
| 391 | InfixOp.BitShiftLeft, | |
| 392 | InfixOp.BitShiftRight, | |
| 393 | InfixOp.BitXor, | |
| 394 | InfixOp.BoolAnd, | |
| 395 | InfixOp.BoolOr, | |
| 396 | InfixOp.Div, | |
| 397 | InfixOp.EqualEqual, | |
| 398 | InfixOp.ErrorUnion, | |
| 399 | InfixOp.GreaterOrEqual, | |
| 400 | InfixOp.GreaterThan, | |
| 401 | InfixOp.LessOrEqual, | |
| 402 | InfixOp.LessThan, | |
| 403 | InfixOp.MergeErrorSets, | |
| 404 | InfixOp.Mod, | |
| 405 | InfixOp.Mult, | |
| 406 | InfixOp.MultWrap, | |
| 407 | InfixOp.Period, | |
| 408 | InfixOp.Sub, | |
| 409 | InfixOp.SubWrap, | |
| 410 | InfixOp.UnwrapMaybe => {}, | |
| 323 | 411 | } |
| 324 | 412 | |
| 325 | 413 | if (i < 1) return self.rhs; |
| ... | ... | @@ -344,9 +432,15 @@ pub const NodePrefixOp = struct { |
| 344 | 432 | rhs: &Node, |
| 345 | 433 | |
| 346 | 434 | const PrefixOp = union(enum) { |
| 435 | AddrOf: AddrOfInfo, | |
| 436 | BitNot, | |
| 437 | BoolNot, | |
| 438 | Deref, | |
| 439 | Negation, | |
| 440 | NegationWrap, | |
| 347 | 441 | Return, |
| 348 | 442 | Try, |
| 349 | AddrOf: AddrOfInfo, | |
| 443 | UnwrapMaybe, | |
| 350 | 444 | }; |
| 351 | 445 | const AddrOfInfo = struct { |
| 352 | 446 | align_expr: ?&Node, |
| ... | ... | @@ -360,14 +454,20 @@ pub const NodePrefixOp = struct { |
| 360 | 454 | var i = index; |
| 361 | 455 | |
| 362 | 456 | switch (self.op) { |
| 363 | PrefixOp.Return, | |
| 364 | PrefixOp.Try => {}, | |
| 365 | 457 | PrefixOp.AddrOf => |addr_of_info| { |
| 366 | 458 | if (addr_of_info.align_expr) |align_expr| { |
| 367 | 459 | if (i < 1) return align_expr; |
| 368 | 460 | i -= 1; |
| 369 | 461 | } |
| 370 | 462 | }, |
| 463 | PrefixOp.BitNot, | |
| 464 | PrefixOp.BoolNot, | |
| 465 | PrefixOp.Deref, | |
| 466 | PrefixOp.Negation, | |
| 467 | PrefixOp.NegationWrap, | |
| 468 | PrefixOp.Return, | |
| 469 | PrefixOp.Try, | |
| 470 | PrefixOp.UnwrapMaybe => {}, | |
| 371 | 471 | } |
| 372 | 472 | |
| 373 | 473 | if (i < 1) return self.rhs; |
| ... | ... | @@ -443,6 +543,33 @@ pub const NodeBuiltinCall = struct { |
| 443 | 543 | } |
| 444 | 544 | }; |
| 445 | 545 | |
| 546 | pub const NodeCall = struct { | |
| 547 | base: Node, | |
| 548 | callee: &Node, | |
| 549 | params: ArrayList(&Node), | |
| 550 | rparen_token: Token, | |
| 551 | ||
| 552 | pub fn iterate(self: &NodeCall, index: usize) ?&Node { | |
| 553 | var i = index; | |
| 554 | ||
| 555 | if (i < 1) return self.callee; | |
| 556 | i -= 1; | |
| 557 | ||
| 558 | if (i < self.params.len) return self.params.at(i); | |
| 559 | i -= self.params.len; | |
| 560 | ||
| 561 | return null; | |
| 562 | } | |
| 563 | ||
| 564 | pub fn firstToken(self: &NodeCall) Token { | |
| 565 | return self.callee.firstToken(); | |
| 566 | } | |
| 567 | ||
| 568 | pub fn lastToken(self: &NodeCall) Token { | |
| 569 | return self.rparen_token; | |
| 570 | } | |
| 571 | }; | |
| 572 | ||
| 446 | 573 | pub const NodeStringLiteral = struct { |
| 447 | 574 | base: Node, |
| 448 | 575 | token: Token, |
| ... | ... | @@ -460,6 +587,23 @@ pub const NodeStringLiteral = struct { |
| 460 | 587 | } |
| 461 | 588 | }; |
| 462 | 589 | |
| 590 | pub const NodeUndefinedLiteral = struct { | |
| 591 | base: Node, | |
| 592 | token: Token, | |
| 593 | ||
| 594 | pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node { | |
| 595 | return null; | |
| 596 | } | |
| 597 | ||
| 598 | pub fn firstToken(self: &NodeUndefinedLiteral) Token { | |
| 599 | return self.token; | |
| 600 | } | |
| 601 | ||
| 602 | pub fn lastToken(self: &NodeUndefinedLiteral) Token { | |
| 603 | return self.token; | |
| 604 | } | |
| 605 | }; | |
| 606 | ||
| 463 | 607 | pub const NodeLineComment = struct { |
| 464 | 608 | base: Node, |
| 465 | 609 | lines: ArrayList(Token), |
| ... | ... | @@ -476,3 +620,28 @@ pub const NodeLineComment = struct { |
| 476 | 620 | return self.lines.at(self.lines.len - 1); |
| 477 | 621 | } |
| 478 | 622 | }; |
| 623 | ||
| 624 | pub const NodeTestDecl = struct { | |
| 625 | base: Node, | |
| 626 | test_token: Token, | |
| 627 | name_token: Token, | |
| 628 | body_node: &Node, | |
| 629 | ||
| 630 | pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node { | |
| 631 | var i = index; | |
| 632 | ||
| 633 | if (i < 1) return self.body_node; | |
| 634 | i -= 1; | |
| 635 | ||
| 636 | return null; | |
| 637 | } | |
| 638 | ||
| 639 | pub fn firstToken(self: &NodeTestDecl) Token { | |
| 640 | return self.test_token; | |
| 641 | } | |
| 642 | ||
| 643 | pub fn lastToken(self: &NodeTestDecl) Token { | |
| 644 | return self.body_node.lastToken(); | |
| 645 | } | |
| 646 | }; | |
| 647 |
std/zig/parser.zig+371-63| ... | ... | @@ -86,6 +86,7 @@ pub const Parser = struct { |
| 86 | 86 | AfterOperand, |
| 87 | 87 | InfixOp: &ast.NodeInfixOp, |
| 88 | 88 | PrefixOp: &ast.NodePrefixOp, |
| 89 | SuffixOp: &ast.Node, | |
| 89 | 90 | AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo, |
| 90 | 91 | TypeExpr: DestPtr, |
| 91 | 92 | VarDecl: &ast.NodeVarDecl, |
| ... | ... | @@ -171,6 +172,22 @@ pub const Parser = struct { |
| 171 | 172 | stack.append(State { .TopLevelExtern = token }) catch unreachable; |
| 172 | 173 | continue; |
| 173 | 174 | }, |
| 175 | Token.Id.Keyword_test => { | |
| 176 | stack.append(State.TopLevel) catch unreachable; | |
| 177 | ||
| 178 | const name_token = self.getNextToken(); | |
| 179 | if (name_token.id != Token.Id.StringLiteral) | |
| 180 | return self.parseError(token, "expected {}, found {}", @tagName(Token.Id.StringLiteral), @tagName(name_token.id)); | |
| 181 | ||
| 182 | const lbrace = self.getNextToken(); | |
| 183 | if (lbrace.id != Token.Id.LBrace) | |
| 184 | return self.parseError(token, "expected {}, found {}", @tagName(Token.Id.LBrace), @tagName(name_token.id)); | |
| 185 | ||
| 186 | const block = try self.createBlock(arena, token); | |
| 187 | const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, name_token, block); | |
| 188 | try stack.append(State { .Block = block }); | |
| 189 | continue; | |
| 190 | }, | |
| 174 | 191 | Token.Id.Eof => { |
| 175 | 192 | root_node.eof_token = token; |
| 176 | 193 | return Tree {.root_node = root_node, .arena_allocator = arena_allocator}; |
| ... | ... | @@ -319,6 +336,42 @@ pub const Parser = struct { |
| 319 | 336 | try stack.append(State.ExpectOperand); |
| 320 | 337 | continue; |
| 321 | 338 | }, |
| 339 | Token.Id.Minus => { | |
| 340 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 341 | ast.NodePrefixOp.PrefixOp.Negation) }); | |
| 342 | try stack.append(State.ExpectOperand); | |
| 343 | continue; | |
| 344 | }, | |
| 345 | Token.Id.MinusPercent => { | |
| 346 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 347 | ast.NodePrefixOp.PrefixOp.NegationWrap) }); | |
| 348 | try stack.append(State.ExpectOperand); | |
| 349 | continue; | |
| 350 | }, | |
| 351 | Token.Id.Tilde => { | |
| 352 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 353 | ast.NodePrefixOp.PrefixOp.BitNot) }); | |
| 354 | try stack.append(State.ExpectOperand); | |
| 355 | continue; | |
| 356 | }, | |
| 357 | Token.Id.QuestionMarkQuestionMark => { | |
| 358 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 359 | ast.NodePrefixOp.PrefixOp.UnwrapMaybe) }); | |
| 360 | try stack.append(State.ExpectOperand); | |
| 361 | continue; | |
| 362 | }, | |
| 363 | Token.Id.Bang => { | |
| 364 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 365 | ast.NodePrefixOp.PrefixOp.BoolNot) }); | |
| 366 | try stack.append(State.ExpectOperand); | |
| 367 | continue; | |
| 368 | }, | |
| 369 | Token.Id.Asterisk => { | |
| 370 | try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token, | |
| 371 | ast.NodePrefixOp.PrefixOp.Deref) }); | |
| 372 | try stack.append(State.ExpectOperand); | |
| 373 | continue; | |
| 374 | }, | |
| 322 | 375 | Token.Id.Ampersand => { |
| 323 | 376 | const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{ |
| 324 | 377 | .AddrOf = ast.NodePrefixOp.AddrOfInfo { |
| ... | ... | @@ -355,6 +408,13 @@ pub const Parser = struct { |
| 355 | 408 | try stack.append(State.AfterOperand); |
| 356 | 409 | continue; |
| 357 | 410 | }, |
| 411 | Token.Id.Keyword_undefined => { | |
| 412 | try stack.append(State { | |
| 413 | .Operand = &(try self.createUndefined(arena, token)).base | |
| 414 | }); | |
| 415 | try stack.append(State.AfterOperand); | |
| 416 | continue; | |
| 417 | }, | |
| 358 | 418 | Token.Id.Builtin => { |
| 359 | 419 | const node = try arena.create(ast.NodeBuiltinCall); |
| 360 | 420 | *node = ast.NodeBuiltinCall { |
| ... | ... | @@ -398,56 +458,62 @@ pub const Parser = struct { |
| 398 | 458 | // or a postfix operator (like () or {}), |
| 399 | 459 | // otherwise this expression is done (like on a ; or else). |
| 400 | 460 | var token = self.getNextToken(); |
| 401 | 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; | |
| 408 | }, | |
| 409 | Token.Id.BangEqual => { | |
| 461 | if (tokenIdToInfixOp(token.id)) |infix_id| { | |
| 410 | 462 | try stack.append(State { |
| 411 | .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BangEqual) | |
| 463 | .InfixOp = try self.createInfixOp(arena, token, infix_id) | |
| 412 | 464 | }); |
| 413 | 465 | try stack.append(State.ExpectOperand); |
| 414 | 466 | continue; |
| 415 | }, | |
| 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); | |
| 421 | continue; | |
| 422 | }, | |
| 423 | else => { | |
| 424 | // no postfix/infix operator after this operand. | |
| 425 | 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, | |
| 447 | } | |
| 467 | ||
| 468 | } else if (token.id == Token.Id.LParen) { | |
| 469 | self.putBackToken(token); | |
| 470 | ||
| 471 | const node = try arena.create(ast.NodeCall); | |
| 472 | *node = ast.NodeCall { | |
| 473 | .base = self.initNode(ast.Node.Id.Call), | |
| 474 | .callee = undefined, | |
| 475 | .params = ArrayList(&ast.Node).init(arena), | |
| 476 | .rparen_token = undefined, | |
| 477 | }; | |
| 478 | try stack.append(State { .SuffixOp = &node.base }); | |
| 479 | try stack.append(State.AfterOperand); | |
| 480 | try stack.append(State {.ExprListItemOrEnd = &node.params }); | |
| 481 | try stack.append(State { | |
| 482 | .ExpectTokenSave = ExpectTokenSave { | |
| 483 | .id = Token.Id.LParen, | |
| 484 | .ptr = &node.rparen_token, | |
| 485 | }, | |
| 486 | }); | |
| 487 | continue; | |
| 488 | ||
| 489 | // TODO: Parse postfix operator | |
| 490 | } else { | |
| 491 | // no postfix/infix operator after this operand. | |
| 492 | self.putBackToken(token); | |
| 493 | ||
| 494 | var expression = popSuffixOp(&stack); | |
| 495 | while (true) { | |
| 496 | switch (stack.pop()) { | |
| 497 | State.Expression => |dest_ptr| { | |
| 498 | // we're done | |
| 499 | try dest_ptr.store(expression); | |
| 500 | break; | |
| 501 | }, | |
| 502 | State.InfixOp => |infix_op| { | |
| 503 | infix_op.rhs = expression; | |
| 504 | infix_op.lhs = popSuffixOp(&stack); | |
| 505 | expression = &infix_op.base; | |
| 506 | continue; | |
| 507 | }, | |
| 508 | State.PrefixOp => |prefix_op| { | |
| 509 | prefix_op.rhs = expression; | |
| 510 | expression = &prefix_op.base; | |
| 511 | continue; | |
| 512 | }, | |
| 513 | else => unreachable, | |
| 448 | 514 | } |
| 449 | continue; | |
| 450 | }, | |
| 515 | } | |
| 516 | continue; | |
| 451 | 517 | } |
| 452 | 518 | }, |
| 453 | 519 | |
| ... | ... | @@ -685,11 +751,86 @@ pub const Parser = struct { |
| 685 | 751 | // These are data, not control flow. |
| 686 | 752 | State.InfixOp => unreachable, |
| 687 | 753 | State.PrefixOp => unreachable, |
| 754 | State.SuffixOp => unreachable, | |
| 688 | 755 | State.Operand => unreachable, |
| 689 | 756 | } |
| 690 | 757 | } |
| 691 | 758 | } |
| 692 | 759 | |
| 760 | fn popSuffixOp(stack: &ArrayList(State)) &ast.Node { | |
| 761 | var expression: &ast.Node = undefined; | |
| 762 | var left_leaf_ptr: &&ast.Node = &expression; | |
| 763 | while (true) { | |
| 764 | switch (stack.pop()) { | |
| 765 | State.SuffixOp => |suffix_op| { | |
| 766 | switch (suffix_op.id) { | |
| 767 | ast.Node.Id.Call => { | |
| 768 | const call = @fieldParentPtr(ast.NodeCall, "base", suffix_op); | |
| 769 | *left_leaf_ptr = &call.base; | |
| 770 | left_leaf_ptr = &call.callee; | |
| 771 | continue; | |
| 772 | }, | |
| 773 | else => unreachable, | |
| 774 | } | |
| 775 | }, | |
| 776 | State.Operand => |operand| { | |
| 777 | *left_leaf_ptr = operand; | |
| 778 | break; | |
| 779 | }, | |
| 780 | else => unreachable, | |
| 781 | } | |
| 782 | } | |
| 783 | ||
| 784 | return expression; | |
| 785 | } | |
| 786 | ||
| 787 | fn tokenIdToInfixOp(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp { | |
| 788 | return switch (*id) { | |
| 789 | Token.Id.Ampersand => ast.NodeInfixOp.InfixOp.BitAnd, | |
| 790 | Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp.AssignBitAnd, | |
| 791 | Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp.BitShiftLeft, | |
| 792 | Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp.AssignBitShiftLeft, | |
| 793 | Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp.BitShiftRight, | |
| 794 | Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp.AssignBitShiftRight, | |
| 795 | Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp.LessThan, | |
| 796 | Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp.LessOrEqual, | |
| 797 | Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp.GreaterThan, | |
| 798 | Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp.GreaterOrEqual, | |
| 799 | Token.Id.Asterisk => ast.NodeInfixOp.InfixOp.Mult, | |
| 800 | Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp.ArrayMult, | |
| 801 | Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp.AssignTimes, | |
| 802 | Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp.MultWrap, | |
| 803 | Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp.AssignTimesWarp, | |
| 804 | Token.Id.Bang => ast.NodeInfixOp.InfixOp.ErrorUnion, | |
| 805 | Token.Id.BangEqual => ast.NodeInfixOp.InfixOp.BangEqual, | |
| 806 | Token.Id.Caret => ast.NodeInfixOp.InfixOp.BitXor, | |
| 807 | Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp.AssignBitXor, | |
| 808 | Token.Id.Equal => ast.NodeInfixOp.InfixOp.Assign, | |
| 809 | Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp.EqualEqual, | |
| 810 | Token.Id.Keyword_and => ast.NodeInfixOp.InfixOp.BoolAnd, | |
| 811 | Token.Id.Keyword_or => ast.NodeInfixOp.InfixOp.BoolOr, | |
| 812 | Token.Id.Minus => ast.NodeInfixOp.InfixOp.Sub, | |
| 813 | Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp.AssignMinus, | |
| 814 | Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp.SubWrap, | |
| 815 | Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp.AssignMinusWrap, | |
| 816 | Token.Id.Percent => ast.NodeInfixOp.InfixOp.Mod, | |
| 817 | Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp.AssignMod, | |
| 818 | Token.Id.Period => ast.NodeInfixOp.InfixOp.Period, | |
| 819 | Token.Id.Pipe => ast.NodeInfixOp.InfixOp.BitOr, | |
| 820 | Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp.AssignBitOr, | |
| 821 | Token.Id.PipePipe => ast.NodeInfixOp.InfixOp.MergeErrorSets, | |
| 822 | Token.Id.Plus => ast.NodeInfixOp.InfixOp.Add, | |
| 823 | Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp.AssignPlus, | |
| 824 | Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp.AddWrap, | |
| 825 | Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp.AssignPlusWrap, | |
| 826 | Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp.ArrayCat, | |
| 827 | Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp.UnwrapMaybe, | |
| 828 | Token.Id.Slash => ast.NodeInfixOp.InfixOp.Div, | |
| 829 | Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp.AssignDiv, | |
| 830 | else => null, | |
| 831 | }; | |
| 832 | } | |
| 833 | ||
| 693 | 834 | fn initNode(self: &Parser, id: ast.Node.Id) ast.Node { |
| 694 | 835 | if (self.pending_line_comment_node) |comment_node| { |
| 695 | 836 | self.pending_line_comment_node = null; |
| ... | ... | @@ -733,6 +874,20 @@ pub const Parser = struct { |
| 733 | 874 | return node; |
| 734 | 875 | } |
| 735 | 876 | |
| 877 | fn createTestDecl(self: &Parser, arena: &mem.Allocator, test_token: &const Token, name_token: &const Token, | |
| 878 | block: &ast.NodeBlock) !&ast.NodeTestDecl | |
| 879 | { | |
| 880 | const node = try arena.create(ast.NodeTestDecl); | |
| 881 | ||
| 882 | *node = ast.NodeTestDecl { | |
| 883 | .base = self.initNode(ast.Node.Id.TestDecl), | |
| 884 | .test_token = *test_token, | |
| 885 | .name_token = *name_token, | |
| 886 | .body_node = &block.base, | |
| 887 | }; | |
| 888 | return node; | |
| 889 | } | |
| 890 | ||
| 736 | 891 | fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token, |
| 737 | 892 | cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto |
| 738 | 893 | { |
| ... | ... | @@ -837,6 +992,16 @@ pub const Parser = struct { |
| 837 | 992 | return node; |
| 838 | 993 | } |
| 839 | 994 | |
| 995 | fn createUndefined(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeUndefinedLiteral { | |
| 996 | const node = try arena.create(ast.NodeUndefinedLiteral); | |
| 997 | ||
| 998 | *node = ast.NodeUndefinedLiteral { | |
| 999 | .base = self.initNode(ast.Node.Id.UndefinedLiteral), | |
| 1000 | .token = *token, | |
| 1001 | }; | |
| 1002 | return node; | |
| 1003 | } | |
| 1004 | ||
| 840 | 1005 | fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier { |
| 841 | 1006 | const node = try self.createIdentifier(arena, name_token); |
| 842 | 1007 | try dest_ptr.store(&node.base); |
| ... | ... | @@ -867,6 +1032,14 @@ pub const Parser = struct { |
| 867 | 1032 | return node; |
| 868 | 1033 | } |
| 869 | 1034 | |
| 1035 | fn createAttachTestDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), | |
| 1036 | test_token: &const Token, name_token: &const Token, block: &ast.NodeBlock) !&ast.NodeTestDecl | |
| 1037 | { | |
| 1038 | const node = try self.createTestDecl(arena, test_token, name_token, block); | |
| 1039 | try list.append(&node.base); | |
| 1040 | return node; | |
| 1041 | } | |
| 1042 | ||
| 870 | 1043 | fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) { |
| 871 | 1044 | const loc = self.tokenizer.getTokenLocation(token); |
| 872 | 1045 | warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args); |
| ... | ... | @@ -1032,7 +1205,11 @@ pub const Parser = struct { |
| 1032 | 1205 | ast.Node.Id.VarDecl => { |
| 1033 | 1206 | const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl); |
| 1034 | 1207 | try stack.append(RenderState { .VarDecl = var_decl}); |
| 1035 | ||
| 1208 | }, | |
| 1209 | ast.Node.Id.TestDecl => { | |
| 1210 | const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl); | |
| 1211 | try stream.print("test {} ", self.tokenizer.getTokenSlice(test_decl.name_token)); | |
| 1212 | try stack.append(RenderState { .Expression = test_decl.body_node }); | |
| 1036 | 1213 | }, |
| 1037 | 1214 | else => unreachable, |
| 1038 | 1215 | } |
| ... | ... | @@ -1131,29 +1308,57 @@ pub const Parser = struct { |
| 1131 | 1308 | ast.Node.Id.InfixOp => { |
| 1132 | 1309 | const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base); |
| 1133 | 1310 | 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 | }, | |
| 1144 | } | |
| 1311 | const text = switch (prefix_op_node.op) { | |
| 1312 | ast.NodeInfixOp.InfixOp.Add => " + ", | |
| 1313 | ast.NodeInfixOp.InfixOp.AddWrap => " +% ", | |
| 1314 | ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ", | |
| 1315 | ast.NodeInfixOp.InfixOp.ArrayMult => " ** ", | |
| 1316 | ast.NodeInfixOp.InfixOp.Assign => " = ", | |
| 1317 | ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ", | |
| 1318 | ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ", | |
| 1319 | ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ", | |
| 1320 | ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ", | |
| 1321 | ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ", | |
| 1322 | ast.NodeInfixOp.InfixOp.AssignDiv => " /= ", | |
| 1323 | ast.NodeInfixOp.InfixOp.AssignMinus => " -= ", | |
| 1324 | ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ", | |
| 1325 | ast.NodeInfixOp.InfixOp.AssignMod => " %= ", | |
| 1326 | ast.NodeInfixOp.InfixOp.AssignPlus => " += ", | |
| 1327 | ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ", | |
| 1328 | ast.NodeInfixOp.InfixOp.AssignTimes => " *= ", | |
| 1329 | ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ", | |
| 1330 | ast.NodeInfixOp.InfixOp.BangEqual => " != ", | |
| 1331 | ast.NodeInfixOp.InfixOp.BitAnd => " & ", | |
| 1332 | ast.NodeInfixOp.InfixOp.BitOr => " | ", | |
| 1333 | ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ", | |
| 1334 | ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ", | |
| 1335 | ast.NodeInfixOp.InfixOp.BitXor => " ^ ", | |
| 1336 | ast.NodeInfixOp.InfixOp.BoolAnd => " and ", | |
| 1337 | ast.NodeInfixOp.InfixOp.BoolOr => " or ", | |
| 1338 | ast.NodeInfixOp.InfixOp.Div => " / ", | |
| 1339 | ast.NodeInfixOp.InfixOp.EqualEqual => " == ", | |
| 1340 | ast.NodeInfixOp.InfixOp.ErrorUnion => "!", | |
| 1341 | ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ", | |
| 1342 | ast.NodeInfixOp.InfixOp.GreaterThan => " > ", | |
| 1343 | ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ", | |
| 1344 | ast.NodeInfixOp.InfixOp.LessThan => " < ", | |
| 1345 | ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ", | |
| 1346 | ast.NodeInfixOp.InfixOp.Mod => " % ", | |
| 1347 | ast.NodeInfixOp.InfixOp.Mult => " * ", | |
| 1348 | ast.NodeInfixOp.InfixOp.MultWrap => " *% ", | |
| 1349 | ast.NodeInfixOp.InfixOp.Period => ".", | |
| 1350 | ast.NodeInfixOp.InfixOp.Sub => " - ", | |
| 1351 | ast.NodeInfixOp.InfixOp.SubWrap => " -% ", | |
| 1352 | ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ", | |
| 1353 | }; | |
| 1354 | ||
| 1355 | try stack.append(RenderState { .Text = text }); | |
| 1145 | 1356 | try stack.append(RenderState { .Expression = prefix_op_node.lhs }); |
| 1146 | 1357 | }, |
| 1147 | 1358 | ast.Node.Id.PrefixOp => { |
| 1148 | 1359 | const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base); |
| 1149 | 1360 | try stack.append(RenderState { .Expression = prefix_op_node.rhs }); |
| 1150 | 1361 | 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 | 1362 | ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| { |
| 1158 | 1363 | try stream.write("&"); |
| 1159 | 1364 | if (addr_of_info.volatile_token != null) { |
| ... | ... | @@ -1168,6 +1373,14 @@ pub const Parser = struct { |
| 1168 | 1373 | try stack.append(RenderState { .Expression = align_expr}); |
| 1169 | 1374 | } |
| 1170 | 1375 | }, |
| 1376 | ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"), | |
| 1377 | ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"), | |
| 1378 | ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"), | |
| 1379 | ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"), | |
| 1380 | ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"), | |
| 1381 | ast.NodePrefixOp.PrefixOp.Return => try stream.write("return "), | |
| 1382 | ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "), | |
| 1383 | ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"), | |
| 1171 | 1384 | } |
| 1172 | 1385 | }, |
| 1173 | 1386 | ast.Node.Id.IntegerLiteral => { |
| ... | ... | @@ -1182,6 +1395,10 @@ pub const Parser = struct { |
| 1182 | 1395 | const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base); |
| 1183 | 1396 | try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token)); |
| 1184 | 1397 | }, |
| 1398 | ast.Node.Id.UndefinedLiteral => { | |
| 1399 | const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base); | |
| 1400 | try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token)); | |
| 1401 | }, | |
| 1185 | 1402 | ast.Node.Id.BuiltinCall => { |
| 1186 | 1403 | const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base); |
| 1187 | 1404 | try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token)); |
| ... | ... | @@ -1196,11 +1413,27 @@ pub const Parser = struct { |
| 1196 | 1413 | } |
| 1197 | 1414 | } |
| 1198 | 1415 | }, |
| 1416 | ast.Node.Id.Call => { | |
| 1417 | const call = @fieldParentPtr(ast.NodeCall, "base", base); | |
| 1418 | try stack.append(RenderState { .Text = ")"}); | |
| 1419 | var i = call.params.len; | |
| 1420 | while (i != 0) { | |
| 1421 | i -= 1; | |
| 1422 | const param_node = call.params.at(i); | |
| 1423 | try stack.append(RenderState { .Expression = param_node}); | |
| 1424 | if (i != 0) { | |
| 1425 | try stack.append(RenderState { .Text = ", " }); | |
| 1426 | } | |
| 1427 | } | |
| 1428 | try stack.append(RenderState { .Text = "("}); | |
| 1429 | try stack.append(RenderState { .Expression = call.callee }); | |
| 1430 | }, | |
| 1199 | 1431 | ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"), |
| 1200 | 1432 | ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"), |
| 1201 | 1433 | |
| 1202 | 1434 | ast.Node.Id.Root, |
| 1203 | 1435 | ast.Node.Id.VarDecl, |
| 1436 | ast.Node.Id.TestDecl, | |
| 1204 | 1437 | ast.Node.Id.ParamDecl => unreachable, |
| 1205 | 1438 | }, |
| 1206 | 1439 | RenderState.FnProtoRParen => |fn_proto| { |
| ... | ... | @@ -1422,4 +1655,79 @@ test "zig fmt" { |
| 1422 | 1655 | \\} |
| 1423 | 1656 | \\ |
| 1424 | 1657 | ); |
| 1658 | ||
| 1659 | try testCanonical( | |
| 1660 | \\test "test name" { | |
| 1661 | \\ const a = 1; | |
| 1662 | \\ var b = 1; | |
| 1663 | \\} | |
| 1664 | \\ | |
| 1665 | ); | |
| 1666 | ||
| 1667 | try testCanonical( | |
| 1668 | \\test "infix operators" { | |
| 1669 | \\ var i = undefined; | |
| 1670 | \\ i = 2; | |
| 1671 | \\ i *= 2; | |
| 1672 | \\ i |= 2; | |
| 1673 | \\ i ^= 2; | |
| 1674 | \\ i <<= 2; | |
| 1675 | \\ i >>= 2; | |
| 1676 | \\ i &= 2; | |
| 1677 | \\ i *= 2; | |
| 1678 | \\ i *%= 2; | |
| 1679 | \\ i -= 2; | |
| 1680 | \\ i -%= 2; | |
| 1681 | \\ i += 2; | |
| 1682 | \\ i +%= 2; | |
| 1683 | \\ i /= 2; | |
| 1684 | \\ i %= 2; | |
| 1685 | \\ _ = i == i; | |
| 1686 | \\ _ = i != i; | |
| 1687 | \\ _ = i != i; | |
| 1688 | \\ _ = i.i; | |
| 1689 | \\ _ = i || i; | |
| 1690 | \\ _ = i!i; | |
| 1691 | \\ _ = i ** i; | |
| 1692 | \\ _ = i ++ i; | |
| 1693 | \\ _ = i ?? i; | |
| 1694 | \\ _ = i % i; | |
| 1695 | \\ _ = i / i; | |
| 1696 | \\ _ = i *% i; | |
| 1697 | \\ _ = i * i; | |
| 1698 | \\ _ = i -% i; | |
| 1699 | \\ _ = i - i; | |
| 1700 | \\ _ = i +% i; | |
| 1701 | \\ _ = i + i; | |
| 1702 | \\ _ = i << i; | |
| 1703 | \\ _ = i >> i; | |
| 1704 | \\ _ = i & i; | |
| 1705 | \\ _ = i ^ i; | |
| 1706 | \\ _ = i | i; | |
| 1707 | \\ _ = i >= i; | |
| 1708 | \\ _ = i <= i; | |
| 1709 | \\ _ = i > i; | |
| 1710 | \\ _ = i < i; | |
| 1711 | \\ _ = i and i; | |
| 1712 | \\ _ = i or i; | |
| 1713 | \\} | |
| 1714 | \\ | |
| 1715 | ); | |
| 1716 | ||
| 1717 | try testCanonical( | |
| 1718 | \\test "prefix operators" { | |
| 1719 | \\ --%~??!*&0; | |
| 1720 | \\} | |
| 1721 | \\ | |
| 1722 | ); | |
| 1723 | ||
| 1724 | try testCanonical( | |
| 1725 | \\test "test calls" { | |
| 1726 | \\ a(); | |
| 1727 | \\ a(1); | |
| 1728 | \\ a(1, 2); | |
| 1729 | \\ a(1, 2) + a(1, 2); | |
| 1730 | \\} | |
| 1731 | \\ | |
| 1732 | ); | |
| 1425 | 1733 | } |
std/zig/tokenizer.zig+288-5| ... | ... | @@ -77,6 +77,7 @@ pub const Token = struct { |
| 77 | 77 | Builtin, |
| 78 | 78 | Bang, |
| 79 | 79 | Pipe, |
| 80 | PipePipe, | |
| 80 | 81 | PipeEqual, |
| 81 | 82 | Equal, |
| 82 | 83 | EqualEqual, |
| ... | ... | @@ -85,18 +86,46 @@ pub const Token = struct { |
| 85 | 86 | RParen, |
| 86 | 87 | Semicolon, |
| 87 | 88 | Percent, |
| 89 | PercentEqual, | |
| 88 | 90 | LBrace, |
| 89 | 91 | RBrace, |
| 90 | 92 | Period, |
| 91 | 93 | Ellipsis2, |
| 92 | 94 | Ellipsis3, |
| 95 | Caret, | |
| 96 | CaretEqual, | |
| 97 | Plus, | |
| 98 | PlusPlus, | |
| 99 | PlusEqual, | |
| 100 | PlusPercent, | |
| 101 | PlusPercentEqual, | |
| 93 | 102 | Minus, |
| 103 | MinusEqual, | |
| 104 | MinusPercent, | |
| 105 | MinusPercentEqual, | |
| 106 | Asterisk, | |
| 107 | AsteriskEqual, | |
| 108 | AsteriskAsterisk, | |
| 109 | AsteriskPercent, | |
| 110 | AsteriskPercentEqual, | |
| 94 | 111 | Arrow, |
| 95 | 112 | Colon, |
| 96 | 113 | Slash, |
| 114 | SlashEqual, | |
| 97 | 115 | Comma, |
| 98 | 116 | Ampersand, |
| 99 | 117 | AmpersandEqual, |
| 118 | QuestionMark, | |
| 119 | QuestionMarkQuestionMark, | |
| 120 | AngleBracketLeft, | |
| 121 | AngleBracketLeftEqual, | |
| 122 | AngleBracketAngleBracketLeft, | |
| 123 | AngleBracketAngleBracketLeftEqual, | |
| 124 | AngleBracketRight, | |
| 125 | AngleBracketRightEqual, | |
| 126 | AngleBracketAngleBracketRight, | |
| 127 | AngleBracketAngleBracketRightEqual, | |
| 128 | Tilde, | |
| 100 | 129 | IntegerLiteral, |
| 101 | 130 | FloatLiteral, |
| 102 | 131 | LineComment, |
| ... | ... | @@ -200,6 +229,9 @@ pub const Tokenizer = struct { |
| 200 | 229 | Bang, |
| 201 | 230 | Pipe, |
| 202 | 231 | Minus, |
| 232 | MinusPercent, | |
| 233 | Asterisk, | |
| 234 | AsteriskPercent, | |
| 203 | 235 | Slash, |
| 204 | 236 | LineComment, |
| 205 | 237 | Zero, |
| ... | ... | @@ -210,6 +242,15 @@ pub const Tokenizer = struct { |
| 210 | 242 | FloatExponentUnsigned, |
| 211 | 243 | FloatExponentNumber, |
| 212 | 244 | Ampersand, |
| 245 | Caret, | |
| 246 | Percent, | |
| 247 | QuestionMark, | |
| 248 | Plus, | |
| 249 | PlusPercent, | |
| 250 | AngleBracketLeft, | |
| 251 | AngleBracketAngleBracketLeft, | |
| 252 | AngleBracketRight, | |
| 253 | AngleBracketAngleBracketRight, | |
| 213 | 254 | Period, |
| 214 | 255 | Period2, |
| 215 | 256 | SawAtSign, |
| ... | ... | @@ -291,9 +332,25 @@ pub const Tokenizer = struct { |
| 291 | 332 | break; |
| 292 | 333 | }, |
| 293 | 334 | '%' => { |
| 294 | result.id = Token.Id.Percent; | |
| 295 | self.index += 1; | |
| 296 | break; | |
| 335 | state = State.Percent; | |
| 336 | }, | |
| 337 | '*' => { | |
| 338 | state = State.Asterisk; | |
| 339 | }, | |
| 340 | '+' => { | |
| 341 | state = State.Plus; | |
| 342 | }, | |
| 343 | '?' => { | |
| 344 | state = State.QuestionMark; | |
| 345 | }, | |
| 346 | '<' => { | |
| 347 | state = State.AngleBracketLeft; | |
| 348 | }, | |
| 349 | '>' => { | |
| 350 | state = State.AngleBracketRight; | |
| 351 | }, | |
| 352 | '^' => { | |
| 353 | state = State.Caret; | |
| 297 | 354 | }, |
| 298 | 355 | '{' => { |
| 299 | 356 | result.id = Token.Id.LBrace; |
| ... | ... | @@ -305,6 +362,11 @@ pub const Tokenizer = struct { |
| 305 | 362 | self.index += 1; |
| 306 | 363 | break; |
| 307 | 364 | }, |
| 365 | '~' => { | |
| 366 | result.id = Token.Id.Tilde; | |
| 367 | self.index += 1; | |
| 368 | break; | |
| 369 | }, | |
| 308 | 370 | '.' => { |
| 309 | 371 | state = State.Period; |
| 310 | 372 | }, |
| ... | ... | @@ -356,6 +418,107 @@ pub const Tokenizer = struct { |
| 356 | 418 | break; |
| 357 | 419 | }, |
| 358 | 420 | }, |
| 421 | ||
| 422 | State.Asterisk => switch (c) { | |
| 423 | '=' => { | |
| 424 | result.id = Token.Id.AsteriskEqual; | |
| 425 | self.index += 1; | |
| 426 | break; | |
| 427 | }, | |
| 428 | '*' => { | |
| 429 | result.id = Token.Id.AsteriskAsterisk; | |
| 430 | self.index += 1; | |
| 431 | break; | |
| 432 | }, | |
| 433 | '%' => { | |
| 434 | state = State.AsteriskPercent; | |
| 435 | }, | |
| 436 | else => { | |
| 437 | result.id = Token.Id.Asterisk; | |
| 438 | break; | |
| 439 | } | |
| 440 | }, | |
| 441 | ||
| 442 | State.AsteriskPercent => switch (c) { | |
| 443 | '=' => { | |
| 444 | result.id = Token.Id.AsteriskPercentEqual; | |
| 445 | self.index += 1; | |
| 446 | break; | |
| 447 | }, | |
| 448 | else => { | |
| 449 | result.id = Token.Id.AsteriskPercent; | |
| 450 | break; | |
| 451 | } | |
| 452 | }, | |
| 453 | ||
| 454 | State.QuestionMark => switch (c) { | |
| 455 | '?' => { | |
| 456 | result.id = Token.Id.QuestionMarkQuestionMark; | |
| 457 | self.index += 1; | |
| 458 | break; | |
| 459 | }, | |
| 460 | else => { | |
| 461 | result.id = Token.Id.QuestionMark; | |
| 462 | break; | |
| 463 | }, | |
| 464 | }, | |
| 465 | ||
| 466 | State.Percent => switch (c) { | |
| 467 | '=' => { | |
| 468 | result.id = Token.Id.PercentEqual; | |
| 469 | self.index += 1; | |
| 470 | break; | |
| 471 | }, | |
| 472 | else => { | |
| 473 | result.id = Token.Id.Percent; | |
| 474 | break; | |
| 475 | }, | |
| 476 | }, | |
| 477 | ||
| 478 | State.Plus => switch (c) { | |
| 479 | '=' => { | |
| 480 | result.id = Token.Id.PlusEqual; | |
| 481 | self.index += 1; | |
| 482 | break; | |
| 483 | }, | |
| 484 | '+' => { | |
| 485 | result.id = Token.Id.PlusPlus; | |
| 486 | self.index += 1; | |
| 487 | break; | |
| 488 | }, | |
| 489 | '%' => { | |
| 490 | state = State.PlusPercent; | |
| 491 | }, | |
| 492 | else => { | |
| 493 | result.id = Token.Id.Plus; | |
| 494 | break; | |
| 495 | }, | |
| 496 | }, | |
| 497 | ||
| 498 | State.PlusPercent => switch (c) { | |
| 499 | '=' => { | |
| 500 | result.id = Token.Id.PlusPercentEqual; | |
| 501 | self.index += 1; | |
| 502 | break; | |
| 503 | }, | |
| 504 | else => { | |
| 505 | result.id = Token.Id.PlusPercent; | |
| 506 | break; | |
| 507 | }, | |
| 508 | }, | |
| 509 | ||
| 510 | State.Caret => switch (c) { | |
| 511 | '=' => { | |
| 512 | result.id = Token.Id.CaretEqual; | |
| 513 | self.index += 1; | |
| 514 | break; | |
| 515 | }, | |
| 516 | else => { | |
| 517 | result.id = Token.Id.Caret; | |
| 518 | break; | |
| 519 | } | |
| 520 | }, | |
| 521 | ||
| 359 | 522 | State.Identifier => switch (c) { |
| 360 | 523 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, |
| 361 | 524 | else => { |
| ... | ... | @@ -417,6 +580,11 @@ pub const Tokenizer = struct { |
| 417 | 580 | self.index += 1; |
| 418 | 581 | break; |
| 419 | 582 | }, |
| 583 | '|' => { | |
| 584 | result.id = Token.Id.PipePipe; | |
| 585 | self.index += 1; | |
| 586 | break; | |
| 587 | }, | |
| 420 | 588 | else => { |
| 421 | 589 | result.id = Token.Id.Pipe; |
| 422 | 590 | break; |
| ... | ... | @@ -441,12 +609,86 @@ pub const Tokenizer = struct { |
| 441 | 609 | self.index += 1; |
| 442 | 610 | break; |
| 443 | 611 | }, |
| 612 | '=' => { | |
| 613 | result.id = Token.Id.MinusEqual; | |
| 614 | self.index += 1; | |
| 615 | break; | |
| 616 | }, | |
| 617 | '%' => { | |
| 618 | state = State.MinusPercent; | |
| 619 | }, | |
| 444 | 620 | else => { |
| 445 | 621 | result.id = Token.Id.Minus; |
| 446 | 622 | break; |
| 447 | 623 | }, |
| 448 | 624 | }, |
| 449 | 625 | |
| 626 | State.MinusPercent => switch (c) { | |
| 627 | '=' => { | |
| 628 | result.id = Token.Id.MinusPercentEqual; | |
| 629 | self.index += 1; | |
| 630 | break; | |
| 631 | }, | |
| 632 | else => { | |
| 633 | result.id = Token.Id.MinusPercent; | |
| 634 | break; | |
| 635 | } | |
| 636 | }, | |
| 637 | ||
| 638 | State.AngleBracketLeft => switch (c) { | |
| 639 | '<' => { | |
| 640 | state = State.AngleBracketAngleBracketLeft; | |
| 641 | }, | |
| 642 | '=' => { | |
| 643 | result.id = Token.Id.AngleBracketLeftEqual; | |
| 644 | self.index += 1; | |
| 645 | break; | |
| 646 | }, | |
| 647 | else => { | |
| 648 | result.id = Token.Id.AngleBracketLeft; | |
| 649 | break; | |
| 650 | }, | |
| 651 | }, | |
| 652 | ||
| 653 | State.AngleBracketAngleBracketLeft => switch (c) { | |
| 654 | '=' => { | |
| 655 | result.id = Token.Id.AngleBracketAngleBracketLeftEqual; | |
| 656 | self.index += 1; | |
| 657 | break; | |
| 658 | }, | |
| 659 | else => { | |
| 660 | result.id = Token.Id.AngleBracketAngleBracketLeft; | |
| 661 | break; | |
| 662 | }, | |
| 663 | }, | |
| 664 | ||
| 665 | State.AngleBracketRight => switch (c) { | |
| 666 | '>' => { | |
| 667 | state = State.AngleBracketAngleBracketRight; | |
| 668 | }, | |
| 669 | '=' => { | |
| 670 | result.id = Token.Id.AngleBracketRightEqual; | |
| 671 | self.index += 1; | |
| 672 | break; | |
| 673 | }, | |
| 674 | else => { | |
| 675 | result.id = Token.Id.AngleBracketRight; | |
| 676 | break; | |
| 677 | }, | |
| 678 | }, | |
| 679 | ||
| 680 | State.AngleBracketAngleBracketRight => switch (c) { | |
| 681 | '=' => { | |
| 682 | result.id = Token.Id.AngleBracketAngleBracketRightEqual; | |
| 683 | self.index += 1; | |
| 684 | break; | |
| 685 | }, | |
| 686 | else => { | |
| 687 | result.id = Token.Id.AngleBracketAngleBracketRight; | |
| 688 | break; | |
| 689 | }, | |
| 690 | }, | |
| 691 | ||
| 450 | 692 | State.Period => switch (c) { |
| 451 | 693 | '.' => { |
| 452 | 694 | state = State.Period2; |
| ... | ... | @@ -474,6 +716,11 @@ pub const Tokenizer = struct { |
| 474 | 716 | result.id = Token.Id.LineComment; |
| 475 | 717 | state = State.LineComment; |
| 476 | 718 | }, |
| 719 | '=' => { | |
| 720 | result.id = Token.Id.SlashEqual; | |
| 721 | self.index += 1; | |
| 722 | break; | |
| 723 | }, | |
| 477 | 724 | else => { |
| 478 | 725 | result.id = Token.Id.Slash; |
| 479 | 726 | break; |
| ... | ... | @@ -609,6 +856,42 @@ pub const Tokenizer = struct { |
| 609 | 856 | State.Pipe => { |
| 610 | 857 | result.id = Token.Id.Pipe; |
| 611 | 858 | }, |
| 859 | State.AngleBracketAngleBracketRight => { | |
| 860 | result.id = Token.Id.AngleBracketAngleBracketRight; | |
| 861 | }, | |
| 862 | State.AngleBracketRight => { | |
| 863 | result.id = Token.Id.AngleBracketRight; | |
| 864 | }, | |
| 865 | State.AngleBracketAngleBracketLeft => { | |
| 866 | result.id = Token.Id.AngleBracketAngleBracketLeft; | |
| 867 | }, | |
| 868 | State.AngleBracketLeft => { | |
| 869 | result.id = Token.Id.AngleBracketLeft; | |
| 870 | }, | |
| 871 | State.PlusPercent => { | |
| 872 | result.id = Token.Id.PlusPercent; | |
| 873 | }, | |
| 874 | State.Plus => { | |
| 875 | result.id = Token.Id.Plus; | |
| 876 | }, | |
| 877 | State.QuestionMark => { | |
| 878 | result.id = Token.Id.QuestionMark; | |
| 879 | }, | |
| 880 | State.Percent => { | |
| 881 | result.id = Token.Id.Percent; | |
| 882 | }, | |
| 883 | State.Caret => { | |
| 884 | result.id = Token.Id.Caret; | |
| 885 | }, | |
| 886 | State.AsteriskPercent => { | |
| 887 | result.id = Token.Id.AsteriskPercent; | |
| 888 | }, | |
| 889 | State.Asterisk => { | |
| 890 | result.id = Token.Id.Asterisk; | |
| 891 | }, | |
| 892 | State.MinusPercent => { | |
| 893 | result.id = Token.Id.MinusPercent; | |
| 894 | }, | |
| 612 | 895 | } |
| 613 | 896 | } |
| 614 | 897 | if (result.id == Token.Id.Eof) { |
| ... | ... | @@ -752,8 +1035,8 @@ test "tokenizer - string identifier and builtin fns" { |
| 752 | 1035 | |
| 753 | 1036 | test "tokenizer - pipe and then invalid" { |
| 754 | 1037 | testTokenize("||=", []Token.Id{ |
| 755 | Token.Id.Pipe, | |
| 756 | Token.Id.PipeEqual, | |
| 1038 | Token.Id.PipePipe, | |
| 1039 | Token.Id.Equal, | |
| 757 | 1040 | }); |
| 758 | 1041 | } |
| 759 | 1042 |
test/cases/coroutines.zig+33| ... | ... | @@ -5,6 +5,7 @@ var x: i32 = 1; |
| 5 | 5 | |
| 6 | 6 | test "create a coroutine and cancel it" { |
| 7 | 7 | const p = try async<std.debug.global_allocator> simpleAsyncFn(); |
| 8 | comptime assert(@typeOf(p) == promise->void); | |
| 8 | 9 | cancel p; |
| 9 | 10 | assert(x == 2); |
| 10 | 11 | } |
| ... | ... | @@ -55,6 +56,7 @@ var result = false; |
| 55 | 56 | |
| 56 | 57 | async fn testSuspendBlock() void { |
| 57 | 58 | suspend |p| { |
| 59 | comptime assert(@typeOf(p) == promise->void); | |
| 58 | 60 | a_promise = p; |
| 59 | 61 | } |
| 60 | 62 | result = true; |
| ... | ... | @@ -156,3 +158,34 @@ test "async function with dot syntax" { |
| 156 | 158 | cancel p; |
| 157 | 159 | assert(S.y == 2); |
| 158 | 160 | } |
| 161 | ||
| 162 | test "async fn pointer in a struct field" { | |
| 163 | var data: i32 = 1; | |
| 164 | const Foo = struct { | |
| 165 | bar: async<&std.mem.Allocator> fn(&i32) void, | |
| 166 | }; | |
| 167 | var foo = Foo { | |
| 168 | .bar = simpleAsyncFn2, | |
| 169 | }; | |
| 170 | const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable; | |
| 171 | assert(data == 2); | |
| 172 | cancel p; | |
| 173 | assert(data == 4); | |
| 174 | } | |
| 175 | ||
| 176 | async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void { | |
| 177 | defer *y += 2; | |
| 178 | *y += 1; | |
| 179 | suspend; | |
| 180 | } | |
| 181 | ||
| 182 | test "async fn with inferred error set" { | |
| 183 | const p = (async<std.debug.global_allocator> failing()) catch unreachable; | |
| 184 | resume p; | |
| 185 | cancel p; | |
| 186 | } | |
| 187 | ||
| 188 | async fn failing() !void { | |
| 189 | suspend; | |
| 190 | return error.Fail; | |
| 191 | } |
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+9| ... | ... | @@ -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, |
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 | } |