authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-04 17:22:26-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-04 17:22:26-04:00
logcca93908e6d57f18054d153ca01d6869739306f2
treeb7316e13386963e5b08aebc1f5707498b64a9ebb
parentc541ac240c3ad17dda964f9de085a5e8f5472c7a
parent8938429ea12ff2857ace5380932a7cd68d3b4ab1

Merge remote-tracking branch 'origin/master' into llvm7


61 files changed, 3135 insertions(+), 1368 deletions(-)

.travis.yml+3-1
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1sudo: required
2services:
3 - docker
1os:4os:
2 - linux5 - linux
3 - osx6 - osx
4dist: trusty7dist: trusty
5osx_image: xcode8.38osx_image: xcode8.3
6sudo: required
7language: cpp9language: cpp
8before_install:10before_install:
9 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi11 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
CMakeLists.txt+5-6
...@@ -30,11 +30,7 @@ if(GIT_EXE)...@@ -30,11 +30,7 @@ if(GIT_EXE)
30endif()30endif()
31message("Configuring zig version ${ZIG_VERSION}")31message("Configuring zig version ${ZIG_VERSION}")
3232
33set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found")33set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
34set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found")
35set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory")
36set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target")
37set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target")
3834
39string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")35string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")
40string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}")36string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}")
...@@ -429,6 +425,7 @@ set(ZIG_STD_FILES...@@ -429,6 +425,7 @@ set(ZIG_STD_FILES
429 "crypto/sha2.zig"425 "crypto/sha2.zig"
430 "crypto/sha3.zig"426 "crypto/sha3.zig"
431 "crypto/blake2.zig"427 "crypto/blake2.zig"
428 "crypto/hmac.zig"
432 "cstr.zig"429 "cstr.zig"
433 "debug/failing_allocator.zig"430 "debug/failing_allocator.zig"
434 "debug/index.zig"431 "debug/index.zig"
...@@ -509,7 +506,7 @@ set(ZIG_STD_FILES...@@ -509,7 +506,7 @@ set(ZIG_STD_FILES
509 "os/windows/index.zig"506 "os/windows/index.zig"
510 "os/windows/util.zig"507 "os/windows/util.zig"
511 "os/zen.zig"508 "os/zen.zig"
512 "rand.zig"509 "rand/index.zig"
513 "sort.zig"510 "sort.zig"
514 "special/bootstrap.zig"511 "special/bootstrap.zig"
515 "special/bootstrap_lib.zig"512 "special/bootstrap_lib.zig"
...@@ -698,6 +695,8 @@ if(MINGW)...@@ -698,6 +695,8 @@ if(MINGW)
698 set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++")695 set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++")
699elseif(MSVC)696elseif(MSVC)
700 set(EXE_LDFLAGS "/STACK:16777216")697 set(EXE_LDFLAGS "/STACK:16777216")
698elseif(ZIG_STATIC)
699 set(EXE_LDFLAGS "-static")
701else()700else()
702 set(EXE_LDFLAGS " ")701 set(EXE_LDFLAGS " ")
703endif()702endif()
README.md+1-7
...@@ -138,14 +138,10 @@ libc. Create demo games using Zig....@@ -138,14 +138,10 @@ libc. Create demo games using Zig.
138138
139##### POSIX139##### POSIX
140140
141If 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```
146mkdir build142mkdir build
147cd build143cd build
148cmake .. -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))144cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
149make145make
150make install146make install
151./zig build --build-file ../build.zig test147./zig build --build-file ../build.zig test
...@@ -153,8 +149,6 @@ make install...@@ -153,8 +149,6 @@ make install
153149
154##### MacOS150##### MacOS
155151
156`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157
158```152```
159brew install cmake llvm@7153brew install cmake llvm@7
160brew outdated llvm@7 || brew upgrade llvm@7154brew outdated llvm@7 || brew upgrade llvm@7
build.zig+5
...@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {...@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {
4545
46 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");46 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
47 exe.setBuildMode(mode);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 exe.addIncludeDir("src");53 exe.addIncludeDir("src");
49 exe.addIncludeDir(cmake_binary_dir);54 exe.addIncludeDir(cmake_binary_dir);
50 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");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,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_
2020
21mkdir %ZIGBUILDDIR%21mkdir %ZIGBUILDDIR%
22cd %ZIGBUILDDIR%22cd %ZIGBUILDDIR%
23cmake.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 /b23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
24msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b24msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
2525
26bin\zig.exe build --build-file ..\build.zig test || exit /b26bin\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 +4,4 @@ set -x
44
5sudo apt-get remove -y llvm-*5sudo apt-get remove -y llvm-*
6sudo rm -rf /usr/local/*6sudo rm -rf /usr/local/*
7sudo 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-amd647sudo 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,25 +8,16 @@ export CXX=clang++-7.0
8echo $PATH8echo $PATH
9mkdir build9mkdir build
10cd build10cd build
11cmake .. -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))11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
12make VERBOSE=112make -j2 install
13make install
14./zig build --build-file ../build.zig test13./zig build --build-file ../build.zig test
1514
16./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc15if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
17wine zig-cache/test.exe16 mkdir $TRAVIS_BUILD_DIR/artifacts
1817 docker run -it --mount type=bind,source="$TRAVIS_BUILD_DIR/artifacts",target=/z ziglang/static-base:llvm6-1 -j2 $TRAVIS_COMMIT
19./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-fast18 echo "access_key = $AWS_ACCESS_KEY_ID" >> ~/.s3cfg
20wine zig-cache/test.exe19 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
2120 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
22./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-safe21 touch empty
23wine zig-cache/test.exe22 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)
2423fi
25./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc
26wine64 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
cmake/Findllvm.cmake+1-1
...@@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE...@@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE
15 "c:/msys64/mingw64/bin"15 "c:/msys64/mingw64/bin"
16 "C:/Libraries/llvm-7.0.0/bin")16 "C:/Libraries/llvm-7.0.0/bin")
1717
18if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug"))18if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug") OR ZIG_STATIC)
19 execute_process(19 execute_process(
20 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static20 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static
21 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES21 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES
doc/docgen.zig+1-1
...@@ -55,7 +55,7 @@ pub fn main() !void {...@@ -55,7 +55,7 @@ pub fn main() !void {
55 // TODO issue #70955 // TODO issue #709
56 // disabled to pass CI tests, but obviously we want to implement this56 // disabled to pass CI tests, but obviously we want to implement this
57 // and then remove this workaround57 // and then remove this workaround
58 if (builtin.os == builtin.Os.linux) {58 if (builtin.os != builtin.Os.windows) {
59 os.deleteTree(allocator, tmp_dir_name) catch {};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,18 +2864,18 @@ const err = (error {FileNotFound}).FileNotFound;
2864 assert to make sure the error value is in fact in the destination error set.2864 assert to make sure the error value is in fact in the destination error set.
2865 </p>2865 </p>
2866 <p>2866 <p>
2867 The global error set should generally be avoided when possible, because it prevents2867 The global error set should generally be avoided because it prevents the
2868 the compiler from knowing what errors are possible at compile-time. Knowing2868 compiler from knowing what errors are possible at compile-time. Knowing
2869 the error set at compile-time is better for generated documentationt and for2869 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#}.2870 helpful error messages, such as forgetting a possible error value in a {#link|switch#}.
2871 </p>2871 </p>
2872 {#header_close#}2872 {#header_close#}
2873 {#header_close#}2873 {#header_close#}
2874 {#header_open|Error Union Type#}2874 {#header_open|Error Union Type#}
2875 <p>2875 <p>
2876 Most of the time you will not find yourself using an error set type. Instead,2876 An error set type and normal type can be combined with the <code>!</code>
2877 likely you will be using the error union type. This is when you take an error set2877 binary operator to form an error union type. You are likely to use an
2878 and a normal type, and create an error union with the <code>!</code> binary operator.2878 error union type more often than an error set type by itself.
2879 </p>2879 </p>
2880 <p>2880 <p>
2881 Here is a function to parse a string into a 64-bit integer:2881 Here is a function to parse a string into a 64-bit integer:
...@@ -5739,7 +5739,7 @@ UseDecl = "use" Expression ";"...@@ -5739,7 +5739,7 @@ UseDecl = "use" Expression ";"
57395739
5740ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"5740ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
57415741
5742FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")5742FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("&lt;" Expression "&gt;"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
57435743
5744FnDef = option("inline" | "export") FnProto Block5744FnDef = option("inline" | "export") FnProto Block
57455745
...@@ -5863,7 +5863,9 @@ StructLiteralField = "." Symbol "=" Expression...@@ -5863,7 +5863,9 @@ StructLiteralField = "." Symbol "=" Expression
58635863
5864PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"5864PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
58655865
5866PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl5866PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
5867
5868PromiseType = "promise" option("-&gt;" TypeExpr)
58675869
5868ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr5870ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
58695871
...@@ -6031,4 +6033,3 @@ hljs.registerLanguage("zig", function(t) {...@@ -6031,4 +6033,3 @@ hljs.registerLanguage("zig", function(t) {
6031 </script>6033 </script>
6032 </body>6034 </body>
6033</html>6035</html>
6034
example/guess_number/main.zig+11-11
...@@ -2,7 +2,6 @@ const builtin = @import("builtin");...@@ -2,7 +2,6 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const io = std.io;3const io = std.io;
4const fmt = std.fmt;4const fmt = std.fmt;
5const Rand = std.rand.Rand;
6const os = std.os;5const os = std.os;
76
8pub fn main() !void {7pub fn main() !void {
...@@ -10,30 +9,31 @@ pub fn main() !void {...@@ -10,30 +9,31 @@ pub fn main() !void {
10 var stdout_file_stream = io.FileOutStream.init(&stdout_file);9 var stdout_file_stream = io.FileOutStream.init(&stdout_file);
11 const stdout = &stdout_file_stream.stream;10 const stdout = &stdout_file_stream.stream;
1211
13 var stdin_file = try io.getStdIn();
14
15 try stdout.print("Welcome to the Guess Number Game in Zig.\n");12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");
1613
17 var seed_bytes: [@sizeOf(usize)]u8 = undefined;14 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
18 os.getRandomBytes(seed_bytes[0..]) catch |err| {15 os.getRandomBytes(seed_bytes[0..]) catch |err| {
19 std.debug.warn("unable to seed random number generator: {}", err);16 std.debug.warn("unable to seed random number generator: {}", err);
20 return err;17 return err;
21 };18 };
22 const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big);19 const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
23 var rand = Rand.init(seed);20 var prng = std.rand.DefaultPrng.init(seed);
2421
25 const answer = rand.range(u8, 0, 100) + 1;22 const answer = prng.random.range(u8, 0, 100) + 1;
2623
27 while (true) {24 while (true) {
28 try stdout.print("\nGuess a number between 1 and 100: ");25 try stdout.print("\nGuess a number between 1 and 100: ");
29 var line_buf : [20]u8 = undefined;26 var line_buf : [20]u8 = undefined;
3027
31 const line_len = stdin_file.read(line_buf[0..]) catch |err| {28 const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
32 try stdout.print("Unable to read from stdin: {}\n", @errorName(err));29 error.InputTooLong => {
33 return err;30 try stdout.print("Input too long.\n");
31 continue;
32 },
33 error.EndOfFile, error.StdInUnavailable => return err,
34 };34 };
3535
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 try stdout.print("Invalid number.\n");37 try stdout.print("Invalid number.\n");
38 continue;38 continue;
39 };39 };
src-self-hosted/main.zig+159
...@@ -41,6 +41,10 @@ pub fn main() !void {...@@ -41,6 +41,10 @@ pub fn main() !void {
41 const args = try os.argsAlloc(allocator);41 const args = try os.argsAlloc(allocator);
42 defer os.argsFree(allocator, args);42 defer os.argsFree(allocator, args);
4343
44 if (args.len >= 2 and mem.eql(u8, args[1], "build")) {
45 return buildMain(allocator, args[2..]);
46 }
47
44 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {48 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
45 return fmtMain(allocator, args[2..]);49 return fmtMain(allocator, args[2..]);
46 }50 }
...@@ -560,6 +564,161 @@ fn printZen() !void {...@@ -560,6 +564,161 @@ fn printZen() !void {
560 );564 );
561}565}
562566
567fn 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
563fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {722fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
564 for (file_paths) |file_path| {723 for (file_paths) |file_path| {
565 var file = try os.File.openRead(allocator, file_path);724 var file = try os.File.openRead(allocator, file_path);
src/all_types.hpp+39-2
...@@ -409,6 +409,7 @@ enum NodeType {...@@ -409,6 +409,7 @@ enum NodeType {
409 NodeTypeResume,409 NodeTypeResume,
410 NodeTypeAwaitExpr,410 NodeTypeAwaitExpr,
411 NodeTypeSuspend,411 NodeTypeSuspend,
412 NodeTypePromiseType,
412};413};
413414
414struct AstNodeRoot {415struct AstNodeRoot {
...@@ -879,6 +880,10 @@ struct AstNodeSuspend {...@@ -879,6 +880,10 @@ struct AstNodeSuspend {
879 AstNode *promise_symbol;880 AstNode *promise_symbol;
880};881};
881882
883struct AstNodePromiseType {
884 AstNode *payload_type; // can be NULL
885};
886
882struct AstNode {887struct AstNode {
883 enum NodeType type;888 enum NodeType type;
884 size_t line;889 size_t line;
...@@ -939,6 +944,7 @@ struct AstNode {...@@ -939,6 +944,7 @@ struct AstNode {
939 AstNodeResumeExpr resume_expr;944 AstNodeResumeExpr resume_expr;
940 AstNodeAwaitExpr await_expr;945 AstNodeAwaitExpr await_expr;
941 AstNodeSuspend suspend;946 AstNodeSuspend suspend;
947 AstNodePromiseType promise_type;
942 } data;948 } data;
943};949};
944950
...@@ -1251,7 +1257,10 @@ struct FnTableEntry {...@@ -1251,7 +1257,10 @@ struct FnTableEntry {
1251 ScopeBlock *def_scope; // parent is child_scope1257 ScopeBlock *def_scope; // parent is child_scope
1252 Buf symbol_name;1258 Buf symbol_name;
1253 TypeTableEntry *type_entry; // function type1259 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 bool is_test;1264 bool is_test;
1256 FnInline fn_inline;1265 FnInline fn_inline;
1257 FnAnalState anal_state;1266 FnAnalState anal_state;
...@@ -1612,7 +1621,8 @@ struct CodeGen {...@@ -1612,7 +1621,8 @@ struct CodeGen {
1612 FnTableEntry *panic_fn;1621 FnTableEntry *panic_fn;
1613 LLVMValueRef cur_ret_ptr;1622 LLVMValueRef cur_ret_ptr;
1614 LLVMValueRef cur_fn_val;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 bool c_want_stdint;1626 bool c_want_stdint;
1617 bool c_want_stdbool;1627 bool c_want_stdbool;
1618 AstNode *root_export_decl;1628 AstNode *root_export_decl;
...@@ -1749,6 +1759,7 @@ enum ScopeId {...@@ -1749,6 +1759,7 @@ enum ScopeId {
1749 ScopeIdLoop,1759 ScopeIdLoop,
1750 ScopeIdFnDef,1760 ScopeIdFnDef,
1751 ScopeIdCompTime,1761 ScopeIdCompTime,
1762 ScopeIdCoroPrelude,
1752};1763};
17531764
1754struct Scope {1765struct Scope {
...@@ -1856,6 +1867,12 @@ struct ScopeFnDef {...@@ -1856,6 +1867,12 @@ struct ScopeFnDef {
1856 FnTableEntry *fn_entry;1867 FnTableEntry *fn_entry;
1857};1868};
18581869
1870// This scope is created to indicate that the code in the scope
1871// is auto-generated coroutine prelude stuff.
1872struct ScopeCoroPrelude {
1873 Scope base;
1874};
1875
1859// synchronized with code in define_builtin_compile_vars1876// synchronized with code in define_builtin_compile_vars
1860enum AtomicOrder {1877enum AtomicOrder {
1861 AtomicOrderUnordered,1878 AtomicOrderUnordered,
...@@ -1942,6 +1959,7 @@ enum IrInstructionId {...@@ -1942,6 +1959,7 @@ enum IrInstructionId {
1942 IrInstructionIdSetRuntimeSafety,1959 IrInstructionIdSetRuntimeSafety,
1943 IrInstructionIdSetFloatMode,1960 IrInstructionIdSetFloatMode,
1944 IrInstructionIdArrayType,1961 IrInstructionIdArrayType,
1962 IrInstructionIdPromiseType,
1945 IrInstructionIdSliceType,1963 IrInstructionIdSliceType,
1946 IrInstructionIdAsm,1964 IrInstructionIdAsm,
1947 IrInstructionIdSizeOf,1965 IrInstructionIdSizeOf,
...@@ -2032,6 +2050,8 @@ enum IrInstructionId {...@@ -2032,6 +2050,8 @@ enum IrInstructionId {
2032 IrInstructionIdAtomicRmw,2050 IrInstructionIdAtomicRmw,
2033 IrInstructionIdPromiseResultType,2051 IrInstructionIdPromiseResultType,
2034 IrInstructionIdAwaitBookkeeping,2052 IrInstructionIdAwaitBookkeeping,
2053 IrInstructionIdSaveErrRetAddr,
2054 IrInstructionIdAddImplicitReturnType,
2035};2055};
20362056
2037struct IrInstruction {2057struct IrInstruction {
...@@ -2358,6 +2378,12 @@ struct IrInstructionArrayType {...@@ -2358,6 +2378,12 @@ struct IrInstructionArrayType {
2358 IrInstruction *child_type;2378 IrInstruction *child_type;
2359};2379};
23602380
2381struct IrInstructionPromiseType {
2382 IrInstruction base;
2383
2384 IrInstruction *payload_type;
2385};
2386
2361struct IrInstructionSliceType {2387struct IrInstructionSliceType {
2362 IrInstruction base;2388 IrInstruction base;
23632389
...@@ -2671,6 +2697,7 @@ struct IrInstructionFnProto {...@@ -2671,6 +2697,7 @@ struct IrInstructionFnProto {
2671 IrInstruction **param_types;2697 IrInstruction **param_types;
2672 IrInstruction *align_value;2698 IrInstruction *align_value;
2673 IrInstruction *return_type;2699 IrInstruction *return_type;
2700 IrInstruction *async_allocator_type_value;
2674 bool is_var_args;2701 bool is_var_args;
2675};2702};
26762703
...@@ -2985,6 +3012,16 @@ struct IrInstructionAwaitBookkeeping {...@@ -2985,6 +3012,16 @@ struct IrInstructionAwaitBookkeeping {
2985 IrInstruction *promise_result_type;3012 IrInstruction *promise_result_type;
2986};3013};
29873014
3015struct IrInstructionSaveErrRetAddr {
3016 IrInstruction base;
3017};
3018
3019struct IrInstructionAddImplicitReturnType {
3020 IrInstruction base;
3021
3022 IrInstruction *value;
3023};
3024
2988static const size_t slice_ptr_index = 0;3025static const size_t slice_ptr_index = 0;
2989static const size_t slice_len_index = 1;3026static const size_t slice_len_index = 1;
29903027
src/analyze.cpp+125-17
...@@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) {...@@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) {
170 return &scope->base;170 return &scope->base;
171}171}
172172
173Scope *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
173ImportTableEntry *get_scope_import(Scope *scope) {179ImportTableEntry *get_scope_import(Scope *scope) {
174 while (scope) {180 while (scope) {
175 if (scope->id == ScopeIdDecls) {181 if (scope->id == ScopeIdDecls) {
...@@ -985,7 +991,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -985,7 +991,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
985 // populate the name of the type991 // populate the name of the type
986 buf_resize(&fn_type->name, 0);992 buf_resize(&fn_type->name, 0);
987 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {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 } else {996 } else {
990 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);997 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
991 buf_appendf(&fn_type->name, "%s", cc_str);998 buf_appendf(&fn_type->name, "%s", cc_str);
...@@ -3253,6 +3260,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3253,6 +3260,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3253 case NodeTypeResume:3260 case NodeTypeResume:
3254 case NodeTypeAwaitExpr:3261 case NodeTypeAwaitExpr:
3255 case NodeTypeSuspend:3262 case NodeTypeSuspend:
3263 case NodeTypePromiseType:
3256 zig_unreachable();3264 zig_unreachable();
3257 }3265 }
3258}3266}
...@@ -3590,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {...@@ -3590,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
3590 case ScopeIdCImport:3598 case ScopeIdCImport:
3591 case ScopeIdLoop:3599 case ScopeIdLoop:
3592 case ScopeIdCompTime:3600 case ScopeIdCompTime:
3601 case ScopeIdCoroPrelude:
3593 scope = scope->parent;3602 scope = scope->parent;
3594 continue;3603 continue;
3595 case ScopeIdFnDef:3604 case ScopeIdFnDef:
...@@ -3864,7 +3873,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3864,7 +3873,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38643873
3865 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,3874 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
3866 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);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;
38683877
3869 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {3878 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
3870 assert(g->errors.length > 0);3879 assert(g->errors.length > 0);
...@@ -3876,10 +3885,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3876,10 +3885,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
3876 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;3885 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
3877 if (return_err_set_type->data.error_set.infer_fn != nullptr) {3886 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
3878 TypeTableEntry *inferred_err_set_type;3887 TypeTableEntry *inferred_err_set_type;
3879 if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) {3888 if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) {
3880 inferred_err_set_type = fn_table_entry->implicit_return_type;3889 inferred_err_set_type = fn_table_entry->src_implicit_return_type;
3881 } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) {3890 } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) {
3882 inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type;3891 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
3883 } else {3892 } else {
3884 add_node_error(g, return_type_node,3893 add_node_error(g, return_type_node,
3885 buf_sprintf("function with inferred error set must return at least one possible error"));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,26 +4285,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
4276 return g->win_sdk;4285 return g->win_sdk;
4277}4286}
42784287
4288
4289Buf *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
4315Buf *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
4279void find_libc_include_path(CodeGen *g) {4376void find_libc_include_path(CodeGen *g) {
4280 if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {4377 if (g->libc_include_dir == nullptr) {
4281 ZigWindowsSDK *sdk = get_windows_sdk(g);
42824378
4283 if (g->zig_target.os == OsWindows) {4379 if (g->zig_target.os == OsWindows) {
4380 ZigWindowsSDK *sdk = get_windows_sdk(g);
4381 g->libc_include_dir = buf_alloc();
4284 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {4382 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
4285 zig_panic("Unable to determine libc include path.");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 }
42894394 assert(buf_len(g->libc_include_dir) != 0);
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 }
4294}4395}
42954396
4296void find_libc_lib_path(CodeGen *g) {4397void find_libc_lib_path(CodeGen *g) {
4297 // later we can handle this better by reporting an error via the normal mechanism4398 // 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 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))4400 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
4300 {4401 {
4301 if (g->zig_target.os == OsWindows) {4402 if (g->zig_target.os == OsWindows) {
...@@ -4319,18 +4420,25 @@ void find_libc_lib_path(CodeGen *g) {...@@ -4319,18 +4420,25 @@ void find_libc_lib_path(CodeGen *g) {
4319 g->msvc_lib_dir = vc_lib_dir;4420 g->msvc_lib_dir = vc_lib_dir;
4320 g->libc_lib_dir = ucrt_lib_path;4421 g->libc_lib_dir = ucrt_lib_path;
4321 g->kernel32_lib_dir = kern_lib_path;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 } else {4425 } else {
4323 zig_panic("Unable to determine libc lib path.");4426 zig_panic("Unable to determine libc lib path.");
4324 }4427 }
4428 } else {
4429 assert(buf_len(g->libc_lib_dir) != 0);
4325 }4430 }
43264431
4327 if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {4432 if (g->libc_static_lib_dir == nullptr) {
4328 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {4433 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
4329 return;4434 return;
4330 }4435 } else if (g->zig_target.os == OsLinux) {
4331 else {4436 g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4437 } else {
4332 zig_panic("Unable to determine libc static lib path.");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}
43364444
src/analyze.hpp+1
...@@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);...@@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);
107ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);107ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
108ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);108ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
109Scope *create_comptime_scope(AstNode *node, Scope *parent);109Scope *create_comptime_scope(AstNode *node, Scope *parent);
110Scope *create_coro_prelude_scope(AstNode *node, Scope *parent);
110111
111void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);112void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
112ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);113ConstExprValue *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,6 +250,8 @@ static const char *node_type_str(NodeType node_type) {
250 return "AwaitExpr";250 return "AwaitExpr";
251 case NodeTypeSuspend:251 case NodeTypeSuspend:
252 return "Suspend";252 return "Suspend";
253 case NodeTypePromiseType:
254 return "PromiseType";
253 }255 }
254 zig_unreachable();256 zig_unreachable();
255}257}
...@@ -658,6 +660,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -658,6 +660,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
658 if (node->data.fn_call_expr.is_builtin) {660 if (node->data.fn_call_expr.is_builtin) {
659 fprintf(ar->f, "@");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 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;672 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
662 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);673 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);
663 render_node_extra(ar, fn_ref_node, grouped);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,6 +783,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
772 render_node_ungrouped(ar, node->data.array_type.child_type);783 render_node_ungrouped(ar, node->data.array_type.child_type);
773 break;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 case NodeTypeErrorType:795 case NodeTypeErrorType:
776 fprintf(ar->f, "error");796 fprintf(ar->f, "error");
777 break;797 break;
...@@ -1023,7 +1043,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1023,7 +1043,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1023 case NodeTypeUnwrapErrorExpr:1043 case NodeTypeUnwrapErrorExpr:
1024 {1044 {
1025 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);1045 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
1026 fprintf(ar->f, " %%%% ");1046 fprintf(ar->f, " catch ");
1027 if (node->data.unwrap_err_expr.symbol) {1047 if (node->data.unwrap_err_expr.symbol) {
1028 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;1048 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
1029 fprintf(ar->f, "|%s| ", buf_ptr(var_name));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,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
112 // that's for native compilation112 // that's for native compilation
113 g->zig_target = *target;113 g->zig_target = *target;
114 resolve_target_object_format(&g->zig_target);114 resolve_target_object_format(&g->zig_target);
115 g->dynamic_linker = buf_create_from_str("");115 g->dynamic_linker = nullptr;
116 g->libc_lib_dir = buf_create_from_str("");116 g->libc_lib_dir = nullptr;
117 g->libc_static_lib_dir = buf_create_from_str("");117 g->libc_static_lib_dir = nullptr;
118 g->libc_include_dir = buf_create_from_str("");118 g->libc_include_dir = nullptr;
119 g->msvc_lib_dir = nullptr;119 g->msvc_lib_dir = nullptr;
120 g->kernel32_lib_dir = nullptr;120 g->kernel32_lib_dir = nullptr;
121 g->each_lib_rpath = false;121 g->each_lib_rpath = false;
...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
123 // native compilation, we can rely on the configuration stuff123 // native compilation, we can rely on the configuration stuff
124 g->is_native_target = true;124 g->is_native_target = true;
125 get_native_target(&g->zig_target);125 get_native_target(&g->zig_target);
126 g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);126 g->dynamic_linker = nullptr; // find it at runtime
127 g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);127 g->libc_lib_dir = nullptr; // find it at runtime
128 g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);128 g->libc_static_lib_dir = nullptr; // find it at runtime
129 g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);129 g->libc_include_dir = nullptr; // find it at runtime
130 g->msvc_lib_dir = nullptr; // find it at runtime130 g->msvc_lib_dir = nullptr; // find it at runtime
131 g->kernel32_lib_dir = nullptr; // find it at runtime131 g->kernel32_lib_dir = nullptr; // find it at runtime
132
133#ifdef ZIG_EACH_LIB_RPATH
134 g->each_lib_rpath = true;132 g->each_lib_rpath = true;
135#endif
136133
137 if (g->zig_target.os == OsMacOSX ||134 if (g->zig_target.os == OsMacOSX ||
138 g->zig_target.os == OsIOS)135 g->zig_target.os == OsIOS)
...@@ -657,6 +654,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -657,6 +654,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
657 case ScopeIdDeferExpr:654 case ScopeIdDeferExpr:
658 case ScopeIdLoop:655 case ScopeIdLoop:
659 case ScopeIdCompTime:656 case ScopeIdCompTime:
657 case ScopeIdCoroPrelude:
660 return get_di_scope(g, scope->parent);658 return get_di_scope(g, scope->parent);
661 }659 }
662 zig_unreachable();660 zig_unreachable();
...@@ -1295,9 +1293,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1295,9 +1293,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1295 return fn_val;1293 return fn_val;
1296}1294}
12971295
1298static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {1296static 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
1308static 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
1321static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) {
1299 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);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 if (err_ret_trace_val == nullptr) {1324 if (err_ret_trace_val == nullptr) {
1302 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);1325 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1303 err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);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,32 +1597,25 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1574 return instruction->llvm_value;1597 return instruction->llvm_value;
1575}1598}
15761599
1600static 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
1577static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1615static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1578 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1616 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1579 TypeTableEntry *return_type = return_instruction->value->value.type;1617 TypeTableEntry *return_type = return_instruction->value->value.type;
15801618
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 if (handle_is_ptr(return_type)) {1619 if (handle_is_ptr(return_type)) {
1604 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1620 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1605 assert(g->cur_ret_ptr);1621 assert(g->cur_ret_ptr);
...@@ -2671,7 +2687,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2671,7 +2687,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2671 gen_param_index += 1;2687 gen_param_index += 1;
2672 }2688 }
2673 if (prefix_arg_err_ret_stack) {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 gen_param_index += 1;2691 gen_param_index += 1;
2676 }2692 }
2677 if (instruction->is_async) {2693 if (instruction->is_async) {
...@@ -3238,11 +3254,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -3238,11 +3254,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
3238static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,3254static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
3239 IrInstructionErrorReturnTrace *instruction)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 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);3259 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
3243 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);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}
32473264
3248static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {3265static 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,7 +3665,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
3648 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);3665 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
36493666
3650 LLVMPositionBuilderAtEnd(g->builder, err_block);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);
36523669
3653 LLVMPositionBuilderAtEnd(g->builder, ok_block);3670 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3654 }3671 }
...@@ -3840,7 +3857,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -3840,7 +3857,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
3840}3857}
38413858
3842static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {3859static 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 return nullptr;3861 return nullptr;
3845}3862}
38463863
...@@ -4127,6 +4144,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4127,6 +4144,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4127 case IrInstructionIdSetRuntimeSafety:4144 case IrInstructionIdSetRuntimeSafety:
4128 case IrInstructionIdSetFloatMode:4145 case IrInstructionIdSetFloatMode:
4129 case IrInstructionIdArrayType:4146 case IrInstructionIdArrayType:
4147 case IrInstructionIdPromiseType:
4130 case IrInstructionIdSliceType:4148 case IrInstructionIdSliceType:
4131 case IrInstructionIdSizeOf:4149 case IrInstructionIdSizeOf:
4132 case IrInstructionIdSwitchTarget:4150 case IrInstructionIdSwitchTarget:
...@@ -4167,6 +4185,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4167,6 +4185,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4167 case IrInstructionIdErrorUnion:4185 case IrInstructionIdErrorUnion:
4168 case IrInstructionIdPromiseResultType:4186 case IrInstructionIdPromiseResultType:
4169 case IrInstructionIdAwaitBookkeeping:4187 case IrInstructionIdAwaitBookkeeping:
4188 case IrInstructionIdAddImplicitReturnType:
4170 zig_unreachable();4189 zig_unreachable();
41714190
4172 case IrInstructionIdReturn:4191 case IrInstructionIdReturn:
...@@ -4315,6 +4334,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4315,6 +4334,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4315 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);4334 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
4316 case IrInstructionIdAtomicRmw:4335 case IrInstructionIdAtomicRmw:
4317 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);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 zig_unreachable();4340 zig_unreachable();
4320}4341}
...@@ -5197,9 +5218,17 @@ static void do_code_gen(CodeGen *g) {...@@ -5197,9 +5218,17 @@ static void do_code_gen(CodeGen *g) {
5197 clear_debug_source_node(g);5218 clear_debug_source_node(g);
51985219
5199 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);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) {5221 bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX;
5201 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);5222 if (have_err_ret_trace_arg) {
5202 } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) {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 // TODO call graph analysis to find out what this number needs to be for every function5232 // TODO call graph analysis to find out what this number needs to be for every function
5204 static const size_t stack_trace_ptr_count = 30;5233 static const size_t stack_trace_ptr_count = 30;
52055234
...@@ -5207,13 +5236,13 @@ static void do_code_gen(CodeGen *g) {...@@ -5207,13 +5236,13 @@ static void do_code_gen(CodeGen *g) {
5207 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);5236 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
5208 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",5237 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
5209 get_abi_alignment(g, array_type));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 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;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 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);5242 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
52145243
5215 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;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, "");
52175246
5218 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;5247 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5219 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;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,7 +5258,7 @@ static void do_code_gen(CodeGen *g) {
5229 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");5258 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5230 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));5259 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5231 } else {5260 } else {
5232 g->cur_err_ret_trace_val = nullptr;5261 g->cur_err_ret_trace_val_stack = nullptr;
5233 }5262 }
52345263
5235 // allocate temporary stack data5264 // allocate temporary stack data
...@@ -6172,7 +6201,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package...@@ -6172,7 +6201,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
6172 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6201 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6173 }6202 }
6174 Buf *import_code = buf_alloc();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 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6205 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6177 }6206 }
61786207
...@@ -6260,7 +6289,7 @@ static void gen_root_source(CodeGen *g) {...@@ -6260,7 +6289,7 @@ static void gen_root_source(CodeGen *g) {
6260 }6289 }
62616290
6262 Buf *source_code = buf_alloc();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 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));6293 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6265 }6294 }
62666295
...@@ -6325,7 +6354,7 @@ static void gen_global_asm(CodeGen *g) {...@@ -6325,7 +6354,7 @@ static void gen_global_asm(CodeGen *g) {
6325 int err;6354 int err;
6326 for (size_t i = 0; i < g->assembly_files.length; i += 1) {6355 for (size_t i = 0; i < g->assembly_files.length; i += 1) {
6327 Buf *asm_file = g->assembly_files.at(i);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 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));6358 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
6330 }6359 }
6331 buf_append_buf(&g->global_asm, &contents);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,6 +6536,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
6507 }6536 }
6508 }6537 }
6509 case TypeTableEntryIdStruct:6538 case TypeTableEntryIdStruct:
6539 case TypeTableEntryIdOpaque:
6510 {6540 {
6511 buf_init_from_str(out_buf, "struct ");6541 buf_init_from_str(out_buf, "struct ");
6512 buf_append_buf(out_buf, &type_entry->name);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,11 +6554,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
6524 buf_append_buf(out_buf, &type_entry->name);6554 buf_append_buf(out_buf, &type_entry->name);
6525 return;6555 return;
6526 }6556 }
6527 case TypeTableEntryIdOpaque:
6528 {
6529 buf_init_from_buf(out_buf, &type_entry->name);
6530 return;
6531 }
6532 case TypeTableEntryIdArray:6557 case TypeTableEntryIdArray:
6533 {6558 {
6534 TypeTableEntryArray *array_data = &type_entry->data.array;6559 TypeTableEntryArray *array_data = &type_entry->data.array;
src/config.h.in-8
...@@ -13,14 +13,6 @@...@@ -13,14 +13,6 @@
13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
14#define ZIG_VERSION_STRING "@ZIG_VERSION@"14#define ZIG_VERSION_STRING "@ZIG_VERSION@"
1515
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// Only used for running tests before installing.16// Only used for running tests before installing.
25#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"17#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2618
src/ir.cpp+234-70
...@@ -34,7 +34,7 @@ struct IrAnalyze {...@@ -34,7 +34,7 @@ struct IrAnalyze {
34 size_t old_bb_index;34 size_t old_bb_index;
35 size_t instruction_index;35 size_t instruction_index;
36 TypeTableEntry *explicit_return_type;36 TypeTableEntry *explicit_return_type;
37 ZigList<IrInstruction *> implicit_return_type_list;37 ZigList<IrInstruction *> src_implicit_return_type_list;
38 IrBasicBlock *const_predecessor_bb;38 IrBasicBlock *const_predecessor_bb;
39};39};
4040
...@@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {...@@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
349 return IrInstructionIdArrayType;349 return IrInstructionIdArrayType;
350}350}
351351
352static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {
353 return IrInstructionIdPromiseType;
354}
355
352static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {356static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
353 return IrInstructionIdSliceType;357 return IrInstructionIdSliceType;
354}358}
...@@ -713,6 +717,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping...@@ -713,6 +717,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping
713 return IrInstructionIdAwaitBookkeeping;717 return IrInstructionIdAwaitBookkeeping;
714}718}
715719
720static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
721 return IrInstructionIdSaveErrRetAddr;
722}
723
724static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) {
725 return IrInstructionIdAddImplicitReturnType;
726}
727
716template<typename T>728template<typename T>
717static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {729static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
718 T *special_instruction = allocate<T>(1);730 T *special_instruction = allocate<T>(1);
...@@ -1461,6 +1473,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode...@@ -1461,6 +1473,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
1461 return &instruction->base;1473 return &instruction->base;
1462}1474}
14631475
1476static 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
1464static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1487static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1465 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)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,12 +2164,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
2141}2164}
21422165
2143static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,2166static 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 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);2170 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
2147 instruction->param_types = param_types;2171 instruction->param_types = param_types;
2148 instruction->align_value = align_value;2172 instruction->align_value = align_value;
2149 instruction->return_type = return_type;2173 instruction->return_type = return_type;
2174 instruction->async_allocator_type_value = async_allocator_type_value;
2150 instruction->is_var_args = is_var_args;2175 instruction->is_var_args = is_var_args;
21512176
2152 assert(source_node->type == NodeTypeFnProto);2177 assert(source_node->type == NodeTypeFnProto);
...@@ -2156,6 +2181,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2156,6 +2181,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
2156 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);2181 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
2157 }2182 }
2158 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);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 ir_ref_instruction(return_type, irb->current_basic_block);2185 ir_ref_instruction(return_type, irb->current_basic_block);
21602186
2161 return &instruction->base;2187 return &instruction->base;
...@@ -2675,6 +2701,22 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A...@@ -2675,6 +2701,22 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A
2675 return &instruction->base;2701 return &instruction->base;
2676}2702}
26772703
2704static 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
2709static 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
2678static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2720static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2679 results[ReturnKindUnconditional] = 0;2721 results[ReturnKindUnconditional] = 0;
2680 results[ReturnKindError] = 0;2722 results[ReturnKindError] = 0;
...@@ -2747,16 +2789,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {...@@ -2747,16 +2789,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
2747 return nullptr;2789 return nullptr;
2748}2790}
27492791
2792static 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
2750static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,2797static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
2751 bool is_generated_code)2798 bool is_generated_code)
2752{2799{
2753 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);2800 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
2754 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;2801
2802 bool is_async = exec_is_async(irb->exec);
2755 if (!is_async) {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 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);2804 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
2761 return_inst->is_gen = is_generated_code;2805 return_inst->is_gen = is_generated_code;
2762 return return_inst;2806 return return_inst;
...@@ -2778,21 +2822,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2778,21 +2822,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2778 // the above blocks are rendered by ir_gen after the rest of codegen2822 // the above blocks are rendered by ir_gen after the rest of codegen
2779}2823}
27802824
2781//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {2825static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2782// if (!irb->codegen->have_err_ret_tracing)2826 if (!g->have_err_ret_tracing)
2783// return;2827 return false;
2784//2828 FnTableEntry *fn_entry = exec_fn_entry(exec);
2785// if (is_async) {2829 if (fn_entry == nullptr)
2786// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);2830 return false;
2787// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);2831 if (exec->is_inline)
2788// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);2832 return false;
2789// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);2833 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2790// return;2834}
2791// }2835
2792//2836static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2793// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);2837 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2794// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);2838 return;
2795//}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}
27962852
2797static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2853static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2798 assert(node->type == NodeTypeReturnExpr);2854 assert(node->type == NodeTypeReturnExpr);
...@@ -2853,7 +2909,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2853,7 +2909,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2853 if (have_err_defers) {2909 if (have_err_defers) {
2854 ir_gen_defers_for_block(irb, scope, outer_scope, true);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 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2913 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28582914
2859 ir_set_cursor_at_end_and_append_block(irb, ok_block);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,6 +2948,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2892 ir_set_cursor_at_end_and_append_block(irb, return_block);2948 ir_set_cursor_at_end_and_append_block(irb, return_block);
2893 ir_gen_defers_for_block(irb, scope, outer_scope, true);2949 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2894 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);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 ir_gen_async_return(irb, scope, node, err_val, false);2952 ir_gen_async_return(irb, scope, node, err_val, false);
28962953
2897 ir_set_cursor_at_end_and_append_block(irb, continue_block);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,6 +5089,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
5032 }5089 }
5033}5090}
50345091
5092static 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
5035static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {5108static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
5036 assert(node->type == NodeTypeUndefinedLiteral);5109 assert(node->type == NodeTypeUndefinedLiteral);
5037 return ir_build_const_undefined(irb, scope, node);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,7 +6062,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
5989 return_type = nullptr;6062 return_type = nullptr;
5990 }6063 }
59916064
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}
59946075
5995static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {6076static 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,6 +6313,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
6232 return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);6313 return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
6233 case NodeTypeArrayType:6314 case NodeTypeArrayType:
6234 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);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 case NodeTypeStringLiteral:6318 case NodeTypeStringLiteral:
6236 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);6319 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);
6237 case NodeTypeUndefinedLiteral:6320 case NodeTypeUndefinedLiteral:
...@@ -6329,58 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6329,58 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6329 VariableTableEntry *coro_size_var;6412 VariableTableEntry *coro_size_var;
6330 if (is_async) {6413 if (is_async) {
6331 // create the coro promise6414 // create the coro promise
6332 const_bool_false = ir_build_const_bool(irb, scope, node, false);6415 Scope *coro_scope = create_coro_prelude_scope(node, scope);
6333 VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);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);
63346418
6335 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;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);6420 IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type);
6337 ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init);6421 ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init);
6338 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false);6422 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
63396423
6340 VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);6424 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6341 IrInstruction *null_value = ir_build_const_null(irb, scope, node);6425 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
6342 IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node,6426 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
6343 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));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);6428 ir_build_var_decl(irb, coro_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,6429 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node,
6346 await_handle_var, false, false);6430 await_handle_var, false, false);
63476431
6348 u8_ptr_type = ir_build_const_type(irb, scope, node,6432 u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
6349 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));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);6434 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
6351 coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr);6435 coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
6352 coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);6436 coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6353 IrInstruction *coro_size = ir_build_coro_size(irb, scope, node);6437 IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
6354 ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size);6438 ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
6355 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,6439 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
6356 ImplicitAllocatorIdArg);6440 ImplicitAllocatorIdArg);
6357 irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false);6441 irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_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);6442 ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
6359 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);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);6444 IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
6361 IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);6445 IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
6362 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size);6446 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
6363 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr);6447 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
6364 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");6448 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
6365 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk");6449 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
6366 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);6450 ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
63676451
6368 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);6452 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6369 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);6453 // we can return undefined here, because the caller passes a pointer to the error struct field
6370 ir_build_return(irb, scope, node, undef);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);
63716457
6372 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);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);6459 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_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);6460 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
63756461
6376 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);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 awaiter_handle_field_name);6464 awaiter_handle_field_name);
6379 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);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 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);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);6468 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_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);6469 ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
63846470
63856471
6386 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");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,6 +6481,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6395 return false;6481 return false;
63966482
6397 if (!instr_is_unreachable(result)) {6483 if (!instr_is_unreachable(result)) {
6484 // no need for save_err_ret_addr because this cannot return error
6398 ir_gen_async_return(irb, scope, result->source_node, result, true);6485 ir_gen_async_return(irb, scope, result->source_node, result, true);
6399 }6486 }
64006487
...@@ -10074,13 +10161,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {...@@ -10074,13 +10161,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
10074 return result;10161 return result;
10075}10162}
1007610163
10164static 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
10077static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,10178static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
10078 IrInstructionReturn *return_instruction)10179 IrInstructionReturn *return_instruction)
10079{10180{
10080 IrInstruction *value = return_instruction->value->other;10181 IrInstruction *value = return_instruction->value->other;
10081 if (type_is_invalid(value->value.type))10182 if (type_is_invalid(value->value.type))
10082 return ir_unreach_error(ira);10183 return ir_unreach_error(ira);
10083 ira->implicit_return_type_list.append(value);
1008410184
10085 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);10185 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
10086 if (casted_value == ira->codegen->invalid_instruction)10186 if (casted_value == ira->codegen->invalid_instruction)
...@@ -10958,6 +11058,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *...@@ -10958,6 +11058,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
10958 result_type = get_array_type(ira->codegen, child_type, new_len);11058 result_type = get_array_type(ira->codegen, child_type, new_len);
1095911059
10960 out_array_val = out_val;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 } else {11079 } else {
10962 new_len += 1; // null byte11080 new_len += 1; // null byte
1096311081
...@@ -11453,13 +11571,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -11453,13 +11571,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
11453 return ira->codegen->builtin_types.entry_void;11571 return ira->codegen->builtin_types.entry_void;
11454}11572}
1145511573
11574static 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
11456static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,11579static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11457 IrInstructionErrorReturnTrace *instruction)11580 IrInstructionErrorReturnTrace *instruction)
11458{11581{
11459 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
11460 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11582 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11461 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);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 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11585 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11464 out_val->data.x_maybe = nullptr;11586 out_val->data.x_maybe = nullptr;
11465 return nullable_type;11587 return nullable_type;
...@@ -13999,6 +14121,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -13999,6 +14121,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
13999 zig_unreachable();14121 zig_unreachable();
14000}14122}
1400114123
14124static 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
14002static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,14142static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
14003 IrInstructionSizeOf *size_of_instruction)14143 IrInstructionSizeOf *size_of_instruction)
14004{14144{
...@@ -14569,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi...@@ -14569,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
14569 return ira->codegen->builtin_types.entry_namespace;14709 return ira->codegen->builtin_types.entry_namespace;
14570 }14710 }
1457114711
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 if (err == ErrorFileNotFound) {14713 if (err == ErrorFileNotFound) {
14574 ir_add_error_node(ira, source_node,14714 ir_add_error_node(ira, source_node,
14575 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));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,7 +15570,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
15430 // load from file system into const expr15570 // load from file system into const expr
15431 Buf *file_contents = buf_alloc();15571 Buf *file_contents = buf_alloc();
15432 int err;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 if (err == ErrorFileNotFound) {15574 if (err == ErrorFileNotFound) {
15435 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));15575 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
15436 return ira->codegen->builtin_types.entry_invalid;15576 return ira->codegen->builtin_types.entry_invalid;
...@@ -16561,6 +16701,13 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -16561,6 +16701,13 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
16561 if (type_is_invalid(fn_type_id.return_type))16701 if (type_is_invalid(fn_type_id.return_type))
16562 return ira->codegen->builtin_types.entry_invalid;16702 return ira->codegen->builtin_types.entry_invalid;
1656316703
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 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);16711 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
16565 out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);16712 out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);
16566 return ira->codegen->builtin_types.entry_type;16713 return ira->codegen->builtin_types.entry_type;
...@@ -16789,18 +16936,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,...@@ -16789,18 +16936,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
16789static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {16936static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {
16790 IrInstruction *msg = instruction->msg->other;16937 IrInstruction *msg = instruction->msg->other;
16791 if (type_is_invalid(msg->value.type))16938 if (type_is_invalid(msg->value.type))
16792 return ira->codegen->builtin_types.entry_invalid;16939 return ir_unreach_error(ira);
1679316940
16794 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {16941 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
16795 ir_add_error(ira, &instruction->base, buf_sprintf("encountered @panic at compile-time"));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 }
1679816945
16799 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);16946 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
16800 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);16947 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
16801 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);16948 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
16802 if (type_is_invalid(casted_msg->value.type))16949 if (type_is_invalid(casted_msg->value.type))
16803 return ira->codegen->builtin_types.entry_invalid;16950 return ir_unreach_error(ira);
1680416951
16805 IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope,16952 IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope,
16806 instruction->base.source_node, casted_msg);16953 instruction->base.source_node, casted_msg);
...@@ -17757,6 +17904,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,...@@ -17757,6 +17904,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
17757 return out_val->type;17904 return out_val->type;
17758}17905}
1775917906
17907static 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
17760static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {17915static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17761 switch (instruction->id) {17916 switch (instruction->id) {
17762 case IrInstructionIdInvalid:17917 case IrInstructionIdInvalid:
...@@ -17822,6 +17977,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17822,6 +17977,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17822 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);17977 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
17823 case IrInstructionIdArrayType:17978 case IrInstructionIdArrayType:
17824 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);17979 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
17980 case IrInstructionIdPromiseType:
17981 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
17825 case IrInstructionIdSizeOf:17982 case IrInstructionIdSizeOf:
17826 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);17983 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
17827 case IrInstructionIdTestNonNull:17984 case IrInstructionIdTestNonNull:
...@@ -17994,6 +18151,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17994,6 +18151,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17994 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);18151 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
17995 case IrInstructionIdAwaitBookkeeping:18152 case IrInstructionIdAwaitBookkeeping:
17996 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);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 zig_unreachable();18159 zig_unreachable();
17999}18160}
...@@ -18067,11 +18228,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -18067,11 +18228,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1806718228
18068 if (new_exec->invalid) {18229 if (new_exec->invalid) {
18069 return ira->codegen->builtin_types.entry_invalid;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 return codegen->builtin_types.entry_unreachable;18232 return codegen->builtin_types.entry_unreachable;
18072 } else {18233 } else {
18073 return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,18234 return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items,
18074 ira->implicit_return_type_list.length);18235 ira->src_implicit_return_type_list.length);
18075 }18236 }
18076}18237}
1807718238
...@@ -18119,6 +18280,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18119,6 +18280,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18119 case IrInstructionIdCoroSave:18280 case IrInstructionIdCoroSave:
18120 case IrInstructionIdCoroAllocHelper:18281 case IrInstructionIdCoroAllocHelper:
18121 case IrInstructionIdAwaitBookkeeping:18282 case IrInstructionIdAwaitBookkeeping:
18283 case IrInstructionIdSaveErrRetAddr:
18284 case IrInstructionIdAddImplicitReturnType:
18122 return true;18285 return true;
1812318286
18124 case IrInstructionIdPhi:18287 case IrInstructionIdPhi:
...@@ -18141,6 +18304,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18141,6 +18304,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18141 case IrInstructionIdStructFieldPtr:18304 case IrInstructionIdStructFieldPtr:
18142 case IrInstructionIdUnionFieldPtr:18305 case IrInstructionIdUnionFieldPtr:
18143 case IrInstructionIdArrayType:18306 case IrInstructionIdArrayType:
18307 case IrInstructionIdPromiseType:
18144 case IrInstructionIdSliceType:18308 case IrInstructionIdSliceType:
18145 case IrInstructionIdSizeOf:18309 case IrInstructionIdSizeOf:
18146 case IrInstructionIdTestNonNull:18310 case IrInstructionIdTestNonNull:
src/ir_print.cpp+29-2
...@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {...@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
201 if (call_instruction->is_async) {201 if (call_instruction->is_async) {
202 fprintf(irp->f, "async");202 fprintf(irp->f, "async");
203 if (call_instruction->async_allocator != nullptr) {203 if (call_instruction->async_allocator != nullptr) {
204 fprintf(irp->f, "(");204 fprintf(irp->f, "<");
205 ir_print_other_instruction(irp, call_instruction->async_allocator);205 ir_print_other_instruction(irp, call_instruction->async_allocator);
206 fprintf(irp->f, ")");206 fprintf(irp->f, ">");
207 }207 }
208 fprintf(irp->f, " ");208 fprintf(irp->f, " ");
209 }209 }
...@@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio...@@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
404 ir_print_other_instruction(irp, instruction->child_type);404 ir_print_other_instruction(irp, instruction->child_type);
405}405}
406406
407static 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
407static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {415static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
408 const char *const_kw = instruction->is_const ? "const " : "";416 const char *const_kw = instruction->is_const ? "const " : "";
409 fprintf(irp->f, "[]%s", const_kw);417 fprintf(irp->f, "[]%s", const_kw);
...@@ -1161,6 +1169,16 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi...@@ -1161,6 +1169,16 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi
1161 fprintf(irp->f, ")");1169 fprintf(irp->f, ")");
1162}1170}
11631171
1172static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
1173 fprintf(irp->f, "@saveErrRetAddr()");
1174}
1175
1176static 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
1164static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1182static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1165 ir_print_prefix(irp, instruction);1183 ir_print_prefix(irp, instruction);
1166 switch (instruction->id) {1184 switch (instruction->id) {
...@@ -1253,6 +1271,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1253,6 +1271,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1253 case IrInstructionIdArrayType:1271 case IrInstructionIdArrayType:
1254 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);1272 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
1255 break;1273 break;
1274 case IrInstructionIdPromiseType:
1275 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1276 break;
1256 case IrInstructionIdSliceType:1277 case IrInstructionIdSliceType:
1257 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);1278 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
1258 break;1279 break;
...@@ -1532,6 +1553,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1532,6 +1553,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1532 case IrInstructionIdAwaitBookkeeping:1553 case IrInstructionIdAwaitBookkeeping:
1533 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);1554 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
1534 break;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 fprintf(irp->f, "\n");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,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164 lj->rpath_table.put(rpath, true);164 lj->rpath_table.put(rpath, true);
165}165}
166166
167static 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
191static 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
167static void construct_linker_job_elf(LinkJob *lj) {208static void construct_linker_job_elf(LinkJob *lj) {
168 CodeGen *g = lj->codegen;209 CodeGen *g = lj->codegen;
169210
...@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {
259 lj->args.append(buf_ptr(g->libc_static_lib_dir));300 lj->args.append(buf_ptr(g->libc_static_lib_dir));
260 }301 }
261302
262 if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) {303 if (!g->is_static) {
263 lj->args.append("-dynamic-linker");304 if (g->dynamic_linker != nullptr) {
264 lj->args.append(buf_ptr(g->dynamic_linker));305 assert(buf_len(g->dynamic_linker) != 0);
265 } else {306 lj->args.append("-dynamic-linker");
266 lj->args.append("-dynamic-linker");307 lj->args.append(buf_ptr(g->dynamic_linker));
267 lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target)));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 }
269314
270 if (shared) {315 if (shared) {
...@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
423 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));468 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
424469
425 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));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 }
428475
429 if (lj->link_in_crt) {476 if (lj->link_in_crt) {
src/main.cpp+52-16
...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
23 " build-exe [source] create executable from source or object files\n"23 " build-exe [source] create executable from source or object files\n"
24 " build-lib [source] create library from source or object files\n"24 " build-lib [source] create library from source or object files\n"
25 " build-obj [source] create object from source or assembly\n"25 " build-obj [source] create object from source or assembly\n"
26 " run [source] create executable and run immediately\n"
26 " translate-c [source] convert c code to zig code\n"27 " translate-c [source] convert c code to zig code\n"
27 " targets list available compilation targets\n"28 " targets list available compilation targets\n"
28 " test [source] create and run a test build\n"29 " test [source] create and run a test build\n"
...@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {...@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {
195 }196 }
196 }197 }
197198
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 return ErrorFileNotFound;199 return ErrorFileNotFound;
206}200}
207201
...@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {...@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
227enum Cmd {221enum Cmd {
228 CmdInvalid,222 CmdInvalid,
229 CmdBuild,223 CmdBuild,
224 CmdRun,
230 CmdTest,225 CmdTest,
231 CmdVersion,226 CmdVersion,
232 CmdZen,227 CmdZen,
...@@ -336,6 +331,8 @@ int main(int argc, char **argv) {...@@ -336,6 +331,8 @@ int main(int argc, char **argv) {
336 CliPkg *cur_pkg = allocate<CliPkg>(1);331 CliPkg *cur_pkg = allocate<CliPkg>(1);
337 BuildMode build_mode = BuildModeDebug;332 BuildMode build_mode = BuildModeDebug;
338 ZigList<const char *> test_exec_args = {0};333 ZigList<const char *> test_exec_args = {0};
334 int comptime_args_end = 0;
335 int runtime_args_start = argc;
339336
340 if (argc >= 2 && strcmp(argv[1], "build") == 0) {337 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
341 const char *zig_exe_path = arg0;338 const char *zig_exe_path = arg0;
...@@ -452,10 +449,11 @@ int main(int argc, char **argv) {...@@ -452,10 +449,11 @@ int main(int argc, char **argv) {
452449
453 if ((err = os_copy_file(build_template_path, &build_file_abs))) {450 if ((err = os_copy_file(build_template_path, &build_file_abs))) {
454 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));451 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));
452 return EXIT_FAILURE;
455 } else {453 } else {
456 fprintf(stderr, "Wrote build.zig template\n");454 fprintf(stderr, "Wrote build.zig template\n");
455 return EXIT_SUCCESS;
457 }456 }
458 return EXIT_SUCCESS;
459 }457 }
460458
461 fprintf(stderr,459 fprintf(stderr,
...@@ -487,11 +485,15 @@ int main(int argc, char **argv) {...@@ -487,11 +485,15 @@ int main(int argc, char **argv) {
487 return (term.how == TerminationIdClean) ? term.code : -1;485 return (term.how == TerminationIdClean) ? term.code : -1;
488 }486 }
489487
490 for (int i = 1; i < argc; i += 1) {488 for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
491 char *arg = argv[i];489 char *arg = argv[i];
492490
493 if (arg[0] == '-') {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 build_mode = BuildModeFastRelease;497 build_mode = BuildModeFastRelease;
496 } else if (strcmp(arg, "--release-safe") == 0) {498 } else if (strcmp(arg, "--release-safe") == 0) {
497 build_mode = BuildModeSafeRelease;499 build_mode = BuildModeSafeRelease;
...@@ -658,6 +660,9 @@ int main(int argc, char **argv) {...@@ -658,6 +660,9 @@ int main(int argc, char **argv) {
658 } else if (strcmp(arg, "build-lib") == 0) {660 } else if (strcmp(arg, "build-lib") == 0) {
659 cmd = CmdBuild;661 cmd = CmdBuild;
660 out_type = OutTypeLib;662 out_type = OutTypeLib;
663 } else if (strcmp(arg, "run") == 0) {
664 cmd = CmdRun;
665 out_type = OutTypeExe;
661 } else if (strcmp(arg, "version") == 0) {666 } else if (strcmp(arg, "version") == 0) {
662 cmd = CmdVersion;667 cmd = CmdVersion;
663 } else if (strcmp(arg, "zen") == 0) {668 } else if (strcmp(arg, "zen") == 0) {
...@@ -676,6 +681,7 @@ int main(int argc, char **argv) {...@@ -676,6 +681,7 @@ int main(int argc, char **argv) {
676 } else {681 } else {
677 switch (cmd) {682 switch (cmd) {
678 case CmdBuild:683 case CmdBuild:
684 case CmdRun:
679 case CmdTranslateC:685 case CmdTranslateC:
680 case CmdTest:686 case CmdTest:
681 if (!in_file) {687 if (!in_file) {
...@@ -730,8 +736,8 @@ int main(int argc, char **argv) {...@@ -730,8 +736,8 @@ int main(int argc, char **argv) {
730 }736 }
731 }737 }
732738
733
734 switch (cmd) {739 switch (cmd) {
740 case CmdRun:
735 case CmdBuild:741 case CmdBuild:
736 case CmdTranslateC:742 case CmdTranslateC:
737 case CmdTest:743 case CmdTest:
...@@ -739,7 +745,7 @@ int main(int argc, char **argv) {...@@ -739,7 +745,7 @@ int main(int argc, char **argv) {
739 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {745 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
740 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");746 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
741 return usage(arg0);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 fprintf(stderr, "Expected source file argument.\n");749 fprintf(stderr, "Expected source file argument.\n");
744 return usage(arg0);750 return usage(arg0);
745 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {751 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
...@@ -751,6 +757,10 @@ int main(int argc, char **argv) {...@@ -751,6 +757,10 @@ int main(int argc, char **argv) {
751757
752 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);758 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
753759
760 if (cmd == CmdRun) {
761 out_name = "run";
762 }
763
754 Buf *in_file_buf = nullptr;764 Buf *in_file_buf = nullptr;
755765
756 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :766 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
...@@ -775,9 +785,23 @@ int main(int argc, char **argv) {...@@ -775,9 +785,23 @@ int main(int argc, char **argv) {
775 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;785 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
776786
777 Buf *full_cache_dir = buf_alloc();787 Buf *full_cache_dir = buf_alloc();
778 os_path_resolve(buf_create_from_str("."),788 Buf *run_exec_path = buf_alloc();
779 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),789 if (cmd == CmdRun) {
780 full_cache_dir);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 }
781805
782 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
783807
...@@ -861,7 +885,7 @@ int main(int argc, char **argv) {...@@ -861,7 +885,7 @@ int main(int argc, char **argv) {
861885
862 add_package(g, cur_pkg, g->root_package);886 add_package(g, cur_pkg, g->root_package);
863887
864 if (cmd == CmdBuild) {888 if (cmd == CmdBuild || cmd == CmdRun) {
865 codegen_set_emit_file_type(g, emit_file_type);889 codegen_set_emit_file_type(g, emit_file_type);
866890
867 for (size_t i = 0; i < objects.length; i += 1) {891 for (size_t i = 0; i < objects.length; i += 1) {
...@@ -874,6 +898,18 @@ int main(int argc, char **argv) {...@@ -874,6 +898,18 @@ int main(int argc, char **argv) {
874 codegen_link(g, out_file);898 codegen_link(g, out_file);
875 if (timing_info)899 if (timing_info)
876 codegen_print_timing_report(g, stdout);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 return EXIT_SUCCESS;913 return EXIT_SUCCESS;
878 } else if (cmd == CmdTranslateC) {914 } else if (cmd == CmdTranslateC) {
879 codegen_translate_c(g, in_file_buf);915 codegen_translate_c(g, in_file_buf);
src/os.cpp+90-11
...@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;...@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;
45#if defined(__MACH__)45#if defined(__MACH__)
46#include <mach/clock.h>46#include <mach/clock.h>
47#include <mach/mach.h>47#include <mach/mach.h>
48#include <mach-o/dyld.h>
48#endif49#endif
4950
50#if defined(ZIG_OS_WINDOWS)51#if defined(ZIG_OS_WINDOWS)
...@@ -57,10 +58,6 @@ static clock_serv_t cclock;...@@ -57,10 +58,6 @@ static clock_serv_t cclock;
57#include <errno.h>58#include <errno.h>
58#include <time.h>59#include <time.h>
5960
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#if defined(ZIG_OS_POSIX)61#if defined(ZIG_OS_POSIX)
65static void populate_termination(Termination *term, int status) {62static void populate_termination(Termination *term, int status) {
66 if (WIFEXITED(status)) {63 if (WIFEXITED(status)) {
...@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {...@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
291 return;288 return;
292}289}
293290
294int os_fetch_file(FILE *f, Buf *out_buf) {291int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
295 static const ssize_t buf_size = 0x2000;292 static const ssize_t buf_size = 0x2000;
296 buf_resize(out_buf, buf_size);293 buf_resize(out_buf, buf_size);
297 ssize_t actual_buf_len = 0;294 ssize_t actual_buf_len = 0;
295
296 bool first_read = true;
297
298 for (;;) {298 for (;;) {
299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
300 actual_buf_len += amt_read;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 if (amt_read != buf_size) {324 if (amt_read != buf_size) {
302 if (feof(f)) {325 if (feof(f)) {
303 buf_resize(out_buf, actual_buf_len);326 buf_resize(out_buf, actual_buf_len);
...@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {...@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
308 }331 }
309332
310 buf_resize(out_buf, actual_buf_len + buf_size);333 buf_resize(out_buf, actual_buf_len + buf_size);
334 first_read = false;
311 }335 }
312 zig_unreachable();336 zig_unreachable();
313}337}
...@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,...@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
377401
378 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");402 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
379 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");403 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
380 os_fetch_file(stdout_f, out_stdout);404 os_fetch_file(stdout_f, out_stdout, false);
381 os_fetch_file(stderr_f, out_stderr);405 os_fetch_file(stderr_f, out_stderr, false);
382406
383 fclose(stdout_f);407 fclose(stdout_f);
384 fclose(stderr_f);408 fclose(stderr_f);
...@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {...@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
591 }615 }
592}616}
593617
594int os_fetch_file_path(Buf *full_path, Buf *out_contents) {618int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
595 FILE *f = fopen(buf_ptr(full_path), "rb");619 FILE *f = fopen(buf_ptr(full_path), "rb");
596 if (!f) {620 if (!f) {
597 switch (errno) {621 switch (errno) {
...@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {...@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
610 return ErrorFileSystem;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 fclose(f);638 fclose(f);
615 return result;639 return result;
616}640}
...@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {...@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
783#endif807#endif
784}808}
785809
810#if defined(ZIG_OS_POSIX)
811int 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)
830int 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
786int os_delete_file(Buf *path) {848int os_delete_file(Buf *path) {
787 if (remove(buf_ptr(path))) {849 if (remove(buf_ptr(path))) {
788 return ErrorFileSystem;850 return ErrorFileSystem;
...@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {...@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {
927 }989 }
928990
929#elif defined(ZIG_OS_DARWIN)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#elif defined(ZIG_OS_LINUX)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#endif1012#endif
934 return ErrorFileNotFound;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,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);
51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
52bool os_path_is_absolute(Buf *path);52bool os_path_is_absolute(Buf *path);
5353
54int os_get_global_cache_directory(Buf *out_tmp_path);
55
54int os_make_path(Buf *path);56int os_make_path(Buf *path);
55int os_make_dir(Buf *path);57int os_make_dir(Buf *path);
5658
57void os_write_file(Buf *full_path, Buf *contents);59void os_write_file(Buf *full_path, Buf *contents);
58int os_copy_file(Buf *src_path, Buf *dest_path);60int os_copy_file(Buf *src_path, Buf *dest_path);
5961
60int os_fetch_file(FILE *file, Buf *out_contents);62int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
61int os_fetch_file_path(Buf *full_path, Buf *out_contents);63int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
6264
63int os_get_cwd(Buf *out_cwd);65int os_get_cwd(Buf *out_cwd);
6466
src/parser.cpp+82-58
...@@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b...@@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
705}705}
706706
707/*707/*
708PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl708PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
709KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"709KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
710ErrorSetDecl = "error" "{" list(Symbol, ",") "}"710ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
711*/711*/
...@@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo...@@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
774 AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);774 AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);
775 *token_index += 1;775 *token_index += 1;
776 return node;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 } else if (token->id == TokenIdKeywordError) {786 } else if (token->id == TokenIdKeywordError) {
778 Token *next_token = &pc->tokens->at(*token_index + 1);787 Token *next_token = &pc->tokens->at(*token_index + 1);
779 if (next_token->id == TokenIdLBrace) {788 if (next_token->id == TokenIdLBrace) {
...@@ -955,6 +964,66 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde...@@ -955,6 +964,66 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
955 }964 }
956}965}
957966
967static 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/*
959SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)1028SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
960FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)1029FnCallExpression : 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,6 +1048,11 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
979 }1048 }
9801049
981 Token *fncall_token = &pc->tokens->at(*token_index);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 AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true);1056 AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true);
983 if (node->type != NodeTypeFnCallExpr) {1057 if (node->type != NodeTypeFnCallExpr) {
984 ast_error(pc, fncall_token, "expected function call, found '%s'", token_name(fncall_token->id));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,9 +2508,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
2434 } else if (first_token->id == TokenIdKeywordAsync) {2508 } else if (first_token->id == TokenIdKeywordAsync) {
2435 *token_index += 1;2509 *token_index += 1;
2436 Token *next_token = &pc->tokens->at(*token_index);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 async_allocator_type_node = ast_parse_type_expr(pc, token_index, true);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 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);2516 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2442 cc = CallingConventionAsync;2517 cc = CallingConventionAsync;
...@@ -2470,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m...@@ -2470,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
2470 return nullptr;2545 return nullptr;
2471 }2546 }
24722547
2473 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);2548 return ast_parse_fn_proto_partial(pc, token_index, fn_token, async_allocator_type_node, cc, is_extern, visib_mod);
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;
2528}2549}
25292550
2530/*2551/*
...@@ -3069,6 +3090,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -3069,6 +3090,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3069 visit_field(&node->data.array_type.child_type, visit, context);3090 visit_field(&node->data.array_type.child_type, visit, context);
3070 visit_field(&node->data.array_type.align_expr, visit, context);3091 visit_field(&node->data.array_type.align_expr, visit, context);
3071 break;3092 break;
3093 case NodeTypePromiseType:
3094 visit_field(&node->data.promise_type.payload_type, visit, context);
3095 break;
3072 case NodeTypeErrorType:3096 case NodeTypeErrorType:
3073 // none3097 // none
3074 break;3098 break;
src/parser.hpp-1
...@@ -16,7 +16,6 @@ ATTRIBUTE_PRINTF(2, 3)...@@ -16,7 +16,6 @@ ATTRIBUTE_PRINTF(2, 3)
16void ast_token_error(Token *token, const char *format, ...);16void ast_token_error(Token *token, const char *format, ...);
1717
1818
19// This function is provided by generated code, generated by parsergen.cpp
20AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);19AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
2120
22void ast_print(AstNode *node, int indent);21void ast_print(AstNode *node, int indent);
src/target.cpp+4
...@@ -862,6 +862,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {...@@ -862,6 +862,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {
862 env == ZigLLVM_GNUX32)862 env == ZigLLVM_GNUX32)
863 {863 {
864 return buf_create_from_str("/libx32/ld-linux-x32.so.2");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 } else {869 } else {
866 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");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,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = {
135 {"null", TokenIdKeywordNull},135 {"null", TokenIdKeywordNull},
136 {"or", TokenIdKeywordOr},136 {"or", TokenIdKeywordOr},
137 {"packed", TokenIdKeywordPacked},137 {"packed", TokenIdKeywordPacked},
138 {"promise", TokenIdKeywordPromise},
138 {"pub", TokenIdKeywordPub},139 {"pub", TokenIdKeywordPub},
139 {"resume", TokenIdKeywordResume},140 {"resume", TokenIdKeywordResume},
140 {"return", TokenIdKeywordReturn},141 {"return", TokenIdKeywordReturn},
...@@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) {...@@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) {
1558 case TokenIdKeywordNull: return "null";1559 case TokenIdKeywordNull: return "null";
1559 case TokenIdKeywordOr: return "or";1560 case TokenIdKeywordOr: return "or";
1560 case TokenIdKeywordPacked: return "packed";1561 case TokenIdKeywordPacked: return "packed";
1562 case TokenIdKeywordPromise: return "promise";
1561 case TokenIdKeywordPub: return "pub";1563 case TokenIdKeywordPub: return "pub";
1562 case TokenIdKeywordReturn: return "return";1564 case TokenIdKeywordReturn: return "return";
1563 case TokenIdKeywordSection: return "section";1565 case TokenIdKeywordSection: return "section";
src/tokenizer.hpp+1
...@@ -76,6 +76,7 @@ enum TokenId {...@@ -76,6 +76,7 @@ enum TokenId {
76 TokenIdKeywordNull,76 TokenIdKeywordNull,
77 TokenIdKeywordOr,77 TokenIdKeywordOr,
78 TokenIdKeywordPacked,78 TokenIdKeywordPacked,
79 TokenIdKeywordPromise,
79 TokenIdKeywordPub,80 TokenIdKeywordPub,
80 TokenIdKeywordResume,81 TokenIdKeywordResume,
81 TokenIdKeywordReturn,82 TokenIdKeywordReturn,
std/c/darwin.zig+10
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1extern "c" fn __error() &c_int;1extern "c" fn __error() &c_int;
2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
33
4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
45
5pub use @import("../os/darwin_errno.zig");6pub use @import("../os/darwin_errno.zig");
67
...@@ -45,3 +46,12 @@ pub const Sigaction = extern struct {...@@ -45,3 +46,12 @@ pub const Sigaction = extern struct {
45 sa_mask: sigset_t,46 sa_mask: sigset_t,
46 sa_flags: c_int,47 sa_flags: c_int,
47};48};
49
50pub 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,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o
44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
47pub extern "c" fn rmdir(path: &const u8) c_int;
4748
48pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;49pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
49pub extern "c" fn malloc(usize) ?&c_void;50pub 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,7 +84,7 @@ fn Blake2s(comptime out_len: usize) type { return struct {
84 }84 }
8585
86 // Full middle blocks.86 // Full middle blocks.
87 while (off + 64 < b.len) : (off += 64) {87 while (off + 64 <= b.len) : (off += 64) {
88 d.t += 64;88 d.t += 64;
89 d.round(b[off..off + 64], false);89 d.round(b[off..off + 64], false);
90 }90 }
...@@ -229,6 +229,15 @@ test "blake2s256 streaming" {...@@ -229,6 +229,15 @@ test "blake2s256 streaming" {
229 htest.assertEqual(h2, out[0..]);229 htest.assertEqual(h2, out[0..]);
230}230}
231231
232test "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
232241
233/////////////////////242/////////////////////
234// Blake2b243// Blake2b
...@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {...@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {
305 }314 }
306315
307 // Full middle blocks.316 // Full middle blocks.
308 while (off + 128 < b.len) : (off += 128) {317 while (off + 128 <= b.len) : (off += 128) {
309 d.t += 128;318 d.t += 128;
310 d.round(b[off..off + 128], false);319 d.round(b[off..off + 128], false);
311 }320 }
...@@ -447,3 +456,12 @@ test "blake2b512 streaming" {...@@ -447,3 +456,12 @@ test "blake2b512 streaming" {
447 h.final(out[0..]);456 h.final(out[0..]);
448 htest.assertEqual(h2, out[0..]);457 htest.assertEqual(h2, out[0..]);
449}458}
459
460test "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 @@
1const std = @import("../index.zig");
2const crypto = std.crypto;
3const debug = std.debug;
4const mem = std.mem;
5
6pub const HmacMd5 = Hmac(crypto.Md5);
7pub const HmacSha1 = Hmac(crypto.Sha1);
8pub const HmacSha256 = Hmac(crypto.Sha256);
9
10pub 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
54const htest = @import("test.zig");
55
56test "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
65test "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
74test "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,10 +19,16 @@ pub const Blake2s256 = blake2.Blake2s256;
19pub const Blake2b384 = blake2.Blake2b384;19pub const Blake2b384 = blake2.Blake2b384;
20pub const Blake2b512 = blake2.Blake2b512;20pub const Blake2b512 = blake2.Blake2b512;
2121
22const hmac = @import("hmac.zig");
23pub const HmacMd5 = hmac.HmacMd5;
24pub const HmacSha1 = hmac.Sha1;
25pub const HmacSha256 = hmac.Sha256;
26
22test "crypto" {27test "crypto" {
23 _ = @import("md5.zig");28 _ = @import("md5.zig");
24 _ = @import("sha1.zig");29 _ = @import("sha1.zig");
25 _ = @import("sha2.zig");30 _ = @import("sha2.zig");
26 _ = @import("sha3.zig");31 _ = @import("sha3.zig");
27 _ = @import("blake2.zig");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,7 +59,7 @@ pub const Md5 = struct {
59 }59 }
6060
61 // Full middle blocks.61 // Full middle blocks.
62 while (off + 64 < b.len) : (off += 64) {62 while (off + 64 <= b.len) : (off += 64) {
63 d.round(b[off..off + 64]);63 d.round(b[off..off + 64]);
64 }64 }
6565
...@@ -253,3 +253,12 @@ test "md5 streaming" {...@@ -253,3 +253,12 @@ test "md5 streaming" {
253253
254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
255}255}
256
257test "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,7 +60,7 @@ pub const Sha1 = struct {
60 }60 }
6161
62 // Full middle blocks.62 // Full middle blocks.
63 while (off + 64 < b.len) : (off += 64) {63 while (off + 64 <= b.len) : (off += 64) {
64 d.round(b[off..off + 64]);64 d.round(b[off..off + 64]);
65 }65 }
6666
...@@ -284,3 +284,12 @@ test "sha1 streaming" {...@@ -284,3 +284,12 @@ test "sha1 streaming" {
284 h.final(out[0..]);284 h.final(out[0..]);
285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
286}286}
287
288test "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,7 +105,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { return struct {
105 }105 }
106106
107 // Full middle blocks.107 // Full middle blocks.
108 while (off + 64 < b.len) : (off += 64) {108 while (off + 64 <= b.len) : (off += 64) {
109 d.round(b[off..off + 64]);109 d.round(b[off..off + 64]);
110 }110 }
111111
...@@ -319,6 +319,15 @@ test "sha256 streaming" {...@@ -319,6 +319,15 @@ test "sha256 streaming" {
319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
320}320}
321321
322test "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
322331
323/////////////////////332/////////////////////
324// Sha384 + Sha512333// Sha384 + Sha512
...@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {...@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {
420 }429 }
421430
422 // Full middle blocks.431 // Full middle blocks.
423 while (off + 128 < b.len) : (off += 128) {432 while (off + 128 <= b.len) : (off += 128) {
424 d.round(b[off..off + 128]);433 d.round(b[off..off + 128]);
425 }434 }
426435
...@@ -669,3 +678,12 @@ test "sha512 streaming" {...@@ -669,3 +678,12 @@ test "sha512 streaming" {
669 h.final(out[0..]);678 h.final(out[0..]);
670 htest.assertEqual(h2, out[0..]);679 htest.assertEqual(h2, out[0..]);
671}680}
681
682test "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,6 +217,15 @@ test "sha3-256 streaming" {
217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);
218}218}
219219
220test "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
220test "sha3-384 single" {229test "sha3-384 single" {
221 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";230 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
222 htest.assertEqualHash(Sha3_384, h1 , "");231 htest.assertEqualHash(Sha3_384, h1 , "");
...@@ -278,3 +287,12 @@ test "sha3-512 streaming" {...@@ -278,3 +287,12 @@ test "sha3-512 streaming" {
278 h.final(out[0..]);287 h.final(out[0..]);
279 htest.assertEqual(h2, out[0..]);288 htest.assertEqual(h2, out[0..]);
280}289}
290
291test "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,7 +26,7 @@ pub const math = @import("math/index.zig");
26pub const mem = @import("mem.zig");26pub const mem = @import("mem.zig");
27pub const net = @import("net.zig");27pub const net = @import("net.zig");
28pub const os = @import("os/index.zig");28pub const os = @import("os/index.zig");
29pub const rand = @import("rand.zig");29pub const rand = @import("rand/index.zig");
30pub const sort = @import("sort.zig");30pub const sort = @import("sort.zig");
31pub const unicode = @import("unicode.zig");31pub const unicode = @import("unicode.zig");
32pub const zig = @import("zig/index.zig");32pub const zig = @import("zig/index.zig");
...@@ -58,7 +58,7 @@ test "std" {...@@ -58,7 +58,7 @@ test "std" {
58 _ = @import("heap.zig");58 _ = @import("heap.zig");
59 _ = @import("net.zig");59 _ = @import("net.zig");
60 _ = @import("os/index.zig");60 _ = @import("os/index.zig");
61 _ = @import("rand.zig");61 _ = @import("rand/index.zig");
62 _ = @import("sort.zig");62 _ = @import("sort.zig");
63 _ = @import("unicode.zig");63 _ = @import("unicode.zig");
64 _ = @import("zig/index.zig");64 _ = @import("zig/index.zig");
std/io.zig+21-4
...@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {
144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
145 /// read from the stream so far are lost.145 /// read from the stream so far are lost.
146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
147 try buf.resize(0);147 try buffer.resize(0);
148148
149 while (true) {149 while (true) {
150 var byte: u8 = try self.readByte();150 var byte: u8 = try self.readByte();
...@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {...@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {
153 return;153 return;
154 }154 }
155155
156 if (buf.len() == max_size) {156 if (buffer.len() == max_size) {
157 return error.StreamTooLong;157 return error.StreamTooLong;
158 }158 }
159159
160 try buf.appendByte(byte);160 try buffer.appendByte(byte);
161 }161 }
162 }162 }
163163
...@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {
171 var buf = Buffer.initNull(allocator);171 var buf = Buffer.initNull(allocator);
172 defer buf.deinit();172 defer buf.deinit();
173173
174 try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);174 try self.readUntilDelimiterBuffer(&buf, delimiter, max_size);
175 return buf.toOwnedSlice();175 return buf.toOwnedSlice();
176 }176 }
177177
...@@ -478,3 +478,20 @@ test "import io tests" {...@@ -478,3 +478,20 @@ test "import io tests" {
478 }478 }
479}479}
480480
481pub 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,7 +1,7 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const io = std.io;2const io = std.io;
3const allocator = std.debug.global_allocator;3const allocator = std.debug.global_allocator;
4const Rand = std.rand.Rand;4const DefaultPrng = std.rand.DefaultPrng;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const mem = std.mem;6const mem = std.mem;
7const os = std.os;7const os = std.os;
...@@ -9,8 +9,8 @@ const builtin = @import("builtin");...@@ -9,8 +9,8 @@ const builtin = @import("builtin");
99
10test "write a file, read it, then delete it" {10test "write a file, read it, then delete it" {
11 var data: [1024]u8 = undefined;11 var data: [1024]u8 = undefined;
12 var rng = Rand.init(1234);12 var prng = DefaultPrng.init(1234);
13 rng.fillBytes(data[0..]);13 prng.random.bytes(data[0..]);
14 const tmp_file_name = "temp_test_file.txt";14 const tmp_file_name = "temp_test_file.txt";
15 {15 {
16 var file = try os.File.openWrite(allocator, tmp_file_name);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,15 +515,28 @@ test "math.negateCast" {
515515
516/// Cast an integer to a different integer type. If the value doesn't fit, 516/// Cast an integer to a different integer type. If the value doesn't fit,
517/// return an error.517/// return an error.
518pub fn cast(comptime T: type, x: var) !T {518pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
519 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer519 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 return error.Overflow;524 return error.Overflow;
522 } else {525 } else {
523 return T(x);526 return T(x);
524 }527 }
525}528}
526529
530test "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
527pub fn floorPowerOfTwo(comptime T: type, value: T) T {540pub fn floorPowerOfTwo(comptime T: type, value: T) T {
528 var x = value;541 var x = value;
529542
std/os/child_process.zig-35
...@@ -13,8 +13,6 @@ const builtin = @import("builtin");...@@ -13,8 +13,6 @@ const builtin = @import("builtin");
13const Os = builtin.Os;13const Os = builtin.Os;
14const LinkedList = std.LinkedList;14const LinkedList = std.LinkedList;
1515
16var children_nodes = LinkedList(&ChildProcess).init();
17
18const is_windows = builtin.os == Os.windows;16const is_windows = builtin.os == Os.windows;
1917
20pub const ChildProcess = struct {18pub const ChildProcess = struct {
...@@ -296,8 +294,6 @@ pub const ChildProcess = struct {...@@ -296,8 +294,6 @@ pub const ChildProcess = struct {
296 }294 }
297295
298 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {296 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
299 children_nodes.remove(&self.llnode);
300
301 defer {297 defer {
302 os.close(self.err_pipe[0]);298 os.close(self.err_pipe[0]);
303 os.close(self.err_pipe[1]);299 os.close(self.err_pipe[1]);
...@@ -427,9 +423,6 @@ pub const ChildProcess = struct {...@@ -427,9 +423,6 @@ pub const ChildProcess = struct {
427 self.llnode = LinkedList(&ChildProcess).Node.init(self);423 self.llnode = LinkedList(&ChildProcess).Node.init(self);
428 self.term = null;424 self.term = null;
429425
430 // TODO make this atomic so it works even with threads
431 children_nodes.prepend(&self.llnode);
432
433 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }426 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
434 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }427 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
435 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }428 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
...@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {...@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {
773 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;766 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;
774 return mem.readInt(bytes[0..], ErrInt, builtin.endian);767 return mem.readInt(bytes[0..], ErrInt, builtin.endian);
775}768}
776
777extern 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
795fn 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,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks
56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
5858
59pub const O_ACCMODE = 3;
60pub const O_ALERT = 536870912;
61pub const O_ASYNC = 64;
62pub const O_DIRECTORY = 1048576;
63pub const O_DP_GETRAWENCRYPTED = 1;
64pub const O_DP_GETRAWUNENCRYPTED = 2;
65pub const O_DSYNC = 4194304;
66pub const O_FSYNC = O_SYNC;
67pub const O_NOCTTY = 131072;
68pub const O_POPUP = 2147483648;
69pub const O_SYNC = 128;
70
59pub const SEEK_SET = 0x0;71pub const SEEK_SET = 0x0;
60pub const SEEK_CUR = 0x1;72pub const SEEK_CUR = 0x1;
61pub const SEEK_END = 0x2;73pub const SEEK_END = 0x2;
6274
75pub const DT_UNKNOWN = 0;
76pub const DT_FIFO = 1;
77pub const DT_CHR = 2;
78pub const DT_DIR = 4;
79pub const DT_BLK = 6;
80pub const DT_REG = 8;
81pub const DT_LNK = 10;
82pub const DT_SOCK = 12;
83pub const DT_WHT = 14;
84
63pub const SIG_BLOCK = 1; /// block specified signal set85pub const SIG_BLOCK = 1; /// block specified signal set
64pub const SIG_UNBLOCK = 2; /// unblock specified signal set86pub const SIG_UNBLOCK = 2; /// unblock specified signal set
65pub const SIG_SETMASK = 3; /// set specified signal set87pub const SIG_SETMASK = 3; /// set specified signal set
...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {
192 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));214 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
193}215}
194216
217
218pub 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
195pub fn mkdir(path: &const u8, mode: u32) usize {222pub fn mkdir(path: &const u8, mode: u32) usize {
196 return errnoWrap(c.mkdir(path, mode));223 return errnoWrap(c.mkdir(path, mode));
197}224}
...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {
204 return errnoWrap(c.rename(old, new));231 return errnoWrap(c.rename(old, new));
205}232}
206233
234pub fn rmdir(path: &const u8) usize {
235 return errnoWrap(c.rmdir(path));
236}
237
207pub fn chdir(path: &const u8) usize {238pub fn chdir(path: &const u8) usize {
208 return errnoWrap(c.chdir(path));239 return errnoWrap(c.chdir(path));
209}240}
...@@ -268,6 +299,7 @@ pub const empty_sigset = sigset_t(0);...@@ -268,6 +299,7 @@ pub const empty_sigset = sigset_t(0);
268299
269pub const timespec = c.timespec;300pub const timespec = c.timespec;
270pub const Stat = c.Stat;301pub const Stat = c.Stat;
302pub const dirent = c.dirent;
271303
272/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.304/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
273pub const Sigaction = struct {305pub const Sigaction = struct {
std/os/file.zig+1-1
...@@ -233,7 +233,7 @@ pub const File = struct {...@@ -233,7 +233,7 @@ pub const File = struct {
233 Unexpected,233 Unexpected,
234 };234 };
235235
236 fn mode(self: &File) ModeError!FileMode {236 fn mode(self: &File) ModeError!os.FileMode {
237 if (is_posix) {237 if (is_posix) {
238 var stat: posix.Stat = undefined;238 var stat: posix.Stat = undefined;
239 const err = posix.getErrno(posix.fstat(self.handle, &stat));239 const err = posix.getErrno(posix.fstat(self.handle, &stat));
std/os/index.zig+99-13
...@@ -1050,15 +1050,16 @@ const DeleteTreeError = error {...@@ -1050,15 +1050,16 @@ const DeleteTreeError = error {
1050};1050};
1051pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {1051pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
1052 start_over: while (true) {1052 start_over: while (true) {
1053 var got_access_denied = false;
1053 // First, try deleting the item as a file. This way we don't follow sym links.1054 // First, try deleting the item as a file. This way we don't follow sym links.
1054 if (deleteFile(allocator, full_path)) {1055 if (deleteFile(allocator, full_path)) {
1055 return;1056 return;
1056 } else |err| switch (err) {1057 } else |err| switch (err) {
1057 error.FileNotFound => return,1058 error.FileNotFound => return,
1058 error.IsDir => {},1059 error.IsDir => {},
1060 error.AccessDenied => got_access_denied = true,
10591061
1060 error.OutOfMemory,1062 error.OutOfMemory,
1061 error.AccessDenied,
1062 error.SymLinkLoop,1063 error.SymLinkLoop,
1063 error.NameTooLong,1064 error.NameTooLong,
1064 error.SystemResources,1065 error.SystemResources,
...@@ -1071,7 +1072,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1071,7 +1072,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1071 }1072 }
1072 {1073 {
1073 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {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 },
10751081
1076 error.OutOfMemory,1082 error.OutOfMemory,
1077 error.AccessDenied,1083 error.AccessDenied,
...@@ -1109,18 +1115,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1109,18 +1115,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1109}1115}
11101116
1111pub const Dir = struct {1117pub const Dir = struct {
1112 // See man getdents
1113 fd: i32,1118 fd: i32,
1119 darwin_seek: darwin_seek_t,
1114 allocator: &Allocator,1120 allocator: &Allocator,
1115 buf: []u8,1121 buf: []u8,
1116 index: usize,1122 index: usize,
1117 end_index: usize,1123 end_index: usize,
11181124
1119 const LinuxEntry = extern struct {1125 const darwin_seek_t = switch (builtin.os) {
1120 d_ino: usize,1126 Os.macosx, Os.ios => i64,
1121 d_off: usize,1127 else => void,
1122 d_reclen: u16,
1123 d_name: u8, // field address is the address of first byte of name
1124 };1128 };
11251129
1126 pub const Entry = struct {1130 pub const Entry = struct {
...@@ -1135,15 +1139,26 @@ pub const Dir = struct {...@@ -1135,15 +1139,26 @@ pub const Dir = struct {
1135 SymLink,1139 SymLink,
1136 File,1140 File,
1137 UnixDomainSocket,1141 UnixDomainSocket,
1142 Whiteout,
1138 Unknown,1143 Unknown,
1139 };1144 };
1140 };1145 };
11411146
1142 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {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 return Dir {1158 return Dir {
1145 .allocator = allocator,1159 .allocator = allocator,
1146 .fd = fd,1160 .fd = fd,
1161 .darwin_seek = darwin_seek_init,
1147 .index = 0,1162 .index = 0,
1148 .end_index = 0,1163 .end_index = 0,
1149 .buf = []u8{},1164 .buf = []u8{},
...@@ -1158,6 +1173,76 @@ pub const Dir = struct {...@@ -1158,6 +1173,76 @@ pub const Dir = struct {
1158 /// Memory such as file names referenced in this returned entry becomes invalid1173 /// Memory such as file names referenced in this returned entry becomes invalid
1159 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.1174 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1160 pub fn next(self: &Dir) !?Entry {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 start_over: while (true) {1246 start_over: while (true) {
1162 if (self.index >= self.end_index) {1247 if (self.index >= self.end_index) {
1163 if (self.buf.len == 0) {1248 if (self.buf.len == 0) {
...@@ -1166,7 +1251,7 @@ pub const Dir = struct {...@@ -1166,7 +1251,7 @@ pub const Dir = struct {
11661251
1167 while (true) {1252 while (true) {
1168 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);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 if (err > 0) {1255 if (err > 0) {
1171 switch (err) {1256 switch (err) {
1172 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,1257 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
...@@ -1184,7 +1269,7 @@ pub const Dir = struct {...@@ -1184,7 +1269,7 @@ pub const Dir = struct {
1184 break;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 const next_index = self.index + linux_entry.d_reclen;1273 const next_index = self.index + linux_entry.d_reclen;
1189 self.index = next_index;1274 self.index = next_index;
11901275
...@@ -1679,6 +1764,7 @@ test "std.os" {...@@ -1679,6 +1764,7 @@ test "std.os" {
1679 _ = @import("linux/index.zig");1764 _ = @import("linux/index.zig");
1680 _ = @import("path.zig");1765 _ = @import("path.zig");
1681 _ = @import("windows/index.zig");1766 _ = @import("windows/index.zig");
1767 _ = @import("test.zig");
1682}1768}
16831769
16841770
...@@ -1690,7 +1776,7 @@ const unexpected_error_tracing = false;...@@ -1690,7 +1776,7 @@ const unexpected_error_tracing = false;
1690pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {1776pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
1691 if (unexpected_error_tracing) {1777 if (unexpected_error_tracing) {
1692 debug.warn("unexpected errno: {}\n", errno);1778 debug.warn("unexpected errno: {}\n", errno);
1693 debug.dumpStackTrace();1779 debug.dumpCurrentStackTrace(null);
1694 }1780 }
1695 return error.Unexpected;1781 return error.Unexpected;
1696}1782}
...@@ -1700,7 +1786,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {...@@ -1700,7 +1786,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
1700pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {1786pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {
1701 if (unexpected_error_tracing) {1787 if (unexpected_error_tracing) {
1702 debug.warn("unexpected GetLastError(): {}\n", err);1788 debug.warn("unexpected GetLastError(): {}\n", err);
1703 debug.dumpStackTrace();1789 debug.dumpCurrentStackTrace(null);
1704 }1790 }
1705 return error.Unexpected;1791 return error.Unexpected;
1706}1792}
std/os/linux/index.zig+67-91
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("../../index.zig");1const std = @import("../../index.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const arch = switch (builtin.arch) {4pub use switch (builtin.arch) {
5 builtin.Arch.x86_64 => @import("x86_64.zig"),5 builtin.Arch.x86_64 => @import("x86_64.zig"),
6 builtin.Arch.i386 => @import("i386.zig"),6 builtin.Arch.i386 => @import("i386.zig"),
7 else => @compileError("unsupported arch"),7 else => @compileError("unsupported arch"),
...@@ -93,27 +93,6 @@ pub const O_RDONLY = 0o0;...@@ -93,27 +93,6 @@ pub const O_RDONLY = 0o0;
93pub const O_WRONLY = 0o1;93pub const O_WRONLY = 0o1;
94pub const O_RDWR = 0o2;94pub const O_RDWR = 0o2;
9595
96pub const O_CREAT = arch.O_CREAT;
97pub const O_EXCL = arch.O_EXCL;
98pub const O_NOCTTY = arch.O_NOCTTY;
99pub const O_TRUNC = arch.O_TRUNC;
100pub const O_APPEND = arch.O_APPEND;
101pub const O_NONBLOCK = arch.O_NONBLOCK;
102pub const O_DSYNC = arch.O_DSYNC;
103pub const O_SYNC = arch.O_SYNC;
104pub const O_RSYNC = arch.O_RSYNC;
105pub const O_DIRECTORY = arch.O_DIRECTORY;
106pub const O_NOFOLLOW = arch.O_NOFOLLOW;
107pub const O_CLOEXEC = arch.O_CLOEXEC;
108
109pub const O_ASYNC = arch.O_ASYNC;
110pub const O_DIRECT = arch.O_DIRECT;
111pub const O_LARGEFILE = arch.O_LARGEFILE;
112pub const O_NOATIME = arch.O_NOATIME;
113pub const O_PATH = arch.O_PATH;
114pub const O_TMPFILE = arch.O_TMPFILE;
115pub const O_NDELAY = arch.O_NDELAY;
116
117pub const SEEK_SET = 0;96pub const SEEK_SET = 0;
118pub const SEEK_CUR = 1;97pub const SEEK_CUR = 1;
119pub const SEEK_END = 2;98pub const SEEK_END = 2;
...@@ -394,65 +373,65 @@ pub fn getErrno(r: usize) usize {...@@ -394,65 +373,65 @@ pub fn getErrno(r: usize) usize {
394}373}
395374
396pub fn dup2(old: i32, new: i32) usize {375pub 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}
399378
400pub fn chdir(path: &const u8) usize {379pub fn chdir(path: &const u8) usize {
401 return arch.syscall1(arch.SYS_chdir, @ptrToInt(path));380 return syscall1(SYS_chdir, @ptrToInt(path));
402}381}
403382
404pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {383pub 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}
407386
408pub fn fork() usize {387pub fn fork() usize {
409 return arch.syscall0(arch.SYS_fork);388 return syscall0(SYS_fork);
410}389}
411390
412pub fn getcwd(buf: &u8, size: usize) usize {391pub 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}
415394
416pub fn getdents(fd: i32, dirp: &u8, count: usize) usize {395pub 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}
419398
420pub fn isatty(fd: i32) bool {399pub fn isatty(fd: i32) bool {
421 var wsz: winsize = undefined;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}
424403
425pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) usize {404pub 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}
428407
429pub fn mkdir(path: &const u8, mode: u32) usize {408pub 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}
432411
433pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {412pub 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 @bitCast(usize, offset));414 @bitCast(usize, offset));
436}415}
437416
438pub fn munmap(address: &u8, length: usize) usize {417pub 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}
441420
442pub fn read(fd: i32, buf: &u8, count: usize) usize {421pub 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}
445424
446pub fn rmdir(path: &const u8) usize {425pub fn rmdir(path: &const u8) usize {
447 return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path));426 return syscall1(SYS_rmdir, @ptrToInt(path));
448}427}
449428
450pub fn symlink(existing: &const u8, new: &const u8) usize {429pub 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}
453432
454pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {433pub 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}
457436
458pub fn pipe(fd: &[2]i32) usize {437pub fn pipe(fd: &[2]i32) usize {
...@@ -460,84 +439,84 @@ pub fn pipe(fd: &[2]i32) usize {...@@ -460,84 +439,84 @@ pub fn pipe(fd: &[2]i32) usize {
460}439}
461440
462pub fn pipe2(fd: &[2]i32, flags: usize) usize {441pub 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}
465444
466pub fn write(fd: i32, buf: &const u8, count: usize) usize {445pub 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}
469448
470pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) usize {449pub 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}
473452
474pub fn rename(old: &const u8, new: &const u8) usize {453pub 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}
477456
478pub fn open(path: &const u8, flags: u32, perm: usize) usize {457pub 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}
481460
482pub fn create(path: &const u8, perm: usize) usize {461pub 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}
485464
486pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) usize {465pub 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}
489468
490pub fn close(fd: i32) usize {469pub fn close(fd: i32) usize {
491 return arch.syscall1(arch.SYS_close, usize(fd));470 return syscall1(SYS_close, usize(fd));
492}471}
493472
494pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {473pub 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}
497476
498pub fn exit(status: i32) noreturn {477pub fn exit(status: i32) noreturn {
499 _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));478 _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
500 unreachable;479 unreachable;
501}480}
502481
503pub fn getrandom(buf: &u8, count: usize, flags: u32) usize {482pub 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}
506485
507pub fn kill(pid: i32, sig: i32) usize {486pub 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}
510489
511pub fn unlink(path: &const u8) usize {490pub fn unlink(path: &const u8) usize {
512 return arch.syscall1(arch.SYS_unlink, @ptrToInt(path));491 return syscall1(SYS_unlink, @ptrToInt(path));
513}492}
514493
515pub fn waitpid(pid: i32, status: &i32, options: i32) usize {494pub 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}
518497
519pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {498pub 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}
522501
523pub fn setuid(uid: u32) usize {502pub fn setuid(uid: u32) usize {
524 return arch.syscall1(arch.SYS_setuid, uid);503 return syscall1(SYS_setuid, uid);
525}504}
526505
527pub fn setgid(gid: u32) usize {506pub fn setgid(gid: u32) usize {
528 return arch.syscall1(arch.SYS_setgid, gid);507 return syscall1(SYS_setgid, gid);
529}508}
530509
531pub fn setreuid(ruid: u32, euid: u32) usize {510pub 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}
534513
535pub fn setregid(rgid: u32, egid: u32) usize {514pub 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}
538517
539pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {518pub 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}
542521
543pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {522pub 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,11 +527,11 @@ pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigacti
548 .handler = act.handler,527 .handler = act.handler,
549 .flags = act.flags | SA_RESTORER,528 .flags = act.flags | SA_RESTORER,
550 .mask = undefined,529 .mask = undefined,
551 .restorer = @ptrCast(extern fn()void, arch.restore_rt),530 .restorer = @ptrCast(extern fn()void, restore_rt),
552 };531 };
553 var ksa_old: k_sigaction = undefined;532 var ksa_old: k_sigaction = undefined;
554 @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);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 const err = getErrno(result);535 const err = getErrno(result);
557 if (err != 0) {536 if (err != 0) {
558 return result;537 return result;
...@@ -592,22 +571,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;...@@ -592,22 +571,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;
592pub fn raise(sig: i32) usize {571pub fn raise(sig: i32) usize {
593 var set: sigset_t = undefined;572 var set: sigset_t = undefined;
594 blockAppSignals(&set);573 blockAppSignals(&set);
595 const tid = i32(arch.syscall0(arch.SYS_gettid));574 const tid = i32(syscall0(SYS_gettid));
596 const ret = arch.syscall2(arch.SYS_tkill, usize(tid), usize(sig));575 const ret = syscall2(SYS_tkill, usize(tid), usize(sig));
597 restoreSignals(&set);576 restoreSignals(&set);
598 return ret;577 return ret;
599}578}
600579
601fn blockAllSignals(set: &sigset_t) void {580fn 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}
604583
605fn blockAppSignals(set: &sigset_t) void {584fn 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}
608587
609fn restoreSignals(set: &sigset_t) void {588fn 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}
612591
613pub fn sigaddset(set: &sigset_t, sig: u6) void {592pub fn sigaddset(set: &sigset_t, sig: u6) void {
...@@ -653,61 +632,61 @@ pub const iovec = extern struct {...@@ -653,61 +632,61 @@ pub const iovec = extern struct {
653};632};
654633
655pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {634pub 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}
658637
659pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {638pub 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}
662641
663pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize {642pub 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}
666645
667pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {646pub 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}
670649
671pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize {650pub 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}
674653
675pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) usize {654pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
676 return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);655 return syscall3(SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
677}656}
678657
679pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) usize {658pub 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}
682661
683pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) usize {662pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {
684 return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);663 return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
685}664}
686665
687pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,666pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
688 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize667 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}
692671
693pub fn shutdown(fd: i32, how: i32) usize {672pub 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}
696675
697pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {676pub 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}
700679
701pub fn listen(fd: i32, backlog: i32) usize {680pub 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}
704683
705pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {684pub 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}
708687
709pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {688pub 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}
712691
713pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {692pub 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,7 +694,7 @@ pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
715}694}
716695
717pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) usize {696pub 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}
720699
721// error NameTooLong;700// error NameTooLong;
...@@ -746,11 +725,8 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:...@@ -746,11 +725,8 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
746// return ifr.ifr_ifindex;725// return ifr.ifr_ifindex;
747// }726// }
748727
749pub const Stat = arch.Stat;
750pub const timespec = arch.timespec;
751
752pub fn fstat(fd: i32, stat_buf: &Stat) usize {728pub 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}
755731
756pub const epoll_data = extern union {732pub const epoll_data = extern union {
...@@ -770,19 +746,19 @@ pub fn epoll_create() usize {...@@ -770,19 +746,19 @@ pub fn epoll_create() usize {
770}746}
771747
772pub fn epoll_create1(flags: usize) usize {748pub fn epoll_create1(flags: usize) usize {
773 return arch.syscall1(arch.SYS_epoll_create1, flags);749 return syscall1(SYS_epoll_create1, flags);
774}750}
775751
776pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) usize {752pub 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}
779755
780pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: u32, timeout: i32) usize {756pub 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}
783759
784pub fn timerfd_create(clockid: i32, flags: u32) usize {760pub 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}
787763
788pub const itimerspec = extern struct {764pub const itimerspec = extern struct {
...@@ -791,11 +767,11 @@ pub const itimerspec = extern struct {...@@ -791,11 +767,11 @@ pub const itimerspec = extern struct {
791};767};
792768
793pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {769pub 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}
796772
797pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) usize {773pub 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}
800776
801test "import linux test" {777test "import linux test" {
std/os/linux/x86_64.zig+8
...@@ -488,3 +488,11 @@ pub const timespec = extern struct {...@@ -488,3 +488,11 @@ pub const timespec = extern struct {
488 tv_sec: isize,488 tv_sec: isize,
489 tv_nsec: isize,489 tv_nsec: isize,
490};490};
491
492pub 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 @@
1const std = @import("../index.zig");
2const os = std.os;
3const assert = std.debug.assert;
4const io = std.io;
5
6const a = std.debug.global_allocator;
7
8const builtin = @import("builtin");
9
10test "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 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const rand_test = @import("rand_test.zig");
5const mem = std.mem;
6const math = std.math;
7
8pub const MT19937_32 = MersenneTwister(
9 u32, 624, 397, 31,
10 0x9908B0DF,
11 11, 0xFFFFFFFF,
12 7, 0x9D2C5680,
13 15, 0xEFC60000,
14 18, 1812433253);
15
16pub 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.
25pub 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
129fn 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
196test "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
206test "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
213test "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
220test "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
227fn 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
17const std = @import("../index.zig");
18const builtin = @import("builtin");
19const assert = std.debug.assert;
20const mem = std.mem;
21const math = std.math;
22
23// When you need fast unbiased random numbers
24pub const DefaultPrng = Xoroshiro128;
25
26// When you need cryptographically secure random numbers
27pub const DefaultCsprng = Isaac64;
28
29pub 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.
141const 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
158test "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
178pub 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
248test "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
271pub 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
358test "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
399pub 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
552test "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.
581test "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
596test "Random scalar" {
597 var prng = DefaultPrng.init(0);
598 const s = prng .random.scalar(u64);
599}
600
601test "Random bytes" {
602 var prng = DefaultPrng.init(0);
603 var buf: [2048]u8 = undefined;
604 prng.random.bytes(buf[0..]);
605}
606
607test "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
626fn sumArray(s: []const u8) u32 {
627 var r: u32 = 0;
628 for (s) |e| r += e;
629 return r;
630}
631
632test "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
639fn 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 @@
1pub const mt64_seed = 0xb334e49d0977c37e;
2pub 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
255pub const mt32_seed = 0x7dc0d160;
256pub 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,7 +67,7 @@ const Iterator = struct {
67 self.numerator -= self.denominator;67 self.numerator -= self.denominator;
68 self.decimal += 1;68 self.decimal += 1;
69 }69 }
70 70
71 return Range {.start = start, .end = self.decimal};71 return Range {.start = start, .end = self.decimal};
72 }72 }
7373
...@@ -82,7 +82,7 @@ const Iterator = struct {...@@ -82,7 +82,7 @@ const Iterator = struct {
82 self.numerator_step -= self.denominator;82 self.numerator_step -= self.denominator;
83 self.decimal_step += 1;83 self.decimal_step += 1;
84 }84 }
85 85
86 return (self.decimal_step < self.size);86 return (self.decimal_step < self.size);
87 }87 }
8888
...@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
219 var B1 = iterator.nextRange();219 var B1 = iterator.nextRange();
220 var A2 = iterator.nextRange();220 var A2 = iterator.nextRange();
221 var B2 = iterator.nextRange();221 var B2 = iterator.nextRange();
222 222
223 if (lessThan(items[B1.end - 1], items[A1.start])) {223 if (lessThan(items[B1.end - 1], items[A1.start])) {
224 // the two ranges are in reverse order, so copy them in reverse order into the cache224 // the two ranges are in reverse order, so copy them in reverse order into the cache
225 mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]);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,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
230 } else {230 } else {
231 // if A1, B1, A2, and B2 are all in order, skip doing anything else231 // if A1, B1, A2, and B2 are all in order, skip doing anything else
232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;
233 233
234 // copy A1 and B1 into the cache in the same order234 // copy A1 and B1 into the cache in the same order
235 mem.copy(T, cache[0..], items[A1.start..A1.end]);235 mem.copy(T, cache[0..], items[A1.start..A1.end]);
236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);
237 }237 }
238 A1 = Range.init(A1.start, B1.end);238 A1 = Range.init(A1.start, B1.end);
239 239
240 // merge A2 and B2 into the cache240 // merge A2 and B2 into the cache
241 if (lessThan(items[B2.end - 1], items[A2.start])) {241 if (lessThan(items[B2.end - 1], items[A2.start])) {
242 // the two ranges are in reverse order, so copy them in reverse order into the cache242 // 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,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);
252 }252 }
253 A2 = Range.init(A2.start, B2.end);253 A2 = Range.init(A2.start, B2.end);
254 254
255 // merge A1 and A2 from the cache into the items255 // merge A1 and A2 from the cache into the items
256 const A3 = Range.init(0, A1.length());256 const A3 = Range.init(0, A1.length());
257 const B3 = Range.init(A1.length(), A1.length() + A2.length());257 const B3 = Range.init(A1.length(), A1.length() + A2.length());
258 258
259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {
260 // the two ranges are in reverse order, so copy them in reverse order into the items260 // the two ranges are in reverse order, so copy them in reverse order into the items
261 mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]);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,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);
270 }270 }
271 }271 }
272 272
273 // we merged two levels at the same time, so we're done with this level already273 // we merged two levels at the same time, so we're done with this level already
274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275 _ = iterator.nextLevel();275 _ = iterator.nextLevel();
276 276
277 } else {277 } else {
278 iterator.begin();278 iterator.begin();
279 while (!iterator.finished()) {279 while (!iterator.finished()) {
280 var A = iterator.nextRange();280 var A = iterator.nextRange();
281 var B = iterator.nextRange();281 var B = iterator.nextRange();
282 282
283 if (lessThan(items[B.end - 1], items[A.start])) {283 if (lessThan(items[B.end - 1], items[A.start])) {
284 // the two ranges are in reverse order, so a simple rotation should fix it284 // the two ranges are in reverse order, so a simple rotation should fix it
285 mem.rotate(T, items[A.start..B.end], A.length());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,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer
302 // 7. sort the second internal buffer if it exists302 // 7. sort the second internal buffer if it exists
303 // 8. redistribute the two internal buffers back into the items303 // 8. redistribute the two internal buffers back into the items
304 304
305 var block_size: usize = math.sqrt(iterator.length());305 var block_size: usize = math.sqrt(iterator.length());
306 var buffer_size = iterator.length()/block_size + 1;306 var buffer_size = iterator.length()/block_size + 1;
307 307
308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
310 var A: Range = undefined;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,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
322322
323 var buffer1 = Range.init(0, 0);323 var buffer1 = Range.init(0, 0);
324 var buffer2 = Range.init(0, 0);324 var buffer2 = Range.init(0, 0);
325 325
326 // find two internal buffers of size 'buffer_size' each326 // find two internal buffers of size 'buffer_size' each
327 find = buffer_size + buffer_size;327 find = buffer_size + buffer_size;
328 var find_separately = false;328 var find_separately = false;
329 329
330 if (block_size <= cache.len) {330 if (block_size <= cache.len) {
331 // if every A block fits into the cache then we won't need the second internal buffer,331 // if every A block fits into the cache then we won't need the second internal buffer,
332 // so we really only need to find 'buffer_size' unique values332 // 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,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
336 find = buffer_size;336 find = buffer_size;
337 find_separately = true;337 find_separately = true;
338 }338 }
339 339
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),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 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,
342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get
343 343
344 // in the case where it couldn't find a single buffer of at least √A unique values,344 // in the case where it couldn't find a single buffer of at least √A unique values,
345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)
346 iterator.begin();346 iterator.begin();
347 while (!iterator.finished()) {347 while (!iterator.finished()) {
348 A = iterator.nextRange();348 A = iterator.nextRange();
349 B = iterator.nextRange();349 B = iterator.nextRange();
350 350
351 // just store information about where the values will be pulled from and to,351 // just store information about where the values will be pulled from and to,
352 // as well as how many values there are, to create the two internal buffers352 // as well as how many values there are, to create the two internal buffers
353 353
354 // check A for the number of unique values we need to fill an internal buffer354 // check A for the number of unique values we need to fill an internal buffer
355 // these values will be pulled out to the start of A355 // these values will be pulled out to the start of A
356 last = A.start;356 last = A.start;
...@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
360 if (index == A.end) break;360 if (index == A.end) break;
361 }361 }
362 index = last;362 index = last;
363 363
364 if (count >= buffer_size) {364 if (count >= buffer_size) {
365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
366 pull[pull_index] = Pull {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,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
370 .to = A.start,370 .to = A.start,
371 };371 };
372 pull_index = 1;372 pull_index = 1;
373 373
374 if (count == buffer_size + buffer_size) {374 if (count == buffer_size + buffer_size) {
375 // we were able to find a single contiguous section containing 2√A unique values,375 // we were able to find a single contiguous section containing 2√A unique values,
376 // so this section can be used to contain both of the internal buffers we'll need376 // 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,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
405 .to = A.start,405 .to = A.start,
406 };406 };
407 }407 }
408 408
409 // check B for the number of unique values we need to fill an internal buffer409 // check B for the number of unique values we need to fill an internal buffer
410 // these values will be pulled out to the end of B410 // these values will be pulled out to the end of B
411 last = B.end - 1;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,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
415 if (index == B.start) break;415 if (index == B.start) break;
416 }416 }
417 index = last;417 index = last;
418 418
419 if (count >= buffer_size) {419 if (count >= buffer_size) {
420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
421 pull[pull_index] = Pull {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,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
425 .to = B.end,425 .to = B.end,
426 };426 };
427 pull_index = 1;427 pull_index = 1;
428 428
429 if (count == buffer_size + buffer_size) {429 if (count == buffer_size + buffer_size) {
430 // we were able to find a single contiguous section containing 2√A unique values,430 // we were able to find a single contiguous section containing 2√A unique values,
431 // so this section can be used to contain both of the internal buffers we'll need431 // 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,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,
450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2
451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;
452 452
453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!
454 buffer2 = Range.init(B.end - count, B.end);454 buffer2 = Range.init(B.end - count, B.end);
455 break;455 break;
...@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -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 // pull out the two ranges so we can use them as internal buffers469 // pull out the two ranges so we can use them as internal buffers
470 pull_index = 0;470 pull_index = 0;
471 while (pull_index < 2) : (pull_index += 1) {471 while (pull_index < 2) : (pull_index += 1) {
472 const length = pull[pull_index].count;472 const length = pull[pull_index].count;
473 473
474 if (pull[pull_index].to < pull[pull_index].from) {474 if (pull[pull_index].to < pull[pull_index].from) {
475 // we're pulling the values out to the left, which means the start of an A subarray475 // we're pulling the values out to the left, which means the start of an A subarray
476 index = pull[pull_index].from;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,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 // adjust block_size and buffer_size based on the values we were able to pull out497 // adjust block_size and buffer_size based on the values we were able to pull out
498 buffer_size = buffer1.length();498 buffer_size = buffer1.length();
499 block_size = iterator.length()/buffer_size + 1;499 block_size = iterator.length()/buffer_size + 1;
500 500
501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502 // so this was originally here to test the math for adjusting block_size above502 // so this was originally here to test the math for adjusting block_size above
503 // assert((iterator.length() + 1)/block_size <= buffer_size);503 // assert((iterator.length() + 1)/block_size <= buffer_size);
504 504
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!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 iterator.begin();506 iterator.begin();
507 while (!iterator.finished()) {507 while (!iterator.finished()) {
508 A = iterator.nextRange();508 A = iterator.nextRange();
509 B = iterator.nextRange();509 B = iterator.nextRange();
510 510
511 // remove any parts of A or B that are being used by the internal buffers511 // remove any parts of A or B that are being used by the internal buffers
512 start = A.start;512 start = A.start;
513 if (start == pull[0].range.start) {513 if (start == pull[0].range.start) {
514 if (pull[0].from > pull[0].to) {514 if (pull[0].from > pull[0].to) {
515 A.start += pull[0].count;515 A.start += pull[0].count;
516 516
517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge
518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,
519 // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal519 // 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,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
532 if (B.length() == 0) continue;532 if (B.length() == 0) continue;
533 }533 }
534 }534 }
535 535
536 if (lessThan(items[B.end - 1], items[A.start])) {536 if (lessThan(items[B.end - 1], items[A.start])) {
537 // the two ranges are in reverse order, so a simple rotation should fix it537 // the two ranges are in reverse order, so a simple rotation should fix it
538 mem.rotate(T, items[A.start..B.end], A.length());538 mem.rotate(T, items[A.start..B.end], A.length());
539 } else if (lessThan(items[A.end], items[A.end - 1])) {539 } else if (lessThan(items[A.end], items[A.end - 1])) {
540 // these two ranges weren't already in order, so we'll need to merge them!540 // these two ranges weren't already in order, so we'll need to merge them!
541 var findA: usize = undefined;541 var findA: usize = undefined;
542 542
543 // break the remainder of A into blocks. firstA is the uneven-sized first A block543 // break the remainder of A into blocks. firstA is the uneven-sized first A block
544 var blockA = Range.init(A.start, A.end);544 var blockA = Range.init(A.start, A.end);
545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);
546 546
547 // swap the first value of each A block with the value in buffer1547 // swap the first value of each A block with the value in buffer1
548 var indexA = buffer1.start;548 var indexA = buffer1.start;
549 index = firstA.end;549 index = firstA.end;
550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
551 mem.swap(T, &items[indexA], &items[index]);551 mem.swap(T, &items[indexA], &items[index]);
552 }552 }
553 553
554 // start rolling the A blocks through the B blocks!554 // start rolling the A blocks through the B blocks!
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 well555 // 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 var lastA = firstA;556 var lastA = firstA;
...@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));
559 blockA.start += firstA.length();559 blockA.start += firstA.length();
560 indexA = buffer1.start;560 indexA = buffer1.start;
561 561
562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it
563 // otherwise, if the second buffer is available, block swap the contents into that563 // otherwise, if the second buffer is available, block swap the contents into that
564 if (lastA.length() <= cache.len) {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,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
566 } else if (buffer2.length() > 0) {566 } else if (buffer2.length() > 0) {
567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());
568 }568 }
569 569
570 if (blockA.length() > 0) {570 if (blockA.length() > 0) {
571 while (true) {571 while (true) {
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,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,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
575 // figure out where to split the previous B block, and rotate it at the split575 // figure out where to split the previous B block, and rotate it at the split
576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);
577 const B_remaining = lastB.end - B_split;577 const B_remaining = lastB.end - B_split;
578 578
579 // swap the minimum A block to the beginning of the rolling A blocks579 // swap the minimum A block to the beginning of the rolling A blocks
580 var minA = blockA.start;580 var minA = blockA.start;
581 findA = minA + block_size;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,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
585 }585 }
586 }586 }
587 blockSwap(T, items, blockA.start, minA, block_size);587 blockSwap(T, items, blockA.start, minA, block_size);
588 588
589 // swap the first item of the previous A block back with its original value, which is stored in buffer1589 // swap the first item of the previous A block back with its original value, which is stored in buffer1
590 mem.swap(T, &items[blockA.start], &items[indexA]);590 mem.swap(T, &items[blockA.start], &items[indexA]);
591 indexA += 1;591 indexA += 1;
592 592
593 // locally merge the previous A block with the B values that follow it593 // locally merge the previous A block with the B values that follow it
594 // if lastA fits into the external cache we'll use that (with MergeExternal),594 // if lastA fits into the external cache we'll use that (with MergeExternal),
595 // or if the second internal buffer exists we'll use that (with MergeInternal),595 // or if the second internal buffer exists we'll use that (with MergeInternal),
596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)
597 597
598 if (lastA.length() <= cache.len) {598 if (lastA.length() <= cache.len) {
599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);
600 } else if (buffer2.length() > 0) {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,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
602 } else {602 } else {
603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);
604 }604 }
605 605
606 if (buffer2.length() > 0 or block_size <= cache.len) {606 if (buffer2.length() > 0 or block_size <= cache.len) {
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 anyway607 // 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 if (block_size <= cache.len) {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,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
610 } else {610 } else {
611 blockSwap(T, items, blockA.start, buffer2.start, block_size);611 blockSwap(T, items, blockA.start, buffer2.start, block_size);
612 }612 }
613 613
614 // this is equivalent to rotating, but faster614 // this is equivalent to rotating, but faster
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 it615 // 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 // 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 belongs616 // 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,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation619 // 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 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);
621 }621 }
622 622
623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split
624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);
625 lastB = Range.init(lastA.end, lastA.end + B_remaining);625 lastB = Range.init(lastA.end, lastA.end + B_remaining);
626 626
627 // if there are no more A blocks remaining, this step is finished!627 // if there are no more A blocks remaining, this step is finished!
628 blockA.start += block_size;628 blockA.start += block_size;
629 if (blockA.length() == 0)629 if (blockA.length() == 0)
630 break;630 break;
631 631
632 } else if (blockB.length() < block_size) {632 } else if (blockB.length() < block_size) {
633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634 // the cache is disabled here since it might contain the contents of the previous A block634 // the cache is disabled here since it might contain the contents of the previous A block
635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);
636 636
637 lastB = Range.init(blockA.start, blockA.start + blockB.length());637 lastB = Range.init(blockA.start, blockA.start + blockB.length());
638 blockA.start += blockB.length();638 blockA.start += blockB.length();
639 blockA.end += blockB.length();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,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
642 // roll the leftmost A block to the end by swapping it with the next B block642 // roll the leftmost A block to the end by swapping it with the next B block
643 blockSwap(T, items, blockA.start, blockB.start, block_size);643 blockSwap(T, items, blockA.start, blockB.start, block_size);
644 lastB = Range.init(blockA.start, blockA.start + block_size);644 lastB = Range.init(blockA.start, blockA.start + block_size);
645 645
646 blockA.start += block_size;646 blockA.start += block_size;
647 blockA.end += block_size;647 blockA.end += block_size;
648 blockB.start += block_size;648 blockB.start += block_size;
649 649
650 if (blockB.end > B.end - block_size) {650 if (blockB.end > B.end - block_size) {
651 blockB.end = B.end;651 blockB.end = B.end;
652 } else {652 } else {
...@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -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 // merge the last A block with the remaining B values659 // merge the last A block with the remaining B values
660 if (lastA.length() <= cache.len) {660 if (lastA.length() <= cache.len) {
661 mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]);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,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 // 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 up670 // 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 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer671 // 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 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,
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 here674 // 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 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);
676 676
677 pull_index = 0;677 pull_index = 0;
678 while (pull_index < 2) : (pull_index += 1) {678 while (pull_index < 2) : (pull_index += 1) {
679 var unique = pull[pull_index].count * 2;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,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 // double the size of each A and B subarray that will be merged in the next level706 // double the size of each A and B subarray that will be merged in the next level
707 if (!iterator.nextLevel()) break;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,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
711// merge operation without a buffer711// merge operation without a buffer
712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {
713 if (A_arg.length() == 0 or B_arg.length() == 0) return;713 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714 714
715 // this just repeatedly binary searches into B and rotates A into position.715 // this just repeatedly binary searches into B and rotates A into position.
716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
717 // but I decided to stick with this because it had better situational performance717 // but I decided to stick with this because it had better situational performance
718 // 718 //
719 // (Hwang and Lin is designed for merging subarrays of very different sizes,719 // (Hwang and Lin is designed for merging subarrays of very different sizes,
720 // but WikiSort almost always uses subarrays that are roughly the same size)720 // but WikiSort almost always uses subarrays that are roughly the same size)
721 // 721 //
722 // normally this is incredibly suboptimal, but this function is only called722 // normally this is incredibly suboptimal, but this function is only called
723 // when none of the A or B blocks in any subarray contained 2√A unique values,723 // when none of the A or B blocks in any subarray contained 2√A unique values,
724 // which places a hard limit on the number of times this will ACTUALLY need724 // which places a hard limit on the number of times this will ACTUALLY need
725 // to binary search and rotate.725 // to binary search and rotate.
726 // 726 //
727 // according to my analysis the worst case is √A rotations performed on √A items727 // according to my analysis the worst case is √A rotations performed on √A items
728 // once the constant factors are removed, which ends up being O(n)728 // once the constant factors are removed, which ends up being O(n)
729 // 729 //
730 // again, this is NOT a general-purpose solution – it only works well in this case!730 // again, this is NOT a general-purpose solution – it only works well in this case!
731 // kind of like how the O(n^2) insertion sort is used in some places731 // kind of like how the O(n^2) insertion sort is used in some places
732732
733 var A = *A_arg;733 var A = *A_arg;
734 var B = *B_arg;734 var B = *B_arg;
735 735
736 while (true) {736 while (true) {
737 // find the first place in B where the first item in A needs to be inserted737 // find the first place in B where the first item in A needs to be inserted
738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);
739 739
740 // rotate A into place740 // rotate A into place
741 const amount = mid - A.end;741 const amount = mid - A.end;
742 mem.rotate(T, items[A.start..mid], A.length());742 mem.rotate(T, items[A.start..mid], A.length());
743 if (B.end == mid) break;743 if (B.end == mid) break;
744 744
745 // calculate the new A and B ranges745 // calculate the new A and B ranges
746 B.start = mid;746 B.start = mid;
747 A = Range.init(A.start + amount, B.start);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,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
757 var A_count: usize = 0;757 var A_count: usize = 0;
758 var B_count: usize = 0;758 var B_count: usize = 0;
759 var insert: usize = 0;759 var insert: usize = 0;
760 760
761 if (B.length() > 0 and A.length() > 0) {761 if (B.length() > 0 and A.length() > 0) {
762 while (true) {762 while (true) {
763 if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) {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,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 // swap the remainder of A into the final array777 // swap the remainder of A into the final array
778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);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,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
791 if (range.length() == 0) return range.start;791 if (range.length() == 0) return range.start;
792 const skip = math.max(range.length()/unique, usize(1));792 const skip = math.max(range.length()/unique, usize(1));
793 793
794 var index = range.start + skip;794 var index = range.start + skip;
795 while (lessThan(items[index - 1], value)) : (index += skip) {795 while (lessThan(items[index - 1], value)) : (index += skip) {
796 if (index >= range.end - skip) {796 if (index >= range.end - skip) {
797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);
798 }798 }
799 }799 }
800 800
801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802}802}
803803
804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
805 if (range.length() == 0) return range.start;805 if (range.length() == 0) return range.start;
806 const skip = math.max(range.length()/unique, usize(1));806 const skip = math.max(range.length()/unique, usize(1));
807 807
808 var index = range.end - skip;808 var index = range.end - skip;
809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
810 if (index < range.start + skip) {810 if (index < range.start + skip) {
811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);
812 }812 }
813 }813 }
814 814
815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816}816}
817817
818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
819 if (range.length() == 0) return range.start;819 if (range.length() == 0) return range.start;
820 const skip = math.max(range.length()/unique, usize(1));820 const skip = math.max(range.length()/unique, usize(1));
821 821
822 var index = range.start + skip;822 var index = range.start + skip;
823 while (!lessThan(value, items[index - 1])) : (index += skip) {823 while (!lessThan(value, items[index - 1])) : (index += skip) {
824 if (index >= range.end - skip) {824 if (index >= range.end - skip) {
825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);
826 }826 }
827 }827 }
828 828
829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830}830}
831831
832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
833 if (range.length() == 0) return range.start;833 if (range.length() == 0) return range.start;
834 const skip = math.max(range.length()/unique, usize(1));834 const skip = math.max(range.length()/unique, usize(1));
835 835
836 var index = range.end - skip;836 var index = range.end - skip;
837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
838 if (index < range.start + skip) {838 if (index < range.start + skip) {
839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);
840 }840 }
841 }841 }
842 842
843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844}844}
845845
...@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less...@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
885 const A_last = A.end;885 const A_last = A.end;
886 const B_last = B.end;886 const B_last = B.end;
887 var insert_index: usize = 0;887 var insert_index: usize = 0;
888 888
889 while (true) {889 while (true) {
890 if (!lessThan(from[B_index], from[A_index])) {890 if (!lessThan(from[B_index], from[A_index])) {
891 into[insert_index] = from[A_index];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,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
916 var insert_index: usize = A.start;916 var insert_index: usize = A.start;
917 const A_last = A.length();917 const A_last = A.length();
918 const B_last = B.end;918 const B_last = B.end;
919 919
920 if (B.length() > 0 and A.length() > 0) {920 if (B.length() > 0 and A.length() > 0) {
921 while (true) {921 while (true) {
922 if (!lessThan(items[B_index], cache[A_index])) {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,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 // copy the remainder of A into the final array936 // copy the remainder of A into the final array
937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938}938}
...@@ -1081,17 +1081,17 @@ test "another sort case" {...@@ -1081,17 +1081,17 @@ test "another sort case" {
1081}1081}
10821082
1083test "sort fuzz testing" {1083test "sort fuzz testing" {
1084 var rng = std.rand.Rand.init(0x12345678);1084 var prng = std.rand.DefaultPrng.init(0x12345678);
1085 const test_case_count = 10;1085 const test_case_count = 10;
1086 var i: usize = 0;1086 var i: usize = 0;
1087 while (i < test_case_count) : (i += 1) {1087 while (i < test_case_count) : (i += 1) {
1088 fuzzTest(&rng);1088 fuzzTest(&prng.random);
1089 }1089 }
1090}1090}
10911091
1092var fixed_buffer_mem: [100 * 1024]u8 = undefined;1092var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10931093
1094fn fuzzTest(rng: &std.rand.Rand) void {1094fn fuzzTest(rng: &std.rand.Random) void {
1095 const array_size = rng.range(usize, 0, 1000);1095 const array_size = rng.range(usize, 0, 1000);
1096 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1096 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1097 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;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,8 +20,11 @@ pub const Node = struct {
20 IntegerLiteral,20 IntegerLiteral,
21 FloatLiteral,21 FloatLiteral,
22 StringLiteral,22 StringLiteral,
23 UndefinedLiteral,
23 BuiltinCall,24 BuiltinCall,
25 Call,
24 LineComment,26 LineComment,
27 TestDecl,
25 };28 };
2629
27 pub fn iterate(base: &Node, index: usize) ?&Node {30 pub fn iterate(base: &Node, index: usize) ?&Node {
...@@ -37,8 +40,11 @@ pub const Node = struct {...@@ -37,8 +40,11 @@ pub const Node = struct {
37 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),40 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
38 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),41 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
39 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),42 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
43 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
40 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),44 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
45 Id.Call => @fieldParentPtr(NodeCall, "base", base).iterate(index),
41 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),46 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
47 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
42 };48 };
43 }49 }
4450
...@@ -55,8 +61,11 @@ pub const Node = struct {...@@ -55,8 +61,11 @@ pub const Node = struct {
55 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),61 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
56 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),62 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
57 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),63 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
64 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
58 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),65 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
66 Id.Call => @fieldParentPtr(NodeCall, "base", base).firstToken(),
59 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),67 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
68 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
60 };69 };
61 }70 }
6271
...@@ -73,8 +82,11 @@ pub const Node = struct {...@@ -73,8 +82,11 @@ pub const Node = struct {
73 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),82 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
74 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),83 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
75 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),84 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
85 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
76 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),86 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
87 Id.Call => @fieldParentPtr(NodeCall, "base", base).lastToken(),
77 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),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,9 +317,47 @@ pub const NodeInfixOp = struct {
305 rhs: &Node,317 rhs: &Node,
306318
307 const InfixOp = enum {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 BangEqual,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 Period,357 Period,
358 Sub,
359 SubWrap,
360 UnwrapMaybe,
311 };361 };
312362
313 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {363 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
...@@ -317,9 +367,47 @@ pub const NodeInfixOp = struct {...@@ -317,9 +367,47 @@ pub const NodeInfixOp = struct {
317 i -= 1;367 i -= 1;
318368
319 switch (self.op) {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 InfixOp.BangEqual,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 }
324412
325 if (i < 1) return self.rhs;413 if (i < 1) return self.rhs;
...@@ -344,9 +432,15 @@ pub const NodePrefixOp = struct {...@@ -344,9 +432,15 @@ pub const NodePrefixOp = struct {
344 rhs: &Node,432 rhs: &Node,
345433
346 const PrefixOp = union(enum) {434 const PrefixOp = union(enum) {
435 AddrOf: AddrOfInfo,
436 BitNot,
437 BoolNot,
438 Deref,
439 Negation,
440 NegationWrap,
347 Return,441 Return,
348 Try,442 Try,
349 AddrOf: AddrOfInfo,443 UnwrapMaybe,
350 };444 };
351 const AddrOfInfo = struct {445 const AddrOfInfo = struct {
352 align_expr: ?&Node,446 align_expr: ?&Node,
...@@ -360,14 +454,20 @@ pub const NodePrefixOp = struct {...@@ -360,14 +454,20 @@ pub const NodePrefixOp = struct {
360 var i = index;454 var i = index;
361455
362 switch (self.op) {456 switch (self.op) {
363 PrefixOp.Return,
364 PrefixOp.Try => {},
365 PrefixOp.AddrOf => |addr_of_info| {457 PrefixOp.AddrOf => |addr_of_info| {
366 if (addr_of_info.align_expr) |align_expr| {458 if (addr_of_info.align_expr) |align_expr| {
367 if (i < 1) return align_expr;459 if (i < 1) return align_expr;
368 i -= 1;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 }
372472
373 if (i < 1) return self.rhs;473 if (i < 1) return self.rhs;
...@@ -443,6 +543,33 @@ pub const NodeBuiltinCall = struct {...@@ -443,6 +543,33 @@ pub const NodeBuiltinCall = struct {
443 }543 }
444};544};
445545
546pub 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
446pub const NodeStringLiteral = struct {573pub const NodeStringLiteral = struct {
447 base: Node,574 base: Node,
448 token: Token,575 token: Token,
...@@ -460,6 +587,23 @@ pub const NodeStringLiteral = struct {...@@ -460,6 +587,23 @@ pub const NodeStringLiteral = struct {
460 }587 }
461};588};
462589
590pub 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
463pub const NodeLineComment = struct {607pub const NodeLineComment = struct {
464 base: Node,608 base: Node,
465 lines: ArrayList(Token),609 lines: ArrayList(Token),
...@@ -476,3 +620,28 @@ pub const NodeLineComment = struct {...@@ -476,3 +620,28 @@ pub const NodeLineComment = struct {
476 return self.lines.at(self.lines.len - 1);620 return self.lines.at(self.lines.len - 1);
477 }621 }
478};622};
623
624pub 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,6 +86,7 @@ pub const Parser = struct {
86 AfterOperand,86 AfterOperand,
87 InfixOp: &ast.NodeInfixOp,87 InfixOp: &ast.NodeInfixOp,
88 PrefixOp: &ast.NodePrefixOp,88 PrefixOp: &ast.NodePrefixOp,
89 SuffixOp: &ast.Node,
89 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,90 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
90 TypeExpr: DestPtr,91 TypeExpr: DestPtr,
91 VarDecl: &ast.NodeVarDecl,92 VarDecl: &ast.NodeVarDecl,
...@@ -171,6 +172,22 @@ pub const Parser = struct {...@@ -171,6 +172,22 @@ pub const Parser = struct {
171 stack.append(State { .TopLevelExtern = token }) catch unreachable;172 stack.append(State { .TopLevelExtern = token }) catch unreachable;
172 continue;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 Token.Id.Eof => {191 Token.Id.Eof => {
175 root_node.eof_token = token;192 root_node.eof_token = token;
176 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};193 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
...@@ -319,6 +336,42 @@ pub const Parser = struct {...@@ -319,6 +336,42 @@ pub const Parser = struct {
319 try stack.append(State.ExpectOperand);336 try stack.append(State.ExpectOperand);
320 continue;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 Token.Id.Ampersand => {375 Token.Id.Ampersand => {
323 const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{376 const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
324 .AddrOf = ast.NodePrefixOp.AddrOfInfo {377 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
...@@ -355,6 +408,13 @@ pub const Parser = struct {...@@ -355,6 +408,13 @@ pub const Parser = struct {
355 try stack.append(State.AfterOperand);408 try stack.append(State.AfterOperand);
356 continue;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 Token.Id.Builtin => {418 Token.Id.Builtin => {
359 const node = try arena.create(ast.NodeBuiltinCall);419 const node = try arena.create(ast.NodeBuiltinCall);
360 *node = ast.NodeBuiltinCall {420 *node = ast.NodeBuiltinCall {
...@@ -398,56 +458,62 @@ pub const Parser = struct {...@@ -398,56 +458,62 @@ pub const Parser = struct {
398 // or a postfix operator (like () or {}),458 // or a postfix operator (like () or {}),
399 // otherwise this expression is done (like on a ; or else).459 // otherwise this expression is done (like on a ; or else).
400 var token = self.getNextToken();460 var token = self.getNextToken();
401 switch (token.id) {461 if (tokenIdToInfixOp(token.id)) |infix_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 => {
410 try stack.append(State {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 try stack.append(State.ExpectOperand);465 try stack.append(State.ExpectOperand);
414 continue;466 continue;
415 },467
416 Token.Id.Period => {468 } else if (token.id == Token.Id.LParen) {
417 try stack.append(State {469 self.putBackToken(token);
418 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period)470
419 });471 const node = try arena.create(ast.NodeCall);
420 try stack.append(State.ExpectOperand);472 *node = ast.NodeCall {
421 continue;473 .base = self.initNode(ast.Node.Id.Call),
422 },474 .callee = undefined,
423 else => {475 .params = ArrayList(&ast.Node).init(arena),
424 // no postfix/infix operator after this operand.476 .rparen_token = undefined,
425 self.putBackToken(token);477 };
426 // reduce the stack478 try stack.append(State { .SuffixOp = &node.base });
427 var expression: &ast.Node = stack.pop().Operand;479 try stack.append(State.AfterOperand);
428 while (true) {480 try stack.append(State {.ExprListItemOrEnd = &node.params });
429 switch (stack.pop()) {481 try stack.append(State {
430 State.Expression => |dest_ptr| {482 .ExpectTokenSave = ExpectTokenSave {
431 // we're done483 .id = Token.Id.LParen,
432 try dest_ptr.store(expression);484 .ptr = &node.rparen_token,
433 break;485 },
434 },486 });
435 State.InfixOp => |infix_op| {487 continue;
436 infix_op.rhs = expression;488
437 infix_op.lhs = stack.pop().Operand;489 // TODO: Parse postfix operator
438 expression = &infix_op.base;490 } else {
439 continue;491 // no postfix/infix operator after this operand.
440 },492 self.putBackToken(token);
441 State.PrefixOp => |prefix_op| {493
442 prefix_op.rhs = expression;494 var expression = popSuffixOp(&stack);
443 expression = &prefix_op.base;495 while (true) {
444 continue;496 switch (stack.pop()) {
445 },497 State.Expression => |dest_ptr| {
446 else => unreachable,498 // we're done
447 }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;515 }
450 },516 continue;
451 }517 }
452 },518 },
453519
...@@ -685,11 +751,86 @@ pub const Parser = struct {...@@ -685,11 +751,86 @@ pub const Parser = struct {
685 // These are data, not control flow.751 // These are data, not control flow.
686 State.InfixOp => unreachable,752 State.InfixOp => unreachable,
687 State.PrefixOp => unreachable,753 State.PrefixOp => unreachable,
754 State.SuffixOp => unreachable,
688 State.Operand => unreachable,755 State.Operand => unreachable,
689 }756 }
690 }757 }
691 }758 }
692759
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 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {834 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {
694 if (self.pending_line_comment_node) |comment_node| {835 if (self.pending_line_comment_node) |comment_node| {
695 self.pending_line_comment_node = null;836 self.pending_line_comment_node = null;
...@@ -733,6 +874,20 @@ pub const Parser = struct {...@@ -733,6 +874,20 @@ pub const Parser = struct {
733 return node;874 return node;
734 }875 }
735876
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 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,891 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,
737 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto892 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,6 +992,16 @@ pub const Parser = struct {
837 return node;992 return node;
838 }993 }
839994
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 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {1005 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
841 const node = try self.createIdentifier(arena, name_token);1006 const node = try self.createIdentifier(arena, name_token);
842 try dest_ptr.store(&node.base);1007 try dest_ptr.store(&node.base);
...@@ -867,6 +1032,14 @@ pub const Parser = struct {...@@ -867,6 +1032,14 @@ pub const Parser = struct {
867 return node;1032 return node;
868 }1033 }
8691034
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 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {1043 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
871 const loc = self.tokenizer.getTokenLocation(token);1044 const loc = self.tokenizer.getTokenLocation(token);
872 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args);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,7 +1205,11 @@ pub const Parser = struct {
1032 ast.Node.Id.VarDecl => {1205 ast.Node.Id.VarDecl => {
1033 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);1206 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
1034 try stack.append(RenderState { .VarDecl = var_decl});1207 try stack.append(RenderState { .VarDecl = var_decl});
10351208 },
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 else => unreachable,1214 else => unreachable,
1038 }1215 }
...@@ -1131,29 +1308,57 @@ pub const Parser = struct {...@@ -1131,29 +1308,57 @@ pub const Parser = struct {
1131 ast.Node.Id.InfixOp => {1308 ast.Node.Id.InfixOp => {
1132 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);1309 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
1133 try stack.append(RenderState { .Expression = prefix_op_node.rhs });1310 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
1134 switch (prefix_op_node.op) {1311 const text = switch (prefix_op_node.op) {
1135 ast.NodeInfixOp.InfixOp.EqualEqual => {1312 ast.NodeInfixOp.InfixOp.Add => " + ",
1136 try stack.append(RenderState { .Text = " == "});1313 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
1137 },1314 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
1138 ast.NodeInfixOp.InfixOp.BangEqual => {1315 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
1139 try stack.append(RenderState { .Text = " != "});1316 ast.NodeInfixOp.InfixOp.Assign => " = ",
1140 },1317 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
1141 ast.NodeInfixOp.InfixOp.Period => {1318 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
1142 try stack.append(RenderState { .Text = "."});1319 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
1143 },1320 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
1144 }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 try stack.append(RenderState { .Expression = prefix_op_node.lhs });1356 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
1146 },1357 },
1147 ast.Node.Id.PrefixOp => {1358 ast.Node.Id.PrefixOp => {
1148 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);1359 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
1149 try stack.append(RenderState { .Expression = prefix_op_node.rhs });1360 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
1150 switch (prefix_op_node.op) {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 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {1362 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
1158 try stream.write("&");1363 try stream.write("&");
1159 if (addr_of_info.volatile_token != null) {1364 if (addr_of_info.volatile_token != null) {
...@@ -1168,6 +1373,14 @@ pub const Parser = struct {...@@ -1168,6 +1373,14 @@ pub const Parser = struct {
1168 try stack.append(RenderState { .Expression = align_expr});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 ast.Node.Id.IntegerLiteral => {1386 ast.Node.Id.IntegerLiteral => {
...@@ -1182,6 +1395,10 @@ pub const Parser = struct {...@@ -1182,6 +1395,10 @@ pub const Parser = struct {
1182 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);1395 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
1183 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));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 ast.Node.Id.BuiltinCall => {1402 ast.Node.Id.BuiltinCall => {
1186 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);1403 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);
1187 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));1404 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
...@@ -1196,11 +1413,27 @@ pub const Parser = struct {...@@ -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 ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),1431 ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),
1200 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),1432 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
12011433
1202 ast.Node.Id.Root,1434 ast.Node.Id.Root,
1203 ast.Node.Id.VarDecl,1435 ast.Node.Id.VarDecl,
1436 ast.Node.Id.TestDecl,
1204 ast.Node.Id.ParamDecl => unreachable,1437 ast.Node.Id.ParamDecl => unreachable,
1205 },1438 },
1206 RenderState.FnProtoRParen => |fn_proto| {1439 RenderState.FnProtoRParen => |fn_proto| {
...@@ -1422,4 +1655,79 @@ test "zig fmt" {...@@ -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,6 +77,7 @@ pub const Token = struct {
77 Builtin,77 Builtin,
78 Bang,78 Bang,
79 Pipe,79 Pipe,
80 PipePipe,
80 PipeEqual,81 PipeEqual,
81 Equal,82 Equal,
82 EqualEqual,83 EqualEqual,
...@@ -85,18 +86,46 @@ pub const Token = struct {...@@ -85,18 +86,46 @@ pub const Token = struct {
85 RParen,86 RParen,
86 Semicolon,87 Semicolon,
87 Percent,88 Percent,
89 PercentEqual,
88 LBrace,90 LBrace,
89 RBrace,91 RBrace,
90 Period,92 Period,
91 Ellipsis2,93 Ellipsis2,
92 Ellipsis3,94 Ellipsis3,
95 Caret,
96 CaretEqual,
97 Plus,
98 PlusPlus,
99 PlusEqual,
100 PlusPercent,
101 PlusPercentEqual,
93 Minus,102 Minus,
103 MinusEqual,
104 MinusPercent,
105 MinusPercentEqual,
106 Asterisk,
107 AsteriskEqual,
108 AsteriskAsterisk,
109 AsteriskPercent,
110 AsteriskPercentEqual,
94 Arrow,111 Arrow,
95 Colon,112 Colon,
96 Slash,113 Slash,
114 SlashEqual,
97 Comma,115 Comma,
98 Ampersand,116 Ampersand,
99 AmpersandEqual,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 IntegerLiteral,129 IntegerLiteral,
101 FloatLiteral,130 FloatLiteral,
102 LineComment,131 LineComment,
...@@ -200,6 +229,9 @@ pub const Tokenizer = struct {...@@ -200,6 +229,9 @@ pub const Tokenizer = struct {
200 Bang,229 Bang,
201 Pipe,230 Pipe,
202 Minus,231 Minus,
232 MinusPercent,
233 Asterisk,
234 AsteriskPercent,
203 Slash,235 Slash,
204 LineComment,236 LineComment,
205 Zero,237 Zero,
...@@ -210,6 +242,15 @@ pub const Tokenizer = struct {...@@ -210,6 +242,15 @@ pub const Tokenizer = struct {
210 FloatExponentUnsigned,242 FloatExponentUnsigned,
211 FloatExponentNumber,243 FloatExponentNumber,
212 Ampersand,244 Ampersand,
245 Caret,
246 Percent,
247 QuestionMark,
248 Plus,
249 PlusPercent,
250 AngleBracketLeft,
251 AngleBracketAngleBracketLeft,
252 AngleBracketRight,
253 AngleBracketAngleBracketRight,
213 Period,254 Period,
214 Period2,255 Period2,
215 SawAtSign,256 SawAtSign,
...@@ -291,9 +332,25 @@ pub const Tokenizer = struct {...@@ -291,9 +332,25 @@ pub const Tokenizer = struct {
291 break;332 break;
292 },333 },
293 '%' => {334 '%' => {
294 result.id = Token.Id.Percent;335 state = State.Percent;
295 self.index += 1;336 },
296 break;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 result.id = Token.Id.LBrace;356 result.id = Token.Id.LBrace;
...@@ -305,6 +362,11 @@ pub const Tokenizer = struct {...@@ -305,6 +362,11 @@ pub const Tokenizer = struct {
305 self.index += 1;362 self.index += 1;
306 break;363 break;
307 },364 },
365 '~' => {
366 result.id = Token.Id.Tilde;
367 self.index += 1;
368 break;
369 },
308 '.' => {370 '.' => {
309 state = State.Period;371 state = State.Period;
310 },372 },
...@@ -356,6 +418,107 @@ pub const Tokenizer = struct {...@@ -356,6 +418,107 @@ pub const Tokenizer = struct {
356 break;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 State.Identifier => switch (c) {522 State.Identifier => switch (c) {
360 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},523 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
361 else => {524 else => {
...@@ -417,6 +580,11 @@ pub const Tokenizer = struct {...@@ -417,6 +580,11 @@ pub const Tokenizer = struct {
417 self.index += 1;580 self.index += 1;
418 break;581 break;
419 },582 },
583 '|' => {
584 result.id = Token.Id.PipePipe;
585 self.index += 1;
586 break;
587 },
420 else => {588 else => {
421 result.id = Token.Id.Pipe;589 result.id = Token.Id.Pipe;
422 break;590 break;
...@@ -441,12 +609,86 @@ pub const Tokenizer = struct {...@@ -441,12 +609,86 @@ pub const Tokenizer = struct {
441 self.index += 1;609 self.index += 1;
442 break;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 else => {620 else => {
445 result.id = Token.Id.Minus;621 result.id = Token.Id.Minus;
446 break;622 break;
447 },623 },
448 },624 },
449625
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 State.Period => switch (c) {692 State.Period => switch (c) {
451 '.' => {693 '.' => {
452 state = State.Period2;694 state = State.Period2;
...@@ -474,6 +716,11 @@ pub const Tokenizer = struct {...@@ -474,6 +716,11 @@ pub const Tokenizer = struct {
474 result.id = Token.Id.LineComment;716 result.id = Token.Id.LineComment;
475 state = State.LineComment;717 state = State.LineComment;
476 },718 },
719 '=' => {
720 result.id = Token.Id.SlashEqual;
721 self.index += 1;
722 break;
723 },
477 else => {724 else => {
478 result.id = Token.Id.Slash;725 result.id = Token.Id.Slash;
479 break;726 break;
...@@ -609,6 +856,42 @@ pub const Tokenizer = struct {...@@ -609,6 +856,42 @@ pub const Tokenizer = struct {
609 State.Pipe => {856 State.Pipe => {
610 result.id = Token.Id.Pipe;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 if (result.id == Token.Id.Eof) {897 if (result.id == Token.Id.Eof) {
...@@ -752,8 +1035,8 @@ test "tokenizer - string identifier and builtin fns" {...@@ -752,8 +1035,8 @@ test "tokenizer - string identifier and builtin fns" {
7521035
753test "tokenizer - pipe and then invalid" {1036test "tokenizer - pipe and then invalid" {
754 testTokenize("||=", []Token.Id{1037 testTokenize("||=", []Token.Id{
755 Token.Id.Pipe,1038 Token.Id.PipePipe,
756 Token.Id.PipeEqual,1039 Token.Id.Equal,
757 });1040 });
758}1041}
7591042
test/cases/coroutines.zig+33
...@@ -5,6 +5,7 @@ var x: i32 = 1;...@@ -5,6 +5,7 @@ var x: i32 = 1;
55
6test "create a coroutine and cancel it" {6test "create a coroutine and cancel it" {
7 const p = try async<std.debug.global_allocator> simpleAsyncFn();7 const p = try async<std.debug.global_allocator> simpleAsyncFn();
8 comptime assert(@typeOf(p) == promise->void);
8 cancel p;9 cancel p;
9 assert(x == 2);10 assert(x == 2);
10}11}
...@@ -55,6 +56,7 @@ var result = false;...@@ -55,6 +56,7 @@ var result = false;
5556
56async fn testSuspendBlock() void {57async fn testSuspendBlock() void {
57 suspend |p| {58 suspend |p| {
59 comptime assert(@typeOf(p) == promise->void);
58 a_promise = p;60 a_promise = p;
59 }61 }
60 result = true;62 result = true;
...@@ -156,3 +158,34 @@ test "async function with dot syntax" {...@@ -156,3 +158,34 @@ test "async function with dot syntax" {
156 cancel p;158 cancel p;
157 assert(S.y == 2);159 assert(S.y == 2);
158}160}
161
162test "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
176async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
177 defer *y += 2;
178 *y += 1;
179 suspend;
180}
181
182test "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
188async fn failing() !void {
189 suspend;
190 return error.Fail;
191}
test/cases/eval.zig+11-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;1const std = @import("std");
2const assert = std.debug.assert;
2const builtin = @import("builtin");3const builtin = @import("builtin");
34
4test "compile time recursion" {5test "compile time recursion" {
...@@ -503,3 +504,12 @@ test "const ptr to comptime mutable data is not memoized" {...@@ -503,3 +504,12 @@ test "const ptr to comptime mutable data is not memoized" {
503 assert(foo.read_x() == 2);504 assert(foo.read_x() == 2);
504 }505 }
505}506}
507
508test "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,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) void {3pub 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 cases.add("@tagName used on union with no associated enum tag",13 cases.add("@tagName used on union with no associated enum tag",
5 \\const FloatInt = extern union {14 \\const FloatInt = extern union {
6 \\ Float: f32,15 \\ Float: f32,
test/gen_h.zig+11
...@@ -51,6 +51,16 @@ pub fn addCases(cases: &tests.GenHContext) void {...@@ -51,6 +51,16 @@ pub fn addCases(cases: &tests.GenHContext) void {
51 \\51 \\
52 );52 );
5353
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 cases.add("array field-type",64 cases.add("array field-type",
55 \\const Foo = extern struct {65 \\const Foo = extern struct {
56 \\ A: [2]i32,66 \\ A: [2]i32,
...@@ -66,4 +76,5 @@ pub fn addCases(cases: &tests.GenHContext) void {...@@ -66,4 +76,5 @@ pub fn addCases(cases: &tests.GenHContext) void {
66 \\TEST_EXPORT void entry(struct Foo foo, uint8_t bar[]);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,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
281 \\ f.float = 12.34;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}