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 @@
1sudo: required
2services:
3 - docker
14os:
25 - linux
36 - osx
47dist: trusty
58osx_image: xcode8.3
6sudo: required
79language: cpp
810before_install:
911 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
CMakeLists.txt+5-6
......@@ -30,11 +30,7 @@ if(GIT_EXE)
3030endif()
3131message("Configuring zig version ${ZIG_VERSION}")
3232
33set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found")
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")
33set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
3834
3935string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")
4036string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}")
......@@ -429,6 +425,7 @@ set(ZIG_STD_FILES
429425 "crypto/sha2.zig"
430426 "crypto/sha3.zig"
431427 "crypto/blake2.zig"
428 "crypto/hmac.zig"
432429 "cstr.zig"
433430 "debug/failing_allocator.zig"
434431 "debug/index.zig"
......@@ -509,7 +506,7 @@ set(ZIG_STD_FILES
509506 "os/windows/index.zig"
510507 "os/windows/util.zig"
511508 "os/zen.zig"
512 "rand.zig"
509 "rand/index.zig"
513510 "sort.zig"
514511 "special/bootstrap.zig"
515512 "special/bootstrap_lib.zig"
......@@ -698,6 +695,8 @@ if(MINGW)
698695 set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++")
699696elseif(MSVC)
700697 set(EXE_LDFLAGS "/STACK:16777216")
698elseif(ZIG_STATIC)
699 set(EXE_LDFLAGS "-static")
701700else()
702701 set(EXE_LDFLAGS " ")
703702endif()
README.md+1-7
......@@ -138,14 +138,10 @@ libc. Create demo games using Zig.
138138
139139##### 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
145141```
146142mkdir build
147143cd 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)
149145make
150146make install
151147./zig build --build-file ../build.zig test
......@@ -153,8 +149,6 @@ make install
153149
154150##### MacOS
155151
156`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157
158152```
159153brew install cmake llvm@7
160154brew outdated llvm@7 || brew upgrade llvm@7
build.zig+5
......@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {
4545
4646 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
4747 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
4853 exe.addIncludeDir("src");
4954 exe.addIncludeDir(cmake_binary_dir);
5055 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_
2020
2121mkdir %ZIGBUILDDIR%
2222cd %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 /b
23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
2424msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
2525
2626bin\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
44
55sudo apt-get remove -y llvm-*
66sudo 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-amd64
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 s3cmd
ci/travis_linux_script+11-20
......@@ -8,25 +8,16 @@ export CXX=clang++-7.0
88echo $PATH
99mkdir build
1010cd 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))
12make VERBOSE=1
13make install
11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
12make -j2 install
1413./zig build --build-file ../build.zig test
1514
16./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc
17wine zig-cache/test.exe
18
19./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-fast
20wine zig-cache/test.exe
21
22./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-safe
23wine zig-cache/test.exe
24
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
15if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
16 mkdir $TRAVIS_BUILD_DIR/artifacts
17 docker run -it --mount type=bind,source="$TRAVIS_BUILD_DIR/artifacts",target=/z ziglang/static-base:llvm6-1 -j2 $TRAVIS_COMMIT
18 echo "access_key = $AWS_ACCESS_KEY_ID" >> ~/.s3cfg
19 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
20 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
21 touch empty
22 s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
23fi
cmake/Findllvm.cmake+1-1
......@@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE
1515 "c:/msys64/mingw64/bin"
1616 "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)
1919 execute_process(
2020 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static
2121 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES
doc/docgen.zig+1-1
......@@ -55,7 +55,7 @@ pub fn main() !void {
5555 // TODO issue #709
5656 // disabled to pass CI tests, but obviously we want to implement this
5757 // and then remove this workaround
58 if (builtin.os == builtin.Os.linux) {
58 if (builtin.os != builtin.Os.windows) {
5959 os.deleteTree(allocator, tmp_dir_name) catch {};
6060 }
6161 }
doc/langref.html.in+11-10
......@@ -2864,18 +2864,18 @@ const err = (error {FileNotFound}).FileNotFound;
28642864 assert to make sure the error value is in fact in the destination error set.
28652865 </p>
28662866 <p>
2867 The global error set should generally be avoided when possible, because it prevents
2868 the compiler from knowing what errors are possible at compile-time. Knowing
2869 the error set at compile-time is better for generated documentationt and for
2870 helpful error messages such as forgetting a possible error value in a {#link|switch#}.
2867 The global error set should generally be avoided because it prevents the
2868 compiler from knowing what errors are possible at compile-time. Knowing
2869 the error set at compile-time is better for generated documentation and
2870 helpful error messages, such as forgetting a possible error value in a {#link|switch#}.
28712871 </p>
28722872 {#header_close#}
28732873 {#header_close#}
28742874 {#header_open|Error Union Type#}
28752875 <p>
2876 Most of the time you will not find yourself using an error set type. Instead,
2877 likely you will be using the error union type. This is when you take an error set
2878 and a normal type, and create an error union with the <code>!</code> binary operator.
2876 An error set type and normal type can be combined with the <code>!</code>
2877 binary operator to form an error union type. You are likely to use an
2878 error union type more often than an error set type by itself.
28792879 </p>
28802880 <p>
28812881 Here is a function to parse a string into a 64-bit integer:
......@@ -5739,7 +5739,7 @@ UseDecl = "use" Expression ";"
57395739
57405740ExternDecl = "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
57445744FnDef = option("inline" | "export") FnProto Block
57455745
......@@ -5863,7 +5863,9 @@ StructLiteralField = "." Symbol "=" Expression
58635863
58645864PrefixOp = "!" | "-" | "~" | "*" | ("&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)) | ErrorSetDecl
5866PrimaryExpression = 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
58685870ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
58695871
......@@ -6031,4 +6033,3 @@ hljs.registerLanguage("zig", function(t) {
60316033 </script>
60326034 </body>
60336035</html>
6034
example/guess_number/main.zig+11-11
......@@ -2,7 +2,6 @@ const builtin = @import("builtin");
22const std = @import("std");
33const io = std.io;
44const fmt = std.fmt;
5const Rand = std.rand.Rand;
65const os = std.os;
76
87pub fn main() !void {
......@@ -10,30 +9,31 @@ pub fn main() !void {
109 var stdout_file_stream = io.FileOutStream.init(&stdout_file);
1110 const stdout = &stdout_file_stream.stream;
1211
13 var stdin_file = try io.getStdIn();
14
1512 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;
1815 os.getRandomBytes(seed_bytes[0..]) catch |err| {
1916 std.debug.warn("unable to seed random number generator: {}", err);
2017 return err;
2118 };
22 const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big);
23 var rand = Rand.init(seed);
19 const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
20 var prng = std.rand.DefaultPrng.init(seed);
2421
25 const answer = rand.range(u8, 0, 100) + 1;
22 const answer = prng.random.range(u8, 0, 100) + 1;
2623
2724 while (true) {
2825 try stdout.print("\nGuess a number between 1 and 100: ");
2926 var line_buf : [20]u8 = undefined;
3027
31 const line_len = stdin_file.read(line_buf[0..]) catch |err| {
32 try stdout.print("Unable to read from stdin: {}\n", @errorName(err));
33 return err;
28 const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
29 error.InputTooLong => {
30 try stdout.print("Input too long.\n");
31 continue;
32 },
33 error.EndOfFile, error.StdInUnavailable => return err,
3434 };
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 {
3737 try stdout.print("Invalid number.\n");
3838 continue;
3939 };
src-self-hosted/main.zig+159
......@@ -41,6 +41,10 @@ pub fn main() !void {
4141 const args = try os.argsAlloc(allocator);
4242 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
4448 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
4549 return fmtMain(allocator, args[2..]);
4650 }
......@@ -560,6 +564,161 @@ fn printZen() !void {
560564 );
561565}
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
563722fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
564723 for (file_paths) |file_path| {
565724 var file = try os.File.openRead(allocator, file_path);
src/all_types.hpp+39-2
......@@ -409,6 +409,7 @@ enum NodeType {
409409 NodeTypeResume,
410410 NodeTypeAwaitExpr,
411411 NodeTypeSuspend,
412 NodeTypePromiseType,
412413};
413414
414415struct AstNodeRoot {
......@@ -879,6 +880,10 @@ struct AstNodeSuspend {
879880 AstNode *promise_symbol;
880881};
881882
883struct AstNodePromiseType {
884 AstNode *payload_type; // can be NULL
885};
886
882887struct AstNode {
883888 enum NodeType type;
884889 size_t line;
......@@ -939,6 +944,7 @@ struct AstNode {
939944 AstNodeResumeExpr resume_expr;
940945 AstNodeAwaitExpr await_expr;
941946 AstNodeSuspend suspend;
947 AstNodePromiseType promise_type;
942948 } data;
943949};
944950
......@@ -1251,7 +1257,10 @@ struct FnTableEntry {
12511257 ScopeBlock *def_scope; // parent is child_scope
12521258 Buf symbol_name;
12531259 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;
12551264 bool is_test;
12561265 FnInline fn_inline;
12571266 FnAnalState anal_state;
......@@ -1612,7 +1621,8 @@ struct CodeGen {
16121621 FnTableEntry *panic_fn;
16131622 LLVMValueRef cur_ret_ptr;
16141623 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;
16161626 bool c_want_stdint;
16171627 bool c_want_stdbool;
16181628 AstNode *root_export_decl;
......@@ -1749,6 +1759,7 @@ enum ScopeId {
17491759 ScopeIdLoop,
17501760 ScopeIdFnDef,
17511761 ScopeIdCompTime,
1762 ScopeIdCoroPrelude,
17521763};
17531764
17541765struct Scope {
......@@ -1856,6 +1867,12 @@ struct ScopeFnDef {
18561867 FnTableEntry *fn_entry;
18571868};
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
18591876// synchronized with code in define_builtin_compile_vars
18601877enum AtomicOrder {
18611878 AtomicOrderUnordered,
......@@ -1942,6 +1959,7 @@ enum IrInstructionId {
19421959 IrInstructionIdSetRuntimeSafety,
19431960 IrInstructionIdSetFloatMode,
19441961 IrInstructionIdArrayType,
1962 IrInstructionIdPromiseType,
19451963 IrInstructionIdSliceType,
19461964 IrInstructionIdAsm,
19471965 IrInstructionIdSizeOf,
......@@ -2032,6 +2050,8 @@ enum IrInstructionId {
20322050 IrInstructionIdAtomicRmw,
20332051 IrInstructionIdPromiseResultType,
20342052 IrInstructionIdAwaitBookkeeping,
2053 IrInstructionIdSaveErrRetAddr,
2054 IrInstructionIdAddImplicitReturnType,
20352055};
20362056
20372057struct IrInstruction {
......@@ -2358,6 +2378,12 @@ struct IrInstructionArrayType {
23582378 IrInstruction *child_type;
23592379};
23602380
2381struct IrInstructionPromiseType {
2382 IrInstruction base;
2383
2384 IrInstruction *payload_type;
2385};
2386
23612387struct IrInstructionSliceType {
23622388 IrInstruction base;
23632389
......@@ -2671,6 +2697,7 @@ struct IrInstructionFnProto {
26712697 IrInstruction **param_types;
26722698 IrInstruction *align_value;
26732699 IrInstruction *return_type;
2700 IrInstruction *async_allocator_type_value;
26742701 bool is_var_args;
26752702};
26762703
......@@ -2985,6 +3012,16 @@ struct IrInstructionAwaitBookkeeping {
29853012 IrInstruction *promise_result_type;
29863013};
29873014
3015struct IrInstructionSaveErrRetAddr {
3016 IrInstruction base;
3017};
3018
3019struct IrInstructionAddImplicitReturnType {
3020 IrInstruction base;
3021
3022 IrInstruction *value;
3023};
3024
29883025static const size_t slice_ptr_index = 0;
29893026static 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) {
170170 return &scope->base;
171171}
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
173179ImportTableEntry *get_scope_import(Scope *scope) {
174180 while (scope) {
175181 if (scope->id == ScopeIdDecls) {
......@@ -985,7 +991,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
985991 // populate the name of the type
986992 buf_resize(&fn_type->name, 0);
987993 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));
989996 } else {
990997 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
991998 buf_appendf(&fn_type->name, "%s", cc_str);
......@@ -3253,6 +3260,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
32533260 case NodeTypeResume:
32543261 case NodeTypeAwaitExpr:
32553262 case NodeTypeSuspend:
3263 case NodeTypePromiseType:
32563264 zig_unreachable();
32573265 }
32583266}
......@@ -3590,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
35903598 case ScopeIdCImport:
35913599 case ScopeIdLoop:
35923600 case ScopeIdCompTime:
3601 case ScopeIdCoroPrelude:
35933602 scope = scope->parent;
35943603 continue;
35953604 case ScopeIdFnDef:
......@@ -3864,7 +3873,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38643873
38653874 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
38663875 &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
38693878 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
38703879 assert(g->errors.length > 0);
......@@ -3876,10 +3885,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38763885 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
38773886 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
38783887 TypeTableEntry *inferred_err_set_type;
3879 if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) {
3880 inferred_err_set_type = fn_table_entry->implicit_return_type;
3881 } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) {
3882 inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type;
3888 if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) {
3889 inferred_err_set_type = fn_table_entry->src_implicit_return_type;
3890 } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) {
3891 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
38833892 } else {
38843893 add_node_error(g, return_type_node,
38853894 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) {
42764285 return g->win_sdk;
42774286}
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
42794376void find_libc_include_path(CodeGen *g) {
4280 if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
4281 ZigWindowsSDK *sdk = get_windows_sdk(g);
4377 if (g->libc_include_dir == nullptr) {
42824378
42834379 if (g->zig_target.os == OsWindows) {
4380 ZigWindowsSDK *sdk = get_windows_sdk(g);
4381 g->libc_include_dir = buf_alloc();
42844382 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
42854383 zig_panic("Unable to determine libc include path.");
42864384 }
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.");
42874392 }
42884393 }
4289
4290 // TODO find libc at runtime for other operating systems
4291 if(!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
4292 zig_panic("Unable to determine libc include path.");
4293 }
4394 assert(buf_len(g->libc_include_dir) != 0);
42944395}
42954396
42964397void find_libc_lib_path(CodeGen *g) {
42974398 // 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 ||
42994400 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
43004401 {
43014402 if (g->zig_target.os == OsWindows) {
......@@ -4319,18 +4420,25 @@ void find_libc_lib_path(CodeGen *g) {
43194420 g->msvc_lib_dir = vc_lib_dir;
43204421 g->libc_lib_dir = ucrt_lib_path;
43214422 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");
43224425 } else {
43234426 zig_panic("Unable to determine libc lib path.");
43244427 }
4428 } else {
4429 assert(buf_len(g->libc_lib_dir) != 0);
43254430 }
43264431
4327 if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {
4432 if (g->libc_static_lib_dir == nullptr) {
43284433 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
43294434 return;
4330 }
4331 else {
4435 } else if (g->zig_target.os == OsLinux) {
4436 g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4437 } else {
43324438 zig_panic("Unable to determine libc static lib path.");
43334439 }
4440 } else {
4441 assert(buf_len(g->libc_static_lib_dir) != 0);
43344442 }
43354443}
43364444
src/analyze.hpp+1
......@@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);
107107ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
108108ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
109109Scope *create_comptime_scope(AstNode *node, Scope *parent);
110Scope *create_coro_prelude_scope(AstNode *node, Scope *parent);
110111
111112void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
112113ConstExprValue *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) {
250250 return "AwaitExpr";
251251 case NodeTypeSuspend:
252252 return "Suspend";
253 case NodeTypePromiseType:
254 return "PromiseType";
253255 }
254256 zig_unreachable();
255257}
......@@ -658,6 +660,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
658660 if (node->data.fn_call_expr.is_builtin) {
659661 fprintf(ar->f, "@");
660662 }
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 }
661672 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
662673 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);
663674 render_node_extra(ar, fn_ref_node, grouped);
......@@ -772,6 +783,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
772783 render_node_ungrouped(ar, node->data.array_type.child_type);
773784 break;
774785 }
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 }
775795 case NodeTypeErrorType:
776796 fprintf(ar->f, "error");
777797 break;
......@@ -1023,7 +1043,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
10231043 case NodeTypeUnwrapErrorExpr:
10241044 {
10251045 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
1026 fprintf(ar->f, " %%%% ");
1046 fprintf(ar->f, " catch ");
10271047 if (node->data.unwrap_err_expr.symbol) {
10281048 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
10291049 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
112112 // that's for native compilation
113113 g->zig_target = *target;
114114 resolve_target_object_format(&g->zig_target);
115 g->dynamic_linker = buf_create_from_str("");
116 g->libc_lib_dir = buf_create_from_str("");
117 g->libc_static_lib_dir = buf_create_from_str("");
118 g->libc_include_dir = buf_create_from_str("");
115 g->dynamic_linker = nullptr;
116 g->libc_lib_dir = nullptr;
117 g->libc_static_lib_dir = nullptr;
118 g->libc_include_dir = nullptr;
119119 g->msvc_lib_dir = nullptr;
120120 g->kernel32_lib_dir = nullptr;
121121 g->each_lib_rpath = false;
......@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
123123 // native compilation, we can rely on the configuration stuff
124124 g->is_native_target = true;
125125 get_native_target(&g->zig_target);
126 g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);
127 g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);
128 g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);
129 g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);
126 g->dynamic_linker = nullptr; // find it at runtime
127 g->libc_lib_dir = nullptr; // find it at runtime
128 g->libc_static_lib_dir = nullptr; // find it at runtime
129 g->libc_include_dir = nullptr; // find it at runtime
130130 g->msvc_lib_dir = nullptr; // find it at runtime
131131 g->kernel32_lib_dir = nullptr; // find it at runtime
132
133#ifdef ZIG_EACH_LIB_RPATH
134132 g->each_lib_rpath = true;
135#endif
136133
137134 if (g->zig_target.os == OsMacOSX ||
138135 g->zig_target.os == OsIOS)
......@@ -657,6 +654,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
657654 case ScopeIdDeferExpr:
658655 case ScopeIdLoop:
659656 case ScopeIdCompTime:
657 case ScopeIdCoroPrelude:
660658 return get_di_scope(g, scope->parent);
661659 }
662660 zig_unreachable();
......@@ -1295,9 +1293,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
12951293 return fn_val;
12961294}
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) {
12991322 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);
13011324 if (err_ret_trace_val == nullptr) {
13021325 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
13031326 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) {
15741597 return instruction->llvm_value;
15751598}
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
15771615static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
15781616 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
15791617 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 }
16031619 if (handle_is_ptr(return_type)) {
16041620 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
16051621 assert(g->cur_ret_ptr);
......@@ -2671,7 +2687,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
26712687 gen_param_index += 1;
26722688 }
26732689 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);
26752691 gen_param_index += 1;
26762692 }
26772693 if (instruction->is_async) {
......@@ -3238,11 +3254,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
32383254static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
32393255 IrInstructionErrorReturnTrace *instruction)
32403256{
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) {
32423259 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
32433260 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);
32443261 }
3245 return g->cur_err_ret_trace_val;
3262 return cur_err_ret_trace_val;
32463263}
32473264
32483265static 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
36483665 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
36493666
36503667 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
36533670 LLVMPositionBuilderAtEnd(g->builder, ok_block);
36543671 }
......@@ -3840,7 +3857,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
38403857}
38413858
38423859static 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));
38443861 return nullptr;
38453862}
38463863
......@@ -4127,6 +4144,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
41274144 case IrInstructionIdSetRuntimeSafety:
41284145 case IrInstructionIdSetFloatMode:
41294146 case IrInstructionIdArrayType:
4147 case IrInstructionIdPromiseType:
41304148 case IrInstructionIdSliceType:
41314149 case IrInstructionIdSizeOf:
41324150 case IrInstructionIdSwitchTarget:
......@@ -4167,6 +4185,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
41674185 case IrInstructionIdErrorUnion:
41684186 case IrInstructionIdPromiseResultType:
41694187 case IrInstructionIdAwaitBookkeeping:
4188 case IrInstructionIdAddImplicitReturnType:
41704189 zig_unreachable();
41714190
41724191 case IrInstructionIdReturn:
......@@ -4315,6 +4334,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
43154334 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
43164335 case IrInstructionIdAtomicRmw:
43174336 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4337 case IrInstructionIdSaveErrRetAddr:
4338 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
43184339 }
43194340 zig_unreachable();
43204341}
......@@ -5197,9 +5218,17 @@ static void do_code_gen(CodeGen *g) {
51975218 clear_debug_source_node(g);
51985219
51995220 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
5200 if (err_ret_trace_arg_index != UINT32_MAX) {
5201 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);
5202 } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) {
5221 bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX;
5222 if (have_err_ret_trace_arg) {
5223 g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index);
5224 } else {
5225 g->cur_err_ret_trace_val_arg = nullptr;
5226 }
5227
5228 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
5229 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&
5230 (is_async || !have_err_ret_trace_arg);
5231 if (have_err_ret_trace_stack) {
52035232 // TODO call graph analysis to find out what this number needs to be for every function
52045233 static const size_t stack_trace_ptr_count = 30;
52055234
......@@ -5207,13 +5236,13 @@ static void do_code_gen(CodeGen *g) {
52075236 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
52085237 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
52095238 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));
52115240 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, "");
52135242 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
52145243
52155244 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
52185247 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
52195248 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) {
52295258 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
52305259 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
52315260 } else {
5232 g->cur_err_ret_trace_val = nullptr;
5261 g->cur_err_ret_trace_val_stack = nullptr;
52335262 }
52345263
52355264 // allocate temporary stack data
......@@ -6172,7 +6201,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
61726201 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
61736202 }
61746203 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))) {
61766205 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
61776206 }
61786207
......@@ -6260,7 +6289,7 @@ static void gen_root_source(CodeGen *g) {
62606289 }
62616290
62626291 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))) {
62646293 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
62656294 }
62666295
......@@ -6325,7 +6354,7 @@ static void gen_global_asm(CodeGen *g) {
63256354 int err;
63266355 for (size_t i = 0; i < g->assembly_files.length; i += 1) {
63276356 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))) {
63296358 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
63306359 }
63316360 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
65076536 }
65086537 }
65096538 case TypeTableEntryIdStruct:
6539 case TypeTableEntryIdOpaque:
65106540 {
65116541 buf_init_from_str(out_buf, "struct ");
65126542 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
65246554 buf_append_buf(out_buf, &type_entry->name);
65256555 return;
65266556 }
6527 case TypeTableEntryIdOpaque:
6528 {
6529 buf_init_from_buf(out_buf, &type_entry->name);
6530 return;
6531 }
65326557 case TypeTableEntryIdArray:
65336558 {
65346559 TypeTableEntryArray *array_data = &type_entry->data.array;
src/config.h.in-8
......@@ -13,14 +13,6 @@
1313#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
1414#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
2416// Only used for running tests before installing.
2517#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2618
src/ir.cpp+234-70
......@@ -34,7 +34,7 @@ struct IrAnalyze {
3434 size_t old_bb_index;
3535 size_t instruction_index;
3636 TypeTableEntry *explicit_return_type;
37 ZigList<IrInstruction *> implicit_return_type_list;
37 ZigList<IrInstruction *> src_implicit_return_type_list;
3838 IrBasicBlock *const_predecessor_bb;
3939};
4040
......@@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
349349 return IrInstructionIdArrayType;
350350}
351351
352static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {
353 return IrInstructionIdPromiseType;
354}
355
352356static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
353357 return IrInstructionIdSliceType;
354358}
......@@ -713,6 +717,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping
713717 return IrInstructionIdAwaitBookkeeping;
714718}
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
716728template<typename T>
717729static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
718730 T *special_instruction = allocate<T>(1);
......@@ -1461,6 +1473,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
14611473 return &instruction->base;
14621474}
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
14641487static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
14651488 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)
14661489{
......@@ -2141,12 +2164,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
21412164}
21422165
21432166static 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)
21452169{
21462170 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
21472171 instruction->param_types = param_types;
21482172 instruction->align_value = align_value;
21492173 instruction->return_type = return_type;
2174 instruction->async_allocator_type_value = async_allocator_type_value;
21502175 instruction->is_var_args = is_var_args;
21512176
21522177 assert(source_node->type == NodeTypeFnProto);
......@@ -2156,6 +2181,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
21562181 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
21572182 }
21582183 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);
21592185 ir_ref_instruction(return_type, irb->current_basic_block);
21602186
21612187 return &instruction->base;
......@@ -2675,6 +2701,22 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A
26752701 return &instruction->base;
26762702}
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
26782720static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
26792721 results[ReturnKindUnconditional] = 0;
26802722 results[ReturnKindError] = 0;
......@@ -2747,16 +2789,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
27472789 return nullptr;
27482790}
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
27502797static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
27512798 bool is_generated_code)
27522799{
2753 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
2754 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2800 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
2801
2802 bool is_async = exec_is_async(irb->exec);
27552803 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 //}
27602804 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
27612805 return_inst->is_gen = is_generated_code;
27622806 return return_inst;
......@@ -2778,21 +2822,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
27782822 // the above blocks are rendered by ir_gen after the rest of codegen
27792823}
27802824
2781//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {
2782// if (!irb->codegen->have_err_ret_tracing)
2783// return;
2784//
2785// if (is_async) {
2786// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2787// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);
2788// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2789// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2790// return;
2791// }
2792//
2793// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2794// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2795//}
2825static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2826 if (!g->have_err_ret_tracing)
2827 return false;
2828 FnTableEntry *fn_entry = exec_fn_entry(exec);
2829 if (fn_entry == nullptr)
2830 return false;
2831 if (exec->is_inline)
2832 return false;
2833 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2834}
2835
2836static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2837 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2838 return;
2839
2840 bool is_async = exec_is_async(irb->exec);
2841
2842 if (is_async) {
2843 //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2844 //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node);
2845 //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2846 //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2847 return;
2848 }
2849
2850 ir_build_save_err_ret_addr(irb, scope, node);
2851}
27962852
27972853static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
27982854 assert(node->type == NodeTypeReturnExpr);
......@@ -2853,7 +2909,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28532909 if (have_err_defers) {
28542910 ir_gen_defers_for_block(irb, scope, outer_scope, true);
28552911 }
2856 //ir_gen_save_err_ret_addr(irb, scope, node, is_async);
2912 ir_gen_save_err_ret_addr(irb, scope, node);
28572913 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28582914
28592915 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,
28922948 ir_set_cursor_at_end_and_append_block(irb, return_block);
28932949 ir_gen_defers_for_block(irb, scope, outer_scope, true);
28942950 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2951 ir_gen_save_err_ret_addr(irb, scope, node);
28952952 ir_gen_async_return(irb, scope, node, err_val, false);
28962953
28972954 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
50325089 }
50335090}
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
50355108static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
50365109 assert(node->type == NodeTypeUndefinedLiteral);
50375110 return ir_build_const_undefined(irb, scope, node);
......@@ -5989,7 +6062,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
59896062 return_type = nullptr;
59906063 }
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);
59936074}
59946075
59956076static 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
62326313 return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
62336314 case NodeTypeArrayType:
62346315 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);
62356318 case NodeTypeStringLiteral:
62366319 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);
62376320 case NodeTypeUndefinedLiteral:
......@@ -6329,58 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
63296412 VariableTableEntry *coro_size_var;
63306413 if (is_async) {
63316414 // create the coro promise
6332 const_bool_false = ir_build_const_bool(irb, scope, node, false);
6333 VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);
6415 Scope *coro_scope = create_coro_prelude_scope(node, scope);
6416 const_bool_false = ir_build_const_bool(irb, coro_scope, node, false);
6417 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
63346418
63356419 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
6336 IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type);
6337 ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init);
6338 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false);
6420 IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type);
6421 ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init);
6422 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
63396423
6340 VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);
6341 IrInstruction *null_value = ir_build_const_null(irb, scope, node);
6342 IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node,
6424 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6425 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
6426 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
63436427 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6344 ir_build_var_decl(irb, scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
6345 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, scope, node,
6428 ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
6429 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node,
63466430 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,
63496433 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
6350 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr);
6351 coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr);
6352 coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);
6353 IrInstruction *coro_size = ir_build_coro_size(irb, scope, node);
6354 ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size);
6355 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
6434 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
6435 coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
6436 coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6437 IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
6438 ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
6439 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
63566440 ImplicitAllocatorIdArg);
6357 irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false);
6358 ir_build_var_decl(irb, scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
6441 irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
6442 ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
63596443 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
6360 IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name);
6361 IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);
6362 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size);
6363 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr);
6364 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");
6365 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk");
6366 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
6444 IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
6445 IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
6446 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
6447 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
6448 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
6449 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
6450 ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
63676451
63686452 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6369 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
6370 ir_build_return(irb, scope, node, undef);
6453 // we can return undefined here, because the caller passes a pointer to the error struct field
6454 // in the error union result, and we populate it in case of allocation failure.
6455 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6456 ir_build_return(irb, coro_scope, node, undef);
63716457
63726458 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
6373 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr);
6374 irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr);
6459 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
6460 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
63756461
63766462 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,
63786464 awaiter_handle_field_name);
63796465 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);
63816467 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6382 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
6383 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6468 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name);
6469 ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
63846470
63856471
63866472 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
63956481 return false;
63966482
63976483 if (!instr_is_unreachable(result)) {
6484 // no need for save_err_ret_addr because this cannot return error
63986485 ir_gen_async_return(irb, scope, result->source_node, result, true);
63996486 }
64006487
......@@ -10074,13 +10161,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
1007410161 return result;
1007510162}
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
1007710178static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
1007810179 IrInstructionReturn *return_instruction)
1007910180{
1008010181 IrInstruction *value = return_instruction->value->other;
1008110182 if (type_is_invalid(value->value.type))
1008210183 return ir_unreach_error(ira);
10083 ira->implicit_return_type_list.append(value);
1008410184
1008510185 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
1008610186 if (casted_value == ira->codegen->invalid_instruction)
......@@ -10958,6 +11058,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
1095811058 result_type = get_array_type(ira->codegen, child_type, new_len);
1095911059
1096011060 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);
1096111079 } else {
1096211080 new_len += 1; // null byte
1096311081
......@@ -11453,13 +11571,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1145311571 return ira->codegen->builtin_types.entry_void;
1145411572}
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
1145611579static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1145711580 IrInstructionErrorReturnTrace *instruction)
1145811581{
11459 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
1146011582 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
1146111583 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)) {
1146311585 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1146411586 out_val->data.x_maybe = nullptr;
1146511587 return nullable_type;
......@@ -13999,6 +14121,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
1399914121 zig_unreachable();
1400014122}
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
1400214142static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
1400314143 IrInstructionSizeOf *size_of_instruction)
1400414144{
......@@ -14569,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
1456914709 return ira->codegen->builtin_types.entry_namespace;
1457014710 }
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))) {
1457314713 if (err == ErrorFileNotFound) {
1457414714 ir_add_error_node(ira, source_node,
1457514715 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
1543015570 // load from file system into const expr
1543115571 Buf *file_contents = buf_alloc();
1543215572 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))) {
1543415574 if (err == ErrorFileNotFound) {
1543515575 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
1543615576 return ira->codegen->builtin_types.entry_invalid;
......@@ -16561,6 +16701,13 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
1656116701 if (type_is_invalid(fn_type_id.return_type))
1656216702 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
1656416711 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1656516712 out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);
1656616713 return ira->codegen->builtin_types.entry_type;
......@@ -16789,18 +16936,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
1678916936static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {
1679016937 IrInstruction *msg = instruction->msg->other;
1679116938 if (type_is_invalid(msg->value.type))
16792 return ira->codegen->builtin_types.entry_invalid;
16939 return ir_unreach_error(ira);
1679316940
1679416941 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
1679516942 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);
1679716944 }
1679816945
1679916946 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
1680016947 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
1680116948 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
1680216949 if (type_is_invalid(casted_msg->value.type))
16803 return ira->codegen->builtin_types.entry_invalid;
16950 return ir_unreach_error(ira);
1680416951
1680516952 IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope,
1680616953 instruction->base.source_node, casted_msg);
......@@ -17757,6 +17904,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
1775717904 return out_val->type;
1775817905}
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
1776017915static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1776117916 switch (instruction->id) {
1776217917 case IrInstructionIdInvalid:
......@@ -17822,6 +17977,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1782217977 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
1782317978 case IrInstructionIdArrayType:
1782417979 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
17980 case IrInstructionIdPromiseType:
17981 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
1782517982 case IrInstructionIdSizeOf:
1782617983 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
1782717984 case IrInstructionIdTestNonNull:
......@@ -17994,6 +18151,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1799418151 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
1799518152 case IrInstructionIdAwaitBookkeeping:
1799618153 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);
1799718158 }
1799818159 zig_unreachable();
1799918160}
......@@ -18067,11 +18228,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1806718228
1806818229 if (new_exec->invalid) {
1806918230 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) {
1807118232 return codegen->builtin_types.entry_unreachable;
1807218233 } else {
18073 return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,
18074 ira->implicit_return_type_list.length);
18234 return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items,
18235 ira->src_implicit_return_type_list.length);
1807518236 }
1807618237}
1807718238
......@@ -18119,6 +18280,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1811918280 case IrInstructionIdCoroSave:
1812018281 case IrInstructionIdCoroAllocHelper:
1812118282 case IrInstructionIdAwaitBookkeeping:
18283 case IrInstructionIdSaveErrRetAddr:
18284 case IrInstructionIdAddImplicitReturnType:
1812218285 return true;
1812318286
1812418287 case IrInstructionIdPhi:
......@@ -18141,6 +18304,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1814118304 case IrInstructionIdStructFieldPtr:
1814218305 case IrInstructionIdUnionFieldPtr:
1814318306 case IrInstructionIdArrayType:
18307 case IrInstructionIdPromiseType:
1814418308 case IrInstructionIdSliceType:
1814518309 case IrInstructionIdSizeOf:
1814618310 case IrInstructionIdTestNonNull:
src/ir_print.cpp+29-2
......@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
201201 if (call_instruction->is_async) {
202202 fprintf(irp->f, "async");
203203 if (call_instruction->async_allocator != nullptr) {
204 fprintf(irp->f, "(");
204 fprintf(irp->f, "<");
205205 ir_print_other_instruction(irp, call_instruction->async_allocator);
206 fprintf(irp->f, ")");
206 fprintf(irp->f, ">");
207207 }
208208 fprintf(irp->f, " ");
209209 }
......@@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
404404 ir_print_other_instruction(irp, instruction->child_type);
405405}
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
407415static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
408416 const char *const_kw = instruction->is_const ? "const " : "";
409417 fprintf(irp->f, "[]%s", const_kw);
......@@ -1161,6 +1169,16 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi
11611169 fprintf(irp->f, ")");
11621170}
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
11641182static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11651183 ir_print_prefix(irp, instruction);
11661184 switch (instruction->id) {
......@@ -1253,6 +1271,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
12531271 case IrInstructionIdArrayType:
12541272 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
12551273 break;
1274 case IrInstructionIdPromiseType:
1275 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1276 break;
12561277 case IrInstructionIdSliceType:
12571278 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
12581279 break;
......@@ -1532,6 +1553,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15321553 case IrInstructionIdAwaitBookkeeping:
15331554 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
15341555 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;
15351562 }
15361563 fprintf(irp->f, "\n");
15371564}
src/link.cpp+54-7
......@@ -164,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164164 lj->rpath_table.put(rpath, true);
165165}
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
167208static void construct_linker_job_elf(LinkJob *lj) {
168209 CodeGen *g = lj->codegen;
169210
......@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {
259300 lj->args.append(buf_ptr(g->libc_static_lib_dir));
260301 }
261302
262 if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) {
263 lj->args.append("-dynamic-linker");
264 lj->args.append(buf_ptr(g->dynamic_linker));
265 } else {
266 lj->args.append("-dynamic-linker");
267 lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target)));
303 if (!g->is_static) {
304 if (g->dynamic_linker != nullptr) {
305 assert(buf_len(g->dynamic_linker) != 0);
306 lj->args.append("-dynamic-linker");
307 lj->args.append(buf_ptr(g->dynamic_linker));
308 } else {
309 Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
310 lj->args.append("-dynamic-linker");
311 lj->args.append(buf_ptr(resolved_dynamic_linker));
312 }
268313 }
269314
270315 if (shared) {
......@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
423468 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
424469
425470 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 }
427474 }
428475
429476 if (lj->link_in_crt) {
src/main.cpp+52-16
......@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
2323 " build-exe [source] create executable from source or object files\n"
2424 " build-lib [source] create library from source or object files\n"
2525 " build-obj [source] create object from source or assembly\n"
26 " run [source] create executable and run immediately\n"
2627 " translate-c [source] convert c code to zig code\n"
2728 " targets list available compilation targets\n"
2829 " test [source] create and run a test build\n"
......@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {
195196 }
196197 }
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
205199 return ErrorFileNotFound;
206200}
207201
......@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
227221enum Cmd {
228222 CmdInvalid,
229223 CmdBuild,
224 CmdRun,
230225 CmdTest,
231226 CmdVersion,
232227 CmdZen,
......@@ -336,6 +331,8 @@ int main(int argc, char **argv) {
336331 CliPkg *cur_pkg = allocate<CliPkg>(1);
337332 BuildMode build_mode = BuildModeDebug;
338333 ZigList<const char *> test_exec_args = {0};
334 int comptime_args_end = 0;
335 int runtime_args_start = argc;
339336
340337 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
341338 const char *zig_exe_path = arg0;
......@@ -452,10 +449,11 @@ int main(int argc, char **argv) {
452449
453450 if ((err = os_copy_file(build_template_path, &build_file_abs))) {
454451 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));
452 return EXIT_FAILURE;
455453 } else {
456454 fprintf(stderr, "Wrote build.zig template\n");
455 return EXIT_SUCCESS;
457456 }
458 return EXIT_SUCCESS;
459457 }
460458
461459 fprintf(stderr,
......@@ -487,11 +485,15 @@ int main(int argc, char **argv) {
487485 return (term.how == TerminationIdClean) ? term.code : -1;
488486 }
489487
490 for (int i = 1; i < argc; i += 1) {
488 for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
491489 char *arg = argv[i];
492490
493491 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) {
495497 build_mode = BuildModeFastRelease;
496498 } else if (strcmp(arg, "--release-safe") == 0) {
497499 build_mode = BuildModeSafeRelease;
......@@ -658,6 +660,9 @@ int main(int argc, char **argv) {
658660 } else if (strcmp(arg, "build-lib") == 0) {
659661 cmd = CmdBuild;
660662 out_type = OutTypeLib;
663 } else if (strcmp(arg, "run") == 0) {
664 cmd = CmdRun;
665 out_type = OutTypeExe;
661666 } else if (strcmp(arg, "version") == 0) {
662667 cmd = CmdVersion;
663668 } else if (strcmp(arg, "zen") == 0) {
......@@ -676,6 +681,7 @@ int main(int argc, char **argv) {
676681 } else {
677682 switch (cmd) {
678683 case CmdBuild:
684 case CmdRun:
679685 case CmdTranslateC:
680686 case CmdTest:
681687 if (!in_file) {
......@@ -730,8 +736,8 @@ int main(int argc, char **argv) {
730736 }
731737 }
732738
733
734739 switch (cmd) {
740 case CmdRun:
735741 case CmdBuild:
736742 case CmdTranslateC:
737743 case CmdTest:
......@@ -739,7 +745,7 @@ int main(int argc, char **argv) {
739745 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
740746 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
741747 return usage(arg0);
742 } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {
748 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
743749 fprintf(stderr, "Expected source file argument.\n");
744750 return usage(arg0);
745751 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
......@@ -751,6 +757,10 @@ int main(int argc, char **argv) {
751757
752758 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
753759
760 if (cmd == CmdRun) {
761 out_name = "run";
762 }
763
754764 Buf *in_file_buf = nullptr;
755765
756766 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
......@@ -775,9 +785,23 @@ int main(int argc, char **argv) {
775785 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
776786
777787 Buf *full_cache_dir = buf_alloc();
778 os_path_resolve(buf_create_from_str("."),
779 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
780 full_cache_dir);
788 Buf *run_exec_path = buf_alloc();
789 if (cmd == CmdRun) {
790 if (buf_out_name == nullptr) {
791 buf_out_name = buf_create_from_str("run");
792 }
793
794 Buf *global_cache_dir = buf_alloc();
795 os_get_global_cache_directory(global_cache_dir);
796 os_path_join(global_cache_dir, buf_out_name, run_exec_path);
797 os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir);
798
799 out_file = buf_ptr(run_exec_path);
800 } else {
801 os_path_resolve(buf_create_from_str("."),
802 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
803 full_cache_dir);
804 }
781805
782806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
783807
......@@ -861,7 +885,7 @@ int main(int argc, char **argv) {
861885
862886 add_package(g, cur_pkg, g->root_package);
863887
864 if (cmd == CmdBuild) {
888 if (cmd == CmdBuild || cmd == CmdRun) {
865889 codegen_set_emit_file_type(g, emit_file_type);
866890
867891 for (size_t i = 0; i < objects.length; i += 1) {
......@@ -874,6 +898,18 @@ int main(int argc, char **argv) {
874898 codegen_link(g, out_file);
875899 if (timing_info)
876900 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
877913 return EXIT_SUCCESS;
878914 } else if (cmd == CmdTranslateC) {
879915 codegen_translate_c(g, in_file_buf);
src/os.cpp+90-11
......@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;
4545#if defined(__MACH__)
4646#include <mach/clock.h>
4747#include <mach/mach.h>
48#include <mach-o/dyld.h>
4849#endif
4950
5051#if defined(ZIG_OS_WINDOWS)
......@@ -57,10 +58,6 @@ static clock_serv_t cclock;
5758#include <errno.h>
5859#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
6461#if defined(ZIG_OS_POSIX)
6562static void populate_termination(Termination *term, int status) {
6663 if (WIFEXITED(status)) {
......@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
291288 return;
292289}
293290
294int os_fetch_file(FILE *f, Buf *out_buf) {
291int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
295292 static const ssize_t buf_size = 0x2000;
296293 buf_resize(out_buf, buf_size);
297294 ssize_t actual_buf_len = 0;
295
296 bool first_read = true;
297
298298 for (;;) {
299299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
300300 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
301324 if (amt_read != buf_size) {
302325 if (feof(f)) {
303326 buf_resize(out_buf, actual_buf_len);
......@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
308331 }
309332
310333 buf_resize(out_buf, actual_buf_len + buf_size);
334 first_read = false;
311335 }
312336 zig_unreachable();
313337}
......@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
377401
378402 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
379403 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
380 os_fetch_file(stdout_f, out_stdout);
381 os_fetch_file(stderr_f, out_stderr);
404 os_fetch_file(stdout_f, out_stdout, false);
405 os_fetch_file(stderr_f, out_stderr, false);
382406
383407 fclose(stdout_f);
384408 fclose(stderr_f);
......@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
591615 }
592616}
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) {
595619 FILE *f = fopen(buf_ptr(full_path), "rb");
596620 if (!f) {
597621 switch (errno) {
......@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
610634 return ErrorFileSystem;
611635 }
612636 }
613 int result = os_fetch_file(f, out_contents);
637 int result = os_fetch_file(f, out_contents, skip_shebang);
614638 fclose(f);
615639 return result;
616640}
......@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
783807#endif
784808}
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
786848int os_delete_file(Buf *path) {
787849 if (remove(buf_ptr(path))) {
788850 return ErrorFileSystem;
......@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {
927989 }
928990
929991#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;
931999#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 }
9331012#endif
9341013 return ErrorFileNotFound;
9351014}
src/os.hpp+4-2
......@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);
5151void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
5252bool os_path_is_absolute(Buf *path);
5353
54int os_get_global_cache_directory(Buf *out_tmp_path);
55
5456int os_make_path(Buf *path);
5557int os_make_dir(Buf *path);
5658
5759void os_write_file(Buf *full_path, Buf *contents);
5860int os_copy_file(Buf *src_path, Buf *dest_path);
5961
60int os_fetch_file(FILE *file, Buf *out_contents);
61int os_fetch_file_path(Buf *full_path, Buf *out_contents);
62int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
63int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
6264
6365int 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
705705}
706706
707707/*
708PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
708PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
709709KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
710710ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
711711*/
......@@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
774774 AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);
775775 *token_index += 1;
776776 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;
777786 } else if (token->id == TokenIdKeywordError) {
778787 Token *next_token = &pc->tokens->at(*token_index + 1);
779788 if (next_token->id == TokenIdLBrace) {
......@@ -955,6 +964,66 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
955964 }
956965}
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
9581027/*
9591028SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
9601029FnCallExpression : 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,
9791048 }
9801049
9811050 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 }
9821056 AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true);
9831057 if (node->type != NodeTypeFnCallExpr) {
9841058 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
24342508 } else if (first_token->id == TokenIdKeywordAsync) {
24352509 *token_index += 1;
24362510 Token *next_token = &pc->tokens->at(*token_index);
2437 if (next_token->id == TokenIdLParen) {
2511 if (next_token->id == TokenIdCmpLessThan) {
2512 *token_index += 1;
24382513 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);
24402515 }
24412516 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
24422517 cc = CallingConventionAsync;
......@@ -2470,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
24702545 return nullptr;
24712546 }
24722547
2473 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
2474 node->data.fn_proto.visib_mod = visib_mod;
2475 node->data.fn_proto.cc = cc;
2476 node->data.fn_proto.is_extern = is_extern;
2477 node->data.fn_proto.async_allocator_type = async_allocator_type_node;
2478
2479 Token *fn_name = &pc->tokens->at(*token_index);
2480
2481 if (fn_name->id == TokenIdSymbol) {
2482 *token_index += 1;
2483 node->data.fn_proto.name = token_buf(fn_name);
2484 } else {
2485 node->data.fn_proto.name = nullptr;
2486 }
2487
2488 ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
2489
2490 Token *next_token = &pc->tokens->at(*token_index);
2491 if (next_token->id == TokenIdKeywordAlign) {
2492 *token_index += 1;
2493 ast_eat_token(pc, token_index, TokenIdLParen);
2494
2495 node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true);
2496 ast_eat_token(pc, token_index, TokenIdRParen);
2497 next_token = &pc->tokens->at(*token_index);
2498 }
2499 if (next_token->id == TokenIdKeywordSection) {
2500 *token_index += 1;
2501 ast_eat_token(pc, token_index, TokenIdLParen);
2502
2503 node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true);
2504 ast_eat_token(pc, token_index, TokenIdRParen);
2505 next_token = &pc->tokens->at(*token_index);
2506 }
2507 if (next_token->id == TokenIdKeywordVar) {
2508 node->data.fn_proto.return_var_token = next_token;
2509 *token_index += 1;
2510 next_token = &pc->tokens->at(*token_index);
2511 } else {
2512 if (next_token->id == TokenIdKeywordError) {
2513 Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
2514 if (maybe_lbrace_tok->id == TokenIdLBrace) {
2515 *token_index += 1;
2516 node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
2517 return node;
2518 }
2519 } else if (next_token->id == TokenIdBang) {
2520 *token_index += 1;
2521 node->data.fn_proto.auto_err_set = true;
2522 next_token = &pc->tokens->at(*token_index);
2523 }
2524 node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
2525 }
2526
2527 return node;
2548 return ast_parse_fn_proto_partial(pc, token_index, fn_token, async_allocator_type_node, cc, is_extern, visib_mod);
25282549}
25292550
25302551/*
......@@ -3069,6 +3090,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30693090 visit_field(&node->data.array_type.child_type, visit, context);
30703091 visit_field(&node->data.array_type.align_expr, visit, context);
30713092 break;
3093 case NodeTypePromiseType:
3094 visit_field(&node->data.promise_type.payload_type, visit, context);
3095 break;
30723096 case NodeTypeErrorType:
30733097 // none
30743098 break;
src/parser.hpp-1
......@@ -16,7 +16,6 @@ ATTRIBUTE_PRINTF(2, 3)
1616void ast_token_error(Token *token, const char *format, ...);
1717
1818
19// This function is provided by generated code, generated by parsergen.cpp
2019AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
2120
2221void ast_print(AstNode *node, int indent);
src/target.cpp+4
......@@ -862,6 +862,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {
862862 env == ZigLLVM_GNUX32)
863863 {
864864 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");
865869 } else {
866870 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");
867871 }
src/tokenizer.cpp+2
......@@ -135,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = {
135135 {"null", TokenIdKeywordNull},
136136 {"or", TokenIdKeywordOr},
137137 {"packed", TokenIdKeywordPacked},
138 {"promise", TokenIdKeywordPromise},
138139 {"pub", TokenIdKeywordPub},
139140 {"resume", TokenIdKeywordResume},
140141 {"return", TokenIdKeywordReturn},
......@@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) {
15581559 case TokenIdKeywordNull: return "null";
15591560 case TokenIdKeywordOr: return "or";
15601561 case TokenIdKeywordPacked: return "packed";
1562 case TokenIdKeywordPromise: return "promise";
15611563 case TokenIdKeywordPub: return "pub";
15621564 case TokenIdKeywordReturn: return "return";
15631565 case TokenIdKeywordSection: return "section";
src/tokenizer.hpp+1
......@@ -76,6 +76,7 @@ enum TokenId {
7676 TokenIdKeywordNull,
7777 TokenIdKeywordOr,
7878 TokenIdKeywordPacked,
79 TokenIdKeywordPromise,
7980 TokenIdKeywordPub,
8081 TokenIdKeywordResume,
8182 TokenIdKeywordReturn,
std/c/darwin.zig+10
......@@ -1,6 +1,7 @@
11extern "c" fn __error() &c_int;
22pub 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
56pub use @import("../os/darwin_errno.zig");
67
......@@ -45,3 +46,12 @@ pub const Sigaction = extern struct {
4546 sa_mask: sigset_t,
4647 sa_flags: c_int,
4748};
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
4444pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
4545pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
4646pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
47pub extern "c" fn rmdir(path: &const u8) c_int;
4748
4849pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
4950pub 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 {
8484 }
8585
8686 // Full middle blocks.
87 while (off + 64 < b.len) : (off += 64) {
87 while (off + 64 <= b.len) : (off += 64) {
8888 d.t += 64;
8989 d.round(b[off..off + 64], false);
9090 }
......@@ -229,6 +229,15 @@ test "blake2s256 streaming" {
229229 htest.assertEqual(h2, out[0..]);
230230}
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
233242/////////////////////
234243// Blake2b
......@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {
305314 }
306315
307316 // Full middle blocks.
308 while (off + 128 < b.len) : (off += 128) {
317 while (off + 128 <= b.len) : (off += 128) {
309318 d.t += 128;
310319 d.round(b[off..off + 128], false);
311320 }
......@@ -447,3 +456,12 @@ test "blake2b512 streaming" {
447456 h.final(out[0..]);
448457 htest.assertEqual(h2, out[0..]);
449458}
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;
1919pub const Blake2b384 = blake2.Blake2b384;
2020pub 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
2227test "crypto" {
2328 _ = @import("md5.zig");
2429 _ = @import("sha1.zig");
2530 _ = @import("sha2.zig");
2631 _ = @import("sha3.zig");
2732 _ = @import("blake2.zig");
33 _ = @import("hmac.zig");
2834}
std/crypto/md5.zig+10-1
......@@ -59,7 +59,7 @@ pub const Md5 = struct {
5959 }
6060
6161 // Full middle blocks.
62 while (off + 64 < b.len) : (off += 64) {
62 while (off + 64 <= b.len) : (off += 64) {
6363 d.round(b[off..off + 64]);
6464 }
6565
......@@ -253,3 +253,12 @@ test "md5 streaming" {
253253
254254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
255255}
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 {
6060 }
6161
6262 // Full middle blocks.
63 while (off + 64 < b.len) : (off += 64) {
63 while (off + 64 <= b.len) : (off += 64) {
6464 d.round(b[off..off + 64]);
6565 }
6666
......@@ -284,3 +284,12 @@ test "sha1 streaming" {
284284 h.final(out[0..]);
285285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
286286}
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 {
105105 }
106106
107107 // Full middle blocks.
108 while (off + 64 < b.len) : (off += 64) {
108 while (off + 64 <= b.len) : (off += 64) {
109109 d.round(b[off..off + 64]);
110110 }
111111
......@@ -319,6 +319,15 @@ test "sha256 streaming" {
319319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
320320}
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
323332/////////////////////
324333// Sha384 + Sha512
......@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {
420429 }
421430
422431 // Full middle blocks.
423 while (off + 128 < b.len) : (off += 128) {
432 while (off + 128 <= b.len) : (off += 128) {
424433 d.round(b[off..off + 128]);
425434 }
426435
......@@ -669,3 +678,12 @@ test "sha512 streaming" {
669678 h.final(out[0..]);
670679 htest.assertEqual(h2, out[0..]);
671680}
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" {
217217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);
218218}
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
220229test "sha3-384 single" {
221230 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
222231 htest.assertEqualHash(Sha3_384, h1 , "");
......@@ -278,3 +287,12 @@ test "sha3-512 streaming" {
278287 h.final(out[0..]);
279288 htest.assertEqual(h2, out[0..]);
280289}
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");
2626pub const mem = @import("mem.zig");
2727pub const net = @import("net.zig");
2828pub const os = @import("os/index.zig");
29pub const rand = @import("rand.zig");
29pub const rand = @import("rand/index.zig");
3030pub const sort = @import("sort.zig");
3131pub const unicode = @import("unicode.zig");
3232pub const zig = @import("zig/index.zig");
......@@ -58,7 +58,7 @@ test "std" {
5858 _ = @import("heap.zig");
5959 _ = @import("net.zig");
6060 _ = @import("os/index.zig");
61 _ = @import("rand.zig");
61 _ = @import("rand/index.zig");
6262 _ = @import("sort.zig");
6363 _ = @import("unicode.zig");
6464 _ = @import("zig/index.zig");
std/io.zig+21-4
......@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {
144144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
145145 /// read from the stream so far are lost.
146146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
147 try buf.resize(0);
147 try buffer.resize(0);
148148
149149 while (true) {
150150 var byte: u8 = try self.readByte();
......@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {
153153 return;
154154 }
155155
156 if (buf.len() == max_size) {
156 if (buffer.len() == max_size) {
157157 return error.StreamTooLong;
158158 }
159159
160 try buf.appendByte(byte);
160 try buffer.appendByte(byte);
161161 }
162162 }
163163
......@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {
171171 var buf = Buffer.initNull(allocator);
172172 defer buf.deinit();
173173
174 try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);
174 try self.readUntilDelimiterBuffer(&buf, delimiter, max_size);
175175 return buf.toOwnedSlice();
176176 }
177177
......@@ -478,3 +478,20 @@ test "import io tests" {
478478 }
479479}
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 @@
11const std = @import("index.zig");
22const io = std.io;
33const allocator = std.debug.global_allocator;
4const Rand = std.rand.Rand;
4const DefaultPrng = std.rand.DefaultPrng;
55const assert = std.debug.assert;
66const mem = std.mem;
77const os = std.os;
......@@ -9,8 +9,8 @@ const builtin = @import("builtin");
99
1010test "write a file, read it, then delete it" {
1111 var data: [1024]u8 = undefined;
12 var rng = Rand.init(1234);
13 rng.fillBytes(data[0..]);
12 var prng = DefaultPrng.init(1234);
13 prng.random.bytes(data[0..]);
1414 const tmp_file_name = "temp_test_file.txt";
1515 {
1616 var file = try os.File.openWrite(allocator, tmp_file_name);
std/math/index.zig+15-2
......@@ -515,15 +515,28 @@ test "math.negateCast" {
515515
516516/// Cast an integer to a different integer type. If the value doesn't fit,
517517/// return an error.
518pub fn cast(comptime T: type, x: var) !T {
518pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
519519 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)) {
521524 return error.Overflow;
522525 } else {
523526 return T(x);
524527 }
525528}
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
527540pub fn floorPowerOfTwo(comptime T: type, value: T) T {
528541 var x = value;
529542
std/os/child_process.zig-35
......@@ -13,8 +13,6 @@ const builtin = @import("builtin");
1313const Os = builtin.Os;
1414const LinkedList = std.LinkedList;
1515
16var children_nodes = LinkedList(&ChildProcess).init();
17
1816const is_windows = builtin.os == Os.windows;
1917
2018pub const ChildProcess = struct {
......@@ -296,8 +294,6 @@ pub const ChildProcess = struct {
296294 }
297295
298296 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
299 children_nodes.remove(&self.llnode);
300
301297 defer {
302298 os.close(self.err_pipe[0]);
303299 os.close(self.err_pipe[1]);
......@@ -427,9 +423,6 @@ pub const ChildProcess = struct {
427423 self.llnode = LinkedList(&ChildProcess).Node.init(self);
428424 self.term = null;
429425
430 // TODO make this atomic so it works even with threads
431 children_nodes.prepend(&self.llnode);
432
433426 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
434427 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
435428 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
......@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {
773766 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;
774767 return mem.readInt(bytes[0..], ErrInt, builtin.endian);
775768}
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
5656pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
5757pub 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
5971pub const SEEK_SET = 0x0;
6072pub const SEEK_CUR = 0x1;
6173pub 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
6385pub const SIG_BLOCK = 1; /// block specified signal set
6486pub const SIG_UNBLOCK = 2; /// unblock specified signal set
6587pub const SIG_SETMASK = 3; /// set specified signal set
......@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {
192214 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
193215}
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
195222pub fn mkdir(path: &const u8, mode: u32) usize {
196223 return errnoWrap(c.mkdir(path, mode));
197224}
......@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {
204231 return errnoWrap(c.rename(old, new));
205232}
206233
234pub fn rmdir(path: &const u8) usize {
235 return errnoWrap(c.rmdir(path));
236}
237
207238pub fn chdir(path: &const u8) usize {
208239 return errnoWrap(c.chdir(path));
209240}
......@@ -268,6 +299,7 @@ pub const empty_sigset = sigset_t(0);
268299
269300pub const timespec = c.timespec;
270301pub const Stat = c.Stat;
302pub const dirent = c.dirent;
271303
272304/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
273305pub const Sigaction = struct {
std/os/file.zig+1-1
......@@ -233,7 +233,7 @@ pub const File = struct {
233233 Unexpected,
234234 };
235235
236 fn mode(self: &File) ModeError!FileMode {
236 fn mode(self: &File) ModeError!os.FileMode {
237237 if (is_posix) {
238238 var stat: posix.Stat = undefined;
239239 const err = posix.getErrno(posix.fstat(self.handle, &stat));
std/os/index.zig+99-13
......@@ -1050,15 +1050,16 @@ const DeleteTreeError = error {
10501050};
10511051pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
10521052 start_over: while (true) {
1053 var got_access_denied = false;
10531054 // First, try deleting the item as a file. This way we don't follow sym links.
10541055 if (deleteFile(allocator, full_path)) {
10551056 return;
10561057 } else |err| switch (err) {
10571058 error.FileNotFound => return,
10581059 error.IsDir => {},
1060 error.AccessDenied => got_access_denied = true,
10591061
10601062 error.OutOfMemory,
1061 error.AccessDenied,
10621063 error.SymLinkLoop,
10631064 error.NameTooLong,
10641065 error.SystemResources,
......@@ -1071,7 +1072,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
10711072 }
10721073 {
10731074 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
10761082 error.OutOfMemory,
10771083 error.AccessDenied,
......@@ -1109,18 +1115,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
11091115}
11101116
11111117pub const Dir = struct {
1112 // See man getdents
11131118 fd: i32,
1119 darwin_seek: darwin_seek_t,
11141120 allocator: &Allocator,
11151121 buf: []u8,
11161122 index: usize,
11171123 end_index: usize,
11181124
1119 const LinuxEntry = extern struct {
1120 d_ino: usize,
1121 d_off: usize,
1122 d_reclen: u16,
1123 d_name: u8, // field address is the address of first byte of name
1125 const darwin_seek_t = switch (builtin.os) {
1126 Os.macosx, Os.ios => i64,
1127 else => void,
11241128 };
11251129
11261130 pub const Entry = struct {
......@@ -1135,15 +1139,26 @@ pub const Dir = struct {
11351139 SymLink,
11361140 File,
11371141 UnixDomainSocket,
1142 Whiteout,
11381143 Unknown,
11391144 };
11401145 };
11411146
11421147 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 };
11441158 return Dir {
11451159 .allocator = allocator,
11461160 .fd = fd,
1161 .darwin_seek = darwin_seek_init,
11471162 .index = 0,
11481163 .end_index = 0,
11491164 .buf = []u8{},
......@@ -1158,6 +1173,76 @@ pub const Dir = struct {
11581173 /// Memory such as file names referenced in this returned entry becomes invalid
11591174 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
11601175 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 {
11611246 start_over: while (true) {
11621247 if (self.index >= self.end_index) {
11631248 if (self.buf.len == 0) {
......@@ -1166,7 +1251,7 @@ pub const Dir = struct {
11661251
11671252 while (true) {
11681253 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
1169 const err = linux.getErrno(result);
1254 const err = posix.getErrno(result);
11701255 if (err > 0) {
11711256 switch (err) {
11721257 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
......@@ -1184,7 +1269,7 @@ pub const Dir = struct {
11841269 break;
11851270 }
11861271 }
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]);
11881273 const next_index = self.index + linux_entry.d_reclen;
11891274 self.index = next_index;
11901275
......@@ -1679,6 +1764,7 @@ test "std.os" {
16791764 _ = @import("linux/index.zig");
16801765 _ = @import("path.zig");
16811766 _ = @import("windows/index.zig");
1767 _ = @import("test.zig");
16821768}
16831769
16841770
......@@ -1690,7 +1776,7 @@ const unexpected_error_tracing = false;
16901776pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
16911777 if (unexpected_error_tracing) {
16921778 debug.warn("unexpected errno: {}\n", errno);
1693 debug.dumpStackTrace();
1779 debug.dumpCurrentStackTrace(null);
16941780 }
16951781 return error.Unexpected;
16961782}
......@@ -1700,7 +1786,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
17001786pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {
17011787 if (unexpected_error_tracing) {
17021788 debug.warn("unexpected GetLastError(): {}\n", err);
1703 debug.dumpStackTrace();
1789 debug.dumpCurrentStackTrace(null);
17041790 }
17051791 return error.Unexpected;
17061792}
std/os/linux/index.zig+67-91
......@@ -1,7 +1,7 @@
11const std = @import("../../index.zig");
22const assert = std.debug.assert;
33const builtin = @import("builtin");
4const arch = switch (builtin.arch) {
4pub use switch (builtin.arch) {
55 builtin.Arch.x86_64 => @import("x86_64.zig"),
66 builtin.Arch.i386 => @import("i386.zig"),
77 else => @compileError("unsupported arch"),
......@@ -93,27 +93,6 @@ pub const O_RDONLY = 0o0;
9393pub const O_WRONLY = 0o1;
9494pub 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
11796pub const SEEK_SET = 0;
11897pub const SEEK_CUR = 1;
11998pub const SEEK_END = 2;
......@@ -394,65 +373,65 @@ pub fn getErrno(r: usize) usize {
394373}
395374
396375pub 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));
398377}
399378
400379pub fn chdir(path: &const u8) usize {
401 return arch.syscall1(arch.SYS_chdir, @ptrToInt(path));
380 return syscall1(SYS_chdir, @ptrToInt(path));
402381}
403382
404383pub 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));
406385}
407386
408387pub fn fork() usize {
409 return arch.syscall0(arch.SYS_fork);
388 return syscall0(SYS_fork);
410389}
411390
412391pub 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);
414393}
415394
416395pub 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);
418397}
419398
420399pub fn isatty(fd: i32) bool {
421400 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;
423402}
424403
425404pub 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);
427406}
428407
429408pub 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);
431410}
432411
433412pub 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),
435414 @bitCast(usize, offset));
436415}
437416
438417pub 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);
440419}
441420
442421pub 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);
444423}
445424
446425pub fn rmdir(path: &const u8) usize {
447 return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path));
426 return syscall1(SYS_rmdir, @ptrToInt(path));
448427}
449428
450429pub 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));
452431}
453432
454433pub 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);
456435}
457436
458437pub fn pipe(fd: &[2]i32) usize {
......@@ -460,84 +439,84 @@ pub fn pipe(fd: &[2]i32) usize {
460439}
461440
462441pub 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);
464443}
465444
466445pub 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);
468447}
469448
470449pub 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);
472451}
473452
474453pub 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));
476455}
477456
478457pub 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);
480459}
481460
482461pub 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);
484463}
485464
486465pub 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);
488467}
489468
490469pub fn close(fd: i32) usize {
491 return arch.syscall1(arch.SYS_close, usize(fd));
470 return syscall1(SYS_close, usize(fd));
492471}
493472
494473pub 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);
496475}
497476
498477pub fn exit(status: i32) noreturn {
499 _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));
478 _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
500479 unreachable;
501480}
502481
503482pub 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));
505484}
506485
507486pub 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));
509488}
510489
511490pub fn unlink(path: &const u8) usize {
512 return arch.syscall1(arch.SYS_unlink, @ptrToInt(path));
491 return syscall1(SYS_unlink, @ptrToInt(path));
513492}
514493
515494pub 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);
517496}
518497
519498pub 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));
521500}
522501
523502pub fn setuid(uid: u32) usize {
524 return arch.syscall1(arch.SYS_setuid, uid);
503 return syscall1(SYS_setuid, uid);
525504}
526505
527506pub fn setgid(gid: u32) usize {
528 return arch.syscall1(arch.SYS_setgid, gid);
507 return syscall1(SYS_setgid, gid);
529508}
530509
531510pub fn setreuid(ruid: u32, euid: u32) usize {
532 return arch.syscall2(arch.SYS_setreuid, ruid, euid);
511 return syscall2(SYS_setreuid, ruid, euid);
533512}
534513
535514pub fn setregid(rgid: u32, egid: u32) usize {
536 return arch.syscall2(arch.SYS_setregid, rgid, egid);
515 return syscall2(SYS_setregid, rgid, egid);
537516}
538517
539518pub 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);
541520}
542521
543522pub 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
548527 .handler = act.handler,
549528 .flags = act.flags | SA_RESTORER,
550529 .mask = undefined,
551 .restorer = @ptrCast(extern fn()void, arch.restore_rt),
530 .restorer = @ptrCast(extern fn()void, restore_rt),
552531 };
553532 var ksa_old: k_sigaction = undefined;
554533 @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)));
556535 const err = getErrno(result);
557536 if (err != 0) {
558537 return result;
......@@ -592,22 +571,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;
592571pub fn raise(sig: i32) usize {
593572 var set: sigset_t = undefined;
594573 blockAppSignals(&set);
595 const tid = i32(arch.syscall0(arch.SYS_gettid));
596 const ret = arch.syscall2(arch.SYS_tkill, usize(tid), usize(sig));
574 const tid = i32(syscall0(SYS_gettid));
575 const ret = syscall2(SYS_tkill, usize(tid), usize(sig));
597576 restoreSignals(&set);
598577 return ret;
599578}
600579
601580fn 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);
603582}
604583
605584fn 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);
607586}
608587
609588fn 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);
611590}
612591
613592pub fn sigaddset(set: &sigset_t, sig: u6) void {
......@@ -653,61 +632,61 @@ pub const iovec = extern struct {
653632};
654633
655634pub 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));
657636}
658637
659638pub 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));
661640}
662641
663642pub 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));
665644}
666645
667646pub 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));
669648}
670649
671650pub 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));
673652}
674653
675pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) usize {
676 return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
654pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
655 return syscall3(SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
677656}
678657
679658pub 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));
681660}
682661
683pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) usize {
684 return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
662pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {
663 return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
685664}
686665
687666pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
688667 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize
689668{
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));
691670}
692671
693672pub 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));
695674}
696675
697676pub 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));
699678}
700679
701680pub 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));
703682}
704683
705684pub 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));
707686}
708687
709688pub 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]));
711690}
712691
713692pub 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 {
715694}
716695
717696pub 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);
719698}
720699
721700// error NameTooLong;
......@@ -746,11 +725,8 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
746725// return ifr.ifr_ifindex;
747726// }
748727
749pub const Stat = arch.Stat;
750pub const timespec = arch.timespec;
751
752728pub 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));
754730}
755731
756732pub const epoll_data = extern union {
......@@ -770,19 +746,19 @@ pub fn epoll_create() usize {
770746}
771747
772748pub fn epoll_create1(flags: usize) usize {
773 return arch.syscall1(arch.SYS_epoll_create1, flags);
749 return syscall1(SYS_epoll_create1, flags);
774750}
775751
776752pub 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));
778754}
779755
780756pub 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));
782758}
783759
784760pub 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));
786762}
787763
788764pub const itimerspec = extern struct {
......@@ -791,11 +767,11 @@ pub const itimerspec = extern struct {
791767};
792768
793769pub 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));
795771}
796772
797773pub 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));
799775}
800776
801777test "import linux test" {
std/os/linux/x86_64.zig+8
......@@ -488,3 +488,11 @@ pub const timespec = extern struct {
488488 tv_sec: isize,
489489 tv_nsec: isize,
490490};
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 {
6767 self.numerator -= self.denominator;
6868 self.decimal += 1;
6969 }
70
70
7171 return Range {.start = start, .end = self.decimal};
7272 }
7373
......@@ -82,7 +82,7 @@ const Iterator = struct {
8282 self.numerator_step -= self.denominator;
8383 self.decimal_step += 1;
8484 }
85
85
8686 return (self.decimal_step < self.size);
8787 }
8888
......@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
219219 var B1 = iterator.nextRange();
220220 var A2 = iterator.nextRange();
221221 var B2 = iterator.nextRange();
222
222
223223 if (lessThan(items[B1.end - 1], items[A1.start])) {
224224 // the two ranges are in reverse order, so copy them in reverse order into the cache
225225 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
230230 } else {
231231 // if A1, B1, A2, and B2 are all in order, skip doing anything else
232232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;
233
233
234234 // copy A1 and B1 into the cache in the same order
235235 mem.copy(T, cache[0..], items[A1.start..A1.end]);
236236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);
237237 }
238238 A1 = Range.init(A1.start, B1.end);
239
239
240240 // merge A2 and B2 into the cache
241241 if (lessThan(items[B2.end - 1], items[A2.start])) {
242242 // 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
251251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);
252252 }
253253 A2 = Range.init(A2.start, B2.end);
254
254
255255 // merge A1 and A2 from the cache into the items
256256 const A3 = Range.init(0, A1.length());
257257 const B3 = Range.init(A1.length(), A1.length() + A2.length());
258
258
259259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {
260260 // the two ranges are in reverse order, so copy them in reverse order into the items
261261 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
269269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);
270270 }
271271 }
272
272
273273 // we merged two levels at the same time, so we're done with this level already
274274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275275 _ = iterator.nextLevel();
276
276
277277 } else {
278278 iterator.begin();
279279 while (!iterator.finished()) {
280280 var A = iterator.nextRange();
281281 var B = iterator.nextRange();
282
282
283283 if (lessThan(items[B.end - 1], items[A.start])) {
284284 // the two ranges are in reverse order, so a simple rotation should fix it
285285 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
301301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer
302302 // 7. sort the second internal buffer if it exists
303303 // 8. redistribute the two internal buffers back into the items
304
304
305305 var block_size: usize = math.sqrt(iterator.length());
306306 var buffer_size = iterator.length()/block_size + 1;
307
307
308308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
310310 var A: Range = undefined;
......@@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
322322
323323 var buffer1 = Range.init(0, 0);
324324 var buffer2 = Range.init(0, 0);
325
325
326326 // find two internal buffers of size 'buffer_size' each
327327 find = buffer_size + buffer_size;
328328 var find_separately = false;
329
329
330330 if (block_size <= cache.len) {
331331 // if every A block fits into the cache then we won't need the second internal buffer,
332332 // 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
336336 find = buffer_size;
337337 find_separately = true;
338338 }
339
339
340340 // 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),
341341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,
342342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get
343
343
344344 // in the case where it couldn't find a single buffer of at least √A unique values,
345345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)
346346 iterator.begin();
347347 while (!iterator.finished()) {
348348 A = iterator.nextRange();
349349 B = iterator.nextRange();
350
350
351351 // just store information about where the values will be pulled from and to,
352352 // as well as how many values there are, to create the two internal buffers
353
353
354354 // check A for the number of unique values we need to fill an internal buffer
355355 // these values will be pulled out to the start of A
356356 last = A.start;
......@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
360360 if (index == A.end) break;
361361 }
362362 index = last;
363
363
364364 if (count >= buffer_size) {
365365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
366366 pull[pull_index] = Pull {
......@@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
370370 .to = A.start,
371371 };
372372 pull_index = 1;
373
373
374374 if (count == buffer_size + buffer_size) {
375375 // we were able to find a single contiguous section containing 2√A unique values,
376376 // 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
405405 .to = A.start,
406406 };
407407 }
408
408
409409 // check B for the number of unique values we need to fill an internal buffer
410410 // these values will be pulled out to the end of B
411411 last = B.end - 1;
......@@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
415415 if (index == B.start) break;
416416 }
417417 index = last;
418
418
419419 if (count >= buffer_size) {
420420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
421421 pull[pull_index] = Pull {
......@@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
425425 .to = B.end,
426426 };
427427 pull_index = 1;
428
428
429429 if (count == buffer_size + buffer_size) {
430430 // we were able to find a single contiguous section containing 2√A unique values,
431431 // 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
449449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,
450450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2
451451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;
452
452
453453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!
454454 buffer2 = Range.init(B.end - count, B.end);
455455 break;
......@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
465465 };
466466 }
467467 }
468
468
469469 // pull out the two ranges so we can use them as internal buffers
470470 pull_index = 0;
471471 while (pull_index < 2) : (pull_index += 1) {
472472 const length = pull[pull_index].count;
473
473
474474 if (pull[pull_index].to < pull[pull_index].from) {
475475 // we're pulling the values out to the left, which means the start of an A subarray
476476 index = pull[pull_index].from;
......@@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
493493 }
494494 }
495495 }
496
496
497497 // adjust block_size and buffer_size based on the values we were able to pull out
498498 buffer_size = buffer1.length();
499499 block_size = iterator.length()/buffer_size + 1;
500
500
501501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502502 // so this was originally here to test the math for adjusting block_size above
503503 // assert((iterator.length() + 1)/block_size <= buffer_size);
504
504
505505 // 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!
506506 iterator.begin();
507507 while (!iterator.finished()) {
508508 A = iterator.nextRange();
509509 B = iterator.nextRange();
510
510
511511 // remove any parts of A or B that are being used by the internal buffers
512512 start = A.start;
513513 if (start == pull[0].range.start) {
514514 if (pull[0].from > pull[0].to) {
515515 A.start += pull[0].count;
516
516
517517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge
518518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,
519519 // 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
532532 if (B.length() == 0) continue;
533533 }
534534 }
535
535
536536 if (lessThan(items[B.end - 1], items[A.start])) {
537537 // the two ranges are in reverse order, so a simple rotation should fix it
538538 mem.rotate(T, items[A.start..B.end], A.length());
539539 } else if (lessThan(items[A.end], items[A.end - 1])) {
540540 // these two ranges weren't already in order, so we'll need to merge them!
541541 var findA: usize = undefined;
542
542
543543 // break the remainder of A into blocks. firstA is the uneven-sized first A block
544544 var blockA = Range.init(A.start, A.end);
545545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);
546
546
547547 // swap the first value of each A block with the value in buffer1
548548 var indexA = buffer1.start;
549549 index = firstA.end;
550550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
551551 mem.swap(T, &items[indexA], &items[index]);
552552 }
553
553
554554 // start rolling the A blocks through the B blocks!
555555 // 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
556556 var lastA = firstA;
......@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
558558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));
559559 blockA.start += firstA.length();
560560 indexA = buffer1.start;
561
561
562562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it
563563 // otherwise, if the second buffer is available, block swap the contents into that
564564 if (lastA.length() <= cache.len) {
......@@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
566566 } else if (buffer2.length() > 0) {
567567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());
568568 }
569
569
570570 if (blockA.length() > 0) {
571571 while (true) {
572572 // 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
575575 // figure out where to split the previous B block, and rotate it at the split
576576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);
577577 const B_remaining = lastB.end - B_split;
578
578
579579 // swap the minimum A block to the beginning of the rolling A blocks
580580 var minA = blockA.start;
581581 findA = minA + block_size;
......@@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
585585 }
586586 }
587587 blockSwap(T, items, blockA.start, minA, block_size);
588
588
589589 // swap the first item of the previous A block back with its original value, which is stored in buffer1
590590 mem.swap(T, &items[blockA.start], &items[indexA]);
591591 indexA += 1;
592
592
593593 // locally merge the previous A block with the B values that follow it
594594 // if lastA fits into the external cache we'll use that (with MergeExternal),
595595 // or if the second internal buffer exists we'll use that (with MergeInternal),
596596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)
597
597
598598 if (lastA.length() <= cache.len) {
599599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);
600600 } else if (buffer2.length() > 0) {
......@@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
602602 } else {
603603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);
604604 }
605
605
606606 if (buffer2.length() > 0 or block_size <= cache.len) {
607607 // 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
608608 if (block_size <= cache.len) {
......@@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
610610 } else {
611611 blockSwap(T, items, blockA.start, buffer2.start, block_size);
612612 }
613
613
614614 // this is equivalent to rotating, but faster
615615 // 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
616616 // 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
619619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation
620620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);
621621 }
622
622
623623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split
624624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);
625625 lastB = Range.init(lastA.end, lastA.end + B_remaining);
626
626
627627 // if there are no more A blocks remaining, this step is finished!
628628 blockA.start += block_size;
629629 if (blockA.length() == 0)
630630 break;
631
631
632632 } else if (blockB.length() < block_size) {
633633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634634 // the cache is disabled here since it might contain the contents of the previous A block
635635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);
636
636
637637 lastB = Range.init(blockA.start, blockA.start + blockB.length());
638638 blockA.start += blockB.length();
639639 blockA.end += blockB.length();
......@@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
642642 // roll the leftmost A block to the end by swapping it with the next B block
643643 blockSwap(T, items, blockA.start, blockB.start, block_size);
644644 lastB = Range.init(blockA.start, blockA.start + block_size);
645
645
646646 blockA.start += block_size;
647647 blockA.end += block_size;
648648 blockB.start += block_size;
649
649
650650 if (blockB.end > B.end - block_size) {
651651 blockB.end = B.end;
652652 } else {
......@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
655655 }
656656 }
657657 }
658
658
659659 // merge the last A block with the remaining B values
660660 if (lastA.length() <= cache.len) {
661661 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
666666 }
667667 }
668668 }
669
669
670670 // 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
671671 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer
672
672
673673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,
674674 // 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
675675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);
676
676
677677 pull_index = 0;
678678 while (pull_index < 2) : (pull_index += 1) {
679679 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
702702 }
703703 }
704704 }
705
705
706706 // double the size of each A and B subarray that will be merged in the next level
707707 if (!iterator.nextLevel()) break;
708708 }
......@@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
711711// merge operation without a buffer
712712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {
713713 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714
714
715715 // this just repeatedly binary searches into B and rotates A into position.
716716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
717717 // but I decided to stick with this because it had better situational performance
718 //
718 //
719719 // (Hwang and Lin is designed for merging subarrays of very different sizes,
720720 // but WikiSort almost always uses subarrays that are roughly the same size)
721 //
721 //
722722 // normally this is incredibly suboptimal, but this function is only called
723723 // when none of the A or B blocks in any subarray contained 2√A unique values,
724724 // which places a hard limit on the number of times this will ACTUALLY need
725725 // to binary search and rotate.
726 //
726 //
727727 // according to my analysis the worst case is √A rotations performed on √A items
728728 // once the constant factors are removed, which ends up being O(n)
729 //
729 //
730730 // again, this is NOT a general-purpose solution – it only works well in this case!
731731 // kind of like how the O(n^2) insertion sort is used in some places
732732
733733 var A = *A_arg;
734734 var B = *B_arg;
735
735
736736 while (true) {
737737 // find the first place in B where the first item in A needs to be inserted
738738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);
739
739
740740 // rotate A into place
741741 const amount = mid - A.end;
742742 mem.rotate(T, items[A.start..mid], A.length());
743743 if (B.end == mid) break;
744
744
745745 // calculate the new A and B ranges
746746 B.start = mid;
747747 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,
757757 var A_count: usize = 0;
758758 var B_count: usize = 0;
759759 var insert: usize = 0;
760
760
761761 if (B.length() > 0 and A.length() > 0) {
762762 while (true) {
763763 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,
773773 }
774774 }
775775 }
776
776
777777 // swap the remainder of A into the final array
778778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);
779779}
......@@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
790790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
791791 if (range.length() == 0) return range.start;
792792 const skip = math.max(range.length()/unique, usize(1));
793
793
794794 var index = range.start + skip;
795795 while (lessThan(items[index - 1], value)) : (index += skip) {
796796 if (index >= range.end - skip) {
797797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);
798798 }
799799 }
800
800
801801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802802}
803803
804804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
805805 if (range.length() == 0) return range.start;
806806 const skip = math.max(range.length()/unique, usize(1));
807
807
808808 var index = range.end - skip;
809809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
810810 if (index < range.start + skip) {
811811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);
812812 }
813813 }
814
814
815815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816816}
817817
818818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
819819 if (range.length() == 0) return range.start;
820820 const skip = math.max(range.length()/unique, usize(1));
821
821
822822 var index = range.start + skip;
823823 while (!lessThan(value, items[index - 1])) : (index += skip) {
824824 if (index >= range.end - skip) {
825825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);
826826 }
827827 }
828
828
829829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830830}
831831
832832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
833833 if (range.length() == 0) return range.start;
834834 const skip = math.max(range.length()/unique, usize(1));
835
835
836836 var index = range.end - skip;
837837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
838838 if (index < range.start + skip) {
839839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);
840840 }
841841 }
842
842
843843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844844}
845845
......@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
885885 const A_last = A.end;
886886 const B_last = B.end;
887887 var insert_index: usize = 0;
888
888
889889 while (true) {
890890 if (!lessThan(from[B_index], from[A_index])) {
891891 into[insert_index] = from[A_index];
......@@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
916916 var insert_index: usize = A.start;
917917 const A_last = A.length();
918918 const B_last = B.end;
919
919
920920 if (B.length() > 0 and A.length() > 0) {
921921 while (true) {
922922 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,
932932 }
933933 }
934934 }
935
935
936936 // copy the remainder of A into the final array
937937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938938}
......@@ -1081,17 +1081,17 @@ test "another sort case" {
10811081}
10821082
10831083test "sort fuzz testing" {
1084 var rng = std.rand.Rand.init(0x12345678);
1084 var prng = std.rand.DefaultPrng.init(0x12345678);
10851085 const test_case_count = 10;
10861086 var i: usize = 0;
10871087 while (i < test_case_count) : (i += 1) {
1088 fuzzTest(&rng);
1088 fuzzTest(&prng.random);
10891089 }
10901090}
10911091
10921092var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10931093
1094fn fuzzTest(rng: &std.rand.Rand) void {
1094fn fuzzTest(rng: &std.rand.Random) void {
10951095 const array_size = rng.range(usize, 0, 1000);
10961096 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
10971097 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 {
2020 IntegerLiteral,
2121 FloatLiteral,
2222 StringLiteral,
23 UndefinedLiteral,
2324 BuiltinCall,
25 Call,
2426 LineComment,
27 TestDecl,
2528 };
2629
2730 pub fn iterate(base: &Node, index: usize) ?&Node {
......@@ -37,8 +40,11 @@ pub const Node = struct {
3740 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
3841 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
3942 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
43 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
4044 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
45 Id.Call => @fieldParentPtr(NodeCall, "base", base).iterate(index),
4146 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
47 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
4248 };
4349 }
4450
......@@ -55,8 +61,11 @@ pub const Node = struct {
5561 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
5662 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
5763 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
64 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
5865 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
66 Id.Call => @fieldParentPtr(NodeCall, "base", base).firstToken(),
5967 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
68 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
6069 };
6170 }
6271
......@@ -73,8 +82,11 @@ pub const Node = struct {
7382 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
7483 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
7584 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
85 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
7686 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
87 Id.Call => @fieldParentPtr(NodeCall, "base", base).lastToken(),
7788 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
89 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
7890 };
7991 }
8092};
......@@ -305,9 +317,47 @@ pub const NodeInfixOp = struct {
305317 rhs: &Node,
306318
307319 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,
309338 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,
310357 Period,
358 Sub,
359 SubWrap,
360 UnwrapMaybe,
311361 };
312362
313363 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
......@@ -317,9 +367,47 @@ pub const NodeInfixOp = struct {
317367 i -= 1;
318368
319369 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,
321388 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 => {},
323411 }
324412
325413 if (i < 1) return self.rhs;
......@@ -344,9 +432,15 @@ pub const NodePrefixOp = struct {
344432 rhs: &Node,
345433
346434 const PrefixOp = union(enum) {
435 AddrOf: AddrOfInfo,
436 BitNot,
437 BoolNot,
438 Deref,
439 Negation,
440 NegationWrap,
347441 Return,
348442 Try,
349 AddrOf: AddrOfInfo,
443 UnwrapMaybe,
350444 };
351445 const AddrOfInfo = struct {
352446 align_expr: ?&Node,
......@@ -360,14 +454,20 @@ pub const NodePrefixOp = struct {
360454 var i = index;
361455
362456 switch (self.op) {
363 PrefixOp.Return,
364 PrefixOp.Try => {},
365457 PrefixOp.AddrOf => |addr_of_info| {
366458 if (addr_of_info.align_expr) |align_expr| {
367459 if (i < 1) return align_expr;
368460 i -= 1;
369461 }
370462 },
463 PrefixOp.BitNot,
464 PrefixOp.BoolNot,
465 PrefixOp.Deref,
466 PrefixOp.Negation,
467 PrefixOp.NegationWrap,
468 PrefixOp.Return,
469 PrefixOp.Try,
470 PrefixOp.UnwrapMaybe => {},
371471 }
372472
373473 if (i < 1) return self.rhs;
......@@ -443,6 +543,33 @@ pub const NodeBuiltinCall = struct {
443543 }
444544};
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
446573pub const NodeStringLiteral = struct {
447574 base: Node,
448575 token: Token,
......@@ -460,6 +587,23 @@ pub const NodeStringLiteral = struct {
460587 }
461588};
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
463607pub const NodeLineComment = struct {
464608 base: Node,
465609 lines: ArrayList(Token),
......@@ -476,3 +620,28 @@ pub const NodeLineComment = struct {
476620 return self.lines.at(self.lines.len - 1);
477621 }
478622};
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 {
8686 AfterOperand,
8787 InfixOp: &ast.NodeInfixOp,
8888 PrefixOp: &ast.NodePrefixOp,
89 SuffixOp: &ast.Node,
8990 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
9091 TypeExpr: DestPtr,
9192 VarDecl: &ast.NodeVarDecl,
......@@ -171,6 +172,22 @@ pub const Parser = struct {
171172 stack.append(State { .TopLevelExtern = token }) catch unreachable;
172173 continue;
173174 },
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 },
174191 Token.Id.Eof => {
175192 root_node.eof_token = token;
176193 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
......@@ -319,6 +336,42 @@ pub const Parser = struct {
319336 try stack.append(State.ExpectOperand);
320337 continue;
321338 },
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 },
322375 Token.Id.Ampersand => {
323376 const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
324377 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
......@@ -355,6 +408,13 @@ pub const Parser = struct {
355408 try stack.append(State.AfterOperand);
356409 continue;
357410 },
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 },
358418 Token.Id.Builtin => {
359419 const node = try arena.create(ast.NodeBuiltinCall);
360420 *node = ast.NodeBuiltinCall {
......@@ -398,56 +458,62 @@ pub const Parser = struct {
398458 // or a postfix operator (like () or {}),
399459 // otherwise this expression is done (like on a ; or else).
400460 var token = self.getNextToken();
401 switch (token.id) {
402 Token.Id.EqualEqual => {
403 try stack.append(State {
404 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.EqualEqual)
405 });
406 try stack.append(State.ExpectOperand);
407 continue;
408 },
409 Token.Id.BangEqual => {
461 if (tokenIdToInfixOp(token.id)) |infix_id| {
410462 try stack.append(State {
411 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BangEqual)
463 .InfixOp = try self.createInfixOp(arena, token, infix_id)
412464 });
413465 try stack.append(State.ExpectOperand);
414466 continue;
415 },
416 Token.Id.Period => {
417 try stack.append(State {
418 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period)
419 });
420 try stack.append(State.ExpectOperand);
421 continue;
422 },
423 else => {
424 // no postfix/infix operator after this operand.
425 self.putBackToken(token);
426 // reduce the stack
427 var expression: &ast.Node = stack.pop().Operand;
428 while (true) {
429 switch (stack.pop()) {
430 State.Expression => |dest_ptr| {
431 // we're done
432 try dest_ptr.store(expression);
433 break;
434 },
435 State.InfixOp => |infix_op| {
436 infix_op.rhs = expression;
437 infix_op.lhs = stack.pop().Operand;
438 expression = &infix_op.base;
439 continue;
440 },
441 State.PrefixOp => |prefix_op| {
442 prefix_op.rhs = expression;
443 expression = &prefix_op.base;
444 continue;
445 },
446 else => unreachable,
447 }
467
468 } else if (token.id == Token.Id.LParen) {
469 self.putBackToken(token);
470
471 const node = try arena.create(ast.NodeCall);
472 *node = ast.NodeCall {
473 .base = self.initNode(ast.Node.Id.Call),
474 .callee = undefined,
475 .params = ArrayList(&ast.Node).init(arena),
476 .rparen_token = undefined,
477 };
478 try stack.append(State { .SuffixOp = &node.base });
479 try stack.append(State.AfterOperand);
480 try stack.append(State {.ExprListItemOrEnd = &node.params });
481 try stack.append(State {
482 .ExpectTokenSave = ExpectTokenSave {
483 .id = Token.Id.LParen,
484 .ptr = &node.rparen_token,
485 },
486 });
487 continue;
488
489 // TODO: Parse postfix operator
490 } else {
491 // no postfix/infix operator after this operand.
492 self.putBackToken(token);
493
494 var expression = popSuffixOp(&stack);
495 while (true) {
496 switch (stack.pop()) {
497 State.Expression => |dest_ptr| {
498 // we're done
499 try dest_ptr.store(expression);
500 break;
501 },
502 State.InfixOp => |infix_op| {
503 infix_op.rhs = expression;
504 infix_op.lhs = popSuffixOp(&stack);
505 expression = &infix_op.base;
506 continue;
507 },
508 State.PrefixOp => |prefix_op| {
509 prefix_op.rhs = expression;
510 expression = &prefix_op.base;
511 continue;
512 },
513 else => unreachable,
448514 }
449 continue;
450 },
515 }
516 continue;
451517 }
452518 },
453519
......@@ -685,11 +751,86 @@ pub const Parser = struct {
685751 // These are data, not control flow.
686752 State.InfixOp => unreachable,
687753 State.PrefixOp => unreachable,
754 State.SuffixOp => unreachable,
688755 State.Operand => unreachable,
689756 }
690757 }
691758 }
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
693834 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {
694835 if (self.pending_line_comment_node) |comment_node| {
695836 self.pending_line_comment_node = null;
......@@ -733,6 +874,20 @@ pub const Parser = struct {
733874 return node;
734875 }
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
736891 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,
737892 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
738893 {
......@@ -837,6 +992,16 @@ pub const Parser = struct {
837992 return node;
838993 }
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
8401005 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
8411006 const node = try self.createIdentifier(arena, name_token);
8421007 try dest_ptr.store(&node.base);
......@@ -867,6 +1032,14 @@ pub const Parser = struct {
8671032 return node;
8681033 }
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
8701043 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
8711044 const loc = self.tokenizer.getTokenLocation(token);
8721045 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args);
......@@ -1032,7 +1205,11 @@ pub const Parser = struct {
10321205 ast.Node.Id.VarDecl => {
10331206 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
10341207 try stack.append(RenderState { .VarDecl = var_decl});
1035
1208 },
1209 ast.Node.Id.TestDecl => {
1210 const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
1211 try stream.print("test {} ", self.tokenizer.getTokenSlice(test_decl.name_token));
1212 try stack.append(RenderState { .Expression = test_decl.body_node });
10361213 },
10371214 else => unreachable,
10381215 }
......@@ -1131,29 +1308,57 @@ pub const Parser = struct {
11311308 ast.Node.Id.InfixOp => {
11321309 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
11331310 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
1134 switch (prefix_op_node.op) {
1135 ast.NodeInfixOp.InfixOp.EqualEqual => {
1136 try stack.append(RenderState { .Text = " == "});
1137 },
1138 ast.NodeInfixOp.InfixOp.BangEqual => {
1139 try stack.append(RenderState { .Text = " != "});
1140 },
1141 ast.NodeInfixOp.InfixOp.Period => {
1142 try stack.append(RenderState { .Text = "."});
1143 },
1144 }
1311 const text = switch (prefix_op_node.op) {
1312 ast.NodeInfixOp.InfixOp.Add => " + ",
1313 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
1314 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
1315 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
1316 ast.NodeInfixOp.InfixOp.Assign => " = ",
1317 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
1318 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
1319 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
1320 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
1321 ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
1322 ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
1323 ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
1324 ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
1325 ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
1326 ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
1327 ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
1328 ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
1329 ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
1330 ast.NodeInfixOp.InfixOp.BangEqual => " != ",
1331 ast.NodeInfixOp.InfixOp.BitAnd => " & ",
1332 ast.NodeInfixOp.InfixOp.BitOr => " | ",
1333 ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
1334 ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
1335 ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
1336 ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
1337 ast.NodeInfixOp.InfixOp.BoolOr => " or ",
1338 ast.NodeInfixOp.InfixOp.Div => " / ",
1339 ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
1340 ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
1341 ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
1342 ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
1343 ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
1344 ast.NodeInfixOp.InfixOp.LessThan => " < ",
1345 ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
1346 ast.NodeInfixOp.InfixOp.Mod => " % ",
1347 ast.NodeInfixOp.InfixOp.Mult => " * ",
1348 ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
1349 ast.NodeInfixOp.InfixOp.Period => ".",
1350 ast.NodeInfixOp.InfixOp.Sub => " - ",
1351 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
1352 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
1353 };
1354
1355 try stack.append(RenderState { .Text = text });
11451356 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
11461357 },
11471358 ast.Node.Id.PrefixOp => {
11481359 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
11491360 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
11501361 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 },
11571362 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
11581363 try stream.write("&");
11591364 if (addr_of_info.volatile_token != null) {
......@@ -1168,6 +1373,14 @@ pub const Parser = struct {
11681373 try stack.append(RenderState { .Expression = align_expr});
11691374 }
11701375 },
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("??"),
11711384 }
11721385 },
11731386 ast.Node.Id.IntegerLiteral => {
......@@ -1182,6 +1395,10 @@ pub const Parser = struct {
11821395 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
11831396 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
11841397 },
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 },
11851402 ast.Node.Id.BuiltinCall => {
11861403 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);
11871404 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
......@@ -1196,11 +1413,27 @@ pub const Parser = struct {
11961413 }
11971414 }
11981415 },
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 },
11991431 ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),
12001432 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
12011433
12021434 ast.Node.Id.Root,
12031435 ast.Node.Id.VarDecl,
1436 ast.Node.Id.TestDecl,
12041437 ast.Node.Id.ParamDecl => unreachable,
12051438 },
12061439 RenderState.FnProtoRParen => |fn_proto| {
......@@ -1422,4 +1655,79 @@ test "zig fmt" {
14221655 \\}
14231656 \\
14241657 );
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 );
14251733}
std/zig/tokenizer.zig+288-5
......@@ -77,6 +77,7 @@ pub const Token = struct {
7777 Builtin,
7878 Bang,
7979 Pipe,
80 PipePipe,
8081 PipeEqual,
8182 Equal,
8283 EqualEqual,
......@@ -85,18 +86,46 @@ pub const Token = struct {
8586 RParen,
8687 Semicolon,
8788 Percent,
89 PercentEqual,
8890 LBrace,
8991 RBrace,
9092 Period,
9193 Ellipsis2,
9294 Ellipsis3,
95 Caret,
96 CaretEqual,
97 Plus,
98 PlusPlus,
99 PlusEqual,
100 PlusPercent,
101 PlusPercentEqual,
93102 Minus,
103 MinusEqual,
104 MinusPercent,
105 MinusPercentEqual,
106 Asterisk,
107 AsteriskEqual,
108 AsteriskAsterisk,
109 AsteriskPercent,
110 AsteriskPercentEqual,
94111 Arrow,
95112 Colon,
96113 Slash,
114 SlashEqual,
97115 Comma,
98116 Ampersand,
99117 AmpersandEqual,
118 QuestionMark,
119 QuestionMarkQuestionMark,
120 AngleBracketLeft,
121 AngleBracketLeftEqual,
122 AngleBracketAngleBracketLeft,
123 AngleBracketAngleBracketLeftEqual,
124 AngleBracketRight,
125 AngleBracketRightEqual,
126 AngleBracketAngleBracketRight,
127 AngleBracketAngleBracketRightEqual,
128 Tilde,
100129 IntegerLiteral,
101130 FloatLiteral,
102131 LineComment,
......@@ -200,6 +229,9 @@ pub const Tokenizer = struct {
200229 Bang,
201230 Pipe,
202231 Minus,
232 MinusPercent,
233 Asterisk,
234 AsteriskPercent,
203235 Slash,
204236 LineComment,
205237 Zero,
......@@ -210,6 +242,15 @@ pub const Tokenizer = struct {
210242 FloatExponentUnsigned,
211243 FloatExponentNumber,
212244 Ampersand,
245 Caret,
246 Percent,
247 QuestionMark,
248 Plus,
249 PlusPercent,
250 AngleBracketLeft,
251 AngleBracketAngleBracketLeft,
252 AngleBracketRight,
253 AngleBracketAngleBracketRight,
213254 Period,
214255 Period2,
215256 SawAtSign,
......@@ -291,9 +332,25 @@ pub const Tokenizer = struct {
291332 break;
292333 },
293334 '%' => {
294 result.id = Token.Id.Percent;
295 self.index += 1;
296 break;
335 state = State.Percent;
336 },
337 '*' => {
338 state = State.Asterisk;
339 },
340 '+' => {
341 state = State.Plus;
342 },
343 '?' => {
344 state = State.QuestionMark;
345 },
346 '<' => {
347 state = State.AngleBracketLeft;
348 },
349 '>' => {
350 state = State.AngleBracketRight;
351 },
352 '^' => {
353 state = State.Caret;
297354 },
298355 '{' => {
299356 result.id = Token.Id.LBrace;
......@@ -305,6 +362,11 @@ pub const Tokenizer = struct {
305362 self.index += 1;
306363 break;
307364 },
365 '~' => {
366 result.id = Token.Id.Tilde;
367 self.index += 1;
368 break;
369 },
308370 '.' => {
309371 state = State.Period;
310372 },
......@@ -356,6 +418,107 @@ pub const Tokenizer = struct {
356418 break;
357419 },
358420 },
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
359522 State.Identifier => switch (c) {
360523 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
361524 else => {
......@@ -417,6 +580,11 @@ pub const Tokenizer = struct {
417580 self.index += 1;
418581 break;
419582 },
583 '|' => {
584 result.id = Token.Id.PipePipe;
585 self.index += 1;
586 break;
587 },
420588 else => {
421589 result.id = Token.Id.Pipe;
422590 break;
......@@ -441,12 +609,86 @@ pub const Tokenizer = struct {
441609 self.index += 1;
442610 break;
443611 },
612 '=' => {
613 result.id = Token.Id.MinusEqual;
614 self.index += 1;
615 break;
616 },
617 '%' => {
618 state = State.MinusPercent;
619 },
444620 else => {
445621 result.id = Token.Id.Minus;
446622 break;
447623 },
448624 },
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
450692 State.Period => switch (c) {
451693 '.' => {
452694 state = State.Period2;
......@@ -474,6 +716,11 @@ pub const Tokenizer = struct {
474716 result.id = Token.Id.LineComment;
475717 state = State.LineComment;
476718 },
719 '=' => {
720 result.id = Token.Id.SlashEqual;
721 self.index += 1;
722 break;
723 },
477724 else => {
478725 result.id = Token.Id.Slash;
479726 break;
......@@ -609,6 +856,42 @@ pub const Tokenizer = struct {
609856 State.Pipe => {
610857 result.id = Token.Id.Pipe;
611858 },
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 },
612895 }
613896 }
614897 if (result.id == Token.Id.Eof) {
......@@ -752,8 +1035,8 @@ test "tokenizer - string identifier and builtin fns" {
7521035
7531036test "tokenizer - pipe and then invalid" {
7541037 testTokenize("||=", []Token.Id{
755 Token.Id.Pipe,
756 Token.Id.PipeEqual,
1038 Token.Id.PipePipe,
1039 Token.Id.Equal,
7571040 });
7581041}
7591042
test/cases/coroutines.zig+33
......@@ -5,6 +5,7 @@ var x: i32 = 1;
55
66test "create a coroutine and cancel it" {
77 const p = try async<std.debug.global_allocator> simpleAsyncFn();
8 comptime assert(@typeOf(p) == promise->void);
89 cancel p;
910 assert(x == 2);
1011}
......@@ -55,6 +56,7 @@ var result = false;
5556
5657async fn testSuspendBlock() void {
5758 suspend |p| {
59 comptime assert(@typeOf(p) == promise->void);
5860 a_promise = p;
5961 }
6062 result = true;
......@@ -156,3 +158,34 @@ test "async function with dot syntax" {
156158 cancel p;
157159 assert(S.y == 2);
158160}
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 @@
1const assert = @import("std").debug.assert;
1const std = @import("std");
2const assert = std.debug.assert;
23const builtin = @import("builtin");
34
45test "compile time recursion" {
......@@ -503,3 +504,12 @@ test "const ptr to comptime mutable data is not memoized" {
503504 assert(foo.read_x() == 2);
504505 }
505506}
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 @@
11const tests = @import("tests.zig");
22
33pub 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
413 cases.add("@tagName used on union with no associated enum tag",
514 \\const FloatInt = extern union {
615 \\ Float: f32,
test/gen_h.zig+11
......@@ -51,6 +51,16 @@ pub fn addCases(cases: &tests.GenHContext) void {
5151 \\
5252 );
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
5464 cases.add("array field-type",
5565 \\const Foo = extern struct {
5666 \\ A: [2]i32,
......@@ -66,4 +76,5 @@ pub fn addCases(cases: &tests.GenHContext) void {
6676 \\TEST_EXPORT void entry(struct Foo foo, uint8_t bar[]);
6777 \\
6878 );
79
6980}
test/runtime_safety.zig+30
......@@ -281,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
281281 \\ f.float = 12.34;
282282 \\}
283283 );
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 );
284314}