authorgravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2018-04-11 00:33:19-07:00
committergravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2018-04-11 00:33:19-07:00
log135a335ce12a33666e44cb13e0be4bb893877565
tree23b10bed3d36e3fb244c6a2e5d5765d8b7a71fb5
parentb01c5a95c468650f143e0ae96f6c3865852fdcda
parentf43711e5fbbedafa1c28c933fdca0949427c77cd

Merge branch 'master' into zen_stdlib


84 files changed, 11186 insertions(+), 2859 deletions(-)

.travis.yml+3-1
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1sudo: required
2services:
3 - docker
1os:4os:
2 - linux5 - linux
3 - osx6 - osx
4dist: trusty7dist: trusty
5osx_image: xcode8.38osx_image: xcode8.3
6sudo: required
7language: cpp9language: cpp
8before_install:10before_install:
9 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi11 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
CMakeLists.txt+33-9
...@@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE)...@@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE)
5 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)5 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
6endif()6endif()
77
8if(NOT CMAKE_INSTALL_PREFIX)
9 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE STRING
10 "Directory to install zig to" FORCE)
11endif()
12
8project(zig C CXX)13project(zig C CXX)
9set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})14set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
1015
...@@ -30,11 +35,7 @@ if(GIT_EXE)...@@ -30,11 +35,7 @@ if(GIT_EXE)
30endif()35endif()
31message("Configuring zig version ${ZIG_VERSION}")36message("Configuring zig version ${ZIG_VERSION}")
3237
33set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found")38set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
34set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found")
35set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory")
36set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target")
37set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target")
3839
39string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")40string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")
40string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}")41string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}")
...@@ -49,6 +50,22 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead...@@ -49,6 +50,22 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead
49find_package(llvm)50find_package(llvm)
50find_package(clang)51find_package(clang)
5152
53if(NOT MSVC)
54 find_library(LIBXML2 NAMES xml2 libxml2)
55 if(${LIBXML2} STREQUAL "LIBXML2-NOTFOUND")
56 message(FATAL_ERROR "Could not find libxml2")
57 else()
58 message("${LIBXML2} found")
59 endif()
60
61 find_library(ZLIB NAMES z zlib libz)
62 if(${ZLIB} STREQUAL "ZLIB-NOTFOUND")
63 message(FATAL_ERROR "Could not find zlib")
64 else()
65 message("${ZLIB} found")
66 endif()
67endif()
68
52set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp")69set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp")
5370
54if(ZIG_FORCE_EXTERNAL_LLD)71if(ZIG_FORCE_EXTERNAL_LLD)
...@@ -413,18 +430,24 @@ set(ZIG_STD_FILES...@@ -413,18 +430,24 @@ set(ZIG_STD_FILES
413 "crypto/sha2.zig"430 "crypto/sha2.zig"
414 "crypto/sha3.zig"431 "crypto/sha3.zig"
415 "crypto/blake2.zig"432 "crypto/blake2.zig"
433 "crypto/hmac.zig"
416 "cstr.zig"434 "cstr.zig"
417 "debug/failing_allocator.zig"435 "debug/failing_allocator.zig"
418 "debug/index.zig"436 "debug/index.zig"
419 "dwarf.zig"437 "dwarf.zig"
420 "elf.zig"438 "elf.zig"
421 "empty.zig"439 "empty.zig"
422 "endian.zig"440 "event.zig"
423 "fmt/errol/enum3.zig"441 "fmt/errol/enum3.zig"
424 "fmt/errol/index.zig"442 "fmt/errol/index.zig"
425 "fmt/errol/lookup.zig"443 "fmt/errol/lookup.zig"
426 "fmt/index.zig"444 "fmt/index.zig"
427 "hash_map.zig"445 "hash_map.zig"
446 "hash/index.zig"
447 "hash/adler.zig"
448 "hash/crc.zig"
449 "hash/fnv.zig"
450 "hash/siphash.zig"
428 "heap.zig"451 "heap.zig"
429 "index.zig"452 "index.zig"
430 "io.zig"453 "io.zig"
...@@ -485,7 +508,6 @@ set(ZIG_STD_FILES...@@ -485,7 +508,6 @@ set(ZIG_STD_FILES
485 "os/get_user_id.zig"508 "os/get_user_id.zig"
486 "os/index.zig"509 "os/index.zig"
487 "os/linux/errno.zig"510 "os/linux/errno.zig"
488 "os/linux/i386.zig"
489 "os/linux/index.zig"511 "os/linux/index.zig"
490 "os/linux/x86_64.zig"512 "os/linux/x86_64.zig"
491 "os/path.zig"513 "os/path.zig"
...@@ -493,7 +515,7 @@ set(ZIG_STD_FILES...@@ -493,7 +515,7 @@ set(ZIG_STD_FILES
493 "os/windows/index.zig"515 "os/windows/index.zig"
494 "os/windows/util.zig"516 "os/windows/util.zig"
495 "os/zen.zig"517 "os/zen.zig"
496 "rand.zig"518 "rand/index.zig"
497 "sort.zig"519 "sort.zig"
498 "special/bootstrap.zig"520 "special/bootstrap.zig"
499 "special/bootstrap_lib.zig"521 "special/bootstrap_lib.zig"
...@@ -682,6 +704,8 @@ if(MINGW)...@@ -682,6 +704,8 @@ if(MINGW)
682 set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++")704 set(EXE_LDFLAGS "-static -static-libgcc -static-libstdc++")
683elseif(MSVC)705elseif(MSVC)
684 set(EXE_LDFLAGS "/STACK:16777216")706 set(EXE_LDFLAGS "/STACK:16777216")
707elseif(ZIG_STATIC)
708 set(EXE_LDFLAGS "-static")
685else()709else()
686 set(EXE_LDFLAGS " ")710 set(EXE_LDFLAGS " ")
687endif()711endif()
...@@ -710,7 +734,7 @@ target_link_libraries(zig LINK_PUBLIC...@@ -710,7 +734,7 @@ target_link_libraries(zig LINK_PUBLIC
710 ${CMAKE_THREAD_LIBS_INIT}734 ${CMAKE_THREAD_LIBS_INIT}
711)735)
712if(NOT MSVC)736if(NOT MSVC)
713 target_link_libraries(zig LINK_PUBLIC xml2)737 target_link_libraries(zig LINK_PUBLIC ${LIBXML2})
714endif()738endif()
715if(ZIG_DIA_GUIDS_LIB)739if(ZIG_DIA_GUIDS_LIB)
716 target_link_libraries(zig LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})740 target_link_libraries(zig LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})
README.md+4-10
...@@ -138,31 +138,25 @@ libc. Create demo games using Zig....@@ -138,31 +138,25 @@ libc. Create demo games using Zig.
138138
139##### POSIX139##### POSIX
140140
141If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
142`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
143(example below).
144
145```141```
146mkdir build142mkdir build
147cd build143cd build
148cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o))144cmake ..
149make145make
150make install146make install
151./zig build --build-file ../build.zig test147bin/zig build --build-file ../build.zig test
152```148```
153149
154##### MacOS150##### MacOS
155151
156`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157
158```152```
159brew install cmake llvm@6153brew install cmake llvm@6
160brew outdated llvm@6 || brew upgrade llvm@6154brew outdated llvm@6 || brew upgrade llvm@6
161mkdir build155mkdir build
162cd build156cd build
163cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@6/ -DCMAKE_INSTALL_PREFIX=$(pwd)157cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@6/
164make install158make install
165./zig build --build-file ../build.zig test159bin/zig build --build-file ../build.zig test
166```160```
167161
168##### Windows162##### Windows
build.zig+13
...@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {...@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {
4545
46 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");46 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
47 exe.setBuildMode(mode);47 exe.setBuildMode(mode);
48
49 // This is for finding /lib/libz.a on alpine linux.
50 // TODO turn this into -Dextra-lib-path=/lib option
51 exe.addLibPath("/lib");
52
48 exe.addIncludeDir("src");53 exe.addIncludeDir("src");
49 exe.addIncludeDir(cmake_binary_dir);54 exe.addIncludeDir(cmake_binary_dir);
50 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");55 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");
...@@ -64,6 +69,14 @@ pub fn build(b: &Builder) !void {...@@ -64,6 +69,14 @@ pub fn build(b: &Builder) !void {
64 if (exe.target.getOs() == builtin.Os.linux) {69 if (exe.target.getOs() == builtin.Os.linux) {
65 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});70 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
66 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();71 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
72 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
73 warn(
74 \\Unable to determine path to libstdc++.a
75 \\On Fedora, install libstdc++-static and try again.
76 \\
77 );
78 return error.RequiredLibraryNotFound;
79 }
67 exe.addObjectFile(libstdcxx_path);80 exe.addObjectFile(libstdcxx_path);
6881
69 exe.linkSystemLibrary("pthread");82 exe.linkSystemLibrary("pthread");
ci/appveyor/build_script.bat+1-3
...@@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_...@@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_
2020
21mkdir %ZIGBUILDDIR%21mkdir %ZIGBUILDDIR%
22cd %ZIGBUILDDIR%22cd %ZIGBUILDDIR%
23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release "-DZIG_LIBC_INCLUDE_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt" "-DZIG_LIBC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\bin\x64\ucrt" "-DZIG_LIBC_STATIC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64" || exit /b23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
24msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b24msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
2525
26bin\zig.exe build --build-file ..\build.zig test || exit /b26bin\zig.exe build --build-file ..\build.zig test || exit /b
27
28@echo "MSVC build succeeded"
ci/travis_linux_install+1-1
...@@ -4,4 +4,4 @@ set -x...@@ -4,4 +4,4 @@ set -x
44
5sudo apt-get remove -y llvm-*5sudo apt-get remove -y llvm-*
6sudo rm -rf /usr/local/*6sudo rm -rf /usr/local/*
7sudo apt-get install -y clang-6.0 libclang-6.0 libclang-6.0-dev llvm-6.0 llvm-6.0-dev liblld-6.0 liblld-6.0-dev cmake wine1.6-amd647sudo apt-get install -y clang-6.0 libclang-6.0 libclang-6.0-dev llvm-6.0 llvm-6.0-dev liblld-6.0 liblld-6.0-dev cmake wine1.6-amd64 s3cmd
ci/travis_linux_script+11-20
...@@ -8,25 +8,16 @@ export CXX=clang++-6.0...@@ -8,25 +8,16 @@ export CXX=clang++-6.0
8echo $PATH8echo $PATH
9mkdir build9mkdir build
10cd build10cd build
11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $($CC -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | $CC -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $($CC -print-file-name=crtbegin.o))11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
12make VERBOSE=112make -j2 install
13make install
14./zig build --build-file ../build.zig test13./zig build --build-file ../build.zig test
1514
16./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc15if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
17wine zig-cache/test.exe16 mkdir $TRAVIS_BUILD_DIR/artifacts
1817 docker run -it --mount type=bind,source="$TRAVIS_BUILD_DIR/artifacts",target=/z ziglang/static-base:llvm6-1 -j2 $TRAVIS_COMMIT
19./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-fast18 echo "access_key = $AWS_ACCESS_KEY_ID" >> ~/.s3cfg
20wine zig-cache/test.exe19 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
2120 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
22./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-safe21 touch empty
23wine zig-cache/test.exe22 s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
2423fi
25./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc
26wine64 zig-cache/test.exe
27
28#./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-fast
29#wine64 test.exe
30#
31#./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-safe
32#wine64 test.exe
cmake/Findclang.cmake+3-1
...@@ -5,6 +5,7 @@...@@ -5,6 +5,7 @@
5# CLANG_FOUND5# CLANG_FOUND
6# CLANG_INCLUDE_DIRS6# CLANG_INCLUDE_DIRS
7# CLANG_LIBRARIES7# CLANG_LIBRARIES
8# CLANG_LIBDIRS
89
9if(MSVC)10if(MSVC)
10 find_package(CLANG REQUIRED CONFIG)11 find_package(CLANG REQUIRED CONFIG)
...@@ -34,6 +35,7 @@ else()...@@ -34,6 +35,7 @@ else()
34 string(TOUPPER ${_libname_} _prettylibname_)35 string(TOUPPER ${_libname_} _prettylibname_)
35 find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_}36 find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_}
36 PATHS37 PATHS
38 ${CLANG_LIBDIRS}
37 /usr/lib/llvm/6/lib39 /usr/lib/llvm/6/lib
38 /usr/lib/llvm-6.0/lib40 /usr/lib/llvm-6.0/lib
39 /mingw64/lib41 /mingw64/lib
...@@ -60,4 +62,4 @@ endif()...@@ -60,4 +62,4 @@ endif()
60include(FindPackageHandleStandardArgs)62include(FindPackageHandleStandardArgs)
61find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)63find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)
6264
63mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES)65mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES CLANG_LIBDIRS)
cmake/Findllvm.cmake+2-2
...@@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE...@@ -15,7 +15,7 @@ find_program(LLVM_CONFIG_EXE
15 "c:/msys64/mingw64/bin"15 "c:/msys64/mingw64/bin"
16 "C:/Libraries/llvm-6.0.0/bin")16 "C:/Libraries/llvm-6.0.0/bin")
1717
18if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug"))18if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug") OR ZIG_STATIC)
19 execute_process(19 execute_process(
20 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static20 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static
21 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES21 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES
...@@ -66,7 +66,7 @@ if(NOT LLVM_LIBRARIES)...@@ -66,7 +66,7 @@ if(NOT LLVM_LIBRARIES)
66endif()66endif()
6767
68link_directories("${CMAKE_PREFIX_PATH}/lib")68link_directories("${CMAKE_PREFIX_PATH}/lib")
6969link_directories("${LLVM_LIBDIRS}")
7070
71include(FindPackageHandleStandardArgs)71include(FindPackageHandleStandardArgs)
72find_package_handle_standard_args(LLVM DEFAULT_MSG LLVM_LIBRARIES LLVM_INCLUDE_DIRS)72find_package_handle_standard_args(LLVM DEFAULT_MSG LLVM_LIBRARIES LLVM_INCLUDE_DIRS)
doc/docgen.zig+1-1
...@@ -55,7 +55,7 @@ pub fn main() !void {...@@ -55,7 +55,7 @@ pub fn main() !void {
55 // TODO issue #70955 // TODO issue #709
56 // disabled to pass CI tests, but obviously we want to implement this56 // disabled to pass CI tests, but obviously we want to implement this
57 // and then remove this workaround57 // and then remove this workaround
58 if (builtin.os == builtin.Os.linux) {58 if (builtin.os != builtin.Os.windows) {
59 os.deleteTree(allocator, tmp_dir_name) catch {};59 os.deleteTree(allocator, tmp_dir_name) catch {};
60 }60 }
61 }61 }
doc/langref.html.in+55-20
...@@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C };...@@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C };
1947export fn entry(foo: Foo) void { }1947export fn entry(foo: Foo) void { }
1948 {#code_end#}1948 {#code_end#}
1949 {#header_close#}1949 {#header_close#}
1950 <p>TODO packed enum</p>1950 {#header_open|packed enum#}
1951 {#see_also|@memberName|@memberCount|@tagName#}1951 <p>By default, the size of enums is not guaranteed.</p>
1952 <p><code>packed enum</code> causes the size of the enum to be the same as the size of the integer tag type
1953 of the enum:</p>
1954 {#code_begin|test#}
1955const std = @import("std");
1956
1957test "packed enum" {
1958 const Number = packed enum(u8) {
1959 One,
1960 Two,
1961 Three,
1962 };
1963 std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
1964}
1965 {#code_end#}
1966 {#header_close#}
1967 {#see_also|@memberName|@memberCount|@tagName|@sizeOf#}
1952 {#header_close#}1968 {#header_close#}
1953 {#header_open|union#}1969 {#header_open|union#}
1954 {#code_begin|test|union#}1970 {#code_begin|test|union#}
...@@ -2017,7 +2033,27 @@ test "union variant switch" {...@@ -2017,7 +2033,27 @@ test "union variant switch" {
2017 assert(mem.eql(u8, what_is_it, "this is a number"));2033 assert(mem.eql(u8, what_is_it, "this is a number"));
2018}2034}
20192035
2020// TODO union methods2036// Unions can have methods just like structs and enums:
2037
2038const Variant = union(enum) {
2039 Int: i32,
2040 Bool: bool,
2041
2042 fn truthy(self: &const Variant) bool {
2043 return switch (*self) {
2044 Variant.Int => |x_int| x_int != 0,
2045 Variant.Bool => |x_bool| x_bool,
2046 };
2047 }
2048};
2049
2050test "union method" {
2051 var v1 = Variant { .Int = 1 };
2052 var v2 = Variant { .Bool = false };
2053
2054 assert(v1.truthy());
2055 assert(!v2.truthy());
2056}
20212057
20222058
2023const Small = union {2059const Small = union {
...@@ -2864,18 +2900,18 @@ const err = (error {FileNotFound}).FileNotFound;...@@ -2864,18 +2900,18 @@ const err = (error {FileNotFound}).FileNotFound;
2864 assert to make sure the error value is in fact in the destination error set.2900 assert to make sure the error value is in fact in the destination error set.
2865 </p>2901 </p>
2866 <p>2902 <p>
2867 The global error set should generally be avoided when possible, because it prevents2903 The global error set should generally be avoided because it prevents the
2868 the compiler from knowing what errors are possible at compile-time. Knowing2904 compiler from knowing what errors are possible at compile-time. Knowing
2869 the error set at compile-time is better for generated documentationt and for2905 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#}.2906 helpful error messages, such as forgetting a possible error value in a {#link|switch#}.
2871 </p>2907 </p>
2872 {#header_close#}2908 {#header_close#}
2873 {#header_close#}2909 {#header_close#}
2874 {#header_open|Error Union Type#}2910 {#header_open|Error Union Type#}
2875 <p>2911 <p>
2876 Most of the time you will not find yourself using an error set type. Instead,2912 An error set type and normal type can be combined with the <code>!</code>
2877 likely you will be using the error union type. This is when you take an error set2913 binary operator to form an error union type. You are likely to use an
2878 and a normal type, and create an error union with the <code>!</code> binary operator.2914 error union type more often than an error set type by itself.
2879 </p>2915 </p>
2880 <p>2916 <p>
2881 Here is a function to parse a string into a 64-bit integer:2917 Here is a function to parse a string into a 64-bit integer:
...@@ -5733,13 +5769,13 @@ VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("alig...@@ -5733,13 +5769,13 @@ VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("alig
57335769
5734ContainerMember = (ContainerField | FnDef | GlobalVarDecl)5770ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
57355771
5736ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","5772ContainerField = Symbol option(":" PrefixOpExpression) option("=" PrefixOpExpression) ","
57375773
5738UseDecl = "use" Expression ";"5774UseDecl = "use" Expression ";"
57395775
5740ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"5776ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
57415777
5742FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")5778FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("&lt;" Expression "&gt;"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
57435779
5744FnDef = option("inline" | "export") FnProto Block5780FnDef = option("inline" | "export") FnProto Block
57455781
...@@ -5751,9 +5787,7 @@ Block = option(Symbol ":") "{" many(Statement) "}"...@@ -5751,9 +5787,7 @@ Block = option(Symbol ":") "{" many(Statement) "}"
57515787
5752Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"5788Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
57535789
5754TypeExpr = ErrorSetExpr5790TypeExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
5755
5756ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
57575791
5758BlockOrExpression = Block | Expression5792BlockOrExpression = Block | Expression
57595793
...@@ -5833,7 +5867,7 @@ BinaryAndExpression = BitShiftExpression "&amp;" BinaryAndExpression | BitShiftE...@@ -5833,7 +5867,7 @@ BinaryAndExpression = BitShiftExpression "&amp;" BinaryAndExpression | BitShiftE
58335867
5834BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression5868BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression
58355869
5836BitShiftOperator = "&lt;&lt;" | "&gt;&gt;" | "&lt;&lt;"5870BitShiftOperator = "&lt;&lt;" | "&gt;&gt;"
58375871
5838AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression5872AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression
58395873
...@@ -5845,9 +5879,9 @@ CurlySuffixExpression = TypeExpr option(ContainerInitExpression)...@@ -5845,9 +5879,9 @@ CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
58455879
5846MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"5880MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
58475881
5848PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression5882PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
58495883
5850SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)5884SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
58515885
5852FieldAccessExpression = "." Symbol5886FieldAccessExpression = "." Symbol
58535887
...@@ -5865,7 +5899,9 @@ StructLiteralField = "." Symbol "=" Expression...@@ -5865,7 +5899,9 @@ StructLiteralField = "." Symbol "=" Expression
58655899
5866PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"5900PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
58675901
5868PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl5902PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
5903
5904PromiseType = "promise" option("-&gt;" TypeExpr)
58695905
5870ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr5906ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
58715907
...@@ -6033,4 +6069,3 @@ hljs.registerLanguage("zig", function(t) {...@@ -6033,4 +6069,3 @@ hljs.registerLanguage("zig", function(t) {
6033 </script>6069 </script>
6034 </body>6070 </body>
6035</html>6071</html>
6036
example/guess_number/main.zig+11-11
...@@ -2,7 +2,6 @@ const builtin = @import("builtin");...@@ -2,7 +2,6 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const io = std.io;3const io = std.io;
4const fmt = std.fmt;4const fmt = std.fmt;
5const Rand = std.rand.Rand;
6const os = std.os;5const os = std.os;
76
8pub fn main() !void {7pub fn main() !void {
...@@ -10,30 +9,31 @@ pub fn main() !void {...@@ -10,30 +9,31 @@ pub fn main() !void {
10 var stdout_file_stream = io.FileOutStream.init(&stdout_file);9 var stdout_file_stream = io.FileOutStream.init(&stdout_file);
11 const stdout = &stdout_file_stream.stream;10 const stdout = &stdout_file_stream.stream;
1211
13 var stdin_file = try io.getStdIn();
14
15 try stdout.print("Welcome to the Guess Number Game in Zig.\n");12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");
1613
17 var seed_bytes: [@sizeOf(usize)]u8 = undefined;14 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
18 os.getRandomBytes(seed_bytes[0..]) catch |err| {15 os.getRandomBytes(seed_bytes[0..]) catch |err| {
19 std.debug.warn("unable to seed random number generator: {}", err);16 std.debug.warn("unable to seed random number generator: {}", err);
20 return err;17 return err;
21 };18 };
22 const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big);19 const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
23 var rand = Rand.init(seed);20 var prng = std.rand.DefaultPrng.init(seed);
2421
25 const answer = rand.range(u8, 0, 100) + 1;22 const answer = prng.random.range(u8, 0, 100) + 1;
2623
27 while (true) {24 while (true) {
28 try stdout.print("\nGuess a number between 1 and 100: ");25 try stdout.print("\nGuess a number between 1 and 100: ");
29 var line_buf : [20]u8 = undefined;26 var line_buf : [20]u8 = undefined;
3027
31 const line_len = stdin_file.read(line_buf[0..]) catch |err| {28 const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
32 try stdout.print("Unable to read from stdin: {}\n", @errorName(err));29 error.InputTooLong => {
33 return err;30 try stdout.print("Input too long.\n");
31 continue;
32 },
33 error.EndOfFile, error.StdInUnavailable => return err,
34 };34 };
3535
36 const guess = fmt.parseUnsigned(u8, line_buf[0..line_len - 1], 10) catch {36 const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch {
37 try stdout.print("Invalid number.\n");37 try stdout.print("Invalid number.\n");
38 continue;38 continue;
39 };39 };
src-self-hosted/main.zig+160
...@@ -41,6 +41,10 @@ pub fn main() !void {...@@ -41,6 +41,10 @@ pub fn main() !void {
41 const args = try os.argsAlloc(allocator);41 const args = try os.argsAlloc(allocator);
42 defer os.argsFree(allocator, args);42 defer os.argsFree(allocator, args);
4343
44 if (args.len >= 2 and mem.eql(u8, args[1], "build")) {
45 return buildMain(allocator, args[2..]);
46 }
47
44 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {48 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
45 return fmtMain(allocator, args[2..]);49 return fmtMain(allocator, args[2..]);
46 }50 }
...@@ -560,6 +564,161 @@ fn printZen() !void {...@@ -560,6 +564,161 @@ fn printZen() !void {
560 );564 );
561}565}
562566
567fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {
568 var build_file: [] const u8 = "build.zig";
569 var cache_dir: ?[] const u8 = null;
570 var zig_install_prefix: ?[] const u8 = null;
571 var asked_for_help = false;
572 var asked_for_init = false;
573
574 var args = ArrayList([] const u8).init(allocator);
575 defer args.deinit();
576
577 var zig_exe_path = try os.selfExePath(allocator);
578 defer allocator.free(zig_exe_path);
579
580 try args.append(""); // Placeholder for zig-cache/build
581 try args.append(""); // Placeholder for zig_exe_path
582 try args.append(""); // Placeholder for build_file_dirname
583 try args.append(""); // Placeholder for full_cache_dir
584
585 var i: usize = 0;
586 while (i < argv.len) : (i += 1) {
587 var arg = argv[i];
588 if (mem.eql(u8, arg, "--help")) {
589 asked_for_help = true;
590 try args.append(argv[i]);
591 } else if (mem.eql(u8, arg, "--init")) {
592 asked_for_init = true;
593 try args.append(argv[i]);
594 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) {
595 build_file = argv[i + 1];
596 i += 1;
597 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) {
598 cache_dir = argv[i + 1];
599 i += 1;
600 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) {
601 try args.append(arg);
602 i += 1;
603 zig_install_prefix = argv[i];
604 try args.append(argv[i]);
605 } else {
606 try args.append(arg);
607 }
608 }
609
610 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
611 defer allocator.free(zig_lib_dir);
612
613 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
614 defer allocator.free(zig_std_dir);
615
616 const special_dir = try os.path.join(allocator, zig_std_dir, "special");
617 defer allocator.free(special_dir);
618
619 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
620 defer allocator.free(build_runner_path);
621
622 // g = codegen_create(build_runner_path, ...)
623 // codegen_set_out_name(g, "build")
624
625 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
626 defer allocator.free(build_file_abs);
627
628 const build_file_basename = os.path.basename(build_file_abs);
629 const build_file_dirname = os.path.dirname(build_file_abs);
630
631 var full_cache_dir: []u8 = undefined;
632 if (cache_dir == null) {
633 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
634 } else {
635 full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir);
636 }
637 defer allocator.free(full_cache_dir);
638
639 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
640 defer allocator.free(path_to_build_exe);
641 // codegen_set_cache_dir(g, full_cache_dir)
642
643 args.items[0] = path_to_build_exe;
644 args.items[1] = zig_exe_path;
645 args.items[2] = build_file_dirname;
646 args.items[3] = full_cache_dir;
647
648 var build_file_exists: bool = undefined;
649 if (os.File.openRead(allocator, build_file_abs)) |*file| {
650 file.close();
651 build_file_exists = true;
652 } else |_| {
653 build_file_exists = false;
654 }
655
656 if (!build_file_exists and asked_for_help) {
657 // TODO(bnoordhuis) Print help message from std/special/build_runner.zig
658 return;
659 }
660
661 if (!build_file_exists and asked_for_init) {
662 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
663 defer allocator.free(build_template_path);
664
665 var srcfile = try os.File.openRead(allocator, build_template_path);
666 defer srcfile.close();
667
668 var dstfile = try os.File.openWrite(allocator, build_file_abs);
669 defer dstfile.close();
670
671 while (true) {
672 var buffer: [4096]u8 = undefined;
673 const n = try srcfile.read(buffer[0..]);
674 if (n == 0) break;
675 try dstfile.write(buffer[0..n]);
676 }
677
678 return;
679 }
680
681 if (!build_file_exists) {
682 warn(
683 \\No 'build.zig' file found.
684 \\Initialize a 'build.zig' template file with `zig build --init`,
685 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
686 \\See: `zig build --help` or `zig help` for more options.
687 \\
688 );
689 os.exit(1);
690 }
691
692 // codegen_build(g)
693 // codegen_link(g, path_to_build_exe)
694 // codegen_destroy(g)
695
696 var proc = try os.ChildProcess.init(args.toSliceConst(), allocator);
697 defer proc.deinit();
698
699 var term = try proc.spawnAndWait();
700 switch (term) {
701 os.ChildProcess.Term.Exited => |status| {
702 if (status != 0) {
703 warn("{} exited with status {}\n", args.at(0), status);
704 os.exit(1);
705 }
706 },
707 os.ChildProcess.Term.Signal => |signal| {
708 warn("{} killed by signal {}\n", args.at(0), signal);
709 os.exit(1);
710 },
711 os.ChildProcess.Term.Stopped => |signal| {
712 warn("{} stopped by signal {}\n", args.at(0), signal);
713 os.exit(1);
714 },
715 os.ChildProcess.Term.Unknown => |status| {
716 warn("{} encountered unknown failure {}\n", args.at(0), status);
717 os.exit(1);
718 },
719 }
720}
721
563fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {722fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
564 for (file_paths) |file_path| {723 for (file_paths) |file_path| {
565 var file = try os.File.openRead(allocator, file_path);724 var file = try os.File.openRead(allocator, file_path);
...@@ -582,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {...@@ -582,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
582 defer baf.destroy();741 defer baf.destroy();
583742
584 try parser.renderSource(baf.stream(), tree.root_node);743 try parser.renderSource(baf.stream(), tree.root_node);
744 try baf.finish();
585 }745 }
586}746}
587747
src/all_types.hpp+71-14
...@@ -359,7 +359,6 @@ enum NodeType {...@@ -359,7 +359,6 @@ enum NodeType {
359 NodeTypeRoot,359 NodeTypeRoot,
360 NodeTypeFnProto,360 NodeTypeFnProto,
361 NodeTypeFnDef,361 NodeTypeFnDef,
362 NodeTypeFnDecl,
363 NodeTypeParamDecl,362 NodeTypeParamDecl,
364 NodeTypeBlock,363 NodeTypeBlock,
365 NodeTypeGroupedExpr,364 NodeTypeGroupedExpr,
...@@ -409,6 +408,7 @@ enum NodeType {...@@ -409,6 +408,7 @@ enum NodeType {
409 NodeTypeResume,408 NodeTypeResume,
410 NodeTypeAwaitExpr,409 NodeTypeAwaitExpr,
411 NodeTypeSuspend,410 NodeTypeSuspend,
411 NodeTypePromiseType,
412};412};
413413
414struct AstNodeRoot {414struct AstNodeRoot {
...@@ -452,10 +452,6 @@ struct AstNodeFnDef {...@@ -452,10 +452,6 @@ struct AstNodeFnDef {
452 AstNode *body;452 AstNode *body;
453};453};
454454
455struct AstNodeFnDecl {
456 AstNode *fn_proto;
457};
458
459struct AstNodeParamDecl {455struct AstNodeParamDecl {
460 Buf *name;456 Buf *name;
461 AstNode *type;457 AstNode *type;
...@@ -712,10 +708,6 @@ struct AstNodeSwitchRange {...@@ -712,10 +708,6 @@ struct AstNodeSwitchRange {
712 AstNode *end;708 AstNode *end;
713};709};
714710
715struct AstNodeLabel {
716 Buf *name;
717};
718
719struct AstNodeCompTime {711struct AstNodeCompTime {
720 AstNode *expr;712 AstNode *expr;
721};713};
...@@ -879,6 +871,10 @@ struct AstNodeSuspend {...@@ -879,6 +871,10 @@ struct AstNodeSuspend {
879 AstNode *promise_symbol;871 AstNode *promise_symbol;
880};872};
881873
874struct AstNodePromiseType {
875 AstNode *payload_type; // can be NULL
876};
877
882struct AstNode {878struct AstNode {
883 enum NodeType type;879 enum NodeType type;
884 size_t line;880 size_t line;
...@@ -887,7 +883,6 @@ struct AstNode {...@@ -887,7 +883,6 @@ struct AstNode {
887 union {883 union {
888 AstNodeRoot root;884 AstNodeRoot root;
889 AstNodeFnDef fn_def;885 AstNodeFnDef fn_def;
890 AstNodeFnDecl fn_decl;
891 AstNodeFnProto fn_proto;886 AstNodeFnProto fn_proto;
892 AstNodeParamDecl param_decl;887 AstNodeParamDecl param_decl;
893 AstNodeBlock block;888 AstNodeBlock block;
...@@ -912,7 +907,6 @@ struct AstNode {...@@ -912,7 +907,6 @@ struct AstNode {
912 AstNodeSwitchExpr switch_expr;907 AstNodeSwitchExpr switch_expr;
913 AstNodeSwitchProng switch_prong;908 AstNodeSwitchProng switch_prong;
914 AstNodeSwitchRange switch_range;909 AstNodeSwitchRange switch_range;
915 AstNodeLabel label;
916 AstNodeCompTime comptime_expr;910 AstNodeCompTime comptime_expr;
917 AstNodeAsmExpr asm_expr;911 AstNodeAsmExpr asm_expr;
918 AstNodeFieldAccessExpr field_access_expr;912 AstNodeFieldAccessExpr field_access_expr;
...@@ -939,6 +933,7 @@ struct AstNode {...@@ -939,6 +933,7 @@ struct AstNode {
939 AstNodeResumeExpr resume_expr;933 AstNodeResumeExpr resume_expr;
940 AstNodeAwaitExpr await_expr;934 AstNodeAwaitExpr await_expr;
941 AstNodeSuspend suspend;935 AstNodeSuspend suspend;
936 AstNodePromiseType promise_type;
942 } data;937 } data;
943};938};
944939
...@@ -1251,7 +1246,10 @@ struct FnTableEntry {...@@ -1251,7 +1246,10 @@ struct FnTableEntry {
1251 ScopeBlock *def_scope; // parent is child_scope1246 ScopeBlock *def_scope; // parent is child_scope
1252 Buf symbol_name;1247 Buf symbol_name;
1253 TypeTableEntry *type_entry; // function type1248 TypeTableEntry *type_entry; // function type
1254 TypeTableEntry *implicit_return_type;1249 // in the case of normal functions this is the implicit return type
1250 // in the case of async functions this is the implicit return type according to the
1251 // zig source code, not according to zig ir
1252 TypeTableEntry *src_implicit_return_type;
1255 bool is_test;1253 bool is_test;
1256 FnInline fn_inline;1254 FnInline fn_inline;
1257 FnAnalState anal_state;1255 FnAnalState anal_state;
...@@ -1612,7 +1610,8 @@ struct CodeGen {...@@ -1612,7 +1610,8 @@ struct CodeGen {
1612 FnTableEntry *panic_fn;1610 FnTableEntry *panic_fn;
1613 LLVMValueRef cur_ret_ptr;1611 LLVMValueRef cur_ret_ptr;
1614 LLVMValueRef cur_fn_val;1612 LLVMValueRef cur_fn_val;
1615 LLVMValueRef cur_err_ret_trace_val;1613 LLVMValueRef cur_err_ret_trace_val_arg;
1614 LLVMValueRef cur_err_ret_trace_val_stack;
1616 bool c_want_stdint;1615 bool c_want_stdint;
1617 bool c_want_stdbool;1616 bool c_want_stdbool;
1618 AstNode *root_export_decl;1617 AstNode *root_export_decl;
...@@ -1646,6 +1645,8 @@ struct CodeGen {...@@ -1646,6 +1645,8 @@ struct CodeGen {
1646 LLVMValueRef coro_save_fn_val;1645 LLVMValueRef coro_save_fn_val;
1647 LLVMValueRef coro_promise_fn_val;1646 LLVMValueRef coro_promise_fn_val;
1648 LLVMValueRef coro_alloc_helper_fn_val;1647 LLVMValueRef coro_alloc_helper_fn_val;
1648 LLVMValueRef merge_err_ret_traces_fn_val;
1649 LLVMValueRef add_error_return_trace_addr_fn_val;
1649 bool error_during_imports;1650 bool error_during_imports;
16501651
1651 const char **clang_argv;1652 const char **clang_argv;
...@@ -1751,6 +1752,7 @@ enum ScopeId {...@@ -1751,6 +1752,7 @@ enum ScopeId {
1751 ScopeIdLoop,1752 ScopeIdLoop,
1752 ScopeIdFnDef,1753 ScopeIdFnDef,
1753 ScopeIdCompTime,1754 ScopeIdCompTime,
1755 ScopeIdCoroPrelude,
1754};1756};
17551757
1756struct Scope {1758struct Scope {
...@@ -1858,6 +1860,12 @@ struct ScopeFnDef {...@@ -1858,6 +1860,12 @@ struct ScopeFnDef {
1858 FnTableEntry *fn_entry;1860 FnTableEntry *fn_entry;
1859};1861};
18601862
1863// This scope is created to indicate that the code in the scope
1864// is auto-generated coroutine prelude stuff.
1865struct ScopeCoroPrelude {
1866 Scope base;
1867};
1868
1861// synchronized with code in define_builtin_compile_vars1869// synchronized with code in define_builtin_compile_vars
1862enum AtomicOrder {1870enum AtomicOrder {
1863 AtomicOrderUnordered,1871 AtomicOrderUnordered,
...@@ -1944,6 +1952,7 @@ enum IrInstructionId {...@@ -1944,6 +1952,7 @@ enum IrInstructionId {
1944 IrInstructionIdSetRuntimeSafety,1952 IrInstructionIdSetRuntimeSafety,
1945 IrInstructionIdSetFloatMode,1953 IrInstructionIdSetFloatMode,
1946 IrInstructionIdArrayType,1954 IrInstructionIdArrayType,
1955 IrInstructionIdPromiseType,
1947 IrInstructionIdSliceType,1956 IrInstructionIdSliceType,
1948 IrInstructionIdAsm,1957 IrInstructionIdAsm,
1949 IrInstructionIdSizeOf,1958 IrInstructionIdSizeOf,
...@@ -2034,6 +2043,10 @@ enum IrInstructionId {...@@ -2034,6 +2043,10 @@ enum IrInstructionId {
2034 IrInstructionIdAtomicRmw,2043 IrInstructionIdAtomicRmw,
2035 IrInstructionIdPromiseResultType,2044 IrInstructionIdPromiseResultType,
2036 IrInstructionIdAwaitBookkeeping,2045 IrInstructionIdAwaitBookkeeping,
2046 IrInstructionIdSaveErrRetAddr,
2047 IrInstructionIdAddImplicitReturnType,
2048 IrInstructionIdMergeErrRetTraces,
2049 IrInstructionIdMarkErrRetTracePtr,
2037};2050};
20382051
2039struct IrInstruction {2052struct IrInstruction {
...@@ -2360,6 +2373,12 @@ struct IrInstructionArrayType {...@@ -2360,6 +2373,12 @@ struct IrInstructionArrayType {
2360 IrInstruction *child_type;2373 IrInstruction *child_type;
2361};2374};
23622375
2376struct IrInstructionPromiseType {
2377 IrInstruction base;
2378
2379 IrInstruction *payload_type;
2380};
2381
2363struct IrInstructionSliceType {2382struct IrInstructionSliceType {
2364 IrInstruction base;2383 IrInstruction base;
23652384
...@@ -2673,6 +2692,7 @@ struct IrInstructionFnProto {...@@ -2673,6 +2692,7 @@ struct IrInstructionFnProto {
2673 IrInstruction **param_types;2692 IrInstruction **param_types;
2674 IrInstruction *align_value;2693 IrInstruction *align_value;
2675 IrInstruction *return_type;2694 IrInstruction *return_type;
2695 IrInstruction *async_allocator_type_value;
2676 bool is_var_args;2696 bool is_var_args;
2677};2697};
26782698
...@@ -2865,6 +2885,11 @@ struct IrInstructionExport {...@@ -2865,6 +2885,11 @@ struct IrInstructionExport {
28652885
2866struct IrInstructionErrorReturnTrace {2886struct IrInstructionErrorReturnTrace {
2867 IrInstruction base;2887 IrInstruction base;
2888
2889 enum Nullable {
2890 Null,
2891 NonNull,
2892 } nullable;
2868};2893};
28692894
2870struct IrInstructionErrorUnion {2895struct IrInstructionErrorUnion {
...@@ -2987,6 +3012,30 @@ struct IrInstructionAwaitBookkeeping {...@@ -2987,6 +3012,30 @@ struct IrInstructionAwaitBookkeeping {
2987 IrInstruction *promise_result_type;3012 IrInstruction *promise_result_type;
2988};3013};
29893014
3015struct IrInstructionSaveErrRetAddr {
3016 IrInstruction base;
3017};
3018
3019struct IrInstructionAddImplicitReturnType {
3020 IrInstruction base;
3021
3022 IrInstruction *value;
3023};
3024
3025struct IrInstructionMergeErrRetTraces {
3026 IrInstruction base;
3027
3028 IrInstruction *coro_promise_ptr;
3029 IrInstruction *src_err_ret_trace_ptr;
3030 IrInstruction *dest_err_ret_trace_ptr;
3031};
3032
3033struct IrInstructionMarkErrRetTracePtr {
3034 IrInstruction base;
3035
3036 IrInstruction *err_ret_trace_ptr;
3037};
3038
2990static const size_t slice_ptr_index = 0;3039static const size_t slice_ptr_index = 0;
2991static const size_t slice_len_index = 1;3040static const size_t slice_len_index = 1;
29923041
...@@ -2996,10 +3045,18 @@ static const size_t maybe_null_index = 1;...@@ -2996,10 +3045,18 @@ static const size_t maybe_null_index = 1;
2996static const size_t err_union_err_index = 0;3045static const size_t err_union_err_index = 0;
2997static const size_t err_union_payload_index = 1;3046static const size_t err_union_payload_index = 1;
29983047
3048// TODO call graph analysis to find out what this number needs to be for every function
3049static const size_t stack_trace_ptr_count = 30;
3050
3051// these belong to the async function
3052#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
3053#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
3054#define RESULT_FIELD_NAME "result"
2999#define ASYNC_ALLOC_FIELD_NAME "allocFn"3055#define ASYNC_ALLOC_FIELD_NAME "allocFn"
3000#define ASYNC_FREE_FIELD_NAME "freeFn"3056#define ASYNC_FREE_FIELD_NAME "freeFn"
3001#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"3057#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
3002#define RESULT_FIELD_NAME "result"3058// these point to data belonging to the awaiter
3059#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3003#define RESULT_PTR_FIELD_NAME "result_ptr"3060#define RESULT_PTR_FIELD_NAME "result_ptr"
30043061
30053062
src/analyze.cpp+148-21
...@@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) {...@@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) {
170 return &scope->base;170 return &scope->base;
171}171}
172172
173Scope *create_coro_prelude_scope(AstNode *node, Scope *parent) {
174 ScopeCoroPrelude *scope = allocate<ScopeCoroPrelude>(1);
175 init_scope(&scope->base, ScopeIdCoroPrelude, node, parent);
176 return &scope->base;
177}
178
173ImportTableEntry *get_scope_import(Scope *scope) {179ImportTableEntry *get_scope_import(Scope *scope) {
174 while (scope) {180 while (scope) {
175 if (scope->id == ScopeIdDecls) {181 if (scope->id == ScopeIdDecls) {
...@@ -462,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)...@@ -462,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
462468
463 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
464 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
465 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};471
466 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};472 ZigList<const char *> field_names = {};
473 field_names.append(AWAITER_HANDLE_FIELD_NAME);
474 field_names.append(RESULT_FIELD_NAME);
475 field_names.append(RESULT_PTR_FIELD_NAME);
476 if (g->have_err_ret_tracing) {
477 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
478 field_names.append(ERR_RET_TRACE_FIELD_NAME);
479 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
480 }
481
482 ZigList<TypeTableEntry *> field_types = {};
483 field_types.append(awaiter_handle_type);
484 field_types.append(return_type);
485 field_types.append(result_ptr_type);
486 if (g->have_err_ret_tracing) {
487 field_types.append(get_ptr_to_stack_trace_type(g));
488 field_types.append(g->stack_trace_type);
489 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
490 }
491
492 assert(field_names.length == field_types.length);
467 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));493 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
468 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3);494 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
469495
470 return_type->promise_frame_parent = entry;496 return_type->promise_frame_parent = entry;
471 return entry;497 return entry;
...@@ -985,7 +1011,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -985,7 +1011,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
985 // populate the name of the type1011 // populate the name of the type
986 buf_resize(&fn_type->name, 0);1012 buf_resize(&fn_type->name, 0);
987 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {1013 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
988 buf_appendf(&fn_type->name, "async(%s) ", buf_ptr(&fn_type_id->async_allocator_type->name));1014 assert(fn_type_id->async_allocator_type != nullptr);
1015 buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name));
989 } else {1016 } else {
990 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);1017 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
991 buf_appendf(&fn_type->name, "%s", cc_str);1018 buf_appendf(&fn_type->name, "%s", cc_str);
...@@ -3209,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3209,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3209 break;3236 break;
3210 case NodeTypeContainerDecl:3237 case NodeTypeContainerDecl:
3211 case NodeTypeParamDecl:3238 case NodeTypeParamDecl:
3212 case NodeTypeFnDecl:
3213 case NodeTypeReturnExpr:3239 case NodeTypeReturnExpr:
3214 case NodeTypeDefer:3240 case NodeTypeDefer:
3215 case NodeTypeBlock:3241 case NodeTypeBlock:
...@@ -3253,6 +3279,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3253,6 +3279,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3253 case NodeTypeResume:3279 case NodeTypeResume:
3254 case NodeTypeAwaitExpr:3280 case NodeTypeAwaitExpr:
3255 case NodeTypeSuspend:3281 case NodeTypeSuspend:
3282 case NodeTypePromiseType:
3256 zig_unreachable();3283 zig_unreachable();
3257 }3284 }
3258}3285}
...@@ -3590,6 +3617,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {...@@ -3590,6 +3617,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
3590 case ScopeIdCImport:3617 case ScopeIdCImport:
3591 case ScopeIdLoop:3618 case ScopeIdLoop:
3592 case ScopeIdCompTime:3619 case ScopeIdCompTime:
3620 case ScopeIdCoroPrelude:
3593 scope = scope->parent;3621 scope = scope->parent;
3594 continue;3622 continue;
3595 case ScopeIdFnDef:3623 case ScopeIdFnDef:
...@@ -3864,7 +3892,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3864,7 +3892,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38643892
3865 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,3893 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
3866 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);3894 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
3867 fn_table_entry->implicit_return_type = block_return_type;3895 fn_table_entry->src_implicit_return_type = block_return_type;
38683896
3869 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {3897 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
3870 assert(g->errors.length > 0);3898 assert(g->errors.length > 0);
...@@ -3876,10 +3904,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ...@@ -3876,10 +3904,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
3876 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;3904 TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
3877 if (return_err_set_type->data.error_set.infer_fn != nullptr) {3905 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
3878 TypeTableEntry *inferred_err_set_type;3906 TypeTableEntry *inferred_err_set_type;
3879 if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) {3907 if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) {
3880 inferred_err_set_type = fn_table_entry->implicit_return_type;3908 inferred_err_set_type = fn_table_entry->src_implicit_return_type;
3881 } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) {3909 } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) {
3882 inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type;3910 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
3883 } else {3911 } else {
3884 add_node_error(g, return_type_node,3912 add_node_error(g, return_type_node,
3885 buf_sprintf("function with inferred error set must return at least one possible error"));3913 buf_sprintf("function with inferred error set must return at least one possible error"));
...@@ -4276,26 +4304,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {...@@ -4276,26 +4304,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
4276 return g->win_sdk;4304 return g->win_sdk;
4277}4305}
42784306
4307
4308Buf *get_linux_libc_lib_path(const char *o_file) {
4309 const char *cc_exe = getenv("CC");
4310 cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
4311 ZigList<const char *> args = {};
4312 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
4313 Termination term;
4314 Buf *out_stderr = buf_alloc();
4315 Buf *out_stdout = buf_alloc();
4316 int err;
4317 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
4318 zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err));
4319 }
4320 if (term.how != TerminationIdClean || term.code != 0) {
4321 zig_panic("unable to determine libc lib path: executing C compiler command failed");
4322 }
4323 if (buf_ends_with_str(out_stdout, "\n")) {
4324 buf_resize(out_stdout, buf_len(out_stdout) - 1);
4325 }
4326 if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
4327 zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file);
4328 }
4329 Buf *result = buf_alloc();
4330 os_path_dirname(out_stdout, result);
4331 return result;
4332}
4333
4334Buf *get_linux_libc_include_path(void) {
4335 const char *cc_exe = getenv("CC");
4336 cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
4337 ZigList<const char *> args = {};
4338 args.append("-E");
4339 args.append("-Wp,-v");
4340 args.append("-xc");
4341 args.append("/dev/null");
4342 Termination term;
4343 Buf *out_stderr = buf_alloc();
4344 Buf *out_stdout = buf_alloc();
4345 int err;
4346 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
4347 zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err));
4348 }
4349 if (term.how != TerminationIdClean || term.code != 0) {
4350 zig_panic("unable to determine libc include path: executing C compiler command failed");
4351 }
4352 char *prev_newline = buf_ptr(out_stderr);
4353 ZigList<const char *> search_paths = {};
4354 bool found_search_paths = false;
4355 for (;;) {
4356 char *newline = strchr(prev_newline, '\n');
4357 if (newline == nullptr) {
4358 zig_panic("unable to determine libc include path: bad output from C compiler command");
4359 }
4360 *newline = 0;
4361 if (found_search_paths) {
4362 if (strcmp(prev_newline, "End of search list.") == 0) {
4363 break;
4364 }
4365 search_paths.append(prev_newline);
4366 } else {
4367 if (strcmp(prev_newline, "#include <...> search starts here:") == 0) {
4368 found_search_paths = true;
4369 }
4370 }
4371 prev_newline = newline + 1;
4372 }
4373 if (search_paths.length == 0) {
4374 zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are");
4375 }
4376 for (size_t i = 0; i < search_paths.length; i += 1) {
4377 // search in reverse order
4378 const char *search_path = search_paths.items[search_paths.length - i - 1];
4379 // cut off spaces
4380 while (*search_path == ' ') {
4381 search_path += 1;
4382 }
4383 Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
4384 bool exists;
4385 if ((err = os_file_exists(stdlib_path, &exists))) {
4386 exists = false;
4387 }
4388 if (exists) {
4389 return buf_create_from_str(search_path);
4390 }
4391 }
4392 zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths");
4393}
4394
4279void find_libc_include_path(CodeGen *g) {4395void find_libc_include_path(CodeGen *g) {
4280 if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {4396 if (g->libc_include_dir == nullptr) {
4281 ZigWindowsSDK *sdk = get_windows_sdk(g);
42824397
4283 if (g->zig_target.os == OsWindows) {4398 if (g->zig_target.os == OsWindows) {
4399 ZigWindowsSDK *sdk = get_windows_sdk(g);
4400 g->libc_include_dir = buf_alloc();
4284 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {4401 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
4285 zig_panic("Unable to determine libc include path.");4402 zig_panic("Unable to determine libc include path.");
4286 }4403 }
4404 } else if (g->zig_target.os == OsLinux) {
4405 g->libc_include_dir = get_linux_libc_include_path();
4406 } else if (g->zig_target.os == OsMacOSX) {
4407 g->libc_include_dir = buf_create_from_str("/usr/include");
4408 } else {
4409 // TODO find libc at runtime for other operating systems
4410 zig_panic("Unable to determine libc include path.");
4287 }4411 }
4288 }4412 }
42894413 assert(buf_len(g->libc_include_dir) != 0);
4290 // TODO find libc at runtime for other operating systems
4291 if(!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
4292 zig_panic("Unable to determine libc include path.");
4293 }
4294}4414}
42954415
4296void find_libc_lib_path(CodeGen *g) {4416void find_libc_lib_path(CodeGen *g) {
4297 // later we can handle this better by reporting an error via the normal mechanism4417 // later we can handle this better by reporting an error via the normal mechanism
4298 if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0 ||4418 if (g->libc_lib_dir == nullptr ||
4299 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))4419 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
4300 {4420 {
4301 if (g->zig_target.os == OsWindows) {4421 if (g->zig_target.os == OsWindows) {
...@@ -4319,18 +4439,25 @@ void find_libc_lib_path(CodeGen *g) {...@@ -4319,18 +4439,25 @@ void find_libc_lib_path(CodeGen *g) {
4319 g->msvc_lib_dir = vc_lib_dir;4439 g->msvc_lib_dir = vc_lib_dir;
4320 g->libc_lib_dir = ucrt_lib_path;4440 g->libc_lib_dir = ucrt_lib_path;
4321 g->kernel32_lib_dir = kern_lib_path;4441 g->kernel32_lib_dir = kern_lib_path;
4442 } else if (g->zig_target.os == OsLinux) {
4443 g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
4322 } else {4444 } else {
4323 zig_panic("Unable to determine libc lib path.");4445 zig_panic("Unable to determine libc lib path.");
4324 }4446 }
4447 } else {
4448 assert(buf_len(g->libc_lib_dir) != 0);
4325 }4449 }
43264450
4327 if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {4451 if (g->libc_static_lib_dir == nullptr) {
4328 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {4452 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
4329 return;4453 return;
4330 }4454 } else if (g->zig_target.os == OsLinux) {
4331 else {4455 g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4456 } else {
4332 zig_panic("Unable to determine libc static lib path.");4457 zig_panic("Unable to determine libc static lib path.");
4333 }4458 }
4459 } else {
4460 assert(buf_len(g->libc_static_lib_dir) != 0);
4334 }4461 }
4335}4462}
43364463
src/analyze.hpp+1
...@@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);...@@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);
107ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);107ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
108ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);108ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
109Scope *create_comptime_scope(AstNode *node, Scope *parent);109Scope *create_comptime_scope(AstNode *node, Scope *parent);
110Scope *create_coro_prelude_scope(AstNode *node, Scope *parent);
110111
111void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);112void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
112ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);113ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
src/ast_render.cpp+21-4
...@@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {...@@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {
148 return "Root";148 return "Root";
149 case NodeTypeFnDef:149 case NodeTypeFnDef:
150 return "FnDef";150 return "FnDef";
151 case NodeTypeFnDecl:
152 return "FnDecl";
153 case NodeTypeFnProto:151 case NodeTypeFnProto:
154 return "FnProto";152 return "FnProto";
155 case NodeTypeParamDecl:153 case NodeTypeParamDecl:
...@@ -250,6 +248,8 @@ static const char *node_type_str(NodeType node_type) {...@@ -250,6 +248,8 @@ static const char *node_type_str(NodeType node_type) {
250 return "AwaitExpr";248 return "AwaitExpr";
251 case NodeTypeSuspend:249 case NodeTypeSuspend:
252 return "Suspend";250 return "Suspend";
251 case NodeTypePromiseType:
252 return "PromiseType";
253 }253 }
254 zig_unreachable();254 zig_unreachable();
255}255}
...@@ -658,6 +658,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -658,6 +658,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
658 if (node->data.fn_call_expr.is_builtin) {658 if (node->data.fn_call_expr.is_builtin) {
659 fprintf(ar->f, "@");659 fprintf(ar->f, "@");
660 }660 }
661 if (node->data.fn_call_expr.is_async) {
662 fprintf(ar->f, "async");
663 if (node->data.fn_call_expr.async_allocator != nullptr) {
664 fprintf(ar->f, "<");
665 render_node_extra(ar, node->data.fn_call_expr.async_allocator, true);
666 fprintf(ar->f, ">");
667 }
668 fprintf(ar->f, " ");
669 }
661 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;670 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
662 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);671 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);
663 render_node_extra(ar, fn_ref_node, grouped);672 render_node_extra(ar, fn_ref_node, grouped);
...@@ -772,6 +781,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -772,6 +781,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
772 render_node_ungrouped(ar, node->data.array_type.child_type);781 render_node_ungrouped(ar, node->data.array_type.child_type);
773 break;782 break;
774 }783 }
784 case NodeTypePromiseType:
785 {
786 fprintf(ar->f, "promise");
787 if (node->data.promise_type.payload_type != nullptr) {
788 fprintf(ar->f, "->");
789 render_node_grouped(ar, node->data.promise_type.payload_type);
790 }
791 break;
792 }
775 case NodeTypeErrorType:793 case NodeTypeErrorType:
776 fprintf(ar->f, "error");794 fprintf(ar->f, "error");
777 break;795 break;
...@@ -1023,7 +1041,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1023,7 +1041,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1023 case NodeTypeUnwrapErrorExpr:1041 case NodeTypeUnwrapErrorExpr:
1024 {1042 {
1025 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);1043 render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
1026 fprintf(ar->f, " %%%% ");1044 fprintf(ar->f, " catch ");
1027 if (node->data.unwrap_err_expr.symbol) {1045 if (node->data.unwrap_err_expr.symbol) {
1028 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;1046 Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
1029 fprintf(ar->f, "|%s| ", buf_ptr(var_name));1047 fprintf(ar->f, "|%s| ", buf_ptr(var_name));
...@@ -1078,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1078,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1078 }1096 }
1079 break;1097 break;
1080 }1098 }
1081 case NodeTypeFnDecl:
1082 case NodeTypeParamDecl:1099 case NodeTypeParamDecl:
1083 case NodeTypeTestDecl:1100 case NodeTypeTestDecl:
1084 case NodeTypeStructField:1101 case NodeTypeStructField:
src/codegen.cpp+328-96
...@@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
112 // that's for native compilation112 // that's for native compilation
113 g->zig_target = *target;113 g->zig_target = *target;
114 resolve_target_object_format(&g->zig_target);114 resolve_target_object_format(&g->zig_target);
115 g->dynamic_linker = buf_create_from_str("");115 g->dynamic_linker = nullptr;
116 g->libc_lib_dir = buf_create_from_str("");116 g->libc_lib_dir = nullptr;
117 g->libc_static_lib_dir = buf_create_from_str("");117 g->libc_static_lib_dir = nullptr;
118 g->libc_include_dir = buf_create_from_str("");118 g->libc_include_dir = nullptr;
119 g->msvc_lib_dir = nullptr;119 g->msvc_lib_dir = nullptr;
120 g->kernel32_lib_dir = nullptr;120 g->kernel32_lib_dir = nullptr;
121 g->each_lib_rpath = false;121 g->each_lib_rpath = false;
...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
123 // native compilation, we can rely on the configuration stuff123 // native compilation, we can rely on the configuration stuff
124 g->is_native_target = true;124 g->is_native_target = true;
125 get_native_target(&g->zig_target);125 get_native_target(&g->zig_target);
126 g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);126 g->dynamic_linker = nullptr; // find it at runtime
127 g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);127 g->libc_lib_dir = nullptr; // find it at runtime
128 g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);128 g->libc_static_lib_dir = nullptr; // find it at runtime
129 g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);129 g->libc_include_dir = nullptr; // find it at runtime
130 g->msvc_lib_dir = nullptr; // find it at runtime130 g->msvc_lib_dir = nullptr; // find it at runtime
131 g->kernel32_lib_dir = nullptr; // find it at runtime131 g->kernel32_lib_dir = nullptr; // find it at runtime
132
133#ifdef ZIG_EACH_LIB_RPATH
134 g->each_lib_rpath = true;132 g->each_lib_rpath = true;
135#endif
136133
137 if (g->zig_target.os == OsMacOSX ||134 if (g->zig_target.os == OsMacOSX ||
138 g->zig_target.os == OsIOS)135 g->zig_target.os == OsIOS)
...@@ -411,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e...@@ -411,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
411 if (!g->have_err_ret_tracing) {408 if (!g->have_err_ret_tracing) {
412 return UINT32_MAX;409 return UINT32_MAX;
413 }410 }
411 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
412 return 0;
413 }
414 TypeTableEntry *fn_type = fn_table_entry->type_entry;414 TypeTableEntry *fn_type = fn_table_entry->type_entry;
415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
416 return UINT32_MAX;416 return UINT32_MAX;
...@@ -653,6 +653,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -653,6 +653,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
653 case ScopeIdDeferExpr:653 case ScopeIdDeferExpr:
654 case ScopeIdLoop:654 case ScopeIdLoop:
655 case ScopeIdCompTime:655 case ScopeIdCompTime:
656 case ScopeIdCoroPrelude:
656 return get_di_scope(g, scope->parent);657 return get_di_scope(g, scope->parent);
657 }658 }
658 zig_unreachable();659 zig_unreachable();
...@@ -1116,22 +1117,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {...@@ -1116,22 +1117,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1116 return g->return_address_fn_val;1117 return g->return_address_fn_val;
1117}1118}
11181119
1119static LLVMValueRef get_return_err_fn(CodeGen *g) {1120static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1120 if (g->return_err_fn != nullptr)1121 if (g->add_error_return_trace_addr_fn_val != nullptr)
1121 return g->return_err_fn;1122 return g->add_error_return_trace_addr_fn_val;
1122
1123 assert(g->err_tag_type != nullptr);
11241123
1125 LLVMTypeRef arg_types[] = {1124 LLVMTypeRef arg_types[] = {
1126 // error return trace pointer
1127 get_ptr_to_stack_trace_type(g)->type_ref,1125 get_ptr_to_stack_trace_type(g)->type_ref,
1126 g->builtin_types.entry_usize->type_ref,
1128 };1127 };
1129 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);1128 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
11301129
1131 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);1130 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false);
1132 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);1131 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1133 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address1132 addLLVMFnAttr(fn_val, "alwaysinline");
1134 addLLVMFnAttr(fn_val, "cold");
1135 LLVMSetLinkage(fn_val, LLVMInternalLinkage);1133 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1136 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1134 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1137 addLLVMFnAttr(fn_val, "nounwind");1135 addLLVMFnAttr(fn_val, "nounwind");
...@@ -1153,6 +1151,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1153,6 +1151,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1153 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;1151 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
11541152
1155 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);1153 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1154 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
1155
1156 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;1156 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1157 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");1157 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
1158 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;1158 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
...@@ -1174,15 +1174,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1174,15 +1174,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1174 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");1174 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
1175 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");1175 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");
11761176
1177 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1178 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1179 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1180
1181 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
1182 gen_store_untyped(g, address_value, address_slot, 0, false);1177 gen_store_untyped(g, address_value, address_slot, 0, false);
11831178
1184 // stack_trace.index += 1;1179 // stack_trace.index += 1;
1185 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");1180 LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
1186 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);1181 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
11871182
1188 // return;1183 // return;
...@@ -1191,6 +1186,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1191,6 +1186,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1191 LLVMPositionBuilderAtEnd(g->builder, prev_block);1186 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1192 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1187 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
11931188
1189 g->add_error_return_trace_addr_fn_val = fn_val;
1190 return fn_val;
1191}
1192
1193static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1194 if (g->merge_err_ret_traces_fn_val)
1195 return g->merge_err_ret_traces_fn_val;
1196
1197 assert(g->stack_trace_type != nullptr);
1198
1199 LLVMTypeRef param_types[] = {
1200 get_ptr_to_stack_trace_type(g)->type_ref,
1201 get_ptr_to_stack_trace_type(g)->type_ref,
1202 };
1203 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1204
1205 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1206 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1207 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1208 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1209 addLLVMFnAttr(fn_val, "nounwind");
1210 add_uwtable_attr(g, fn_val);
1211 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1212 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1213 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1214 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1215 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1216 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1217 if (g->build_mode == BuildModeDebug) {
1218 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1219 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1220 }
1221
1222 // this is above the ZigLLVMClearCurrentDebugLocation
1223 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1224
1225 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1226 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1227 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1228 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1229 ZigLLVMClearCurrentDebugLocation(g->builder);
1230
1231 // var frame_index: usize = undefined;
1232 // var frames_left: usize = undefined;
1233 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1234 // frame_index = 0;
1235 // frames_left = src_stack_trace.index;
1236 // if (frames_left == 0) return;
1237 // } else {
1238 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1239 // frames_left = src_stack_trace.instruction_addresses.len;
1240 // }
1241 // while (true) {
1242 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1243 // frames_left -= 1;
1244 // if (frames_left == 0) return;
1245 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1246 // }
1247 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1248
1249 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index");
1250 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left");
1251
1252 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1253 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1254
1255 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1256 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1257 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1258 (unsigned)src_index_field_index, "");
1259 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1260 (unsigned)src_addresses_field_index, "");
1261 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1262 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1263 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1264 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1265 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1266 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1267 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1268 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1269 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1270 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1271 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1272 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1273 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1274
1275 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1276 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
1277 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1278 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1279 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1280 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1281
1282 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1283 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
1284 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1285 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1286 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1287 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1288 LLVMBuildBr(g->builder, loop_block);
1289
1290 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1291 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1292 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1293 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1294 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1295 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1296 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1297 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1298 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1299 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1300 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1301
1302 LLVMPositionBuilderAtEnd(g->builder, return_block);
1303 LLVMBuildRetVoid(g->builder);
1304
1305 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1306 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1307 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1308 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1309 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1310 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1311 LLVMBuildBr(g->builder, loop_block);
1312
1313 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1314 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1315
1316 g->merge_err_ret_traces_fn_val = fn_val;
1317 return fn_val;
1318
1319}
1320
1321static LLVMValueRef get_return_err_fn(CodeGen *g) {
1322 if (g->return_err_fn != nullptr)
1323 return g->return_err_fn;
1324
1325 assert(g->err_tag_type != nullptr);
1326
1327 LLVMTypeRef arg_types[] = {
1328 // error return trace pointer
1329 get_ptr_to_stack_trace_type(g)->type_ref,
1330 };
1331 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
1332
1333 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
1334 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1335 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address
1336 addLLVMFnAttr(fn_val, "cold");
1337 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1338 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1339 addLLVMFnAttr(fn_val, "nounwind");
1340 add_uwtable_attr(g, fn_val);
1341 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1342 if (g->build_mode == BuildModeDebug) {
1343 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1344 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1345 }
1346
1347 // this is above the ZigLLVMClearCurrentDebugLocation
1348 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1349
1350 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1351 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1352 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1353 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1354 ZigLLVMClearCurrentDebugLocation(g->builder);
1355
1356 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1357
1358 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
1359 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1360 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1361 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1362
1363 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1364 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1365 LLVMBuildRetVoid(g->builder);
1366
1367 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1368 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1369
1194 g->return_err_fn = fn_val;1370 g->return_err_fn = fn_val;
1195 return fn_val;1371 return fn_val;
1196}1372}
...@@ -1318,9 +1494,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1318,9 +1494,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1318 return fn_val;1494 return fn_val;
1319}1495}
13201496
1321static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {1497static bool is_coro_prelude_scope(Scope *scope) {
1498 while (scope != nullptr) {
1499 if (scope->id == ScopeIdCoroPrelude) {
1500 return true;
1501 } else if (scope->id == ScopeIdFnDef) {
1502 break;
1503 }
1504 scope = scope->parent;
1505 }
1506 return false;
1507}
1508
1509static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
1510 if (!g->have_err_ret_tracing) {
1511 return nullptr;
1512 }
1513 if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
1514 return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack;
1515 }
1516 if (g->cur_err_ret_trace_val_stack != nullptr) {
1517 return g->cur_err_ret_trace_val_stack;
1518 }
1519 return g->cur_err_ret_trace_val_arg;
1520}
1521
1522static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) {
1322 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);1523 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
1323 LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val;1524 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
1324 if (err_ret_trace_val == nullptr) {1525 if (err_ret_trace_val == nullptr) {
1325 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);1526 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1326 err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);1527 err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
...@@ -1607,32 +1808,24 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1607,32 +1808,24 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1607 return instruction->llvm_value;1808 return instruction->llvm_value;
1608}1809}
16091810
1811static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
1812 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
1813{
1814 assert(g->have_err_ret_tracing);
1815
1816 LLVMValueRef return_err_fn = get_return_err_fn(g);
1817 LLVMValueRef args[] = {
1818 get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope),
1819 };
1820 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1821 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1822 return call_instruction;
1823}
1824
1610static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1825static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1611 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1826 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1612 TypeTableEntry *return_type = return_instruction->value->value.type;1827 TypeTableEntry *return_type = return_instruction->value->value.type;
16131828
1614 if (g->have_err_ret_tracing) {
1615 bool is_err_return = false;
1616 if (return_type->id == TypeTableEntryIdErrorUnion) {
1617 if (return_instruction->value->value.special == ConstValSpecialStatic) {
1618 is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
1619 } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
1620 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1621 // TODO: emit a branch to check if the return value is an error
1622 }
1623 } else if (return_type->id == TypeTableEntryIdErrorSet) {
1624 is_err_return = true;
1625 }
1626 if (is_err_return) {
1627 LLVMValueRef return_err_fn = get_return_err_fn(g);
1628 LLVMValueRef args[] = {
1629 g->cur_err_ret_trace_val,
1630 };
1631 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1632 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1633 LLVMSetTailCall(call_instruction, true);
1634 }
1635 }
1636 if (handle_is_ptr(return_type)) {1829 if (handle_is_ptr(return_type)) {
1637 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1830 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1638 assert(g->cur_ret_ptr);1831 assert(g->cur_ret_ptr);
...@@ -2732,7 +2925,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2732,7 +2925,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2732 gen_param_index += 1;2925 gen_param_index += 1;
2733 }2926 }
2734 if (prefix_arg_err_ret_stack) {2927 if (prefix_arg_err_ret_stack) {
2735 gen_param_values[gen_param_index] = g->cur_err_ret_trace_val;2928 gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope);
2736 gen_param_index += 1;2929 gen_param_index += 1;
2737 }2930 }
2738 if (instruction->is_async) {2931 if (instruction->is_async) {
...@@ -3299,11 +3492,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -3299,11 +3492,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
3299static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,3492static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
3300 IrInstructionErrorReturnTrace *instruction)3493 IrInstructionErrorReturnTrace *instruction)
3301{3494{
3302 if (g->cur_err_ret_trace_val == nullptr) {3495 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
3496 if (cur_err_ret_trace_val == nullptr) {
3303 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);3497 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
3304 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);3498 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);
3305 }3499 }
3306 return g->cur_err_ret_trace_val;3500 return cur_err_ret_trace_val;
3307}3501}
33083502
3309static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {3503static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {
...@@ -3733,7 +3927,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu...@@ -3733,7 +3927,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
3733 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);3927 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
37343928
3735 LLVMPositionBuilderAtEnd(g->builder, err_block);3929 LLVMPositionBuilderAtEnd(g->builder, err_block);
3736 gen_safety_crash_for_err(g, err_val);3930 gen_safety_crash_for_err(g, err_val, instruction->base.scope);
37373931
3738 LLVMPositionBuilderAtEnd(g->builder, ok_block);3932 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3739 }3933 }
...@@ -3925,7 +4119,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -3925,7 +4119,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
3925}4119}
39264120
3927static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {4121static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
3928 gen_panic(g, ir_llvm_value(g, instruction->msg), g->cur_err_ret_trace_val);4122 gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope));
3929 return nullptr;4123 return nullptr;
3930}4124}
39314125
...@@ -4187,6 +4381,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -4187,6 +4381,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4187 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");4381 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
4188}4382}
41894383
4384static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
4385 IrInstructionMergeErrRetTraces *instruction)
4386{
4387 assert(g->have_err_ret_tracing);
4388
4389 LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr);
4390 LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr);
4391
4392 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
4393 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4394 return nullptr;
4395}
4396
4397static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable,
4398 IrInstructionMarkErrRetTracePtr *instruction)
4399{
4400 assert(g->have_err_ret_tracing);
4401 g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr);
4402 return nullptr;
4403}
4404
4190static void set_debug_location(CodeGen *g, IrInstruction *instruction) {4405static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
4191 AstNode *source_node = instruction->source_node;4406 AstNode *source_node = instruction->source_node;
4192 Scope *scope = instruction->scope;4407 Scope *scope = instruction->scope;
...@@ -4212,6 +4427,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4212,6 +4427,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4212 case IrInstructionIdSetRuntimeSafety:4427 case IrInstructionIdSetRuntimeSafety:
4213 case IrInstructionIdSetFloatMode:4428 case IrInstructionIdSetFloatMode:
4214 case IrInstructionIdArrayType:4429 case IrInstructionIdArrayType:
4430 case IrInstructionIdPromiseType:
4215 case IrInstructionIdSliceType:4431 case IrInstructionIdSliceType:
4216 case IrInstructionIdSizeOf:4432 case IrInstructionIdSizeOf:
4217 case IrInstructionIdSwitchTarget:4433 case IrInstructionIdSwitchTarget:
...@@ -4252,6 +4468,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4252,6 +4468,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4252 case IrInstructionIdErrorUnion:4468 case IrInstructionIdErrorUnion:
4253 case IrInstructionIdPromiseResultType:4469 case IrInstructionIdPromiseResultType:
4254 case IrInstructionIdAwaitBookkeeping:4470 case IrInstructionIdAwaitBookkeeping:
4471 case IrInstructionIdAddImplicitReturnType:
4255 zig_unreachable();4472 zig_unreachable();
42564473
4257 case IrInstructionIdReturn:4474 case IrInstructionIdReturn:
...@@ -4400,6 +4617,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4400,6 +4617,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4400 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);4617 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
4401 case IrInstructionIdAtomicRmw:4618 case IrInstructionIdAtomicRmw:
4402 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);4619 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4620 case IrInstructionIdSaveErrRetAddr:
4621 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
4622 case IrInstructionIdMergeErrRetTraces:
4623 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
4624 case IrInstructionIdMarkErrRetTracePtr:
4625 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
4403 }4626 }
4404 zig_unreachable();4627 zig_unreachable();
4405}4628}
...@@ -5282,39 +5505,23 @@ static void do_code_gen(CodeGen *g) {...@@ -5282,39 +5505,23 @@ static void do_code_gen(CodeGen *g) {
5282 clear_debug_source_node(g);5505 clear_debug_source_node(g);
52835506
5284 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);5507 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
5285 if (err_ret_trace_arg_index != UINT32_MAX) {5508 bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX;
5286 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);5509 if (have_err_ret_trace_arg) {
5287 } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) {5510 g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index);
5288 // TODO call graph analysis to find out what this number needs to be for every function5511 } else {
5289 static const size_t stack_trace_ptr_count = 30;5512 g->cur_err_ret_trace_val_arg = nullptr;
52905513 }
5291 TypeTableEntry *usize = g->builtin_types.entry_usize;
5292 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
5293 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
5294 get_abi_alignment(g, array_type));
5295 g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
5296 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5297 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
5298 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5299
5300 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5301 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, "");
5302
5303 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5304 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5305 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5306 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5307 LLVMValueRef indices[] = {zero, zero};
5308 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5309 indices, 2, "");
5310 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr,
5311 get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false));
53125514
5313 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;5515 // error return tracing setup
5314 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");5516 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
5315 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));5517 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
5518 LLVMValueRef err_ret_array_val = nullptr;
5519 if (have_err_ret_trace_stack) {
5520 TypeTableEntry *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
5521 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
5522 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
5316 } else {5523 } else {
5317 g->cur_err_ret_trace_val = nullptr;5524 g->cur_err_ret_trace_val_stack = nullptr;
5318 }5525 }
53195526
5320 // allocate temporary stack data5527 // allocate temporary stack data
...@@ -5407,6 +5614,31 @@ static void do_code_gen(CodeGen *g) {...@@ -5407,6 +5614,31 @@ static void do_code_gen(CodeGen *g) {
5407 }5614 }
5408 }5615 }
54095616
5617 // finishing error return trace setup. we have to do this after all the allocas.
5618 if (have_err_ret_trace_stack) {
5619 TypeTableEntry *usize = g->builtin_types.entry_usize;
5620 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5621 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5622 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5623
5624 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5625 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5626
5627 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5628 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5629 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5630 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5631 LLVMValueRef indices[] = {zero, zero};
5632 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5633 indices, 2, "");
5634 TypeTableEntry *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false);
5635 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type);
5636
5637 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5638 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5639 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5640 }
5641
5410 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;5642 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
54115643
5412 // create debug variable declarations for parameters5644 // create debug variable declarations for parameters
...@@ -5914,6 +6146,8 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5914,6 +6146,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
5914 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);6146 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5915 Buf *contents = buf_alloc();6147 Buf *contents = buf_alloc();
59166148
6149 // Modifications to this struct must be coordinated with code that does anything with
6150 // g->stack_trace_type. There are hard-coded references to the field indexes.
5917 buf_append_str(contents,6151 buf_append_str(contents,
5918 "pub const StackTrace = struct {\n"6152 "pub const StackTrace = struct {\n"
5919 " index: usize,\n"6153 " index: usize,\n"
...@@ -6178,7 +6412,9 @@ static void init(CodeGen *g) {...@@ -6178,7 +6412,9 @@ static void init(CodeGen *g) {
6178 g->builder = LLVMCreateBuilder();6412 g->builder = LLVMCreateBuilder();
6179 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);6413 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);
61806414
6181 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);6415 // Don't use ZIG_VERSION_STRING here, llvm misparses it when it includes
6416 // the git revision.
6417 Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH);
6182 const char *flags = "";6418 const char *flags = "";
6183 unsigned runtime_version = 0;6419 unsigned runtime_version = 0;
6184 ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),6420 ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),
...@@ -6257,7 +6493,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package...@@ -6257,7 +6493,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
6257 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6493 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6258 }6494 }
6259 Buf *import_code = buf_alloc();6495 Buf *import_code = buf_alloc();
6260 if ((err = os_fetch_file_path(abs_full_path, import_code))) {6496 if ((err = os_fetch_file_path(abs_full_path, import_code, false))) {
6261 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6497 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6262 }6498 }
62636499
...@@ -6345,7 +6581,7 @@ static void gen_root_source(CodeGen *g) {...@@ -6345,7 +6581,7 @@ static void gen_root_source(CodeGen *g) {
6345 }6581 }
63466582
6347 Buf *source_code = buf_alloc();6583 Buf *source_code = buf_alloc();
6348 if ((err = os_fetch_file_path(rel_full_path, source_code))) {6584 if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
6349 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));6585 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6350 }6586 }
63516587
...@@ -6410,7 +6646,7 @@ static void gen_global_asm(CodeGen *g) {...@@ -6410,7 +6646,7 @@ static void gen_global_asm(CodeGen *g) {
6410 int err;6646 int err;
6411 for (size_t i = 0; i < g->assembly_files.length; i += 1) {6647 for (size_t i = 0; i < g->assembly_files.length; i += 1) {
6412 Buf *asm_file = g->assembly_files.at(i);6648 Buf *asm_file = g->assembly_files.at(i);
6413 if ((err = os_fetch_file_path(asm_file, &contents))) {6649 if ((err = os_fetch_file_path(asm_file, &contents, false))) {
6414 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));6650 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
6415 }6651 }
6416 buf_append_buf(&g->global_asm, &contents);6652 buf_append_buf(&g->global_asm, &contents);
...@@ -6592,6 +6828,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf...@@ -6592,6 +6828,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
6592 }6828 }
6593 }6829 }
6594 case TypeTableEntryIdStruct:6830 case TypeTableEntryIdStruct:
6831 case TypeTableEntryIdOpaque:
6595 {6832 {
6596 buf_init_from_str(out_buf, "struct ");6833 buf_init_from_str(out_buf, "struct ");
6597 buf_append_buf(out_buf, &type_entry->name);6834 buf_append_buf(out_buf, &type_entry->name);
...@@ -6609,11 +6846,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf...@@ -6609,11 +6846,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
6609 buf_append_buf(out_buf, &type_entry->name);6846 buf_append_buf(out_buf, &type_entry->name);
6610 return;6847 return;
6611 }6848 }
6612 case TypeTableEntryIdOpaque:
6613 {
6614 buf_init_from_buf(out_buf, &type_entry->name);
6615 return;
6616 }
6617 case TypeTableEntryIdArray:6849 case TypeTableEntryIdArray:
6618 {6850 {
6619 TypeTableEntryArray *array_data = &type_entry->data.array;6851 TypeTableEntryArray *array_data = &type_entry->data.array;
src/config.h.in-8
...@@ -13,14 +13,6 @@...@@ -13,14 +13,6 @@
13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
14#define ZIG_VERSION_STRING "@ZIG_VERSION@"14#define ZIG_VERSION_STRING "@ZIG_VERSION@"
1515
16#define ZIG_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
17#define ZIG_LIBC_INCLUDE_DIR "@ZIG_LIBC_INCLUDE_DIR_ESCAPED@"
18#define ZIG_LIBC_LIB_DIR "@ZIG_LIBC_LIB_DIR_ESCAPED@"
19#define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR_ESCAPED@"
20#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@"
21
22#cmakedefine ZIG_EACH_LIB_RPATH
23
24// Only used for running tests before installing.16// Only used for running tests before installing.
25#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"17#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2618
src/ir.cpp+381-111
...@@ -34,7 +34,7 @@ struct IrAnalyze {...@@ -34,7 +34,7 @@ struct IrAnalyze {
34 size_t old_bb_index;34 size_t old_bb_index;
35 size_t instruction_index;35 size_t instruction_index;
36 TypeTableEntry *explicit_return_type;36 TypeTableEntry *explicit_return_type;
37 ZigList<IrInstruction *> implicit_return_type_list;37 ZigList<IrInstruction *> src_implicit_return_type_list;
38 IrBasicBlock *const_predecessor_bb;38 IrBasicBlock *const_predecessor_bb;
39};39};
4040
...@@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {...@@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
349 return IrInstructionIdArrayType;349 return IrInstructionIdArrayType;
350}350}
351351
352static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {
353 return IrInstructionIdPromiseType;
354}
355
352static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {356static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
353 return IrInstructionIdSliceType;357 return IrInstructionIdSliceType;
354}358}
...@@ -713,6 +717,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping...@@ -713,6 +717,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping
713 return IrInstructionIdAwaitBookkeeping;717 return IrInstructionIdAwaitBookkeeping;
714}718}
715719
720static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
721 return IrInstructionIdSaveErrRetAddr;
722}
723
724static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) {
725 return IrInstructionIdAddImplicitReturnType;
726}
727
728static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
729 return IrInstructionIdMergeErrRetTraces;
730}
731
732static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
733 return IrInstructionIdMarkErrRetTracePtr;
734}
735
716template<typename T>736template<typename T>
717static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {737static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
718 T *special_instruction = allocate<T>(1);738 T *special_instruction = allocate<T>(1);
...@@ -944,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast...@@ -944,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
944 return &const_instruction->base;964 return &const_instruction->base;
945}965}
946966
947static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
948 TypeTableEntry *return_type)
949{
950 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
951
952 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
953 const_instruction->base.value.type = struct_type;
954 const_instruction->base.value.special = ConstValSpecialStatic;
955 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
956 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
957 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
958 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
959 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
960 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
961 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
962 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
963 return &const_instruction->base;
964}
965
966static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,967static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
967 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)968 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
968{969{
...@@ -1461,6 +1462,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode...@@ -1461,6 +1462,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
1461 return &instruction->base;1462 return &instruction->base;
1462}1463}
14631464
1465static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1466 IrInstruction *payload_type)
1467{
1468 IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node);
1469 instruction->payload_type = payload_type;
1470
1471 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
1472
1473 return &instruction->base;
1474}
1475
1464static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1476static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1465 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)1477 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)
1466{1478{
...@@ -2141,12 +2153,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc...@@ -2141,12 +2153,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
2141}2153}
21422154
2143static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,2155static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
2144 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, bool is_var_args)2156 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
2157 IrInstruction *async_allocator_type_value, bool is_var_args)
2145{2158{
2146 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);2159 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
2147 instruction->param_types = param_types;2160 instruction->param_types = param_types;
2148 instruction->align_value = align_value;2161 instruction->align_value = align_value;
2149 instruction->return_type = return_type;2162 instruction->return_type = return_type;
2163 instruction->async_allocator_type_value = async_allocator_type_value;
2150 instruction->is_var_args = is_var_args;2164 instruction->is_var_args = is_var_args;
21512165
2152 assert(source_node->type == NodeTypeFnProto);2166 assert(source_node->type == NodeTypeFnProto);
...@@ -2156,6 +2170,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2156,6 +2170,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
2156 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);2170 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
2157 }2171 }
2158 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);2172 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
2173 if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block);
2159 ir_ref_instruction(return_type, irb->current_basic_block);2174 ir_ref_instruction(return_type, irb->current_basic_block);
21602175
2161 return &instruction->base;2176 return &instruction->base;
...@@ -2469,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2469,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
2469 return &instruction->base;2484 return &instruction->base;
2470}2485}
24712486
2472static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {2487static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
2473 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);2488 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2489 instruction->nullable = nullable;
24742490
2475 return &instruction->base;2491 return &instruction->base;
2476}2492}
...@@ -2675,6 +2691,46 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A...@@ -2675,6 +2691,46 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A
2675 return &instruction->base;2691 return &instruction->base;
2676}2692}
26772693
2694static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2695 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
2696 return &instruction->base;
2697}
2698
2699static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
2700 IrInstruction *value)
2701{
2702 IrInstructionAddImplicitReturnType *instruction = ir_build_instruction<IrInstructionAddImplicitReturnType>(irb, scope, source_node);
2703 instruction->value = value;
2704
2705 ir_ref_instruction(value, irb->current_basic_block);
2706
2707 return &instruction->base;
2708}
2709
2710static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
2711 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
2712{
2713 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
2714 instruction->coro_promise_ptr = coro_promise_ptr;
2715 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
2716 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
2717
2718 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
2719 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
2720 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
2721
2722 return &instruction->base;
2723}
2724
2725static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
2726 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
2727 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
2728
2729 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
2730
2731 return &instruction->base;
2732}
2733
2678static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2734static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2679 results[ReturnKindUnconditional] = 0;2735 results[ReturnKindUnconditional] = 0;
2680 results[ReturnKindError] = 0;2736 results[ReturnKindError] = 0;
...@@ -2699,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {...@@ -2699,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
26992755
2700static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {2756static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
2701 Scope *scope = inner_scope;2757 Scope *scope = inner_scope;
2758 bool is_noreturn = false;
2702 while (scope != outer_scope) {2759 while (scope != outer_scope) {
2703 if (!scope)2760 if (!scope)
2704 return false;2761 return is_noreturn;
27052762
2706 if (scope->id == ScopeIdDefer) {2763 if (scope->id == ScopeIdDefer) {
2707 AstNode *defer_node = scope->source_node;2764 AstNode *defer_node = scope->source_node;
...@@ -2714,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -2714,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
2714 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;2771 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
2715 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);2772 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
2716 if (defer_expr_value != irb->codegen->invalid_instruction) {2773 if (defer_expr_value != irb->codegen->invalid_instruction) {
2717 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));2774 if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
2775 is_noreturn = true;
2776 } else {
2777 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
2778 }
2718 }2779 }
2719 }2780 }
27202781
2721 }2782 }
2722 scope = scope->parent;2783 scope = scope->parent;
2723 }2784 }
2724 return true;2785 return is_noreturn;
2725}2786}
27262787
2727static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {2788static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
...@@ -2747,16 +2808,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {...@@ -2747,16 +2808,18 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
2747 return nullptr;2808 return nullptr;
2748}2809}
27492810
2811static bool exec_is_async(IrExecutable *exec) {
2812 FnTableEntry *fn_entry = exec_fn_entry(exec);
2813 return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2814}
2815
2750static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,2816static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
2751 bool is_generated_code)2817 bool is_generated_code)
2752{2818{
2753 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);2819 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
2754 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;2820
2821 bool is_async = exec_is_async(irb->exec);
2755 if (!is_async) {2822 if (!is_async) {
2756 //if (irb->codegen->have_err_ret_tracing) {
2757 // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2758 // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2759 //}
2760 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);2823 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
2761 return_inst->is_gen = is_generated_code;2824 return_inst->is_gen = is_generated_code;
2762 return return_inst;2825 return return_inst;
...@@ -2778,22 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2778,22 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2778 // the above blocks are rendered by ir_gen after the rest of codegen2841 // the above blocks are rendered by ir_gen after the rest of codegen
2779}2842}
27802843
2781//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {
2782// if (!irb->codegen->have_err_ret_tracing)
2783// return;
2784//
2785// if (is_async) {
2786// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2787// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);
2788// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2789// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2790// return;
2791// }
2792//
2793// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2794// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2795//}
2796
2797static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2844static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2798 assert(node->type == NodeTypeReturnExpr);2845 assert(node->type == NodeTypeReturnExpr);
27992846
...@@ -2839,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2839,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28392886
2840 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);2887 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
28412888
2889 bool should_inline = ir_should_inline(irb->exec, scope);
2842 IrInstruction *is_comptime;2890 IrInstruction *is_comptime;
2843 if (ir_should_inline(irb->exec, scope)) {2891 if (should_inline) {
2844 is_comptime = ir_build_const_bool(irb, scope, node, true);2892 is_comptime = ir_build_const_bool(irb, scope, node, true);
2845 } else {2893 } else {
2846 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);2894 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
...@@ -2853,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2853,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2853 if (have_err_defers) {2901 if (have_err_defers) {
2854 ir_gen_defers_for_block(irb, scope, outer_scope, true);2902 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2855 }2903 }
2856 //ir_gen_save_err_ret_addr(irb, scope, node, is_async);2904 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2905 ir_build_save_err_ret_addr(irb, scope, node);
2906 }
2857 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2907 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28582908
2859 ir_set_cursor_at_end_and_append_block(irb, ok_block);2909 ir_set_cursor_at_end_and_append_block(irb, ok_block);
...@@ -2882,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2882,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2882 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");2932 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
2883 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");2933 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
2884 IrInstruction *is_comptime;2934 IrInstruction *is_comptime;
2885 if (ir_should_inline(irb->exec, scope)) {2935 bool should_inline = ir_should_inline(irb->exec, scope);
2936 if (should_inline) {
2886 is_comptime = ir_build_const_bool(irb, scope, node, true);2937 is_comptime = ir_build_const_bool(irb, scope, node, true);
2887 } else {2938 } else {
2888 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);2939 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
...@@ -2890,9 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2890,9 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2890 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));2941 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
28912942
2892 ir_set_cursor_at_end_and_append_block(irb, return_block);2943 ir_set_cursor_at_end_and_append_block(irb, return_block);
2893 ir_gen_defers_for_block(irb, scope, outer_scope, true);2944 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
2894 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);2945 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2895 ir_gen_async_return(irb, scope, node, err_val, false);2946 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2947 ir_build_save_err_ret_addr(irb, scope, node);
2948 }
2949 ir_gen_async_return(irb, scope, node, err_val, false);
2950 }
28962951
2897 ir_set_cursor_at_end_and_append_block(irb, continue_block);2952 ir_set_cursor_at_end_and_append_block(irb, continue_block);
2898 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);2953 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
...@@ -4185,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4185,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4185 }4240 }
4186 case BuiltinFnIdErrorReturnTrace:4241 case BuiltinFnIdErrorReturnTrace:
4187 {4242 {
4188 return ir_build_error_return_trace(irb, scope, node);4243 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4189 }4244 }
4190 case BuiltinFnIdAtomicRmw:4245 case BuiltinFnIdAtomicRmw:
4191 {4246 {
...@@ -5032,6 +5087,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5032,6 +5087,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
5032 }5087 }
5033}5088}
50345089
5090static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) {
5091 assert(node->type == NodeTypePromiseType);
5092
5093 AstNode *payload_type_node = node->data.promise_type.payload_type;
5094 IrInstruction *payload_type_value = nullptr;
5095
5096 if (payload_type_node != nullptr) {
5097 payload_type_value = ir_gen_node(irb, payload_type_node, scope);
5098 if (payload_type_value == irb->codegen->invalid_instruction)
5099 return payload_type_value;
5100
5101 }
5102
5103 return ir_build_promise_type(irb, scope, node, payload_type_value);
5104}
5105
5035static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {5106static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
5036 assert(node->type == NodeTypeUndefinedLiteral);5107 assert(node->type == NodeTypeUndefinedLiteral);
5037 return ir_build_const_undefined(irb, scope, node);5108 return ir_build_const_undefined(irb, scope, node);
...@@ -5630,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -5630,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
56305701
5631 IrBasicBlock *dest_block = loop_scope->continue_block;5702 IrBasicBlock *dest_block = loop_scope->continue_block;
5632 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);5703 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);
5633 return ir_build_br(irb, continue_scope, node, dest_block, is_comptime);5704 return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime));
5634}5705}
56355706
5636static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {5707static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -5989,7 +6060,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -5989,7 +6060,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
5989 return_type = nullptr;6060 return_type = nullptr;
5990 }6061 }
59916062
5992 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);6063 IrInstruction *async_allocator_type_value = nullptr;
6064 if (node->data.fn_proto.async_allocator_type != nullptr) {
6065 async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope);
6066 if (async_allocator_type_value == irb->codegen->invalid_instruction)
6067 return irb->codegen->invalid_instruction;
6068 }
6069
6070 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type,
6071 async_allocator_type_value, is_var_args);
5993}6072}
59946073
5995static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {6074static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
...@@ -6044,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6044,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6044 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6123 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6045 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);6124 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
60466125
6126 if (irb->codegen->have_err_ret_tracing) {
6127 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6128 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6129 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6130 ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
6131 }
6132
6047 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6133 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6048 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,6134 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
6049 awaiter_handle_field_name);6135 awaiter_handle_field_name);
...@@ -6067,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6067,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6067 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);6153 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6068 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");6154 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6069 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");6155 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6070 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");6156 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend");
6071 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);6157 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
60726158
6073 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);6159 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6160 if (irb->codegen->have_err_ret_tracing) {
6161 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6162 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name);
6163 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6164 ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
6165 }
6074 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6166 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6075 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);6167 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6076 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);6168 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
...@@ -6092,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6092,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
60926184
6093 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6185 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6094 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6186 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6095 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6187 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
60966188
6097 ir_set_cursor_at_end_and_append_block(irb, resume_block);6189 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6098 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);6190 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
...@@ -6168,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -6168,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
61686260
6169 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6261 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6170 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6262 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6171 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6263 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
61726264
6173 ir_set_cursor_at_end_and_append_block(irb, resume_block);6265 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6174 return ir_build_const_void(irb, parent_scope, node);6266 return ir_build_const_void(irb, parent_scope, node);
...@@ -6187,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -6187,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
6187 case NodeTypeSwitchRange:6279 case NodeTypeSwitchRange:
6188 case NodeTypeStructField:6280 case NodeTypeStructField:
6189 case NodeTypeFnDef:6281 case NodeTypeFnDef:
6190 case NodeTypeFnDecl:
6191 case NodeTypeTestDecl:6282 case NodeTypeTestDecl:
6192 zig_unreachable();6283 zig_unreachable();
6193 case NodeTypeBlock:6284 case NodeTypeBlock:
...@@ -6232,6 +6323,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -6232,6 +6323,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
6232 return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);6323 return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
6233 case NodeTypeArrayType:6324 case NodeTypeArrayType:
6234 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);6325 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);
6326 case NodeTypePromiseType:
6327 return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval);
6235 case NodeTypeStringLiteral:6328 case NodeTypeStringLiteral:
6236 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);6329 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);
6237 case NodeTypeUndefinedLiteral:6330 case NodeTypeUndefinedLiteral:
...@@ -6324,63 +6417,92 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6324,63 +6417,92 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6324 IrInstruction *coro_id;6417 IrInstruction *coro_id;
6325 IrInstruction *u8_ptr_type;6418 IrInstruction *u8_ptr_type;
6326 IrInstruction *const_bool_false;6419 IrInstruction *const_bool_false;
6420 IrInstruction *coro_promise_ptr;
6421 IrInstruction *err_ret_trace_ptr;
6327 TypeTableEntry *return_type;6422 TypeTableEntry *return_type;
6328 Buf *result_ptr_field_name;6423 Buf *result_ptr_field_name;
6329 VariableTableEntry *coro_size_var;6424 VariableTableEntry *coro_size_var;
6330 if (is_async) {6425 if (is_async) {
6331 // create the coro promise6426 // create the coro promise
6332 const_bool_false = ir_build_const_bool(irb, scope, node, false);6427 Scope *coro_scope = create_coro_prelude_scope(node, scope);
6333 VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);6428 const_bool_false = ir_build_const_bool(irb, coro_scope, node, false);
6429 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
63346430
6335 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;6431 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
6336 IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type);6432 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6337 ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init);6433 TypeTableEntry *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
6338 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false);6434 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
63396435 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
6340 VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);6436 ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
6341 IrInstruction *null_value = ir_build_const_null(irb, scope, node);6437 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
6342 IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node,6438
6439 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6440 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
6441 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
6343 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));6442 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6344 ir_build_var_decl(irb, scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);6443 ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
6345 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, scope, node,6444 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node,
6346 await_handle_var, false, false);6445 await_handle_var, false, false);
63476446
6348 u8_ptr_type = ir_build_const_type(irb, scope, node,6447 u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
6349 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));6448 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
6350 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr);6449 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
6351 coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr);6450 coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
6352 coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);6451 coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6353 IrInstruction *coro_size = ir_build_coro_size(irb, scope, node);6452 IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
6354 ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size);6453 ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
6355 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,6454 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
6356 ImplicitAllocatorIdArg);6455 ImplicitAllocatorIdArg);
6357 irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false);6456 irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
6358 ir_build_var_decl(irb, scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);6457 ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
6359 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);6458 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
6360 IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name);6459 IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
6361 IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);6460 IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
6362 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size);6461 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
6363 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr);6462 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
6364 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");6463 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
6365 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk");6464 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
6366 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);6465 ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
63676466
6368 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);6467 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6369 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);6468 // we can return undefined here, because the caller passes a pointer to the error struct field
6370 ir_build_return(irb, scope, node, undef);6469 // in the error union result, and we populate it in case of allocation failure.
6470 ir_build_return(irb, coro_scope, node, undef);
63716471
6372 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);6472 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
6373 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr);6473 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
6374 irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr);6474 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
63756475
6376 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6476 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,6477 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6378 awaiter_handle_field_name);6478 awaiter_handle_field_name);
6479 ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value);
6379 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6480 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);6481 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6381 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6482 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);6483 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);6484 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6485 if (irb->codegen->have_err_ret_tracing) {
6486 // initialize the error return trace
6487 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
6488 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
6489
6490 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6491 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
6492 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
6493
6494 // coordinate with builtin.zig
6495 Buf *index_name = buf_create_from_str("index");
6496 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name);
6497 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6498 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
6499
6500 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
6501 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
6502
6503 IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false);
6504 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
6505 }
63846506
63856507
6386 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");6508 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
...@@ -6395,6 +6517,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6395,6 +6517,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6395 return false;6517 return false;
63966518
6397 if (!instr_is_unreachable(result)) {6519 if (!instr_is_unreachable(result)) {
6520 // no need for save_err_ret_addr because this cannot return error
6398 ir_gen_async_return(irb, scope, result->source_node, result, true);6521 ir_gen_async_return(irb, scope, result->source_node, result, true);
6399 }6522 }
64006523
...@@ -6430,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6430,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6430 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);6553 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
6431 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);6554 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
6432 }6555 }
6556 if (irb->codegen->have_err_ret_tracing) {
6557 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6558 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6559 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
6560 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
6561 }
6433 ir_build_br(irb, scope, node, check_free_block, const_bool_false);6562 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
64346563
6435 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);6564 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
...@@ -10074,13 +10203,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {...@@ -10074,13 +10203,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
10074 return result;10203 return result;
10075}10204}
1007610205
10206static TypeTableEntry *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira,
10207 IrInstructionAddImplicitReturnType *instruction)
10208{
10209 IrInstruction *value = instruction->value->other;
10210 if (type_is_invalid(value->value.type))
10211 return ir_unreach_error(ira);
10212
10213 ira->src_implicit_return_type_list.append(value);
10214
10215 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
10216 out_val->type = ira->codegen->builtin_types.entry_void;
10217 return out_val->type;
10218}
10219
10077static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,10220static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
10078 IrInstructionReturn *return_instruction)10221 IrInstructionReturn *return_instruction)
10079{10222{
10080 IrInstruction *value = return_instruction->value->other;10223 IrInstruction *value = return_instruction->value->other;
10081 if (type_is_invalid(value->value.type))10224 if (type_is_invalid(value->value.type))
10082 return ir_unreach_error(ira);10225 return ir_unreach_error(ira);
10083 ira->implicit_return_type_list.append(value);
1008410226
10085 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);10227 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
10086 if (casted_value == ira->codegen->invalid_instruction)10228 if (casted_value == ira->codegen->invalid_instruction)
...@@ -10958,6 +11100,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *...@@ -10958,6 +11100,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
10958 result_type = get_array_type(ira->codegen, child_type, new_len);11100 result_type = get_array_type(ira->codegen, child_type, new_len);
1095911101
10960 out_array_val = out_val;11102 out_array_val = out_val;
11103 } else if (is_slice(op1_type) || is_slice(op2_type)) {
11104 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, child_type, true);
11105 result_type = get_slice_type(ira->codegen, ptr_type);
11106 out_array_val = create_const_vals(1);
11107 out_array_val->special = ConstValSpecialStatic;
11108 out_array_val->type = get_array_type(ira->codegen, child_type, new_len);
11109
11110 out_val->data.x_struct.fields = create_const_vals(2);
11111
11112 out_val->data.x_struct.fields[slice_ptr_index].type = ptr_type;
11113 out_val->data.x_struct.fields[slice_ptr_index].special = ConstValSpecialStatic;
11114 out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.special = ConstPtrSpecialBaseArray;
11115 out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.data.base_array.array_val = out_array_val;
11116 out_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.data.base_array.elem_index = 0;
11117
11118 out_val->data.x_struct.fields[slice_len_index].type = ira->codegen->builtin_types.entry_usize;
11119 out_val->data.x_struct.fields[slice_len_index].special = ConstValSpecialStatic;
11120 bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index].data.x_bigint, new_len);
10961 } else {11121 } else {
10962 new_len += 1; // null byte11122 new_len += 1; // null byte
1096311123
...@@ -11453,22 +11613,33 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -11453,22 +11613,33 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
11453 return ira->codegen->builtin_types.entry_void;11613 return ira->codegen->builtin_types.entry_void;
11454}11614}
1145511615
11616static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
11617 FnTableEntry *fn_entry = exec_fn_entry(exec);
11618 return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing;
11619}
11620
11456static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,11621static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11457 IrInstructionErrorReturnTrace *instruction)11622 IrInstructionErrorReturnTrace *instruction)
11458{11623{
11459 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);11624 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
11460 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11625 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11461 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);11626 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) {11627 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11463 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11628 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11464 out_val->data.x_maybe = nullptr;11629 out_val->data.x_maybe = nullptr;
11630 return nullable_type;
11631 }
11632 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11633 instruction->base.source_node, instruction->nullable);
11634 ir_link_new_instruction(new_instruction, &instruction->base);
11465 return nullable_type;11635 return nullable_type;
11636 } else {
11637 assert(ira->codegen->have_err_ret_tracing);
11638 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11639 instruction->base.source_node, instruction->nullable);
11640 ir_link_new_instruction(new_instruction, &instruction->base);
11641 return get_ptr_to_stack_trace_type(ira->codegen);
11466 }11642 }
11467
11468 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11469 instruction->base.source_node);
11470 ir_link_new_instruction(new_instruction, &instruction->base);
11471 return nullable_type;
11472}11643}
1147311644
11474static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,11645static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
...@@ -12950,6 +13121,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -12950,6 +13121,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
12950{13121{
12951 if (!is_slice(bare_struct_type)) {13122 if (!is_slice(bare_struct_type)) {
12952 ScopeDecls *container_scope = get_container_scope(bare_struct_type);13123 ScopeDecls *container_scope = get_container_scope(bare_struct_type);
13124 assert(container_scope != nullptr);
12953 auto entry = container_scope->decl_table.maybe_get(field_name);13125 auto entry = container_scope->decl_table.maybe_get(field_name);
12954 Tld *tld = entry ? entry->value : nullptr;13126 Tld *tld = entry ? entry->value : nullptr;
12955 if (tld && tld->id == TldIdFn) {13127 if (tld && tld->id == TldIdFn) {
...@@ -13999,6 +14171,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -13999,6 +14171,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
13999 zig_unreachable();14171 zig_unreachable();
14000}14172}
1400114173
14174static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) {
14175 TypeTableEntry *promise_type;
14176
14177 if (instruction->payload_type == nullptr) {
14178 promise_type = ira->codegen->builtin_types.entry_promise;
14179 } else {
14180 TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload_type->other);
14181 if (type_is_invalid(payload_type))
14182 return ira->codegen->builtin_types.entry_invalid;
14183
14184 promise_type = get_promise_type(ira->codegen, payload_type);
14185 }
14186
14187 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14188 out_val->data.x_type = promise_type;
14189 return ira->codegen->builtin_types.entry_type;
14190}
14191
14002static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,14192static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
14003 IrInstructionSizeOf *size_of_instruction)14193 IrInstructionSizeOf *size_of_instruction)
14004{14194{
...@@ -14569,7 +14759,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi...@@ -14569,7 +14759,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
14569 return ira->codegen->builtin_types.entry_namespace;14759 return ira->codegen->builtin_types.entry_namespace;
14570 }14760 }
1457114761
14572 if ((err = os_fetch_file_path(abs_full_path, import_code))) {14762 if ((err = os_fetch_file_path(abs_full_path, import_code, true))) {
14573 if (err == ErrorFileNotFound) {14763 if (err == ErrorFileNotFound) {
14574 ir_add_error_node(ira, source_node,14764 ir_add_error_node(ira, source_node,
14575 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));14765 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
...@@ -15430,7 +15620,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr...@@ -15430,7 +15620,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
15430 // load from file system into const expr15620 // load from file system into const expr
15431 Buf *file_contents = buf_alloc();15621 Buf *file_contents = buf_alloc();
15432 int err;15622 int err;
15433 if ((err = os_fetch_file_path(&file_path, file_contents))) {15623 if ((err = os_fetch_file_path(&file_path, file_contents, false))) {
15434 if (err == ErrorFileNotFound) {15624 if (err == ErrorFileNotFound) {
15435 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));15625 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
15436 return ira->codegen->builtin_types.entry_invalid;15626 return ira->codegen->builtin_types.entry_invalid;
...@@ -16561,6 +16751,18 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -16561,6 +16751,18 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
16561 if (type_is_invalid(fn_type_id.return_type))16751 if (type_is_invalid(fn_type_id.return_type))
16562 return ira->codegen->builtin_types.entry_invalid;16752 return ira->codegen->builtin_types.entry_invalid;
1656316753
16754 if (fn_type_id.cc == CallingConventionAsync) {
16755 if (instruction->async_allocator_type_value == nullptr) {
16756 ir_add_error(ira, &instruction->base,
16757 buf_sprintf("async fn proto missing allocator type"));
16758 return ira->codegen->builtin_types.entry_invalid;
16759 }
16760 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;
16761 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
16762 if (type_is_invalid(fn_type_id.async_allocator_type))
16763 return ira->codegen->builtin_types.entry_invalid;
16764 }
16765
16564 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);16766 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
16565 out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);16767 out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);
16566 return ira->codegen->builtin_types.entry_type;16768 return ira->codegen->builtin_types.entry_type;
...@@ -16789,18 +16991,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,...@@ -16789,18 +16991,18 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
16789static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {16991static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {
16790 IrInstruction *msg = instruction->msg->other;16992 IrInstruction *msg = instruction->msg->other;
16791 if (type_is_invalid(msg->value.type))16993 if (type_is_invalid(msg->value.type))
16792 return ira->codegen->builtin_types.entry_invalid;16994 return ir_unreach_error(ira);
1679316995
16794 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {16996 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
16795 ir_add_error(ira, &instruction->base, buf_sprintf("encountered @panic at compile-time"));16997 ir_add_error(ira, &instruction->base, buf_sprintf("encountered @panic at compile-time"));
16796 return ira->codegen->builtin_types.entry_invalid;16998 return ir_unreach_error(ira);
16797 }16999 }
1679817000
16799 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);17001 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
16800 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);17002 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
16801 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);17003 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
16802 if (type_is_invalid(casted_msg->value.type))17004 if (type_is_invalid(casted_msg->value.type))
16803 return ira->codegen->builtin_types.entry_invalid;17005 return ir_unreach_error(ira);
1680417006
16805 IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope,17007 IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope,
16806 instruction->base.source_node, casted_msg);17008 instruction->base.source_node, casted_msg);
...@@ -17757,6 +17959,59 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,...@@ -17757,6 +17959,59 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
17757 return out_val->type;17959 return out_val->type;
17758}17960}
1775917961
17962static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
17963 IrInstructionMergeErrRetTraces *instruction)
17964{
17965 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other;
17966 if (type_is_invalid(coro_promise_ptr->value.type))
17967 return ira->codegen->builtin_types.entry_invalid;
17968
17969 assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer);
17970 TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
17971 assert(promise_frame_type->id == TypeTableEntryIdStruct);
17972 TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
17973
17974 if (!type_can_fail(promise_result_type)) {
17975 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17976 out_val->type = ira->codegen->builtin_types.entry_void;
17977 return out_val->type;
17978 }
17979
17980 IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other;
17981 if (type_is_invalid(src_err_ret_trace_ptr->value.type))
17982 return ira->codegen->builtin_types.entry_invalid;
17983
17984 IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other;
17985 if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
17986 return ira->codegen->builtin_types.entry_invalid;
17987
17988 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
17989 instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
17990 ir_link_new_instruction(result, &instruction->base);
17991 result->value.type = ira->codegen->builtin_types.entry_void;
17992 return result->value.type;
17993}
17994
17995static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
17996 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
17997 instruction->base.source_node);
17998 ir_link_new_instruction(result, &instruction->base);
17999 result->value.type = ira->codegen->builtin_types.entry_void;
18000 return result->value.type;
18001}
18002
18003static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) {
18004 IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other;
18005 if (type_is_invalid(err_ret_trace_ptr->value.type))
18006 return ira->codegen->builtin_types.entry_invalid;
18007
18008 IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope,
18009 instruction->base.source_node, err_ret_trace_ptr);
18010 ir_link_new_instruction(result, &instruction->base);
18011 result->value.type = ira->codegen->builtin_types.entry_void;
18012 return result->value.type;
18013}
18014
17760static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {18015static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17761 switch (instruction->id) {18016 switch (instruction->id) {
17762 case IrInstructionIdInvalid:18017 case IrInstructionIdInvalid:
...@@ -17822,6 +18077,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17822,6 +18077,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17822 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);18077 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
17823 case IrInstructionIdArrayType:18078 case IrInstructionIdArrayType:
17824 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);18079 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
18080 case IrInstructionIdPromiseType:
18081 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
17825 case IrInstructionIdSizeOf:18082 case IrInstructionIdSizeOf:
17826 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);18083 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
17827 case IrInstructionIdTestNonNull:18084 case IrInstructionIdTestNonNull:
...@@ -17994,6 +18251,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17994,6 +18251,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17994 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);18251 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
17995 case IrInstructionIdAwaitBookkeeping:18252 case IrInstructionIdAwaitBookkeeping:
17996 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);18253 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
18254 case IrInstructionIdSaveErrRetAddr:
18255 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
18256 case IrInstructionIdAddImplicitReturnType:
18257 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
18258 case IrInstructionIdMergeErrRetTraces:
18259 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
18260 case IrInstructionIdMarkErrRetTracePtr:
18261 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
17997 }18262 }
17998 zig_unreachable();18263 zig_unreachable();
17999}18264}
...@@ -18067,11 +18332,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -18067,11 +18332,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1806718332
18068 if (new_exec->invalid) {18333 if (new_exec->invalid) {
18069 return ira->codegen->builtin_types.entry_invalid;18334 return ira->codegen->builtin_types.entry_invalid;
18070 } else if (ira->implicit_return_type_list.length == 0) {18335 } else if (ira->src_implicit_return_type_list.length == 0) {
18071 return codegen->builtin_types.entry_unreachable;18336 return codegen->builtin_types.entry_unreachable;
18072 } else {18337 } else {
18073 return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,18338 return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items,
18074 ira->implicit_return_type_list.length);18339 ira->src_implicit_return_type_list.length);
18075 }18340 }
18076}18341}
1807718342
...@@ -18119,6 +18384,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18119,6 +18384,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18119 case IrInstructionIdCoroSave:18384 case IrInstructionIdCoroSave:
18120 case IrInstructionIdCoroAllocHelper:18385 case IrInstructionIdCoroAllocHelper:
18121 case IrInstructionIdAwaitBookkeeping:18386 case IrInstructionIdAwaitBookkeeping:
18387 case IrInstructionIdSaveErrRetAddr:
18388 case IrInstructionIdAddImplicitReturnType:
18389 case IrInstructionIdMergeErrRetTraces:
18390 case IrInstructionIdMarkErrRetTracePtr:
18122 return true;18391 return true;
1812318392
18124 case IrInstructionIdPhi:18393 case IrInstructionIdPhi:
...@@ -18141,6 +18410,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18141,6 +18410,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18141 case IrInstructionIdStructFieldPtr:18410 case IrInstructionIdStructFieldPtr:
18142 case IrInstructionIdUnionFieldPtr:18411 case IrInstructionIdUnionFieldPtr:
18143 case IrInstructionIdArrayType:18412 case IrInstructionIdArrayType:
18413 case IrInstructionIdPromiseType:
18144 case IrInstructionIdSliceType:18414 case IrInstructionIdSliceType:
18145 case IrInstructionIdSizeOf:18415 case IrInstructionIdSizeOf:
18146 case IrInstructionIdTestNonNull:18416 case IrInstructionIdTestNonNull:
src/ir_print.cpp+61-3
...@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {...@@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
201 if (call_instruction->is_async) {201 if (call_instruction->is_async) {
202 fprintf(irp->f, "async");202 fprintf(irp->f, "async");
203 if (call_instruction->async_allocator != nullptr) {203 if (call_instruction->async_allocator != nullptr) {
204 fprintf(irp->f, "(");204 fprintf(irp->f, "<");
205 ir_print_other_instruction(irp, call_instruction->async_allocator);205 ir_print_other_instruction(irp, call_instruction->async_allocator);
206 fprintf(irp->f, ")");206 fprintf(irp->f, ">");
207 }207 }
208 fprintf(irp->f, " ");208 fprintf(irp->f, " ");
209 }209 }
...@@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio...@@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
404 ir_print_other_instruction(irp, instruction->child_type);404 ir_print_other_instruction(irp, instruction->child_type);
405}405}
406406
407static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) {
408 fprintf(irp->f, "promise");
409 if (instruction->payload_type != nullptr) {
410 fprintf(irp->f, "->");
411 ir_print_other_instruction(irp, instruction->payload_type);
412 }
413}
414
407static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {415static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
408 const char *const_kw = instruction->is_const ? "const " : "";416 const char *const_kw = instruction->is_const ? "const " : "";
409 fprintf(irp->f, "[]%s", const_kw);417 fprintf(irp->f, "[]%s", const_kw);
...@@ -1016,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {...@@ -1016,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
1016}1024}
10171025
1018static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1019 fprintf(irp->f, "@errorReturnTrace()");1027 fprintf(irp->f, "@errorReturnTrace(");
1028 switch (instruction->nullable) {
1029 case IrInstructionErrorReturnTrace::Null:
1030 fprintf(irp->f, "Null");
1031 break;
1032 case IrInstructionErrorReturnTrace::NonNull:
1033 fprintf(irp->f, "NonNull");
1034 break;
1035 }
1036 fprintf(irp->f, ")");
1020}1037}
10211038
1022static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {1039static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
...@@ -1161,6 +1178,32 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi...@@ -1161,6 +1178,32 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi
1161 fprintf(irp->f, ")");1178 fprintf(irp->f, ")");
1162}1179}
11631180
1181static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
1182 fprintf(irp->f, "@saveErrRetAddr()");
1183}
1184
1185static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImplicitReturnType *instruction) {
1186 fprintf(irp->f, "@addImplicitReturnType(");
1187 ir_print_other_instruction(irp, instruction->value);
1188 fprintf(irp->f, ")");
1189}
1190
1191static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1192 fprintf(irp->f, "@mergeErrRetTraces(");
1193 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1194 fprintf(irp->f, ",");
1195 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1196 fprintf(irp->f, ",");
1197 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1198 fprintf(irp->f, ")");
1199}
1200
1201static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1202 fprintf(irp->f, "@markErrRetTracePtr(");
1203 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1204 fprintf(irp->f, ")");
1205}
1206
1164static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1207static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1165 ir_print_prefix(irp, instruction);1208 ir_print_prefix(irp, instruction);
1166 switch (instruction->id) {1209 switch (instruction->id) {
...@@ -1253,6 +1296,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1253,6 +1296,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1253 case IrInstructionIdArrayType:1296 case IrInstructionIdArrayType:
1254 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);1297 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
1255 break;1298 break;
1299 case IrInstructionIdPromiseType:
1300 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1301 break;
1256 case IrInstructionIdSliceType:1302 case IrInstructionIdSliceType:
1257 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);1303 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
1258 break;1304 break;
...@@ -1532,6 +1578,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1532,6 +1578,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1532 case IrInstructionIdAwaitBookkeeping:1578 case IrInstructionIdAwaitBookkeeping:
1533 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);1579 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
1534 break;1580 break;
1581 case IrInstructionIdSaveErrRetAddr:
1582 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
1583 break;
1584 case IrInstructionIdAddImplicitReturnType:
1585 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
1586 break;
1587 case IrInstructionIdMergeErrRetTraces:
1588 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
1589 break;
1590 case IrInstructionIdMarkErrRetTracePtr:
1591 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
1592 break;
1535 }1593 }
1536 fprintf(irp->f, "\n");1594 fprintf(irp->f, "\n");
1537}1595}
src/link.cpp+54-7
...@@ -164,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {...@@ -164,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164 lj->rpath_table.put(rpath, true);164 lj->rpath_table.put(rpath, true);
165}165}
166166
167static Buf *try_dynamic_linker_path(const char *ld_name) {
168 const char *cc_exe = getenv("CC");
169 cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
170 ZigList<const char *> args = {};
171 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", ld_name)));
172 Termination term;
173 Buf *out_stderr = buf_alloc();
174 Buf *out_stdout = buf_alloc();
175 int err;
176 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
177 return nullptr;
178 }
179 if (term.how != TerminationIdClean || term.code != 0) {
180 return nullptr;
181 }
182 if (buf_ends_with_str(out_stdout, "\n")) {
183 buf_resize(out_stdout, buf_len(out_stdout) - 1);
184 }
185 if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, ld_name)) {
186 return nullptr;
187 }
188 return out_stdout;
189}
190
191static Buf *get_dynamic_linker_path(CodeGen *g) {
192 if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) {
193 static const char *ld_names[] = {
194 "ld-linux-x86-64.so.2",
195 "ld-musl-x86_64.so.1",
196 };
197 for (size_t i = 0; i < array_length(ld_names); i += 1) {
198 const char *ld_name = ld_names[i];
199 Buf *result = try_dynamic_linker_path(ld_name);
200 if (result != nullptr) {
201 return result;
202 }
203 }
204 }
205 return target_dynamic_linker(&g->zig_target);
206}
207
167static void construct_linker_job_elf(LinkJob *lj) {208static void construct_linker_job_elf(LinkJob *lj) {
168 CodeGen *g = lj->codegen;209 CodeGen *g = lj->codegen;
169210
...@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {
259 lj->args.append(buf_ptr(g->libc_static_lib_dir));300 lj->args.append(buf_ptr(g->libc_static_lib_dir));
260 }301 }
261302
262 if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) {303 if (!g->is_static) {
263 lj->args.append("-dynamic-linker");304 if (g->dynamic_linker != nullptr) {
264 lj->args.append(buf_ptr(g->dynamic_linker));305 assert(buf_len(g->dynamic_linker) != 0);
265 } else {306 lj->args.append("-dynamic-linker");
266 lj->args.append("-dynamic-linker");307 lj->args.append(buf_ptr(g->dynamic_linker));
267 lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target)));308 } else {
309 Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
310 lj->args.append("-dynamic-linker");
311 lj->args.append(buf_ptr(resolved_dynamic_linker));
312 }
268 }313 }
269314
270 if (shared) {315 if (shared) {
...@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
423 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));468 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
424469
425 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));470 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
426 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));471 if (g->libc_static_lib_dir != nullptr) {
472 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
473 }
427 }474 }
428475
429 if (lj->link_in_crt) {476 if (lj->link_in_crt) {
src/main.cpp+52-16
...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
23 " build-exe [source] create executable from source or object files\n"23 " build-exe [source] create executable from source or object files\n"
24 " build-lib [source] create library from source or object files\n"24 " build-lib [source] create library from source or object files\n"
25 " build-obj [source] create object from source or assembly\n"25 " build-obj [source] create object from source or assembly\n"
26 " run [source] create executable and run immediately\n"
26 " translate-c [source] convert c code to zig code\n"27 " translate-c [source] convert c code to zig code\n"
27 " targets list available compilation targets\n"28 " targets list available compilation targets\n"
28 " test [source] create and run a test build\n"29 " test [source] create and run a test build\n"
...@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {...@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {
195 }196 }
196 }197 }
197198
198 if (ZIG_INSTALL_PREFIX != nullptr) {
199 if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
200 return 0;
201 }
202 }
203
204
205 return ErrorFileNotFound;199 return ErrorFileNotFound;
206}200}
207201
...@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {...@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
227enum Cmd {221enum Cmd {
228 CmdInvalid,222 CmdInvalid,
229 CmdBuild,223 CmdBuild,
224 CmdRun,
230 CmdTest,225 CmdTest,
231 CmdVersion,226 CmdVersion,
232 CmdZen,227 CmdZen,
...@@ -336,6 +331,8 @@ int main(int argc, char **argv) {...@@ -336,6 +331,8 @@ int main(int argc, char **argv) {
336 CliPkg *cur_pkg = allocate<CliPkg>(1);331 CliPkg *cur_pkg = allocate<CliPkg>(1);
337 BuildMode build_mode = BuildModeDebug;332 BuildMode build_mode = BuildModeDebug;
338 ZigList<const char *> test_exec_args = {0};333 ZigList<const char *> test_exec_args = {0};
334 int comptime_args_end = 0;
335 int runtime_args_start = argc;
339336
340 if (argc >= 2 && strcmp(argv[1], "build") == 0) {337 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
341 const char *zig_exe_path = arg0;338 const char *zig_exe_path = arg0;
...@@ -452,10 +449,11 @@ int main(int argc, char **argv) {...@@ -452,10 +449,11 @@ int main(int argc, char **argv) {
452449
453 if ((err = os_copy_file(build_template_path, &build_file_abs))) {450 if ((err = os_copy_file(build_template_path, &build_file_abs))) {
454 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));451 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));
452 return EXIT_FAILURE;
455 } else {453 } else {
456 fprintf(stderr, "Wrote build.zig template\n");454 fprintf(stderr, "Wrote build.zig template\n");
455 return EXIT_SUCCESS;
457 }456 }
458 return EXIT_SUCCESS;
459 }457 }
460458
461 fprintf(stderr,459 fprintf(stderr,
...@@ -487,11 +485,15 @@ int main(int argc, char **argv) {...@@ -487,11 +485,15 @@ int main(int argc, char **argv) {
487 return (term.how == TerminationIdClean) ? term.code : -1;485 return (term.how == TerminationIdClean) ? term.code : -1;
488 }486 }
489487
490 for (int i = 1; i < argc; i += 1) {488 for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
491 char *arg = argv[i];489 char *arg = argv[i];
492490
493 if (arg[0] == '-') {491 if (arg[0] == '-') {
494 if (strcmp(arg, "--release-fast") == 0) {492 if (strcmp(arg, "--") == 0) {
493 // ignore -- from both compile and runtime arg sets
494 runtime_args_start = i + 1;
495 break;
496 } else if (strcmp(arg, "--release-fast") == 0) {
495 build_mode = BuildModeFastRelease;497 build_mode = BuildModeFastRelease;
496 } else if (strcmp(arg, "--release-safe") == 0) {498 } else if (strcmp(arg, "--release-safe") == 0) {
497 build_mode = BuildModeSafeRelease;499 build_mode = BuildModeSafeRelease;
...@@ -658,6 +660,9 @@ int main(int argc, char **argv) {...@@ -658,6 +660,9 @@ int main(int argc, char **argv) {
658 } else if (strcmp(arg, "build-lib") == 0) {660 } else if (strcmp(arg, "build-lib") == 0) {
659 cmd = CmdBuild;661 cmd = CmdBuild;
660 out_type = OutTypeLib;662 out_type = OutTypeLib;
663 } else if (strcmp(arg, "run") == 0) {
664 cmd = CmdRun;
665 out_type = OutTypeExe;
661 } else if (strcmp(arg, "version") == 0) {666 } else if (strcmp(arg, "version") == 0) {
662 cmd = CmdVersion;667 cmd = CmdVersion;
663 } else if (strcmp(arg, "zen") == 0) {668 } else if (strcmp(arg, "zen") == 0) {
...@@ -676,6 +681,7 @@ int main(int argc, char **argv) {...@@ -676,6 +681,7 @@ int main(int argc, char **argv) {
676 } else {681 } else {
677 switch (cmd) {682 switch (cmd) {
678 case CmdBuild:683 case CmdBuild:
684 case CmdRun:
679 case CmdTranslateC:685 case CmdTranslateC:
680 case CmdTest:686 case CmdTest:
681 if (!in_file) {687 if (!in_file) {
...@@ -730,8 +736,8 @@ int main(int argc, char **argv) {...@@ -730,8 +736,8 @@ int main(int argc, char **argv) {
730 }736 }
731 }737 }
732738
733
734 switch (cmd) {739 switch (cmd) {
740 case CmdRun:
735 case CmdBuild:741 case CmdBuild:
736 case CmdTranslateC:742 case CmdTranslateC:
737 case CmdTest:743 case CmdTest:
...@@ -739,7 +745,7 @@ int main(int argc, char **argv) {...@@ -739,7 +745,7 @@ int main(int argc, char **argv) {
739 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {745 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
740 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");746 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
741 return usage(arg0);747 return usage(arg0);
742 } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {748 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
743 fprintf(stderr, "Expected source file argument.\n");749 fprintf(stderr, "Expected source file argument.\n");
744 return usage(arg0);750 return usage(arg0);
745 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {751 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
...@@ -751,6 +757,10 @@ int main(int argc, char **argv) {...@@ -751,6 +757,10 @@ int main(int argc, char **argv) {
751757
752 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);758 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
753759
760 if (cmd == CmdRun) {
761 out_name = "run";
762 }
763
754 Buf *in_file_buf = nullptr;764 Buf *in_file_buf = nullptr;
755765
756 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :766 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
...@@ -775,9 +785,23 @@ int main(int argc, char **argv) {...@@ -775,9 +785,23 @@ int main(int argc, char **argv) {
775 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;785 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
776786
777 Buf *full_cache_dir = buf_alloc();787 Buf *full_cache_dir = buf_alloc();
778 os_path_resolve(buf_create_from_str("."),788 Buf *run_exec_path = buf_alloc();
779 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),789 if (cmd == CmdRun) {
780 full_cache_dir);790 if (buf_out_name == nullptr) {
791 buf_out_name = buf_create_from_str("run");
792 }
793
794 Buf *global_cache_dir = buf_alloc();
795 os_get_global_cache_directory(global_cache_dir);
796 os_path_join(global_cache_dir, buf_out_name, run_exec_path);
797 os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir);
798
799 out_file = buf_ptr(run_exec_path);
800 } else {
801 os_path_resolve(buf_create_from_str("."),
802 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
803 full_cache_dir);
804 }
781805
782 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
783807
...@@ -861,7 +885,7 @@ int main(int argc, char **argv) {...@@ -861,7 +885,7 @@ int main(int argc, char **argv) {
861885
862 add_package(g, cur_pkg, g->root_package);886 add_package(g, cur_pkg, g->root_package);
863887
864 if (cmd == CmdBuild) {888 if (cmd == CmdBuild || cmd == CmdRun) {
865 codegen_set_emit_file_type(g, emit_file_type);889 codegen_set_emit_file_type(g, emit_file_type);
866890
867 for (size_t i = 0; i < objects.length; i += 1) {891 for (size_t i = 0; i < objects.length; i += 1) {
...@@ -874,6 +898,18 @@ int main(int argc, char **argv) {...@@ -874,6 +898,18 @@ int main(int argc, char **argv) {
874 codegen_link(g, out_file);898 codegen_link(g, out_file);
875 if (timing_info)899 if (timing_info)
876 codegen_print_timing_report(g, stdout);900 codegen_print_timing_report(g, stdout);
901
902 if (cmd == CmdRun) {
903 ZigList<const char*> args = {0};
904 for (int i = runtime_args_start; i < argc; ++i) {
905 args.append(argv[i]);
906 }
907
908 Termination term;
909 os_spawn_process(buf_ptr(run_exec_path), args, &term);
910 return term.code;
911 }
912
877 return EXIT_SUCCESS;913 return EXIT_SUCCESS;
878 } else if (cmd == CmdTranslateC) {914 } else if (cmd == CmdTranslateC) {
879 codegen_translate_c(g, in_file_buf);915 codegen_translate_c(g, in_file_buf);
src/os.cpp+90-11
...@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;...@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;
45#if defined(__MACH__)45#if defined(__MACH__)
46#include <mach/clock.h>46#include <mach/clock.h>
47#include <mach/mach.h>47#include <mach/mach.h>
48#include <mach-o/dyld.h>
48#endif49#endif
4950
50#if defined(ZIG_OS_WINDOWS)51#if defined(ZIG_OS_WINDOWS)
...@@ -57,10 +58,6 @@ static clock_serv_t cclock;...@@ -57,10 +58,6 @@ static clock_serv_t cclock;
57#include <errno.h>58#include <errno.h>
58#include <time.h>59#include <time.h>
5960
60// these implementations are lazy. But who cares, we'll make a robust
61// implementation in the zig standard library and then this code all gets
62// deleted when we self-host. it works for now.
63
64#if defined(ZIG_OS_POSIX)61#if defined(ZIG_OS_POSIX)
65static void populate_termination(Termination *term, int status) {62static void populate_termination(Termination *term, int status) {
66 if (WIFEXITED(status)) {63 if (WIFEXITED(status)) {
...@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {...@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
291 return;288 return;
292}289}
293290
294int os_fetch_file(FILE *f, Buf *out_buf) {291int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
295 static const ssize_t buf_size = 0x2000;292 static const ssize_t buf_size = 0x2000;
296 buf_resize(out_buf, buf_size);293 buf_resize(out_buf, buf_size);
297 ssize_t actual_buf_len = 0;294 ssize_t actual_buf_len = 0;
295
296 bool first_read = true;
297
298 for (;;) {298 for (;;) {
299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
300 actual_buf_len += amt_read;300 actual_buf_len += amt_read;
301
302 if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) {
303 size_t i = 0;
304 while (true) {
305 if (i > buf_len(out_buf)) {
306 zig_panic("shebang line exceeded %zd characters", buf_size);
307 }
308
309 size_t current_pos = i;
310 i += 1;
311
312 if (out_buf->list.at(current_pos) == '\n') {
313 break;
314 }
315 }
316
317 ZigList<char> *list = &out_buf->list;
318 memmove(list->items, list->items + i, list->length - i);
319 list->length -= i;
320
321 actual_buf_len -= i;
322 }
323
301 if (amt_read != buf_size) {324 if (amt_read != buf_size) {
302 if (feof(f)) {325 if (feof(f)) {
303 buf_resize(out_buf, actual_buf_len);326 buf_resize(out_buf, actual_buf_len);
...@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {...@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
308 }331 }
309332
310 buf_resize(out_buf, actual_buf_len + buf_size);333 buf_resize(out_buf, actual_buf_len + buf_size);
334 first_read = false;
311 }335 }
312 zig_unreachable();336 zig_unreachable();
313}337}
...@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,...@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
377401
378 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");402 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
379 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");403 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
380 os_fetch_file(stdout_f, out_stdout);404 os_fetch_file(stdout_f, out_stdout, false);
381 os_fetch_file(stderr_f, out_stderr);405 os_fetch_file(stderr_f, out_stderr, false);
382406
383 fclose(stdout_f);407 fclose(stdout_f);
384 fclose(stderr_f);408 fclose(stderr_f);
...@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {...@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
591 }615 }
592}616}
593617
594int os_fetch_file_path(Buf *full_path, Buf *out_contents) {618int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
595 FILE *f = fopen(buf_ptr(full_path), "rb");619 FILE *f = fopen(buf_ptr(full_path), "rb");
596 if (!f) {620 if (!f) {
597 switch (errno) {621 switch (errno) {
...@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {...@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
610 return ErrorFileSystem;634 return ErrorFileSystem;
611 }635 }
612 }636 }
613 int result = os_fetch_file(f, out_contents);637 int result = os_fetch_file(f, out_contents, skip_shebang);
614 fclose(f);638 fclose(f);
615 return result;639 return result;
616}640}
...@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {...@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
783#endif807#endif
784}808}
785809
810#if defined(ZIG_OS_POSIX)
811int os_get_global_cache_directory(Buf *out_tmp_path) {
812 const char *tmp_dir = getenv("TMPDIR");
813 if (!tmp_dir) {
814 tmp_dir = P_tmpdir;
815 }
816
817 Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
818 Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
819
820 buf_resize(out_tmp_path, 0);
821 os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
822
823 buf_deinit(tmp_dir_buf);
824 buf_deinit(cache_dirname_buf);
825 return 0;
826}
827#endif
828
829#if defined(ZIG_OS_WINDOWS)
830int os_get_global_cache_directory(Buf *out_tmp_path) {
831 char tmp_dir[MAX_PATH + 1];
832 if (GetTempPath(MAX_PATH, tmp_dir) == 0) {
833 zig_panic("GetTempPath failed");
834 }
835
836 Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
837 Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
838
839 buf_resize(out_tmp_path, 0);
840 os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
841
842 buf_deinit(tmp_dir_buf);
843 buf_deinit(cache_dirname_buf);
844 return 0;
845}
846#endif
847
786int os_delete_file(Buf *path) {848int os_delete_file(Buf *path) {
787 if (remove(buf_ptr(path))) {849 if (remove(buf_ptr(path))) {
788 return ErrorFileSystem;850 return ErrorFileSystem;
...@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {...@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {
927 }989 }
928990
929#elif defined(ZIG_OS_DARWIN)991#elif defined(ZIG_OS_DARWIN)
930 return ErrorFileNotFound;992 uint32_t u32_len = 0;
993 int ret1 = _NSGetExecutablePath(nullptr, &u32_len);
994 assert(ret1 != 0);
995 buf_resize(out_path, u32_len);
996 int ret2 = _NSGetExecutablePath(buf_ptr(out_path), &u32_len);
997 assert(ret2 == 0);
998 return 0;
931#elif defined(ZIG_OS_LINUX)999#elif defined(ZIG_OS_LINUX)
932 return ErrorFileNotFound;1000 buf_resize(out_path, 256);
1001 for (;;) {
1002 ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
1003 if (amt == -1) {
1004 return ErrorUnexpected;
1005 }
1006 if (amt == (ssize_t)buf_len(out_path)) {
1007 buf_resize(out_path, buf_len(out_path) * 2);
1008 continue;
1009 }
1010 return 0;
1011 }
933#endif1012#endif
934 return ErrorFileNotFound;1013 return ErrorFileNotFound;
935}1014}
src/os.hpp+4-2
...@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);...@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);
51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
52bool os_path_is_absolute(Buf *path);52bool os_path_is_absolute(Buf *path);
5353
54int os_get_global_cache_directory(Buf *out_tmp_path);
55
54int os_make_path(Buf *path);56int os_make_path(Buf *path);
55int os_make_dir(Buf *path);57int os_make_dir(Buf *path);
5658
57void os_write_file(Buf *full_path, Buf *contents);59void os_write_file(Buf *full_path, Buf *contents);
58int os_copy_file(Buf *src_path, Buf *dest_path);60int os_copy_file(Buf *src_path, Buf *dest_path);
5961
60int os_fetch_file(FILE *file, Buf *out_contents);62int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
61int os_fetch_file_path(Buf *full_path, Buf *out_contents);63int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
6264
63int os_get_cwd(Buf *out_cwd);65int os_get_cwd(Buf *out_cwd);
6466
src/parser.cpp+92-70
...@@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b...@@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
705}705}
706706
707/*707/*
708PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl708PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
709KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"709KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
710ErrorSetDecl = "error" "{" list(Symbol, ",") "}"710ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
711*/711*/
...@@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo...@@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
774 AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);774 AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);
775 *token_index += 1;775 *token_index += 1;
776 return node;776 return node;
777 } else if (token->id == TokenIdKeywordPromise) {
778 AstNode *node = ast_create_node(pc, NodeTypePromiseType, token);
779 *token_index += 1;
780 Token *arrow_tok = &pc->tokens->at(*token_index);
781 if (arrow_tok->id == TokenIdArrow) {
782 *token_index += 1;
783 node->data.promise_type.payload_type = ast_parse_type_expr(pc, token_index, true);
784 }
785 return node;
777 } else if (token->id == TokenIdKeywordError) {786 } else if (token->id == TokenIdKeywordError) {
778 Token *next_token = &pc->tokens->at(*token_index + 1);787 Token *next_token = &pc->tokens->at(*token_index + 1);
779 if (next_token->id == TokenIdLBrace) {788 if (next_token->id == TokenIdLBrace) {
...@@ -955,8 +964,68 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde...@@ -955,8 +964,68 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
955 }964 }
956}965}
957966
967static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index, Token *fn_token,
968 AstNode *async_allocator_type_node, CallingConvention cc, bool is_extern, VisibMod visib_mod)
969{
970 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
971 node->data.fn_proto.visib_mod = visib_mod;
972 node->data.fn_proto.cc = cc;
973 node->data.fn_proto.is_extern = is_extern;
974 node->data.fn_proto.async_allocator_type = async_allocator_type_node;
975
976 Token *fn_name = &pc->tokens->at(*token_index);
977
978 if (fn_name->id == TokenIdSymbol) {
979 *token_index += 1;
980 node->data.fn_proto.name = token_buf(fn_name);
981 } else {
982 node->data.fn_proto.name = nullptr;
983 }
984
985 ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
986
987 Token *next_token = &pc->tokens->at(*token_index);
988 if (next_token->id == TokenIdKeywordAlign) {
989 *token_index += 1;
990 ast_eat_token(pc, token_index, TokenIdLParen);
991
992 node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true);
993 ast_eat_token(pc, token_index, TokenIdRParen);
994 next_token = &pc->tokens->at(*token_index);
995 }
996 if (next_token->id == TokenIdKeywordSection) {
997 *token_index += 1;
998 ast_eat_token(pc, token_index, TokenIdLParen);
999
1000 node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true);
1001 ast_eat_token(pc, token_index, TokenIdRParen);
1002 next_token = &pc->tokens->at(*token_index);
1003 }
1004 if (next_token->id == TokenIdKeywordVar) {
1005 node->data.fn_proto.return_var_token = next_token;
1006 *token_index += 1;
1007 next_token = &pc->tokens->at(*token_index);
1008 } else {
1009 if (next_token->id == TokenIdKeywordError) {
1010 Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
1011 if (maybe_lbrace_tok->id == TokenIdLBrace) {
1012 *token_index += 1;
1013 node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
1014 return node;
1015 }
1016 } else if (next_token->id == TokenIdBang) {
1017 *token_index += 1;
1018 node->data.fn_proto.auto_err_set = true;
1019 next_token = &pc->tokens->at(*token_index);
1020 }
1021 node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
1022 }
1023
1024 return node;
1025}
1026
958/*1027/*
959SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)1028SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
960FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)1029FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
961ArrayAccessExpression : token(LBracket) Expression token(RBracket)1030ArrayAccessExpression : token(LBracket) Expression token(RBracket)
962SliceExpression = "[" Expression ".." option(Expression) "]"1031SliceExpression = "[" Expression ".." option(Expression) "]"
...@@ -972,19 +1041,25 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,...@@ -972,19 +1041,25 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
9721041
973 AstNode *allocator_expr_node = nullptr;1042 AstNode *allocator_expr_node = nullptr;
974 Token *async_lparen_tok = &pc->tokens->at(*token_index);1043 Token *async_lparen_tok = &pc->tokens->at(*token_index);
975 if (async_lparen_tok->id == TokenIdLParen) {1044 if (async_lparen_tok->id == TokenIdCmpLessThan) {
976 *token_index += 1;1045 *token_index += 1;
977 allocator_expr_node = ast_parse_expression(pc, token_index, true);1046 allocator_expr_node = ast_parse_prefix_op_expr(pc, token_index, true);
978 ast_eat_token(pc, token_index, TokenIdRParen);1047 ast_eat_token(pc, token_index, TokenIdCmpGreaterThan);
979 }1048 }
9801049
981 AstNode *fn_ref_expr_node = ast_parse_primary_expr(pc, token_index, true);1050 Token *fncall_token = &pc->tokens->at(*token_index);
982 Token *lparen_tok = ast_eat_token(pc, token_index, TokenIdLParen);1051 if (fncall_token->id == TokenIdKeywordFn) {
983 AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, lparen_tok);1052 *token_index += 1;
1053 return ast_parse_fn_proto_partial(pc, token_index, fncall_token, allocator_expr_node, CallingConventionAsync,
1054 false, VisibModPrivate);
1055 }
1056 AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true);
1057 if (node->type != NodeTypeFnCallExpr) {
1058 ast_error(pc, fncall_token, "expected function call, found '%s'", token_name(fncall_token->id));
1059 }
984 node->data.fn_call_expr.is_async = true;1060 node->data.fn_call_expr.is_async = true;
985 node->data.fn_call_expr.async_allocator = allocator_expr_node;1061 node->data.fn_call_expr.async_allocator = allocator_expr_node;
986 node->data.fn_call_expr.fn_ref_expr = fn_ref_expr_node;1062 assert(node->data.fn_call_expr.fn_ref_expr != nullptr);
987 ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
9881063
989 primary_expr = node;1064 primary_expr = node;
990 } else {1065 } else {
...@@ -2433,9 +2508,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m...@@ -2433,9 +2508,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
2433 } else if (first_token->id == TokenIdKeywordAsync) {2508 } else if (first_token->id == TokenIdKeywordAsync) {
2434 *token_index += 1;2509 *token_index += 1;
2435 Token *next_token = &pc->tokens->at(*token_index);2510 Token *next_token = &pc->tokens->at(*token_index);
2436 if (next_token->id == TokenIdLParen) {2511 if (next_token->id == TokenIdCmpLessThan) {
2512 *token_index += 1;
2437 async_allocator_type_node = ast_parse_type_expr(pc, token_index, true);2513 async_allocator_type_node = ast_parse_type_expr(pc, token_index, true);
2438 ast_eat_token(pc, token_index, TokenIdRParen);2514 ast_eat_token(pc, token_index, TokenIdCmpGreaterThan);
2439 }2515 }
2440 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);2516 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2441 cc = CallingConventionAsync;2517 cc = CallingConventionAsync;
...@@ -2469,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m...@@ -2469,61 +2545,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
2469 return nullptr;2545 return nullptr;
2470 }2546 }
24712547
2472 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);2548 return ast_parse_fn_proto_partial(pc, token_index, fn_token, async_allocator_type_node, cc, is_extern, visib_mod);
2473 node->data.fn_proto.visib_mod = visib_mod;
2474 node->data.fn_proto.cc = cc;
2475 node->data.fn_proto.is_extern = is_extern;
2476 node->data.fn_proto.async_allocator_type = async_allocator_type_node;
2477
2478 Token *fn_name = &pc->tokens->at(*token_index);
2479
2480 if (fn_name->id == TokenIdSymbol) {
2481 *token_index += 1;
2482 node->data.fn_proto.name = token_buf(fn_name);
2483 } else {
2484 node->data.fn_proto.name = nullptr;
2485 }
2486
2487 ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
2488
2489 Token *next_token = &pc->tokens->at(*token_index);
2490 if (next_token->id == TokenIdKeywordAlign) {
2491 *token_index += 1;
2492 ast_eat_token(pc, token_index, TokenIdLParen);
2493
2494 node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true);
2495 ast_eat_token(pc, token_index, TokenIdRParen);
2496 next_token = &pc->tokens->at(*token_index);
2497 }
2498 if (next_token->id == TokenIdKeywordSection) {
2499 *token_index += 1;
2500 ast_eat_token(pc, token_index, TokenIdLParen);
2501
2502 node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true);
2503 ast_eat_token(pc, token_index, TokenIdRParen);
2504 next_token = &pc->tokens->at(*token_index);
2505 }
2506 if (next_token->id == TokenIdKeywordVar) {
2507 node->data.fn_proto.return_var_token = next_token;
2508 *token_index += 1;
2509 next_token = &pc->tokens->at(*token_index);
2510 } else {
2511 if (next_token->id == TokenIdKeywordError) {
2512 Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
2513 if (maybe_lbrace_tok->id == TokenIdLBrace) {
2514 *token_index += 1;
2515 node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
2516 return node;
2517 }
2518 } else if (next_token->id == TokenIdBang) {
2519 *token_index += 1;
2520 node->data.fn_proto.auto_err_set = true;
2521 next_token = &pc->tokens->at(*token_index);
2522 }
2523 node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
2524 }
2525
2526 return node;
2527}2549}
25282550
2529/*2551/*
...@@ -2901,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2901,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2901 visit_field(&node->data.fn_def.fn_proto, visit, context);2923 visit_field(&node->data.fn_def.fn_proto, visit, context);
2902 visit_field(&node->data.fn_def.body, visit, context);2924 visit_field(&node->data.fn_def.body, visit, context);
2903 break;2925 break;
2904 case NodeTypeFnDecl:
2905 visit_field(&node->data.fn_decl.fn_proto, visit, context);
2906 break;
2907 case NodeTypeParamDecl:2926 case NodeTypeParamDecl:
2908 visit_field(&node->data.param_decl.type, visit, context);2927 visit_field(&node->data.param_decl.type, visit, context);
2909 break;2928 break;
...@@ -3068,6 +3087,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -3068,6 +3087,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3068 visit_field(&node->data.array_type.child_type, visit, context);3087 visit_field(&node->data.array_type.child_type, visit, context);
3069 visit_field(&node->data.array_type.align_expr, visit, context);3088 visit_field(&node->data.array_type.align_expr, visit, context);
3070 break;3089 break;
3090 case NodeTypePromiseType:
3091 visit_field(&node->data.promise_type.payload_type, visit, context);
3092 break;
3071 case NodeTypeErrorType:3093 case NodeTypeErrorType:
3072 // none3094 // none
3073 break;3095 break;
src/parser.hpp-1
...@@ -16,7 +16,6 @@ ATTRIBUTE_PRINTF(2, 3)...@@ -16,7 +16,6 @@ ATTRIBUTE_PRINTF(2, 3)
16void ast_token_error(Token *token, const char *format, ...);16void ast_token_error(Token *token, const char *format, ...);
1717
1818
19// This function is provided by generated code, generated by parsergen.cpp
20AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);19AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
2120
22void ast_print(AstNode *node, int indent);21void ast_print(AstNode *node, int indent);
src/target.cpp+4
...@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {...@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {
863 env == ZigLLVM_GNUX32)863 env == ZigLLVM_GNUX32)
864 {864 {
865 return buf_create_from_str("/libx32/ld-linux-x32.so.2");865 return buf_create_from_str("/libx32/ld-linux-x32.so.2");
866 } else if (arch == ZigLLVM_x86_64 &&
867 (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF))
868 {
869 return buf_create_from_str("/lib/ld-musl-x86_64.so.1");
866 } else {870 } else {
867 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");871 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");
868 }872 }
src/tokenizer.cpp+2
...@@ -135,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -135,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = {
135 {"null", TokenIdKeywordNull},135 {"null", TokenIdKeywordNull},
136 {"or", TokenIdKeywordOr},136 {"or", TokenIdKeywordOr},
137 {"packed", TokenIdKeywordPacked},137 {"packed", TokenIdKeywordPacked},
138 {"promise", TokenIdKeywordPromise},
138 {"pub", TokenIdKeywordPub},139 {"pub", TokenIdKeywordPub},
139 {"resume", TokenIdKeywordResume},140 {"resume", TokenIdKeywordResume},
140 {"return", TokenIdKeywordReturn},141 {"return", TokenIdKeywordReturn},
...@@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) {...@@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) {
1558 case TokenIdKeywordNull: return "null";1559 case TokenIdKeywordNull: return "null";
1559 case TokenIdKeywordOr: return "or";1560 case TokenIdKeywordOr: return "or";
1560 case TokenIdKeywordPacked: return "packed";1561 case TokenIdKeywordPacked: return "packed";
1562 case TokenIdKeywordPromise: return "promise";
1561 case TokenIdKeywordPub: return "pub";1563 case TokenIdKeywordPub: return "pub";
1562 case TokenIdKeywordReturn: return "return";1564 case TokenIdKeywordReturn: return "return";
1563 case TokenIdKeywordSection: return "section";1565 case TokenIdKeywordSection: return "section";
src/tokenizer.hpp+1
...@@ -76,6 +76,7 @@ enum TokenId {...@@ -76,6 +76,7 @@ enum TokenId {
76 TokenIdKeywordNull,76 TokenIdKeywordNull,
77 TokenIdKeywordOr,77 TokenIdKeywordOr,
78 TokenIdKeywordPacked,78 TokenIdKeywordPacked,
79 TokenIdKeywordPromise,
79 TokenIdKeywordPub,80 TokenIdKeywordPub,
80 TokenIdKeywordResume,81 TokenIdKeywordResume,
81 TokenIdKeywordReturn,82 TokenIdKeywordReturn,
std/buf_map.zig+34-17
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const HashMap = @import("hash_map.zig").HashMap;1const std = @import("index.zig");
2const mem = @import("mem.zig");2const HashMap = std.HashMap;
3const mem = std.mem;
3const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
5const assert = std.debug.assert;
46
5/// BufMap copies keys and values before they go into the map, and7/// BufMap copies keys and values before they go into the map, and
6/// frees them when they get removed.8/// frees them when they get removed.
...@@ -28,18 +30,12 @@ pub const BufMap = struct {...@@ -28,18 +30,12 @@ pub const BufMap = struct {
28 }30 }
2931
30 pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void {32 pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void {
31 if (self.hash_map.get(key)) |entry| {33 self.delete(key);
32 const value_copy = try self.copy(value);34 const key_copy = try self.copy(key);
33 errdefer self.free(value_copy);35 errdefer self.free(key_copy);
34 _ = try self.hash_map.put(key, value_copy);36 const value_copy = try self.copy(value);
35 self.free(entry.value);37 errdefer self.free(value_copy);
36 } else {38 _ = try self.hash_map.put(key_copy, value_copy);
37 const key_copy = try self.copy(key);
38 errdefer self.free(key_copy);
39 const value_copy = try self.copy(value);
40 errdefer self.free(value_copy);
41 _ = try self.hash_map.put(key_copy, value_copy);
42 }
43 }39 }
4440
45 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {41 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {
...@@ -66,8 +62,29 @@ pub const BufMap = struct {...@@ -66,8 +62,29 @@ pub const BufMap = struct {
66 }62 }
6763
68 fn copy(self: &BufMap, value: []const u8) ![]const u8 {64 fn copy(self: &BufMap, value: []const u8) ![]const u8 {
69 const result = try self.hash_map.allocator.alloc(u8, value.len);65 return mem.dupe(self.hash_map.allocator, u8, value);
70 mem.copy(u8, result, value);
71 return result;
72 }66 }
73};67};
68
69test "BufMap" {
70 var direct_allocator = std.heap.DirectAllocator.init();
71 defer direct_allocator.deinit();
72
73 var bufmap = BufMap.init(&direct_allocator.allocator);
74 defer bufmap.deinit();
75
76 try bufmap.set("x", "1");
77 assert(mem.eql(u8, ??bufmap.get("x"), "1"));
78 assert(1 == bufmap.count());
79
80 try bufmap.set("x", "2");
81 assert(mem.eql(u8, ??bufmap.get("x"), "2"));
82 assert(1 == bufmap.count());
83
84 try bufmap.set("x", "3");
85 assert(mem.eql(u8, ??bufmap.get("x"), "3"));
86 assert(1 == bufmap.count());
87
88 bufmap.delete("x");
89 assert(0 == bufmap.count());
90}
std/build.zig+11
...@@ -1627,6 +1627,7 @@ pub const TestStep = struct {...@@ -1627,6 +1627,7 @@ pub const TestStep = struct {
1627 filter: ?[]const u8,1627 filter: ?[]const u8,
1628 target: Target,1628 target: Target,
1629 exec_cmd_args: ?[]const ?[]const u8,1629 exec_cmd_args: ?[]const ?[]const u8,
1630 include_dirs: ArrayList([]const u8),
16301631
1631 pub fn init(builder: &Builder, root_src: []const u8) TestStep {1632 pub fn init(builder: &Builder, root_src: []const u8) TestStep {
1632 const step_name = builder.fmt("test {}", root_src);1633 const step_name = builder.fmt("test {}", root_src);
...@@ -1641,6 +1642,7 @@ pub const TestStep = struct {...@@ -1641,6 +1642,7 @@ pub const TestStep = struct {
1641 .link_libs = BufSet.init(builder.allocator),1642 .link_libs = BufSet.init(builder.allocator),
1642 .target = Target { .Native = {} },1643 .target = Target { .Native = {} },
1643 .exec_cmd_args = null,1644 .exec_cmd_args = null,
1645 .include_dirs = ArrayList([]const u8).init(builder.allocator),
1644 };1646 };
1645 }1647 }
16461648
...@@ -1648,6 +1650,10 @@ pub const TestStep = struct {...@@ -1648,6 +1650,10 @@ pub const TestStep = struct {
1648 self.verbose = value;1650 self.verbose = value;
1649 }1651 }
16501652
1653 pub fn addIncludeDir(self: &TestStep, path: []const u8) void {
1654 self.include_dirs.append(path) catch unreachable;
1655 }
1656
1651 pub fn setBuildMode(self: &TestStep, mode: builtin.Mode) void {1657 pub fn setBuildMode(self: &TestStep, mode: builtin.Mode) void {
1652 self.build_mode = mode;1658 self.build_mode = mode;
1653 }1659 }
...@@ -1746,6 +1752,11 @@ pub const TestStep = struct {...@@ -1746,6 +1752,11 @@ pub const TestStep = struct {
1746 }1752 }
1747 }1753 }
17481754
1755 for (self.include_dirs.toSliceConst()) |include_path| {
1756 try zig_args.append("-isystem");
1757 try zig_args.append(builder.pathFromRoot(include_path));
1758 }
1759
1749 for (builder.include_paths.toSliceConst()) |include_path| {1760 for (builder.include_paths.toSliceConst()) |include_path| {
1750 try zig_args.append("-isystem");1761 try zig_args.append("-isystem");
1751 try zig_args.append(builder.pathFromRoot(include_path));1762 try zig_args.append(builder.pathFromRoot(include_path));
std/c/darwin.zig+18
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1extern "c" fn __error() &c_int;1extern "c" fn __error() &c_int;
2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
33
4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
45
5pub use @import("../os/darwin_errno.zig");6pub use @import("../os/darwin_errno.zig");
67
...@@ -45,3 +46,20 @@ pub const Sigaction = extern struct {...@@ -45,3 +46,20 @@ pub const Sigaction = extern struct {
45 sa_mask: sigset_t,46 sa_mask: sigset_t,
46 sa_flags: c_int,47 sa_flags: c_int,
47};48};
49
50pub const dirent = extern struct {
51 d_ino: usize,
52 d_seekoff: usize,
53 d_reclen: u16,
54 d_namlen: u16,
55 d_type: u8,
56 d_name: u8, // field address is address of first byte of name
57};
58
59pub const sockaddr = extern struct {
60 sa_len: u8,
61 sa_family: sa_family_t,
62 sa_data: [14]u8,
63};
64
65pub const sa_family_t = u8;
std/c/index.zig+1
...@@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o...@@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o
44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
47pub extern "c" fn rmdir(path: &const u8) c_int;
4748
48pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;49pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
49pub extern "c" fn malloc(usize) ?&c_void;50pub extern "c" fn malloc(usize) ?&c_void;
std/crypto/blake2.zig+20-2
...@@ -84,7 +84,7 @@ fn Blake2s(comptime out_len: usize) type { return struct {...@@ -84,7 +84,7 @@ fn Blake2s(comptime out_len: usize) type { return struct {
84 }84 }
8585
86 // Full middle blocks.86 // Full middle blocks.
87 while (off + 64 < b.len) : (off += 64) {87 while (off + 64 <= b.len) : (off += 64) {
88 d.t += 64;88 d.t += 64;
89 d.round(b[off..off + 64], false);89 d.round(b[off..off + 64], false);
90 }90 }
...@@ -229,6 +229,15 @@ test "blake2s256 streaming" {...@@ -229,6 +229,15 @@ test "blake2s256 streaming" {
229 htest.assertEqual(h2, out[0..]);229 htest.assertEqual(h2, out[0..]);
230}230}
231231
232test "blake2s256 aligned final" {
233 var block = []u8 {0} ** Blake2s256.block_size;
234 var out: [Blake2s256.digest_size]u8 = undefined;
235
236 var h = Blake2s256.init();
237 h.update(block);
238 h.final(out[0..]);
239}
240
232241
233/////////////////////242/////////////////////
234// Blake2b243// Blake2b
...@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {...@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {
305 }314 }
306315
307 // Full middle blocks.316 // Full middle blocks.
308 while (off + 128 < b.len) : (off += 128) {317 while (off + 128 <= b.len) : (off += 128) {
309 d.t += 128;318 d.t += 128;
310 d.round(b[off..off + 128], false);319 d.round(b[off..off + 128], false);
311 }320 }
...@@ -447,3 +456,12 @@ test "blake2b512 streaming" {...@@ -447,3 +456,12 @@ test "blake2b512 streaming" {
447 h.final(out[0..]);456 h.final(out[0..]);
448 htest.assertEqual(h2, out[0..]);457 htest.assertEqual(h2, out[0..]);
449}458}
459
460test "blake2b512 aligned final" {
461 var block = []u8 {0} ** Blake2b512.block_size;
462 var out: [Blake2b512.digest_size]u8 = undefined;
463
464 var h = Blake2b512.init();
465 h.update(block);
466 h.final(out[0..]);
467}
std/crypto/hmac.zig created+81
...@@ -0,0 +1,81 @@
1const std = @import("../index.zig");
2const crypto = std.crypto;
3const debug = std.debug;
4const mem = std.mem;
5
6pub const HmacMd5 = Hmac(crypto.Md5);
7pub const HmacSha1 = Hmac(crypto.Sha1);
8pub const HmacSha256 = Hmac(crypto.Sha256);
9
10pub fn Hmac(comptime H: type) type {
11 return struct {
12 const digest_size = H.digest_size;
13
14 pub fn hash(output: []u8, key: []const u8, message: []const u8) void {
15 debug.assert(output.len >= H.digest_size);
16 debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
17 var scratch: [H.block_size]u8 = undefined;
18
19 // Normalize key length to block size of hash
20 if (key.len > H.block_size) {
21 H.hash(key, scratch[0..H.digest_size]);
22 mem.set(u8, scratch[H.digest_size..H.block_size], 0);
23 } else if (key.len < H.block_size) {
24 mem.copy(u8, scratch[0..key.len], key);
25 mem.set(u8, scratch[key.len..H.block_size], 0);
26 } else {
27 mem.copy(u8, scratch[0..], key);
28 }
29
30 var o_key_pad: [H.block_size]u8 = undefined;
31 for (o_key_pad) |*b, i| {
32 *b = scratch[i] ^ 0x5c;
33 }
34
35 var i_key_pad: [H.block_size]u8 = undefined;
36 for (i_key_pad) |*b, i| {
37 *b = scratch[i] ^ 0x36;
38 }
39
40 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation
41 var hmac = H.init();
42 hmac.update(i_key_pad[0..]);
43 hmac.update(message);
44 hmac.final(scratch[0..H.digest_size]);
45
46 hmac.reset();
47 hmac.update(o_key_pad[0..]);
48 hmac.update(scratch[0..H.digest_size]);
49 hmac.final(output[0..H.digest_size]);
50 }
51 };
52}
53
54const htest = @import("test.zig");
55
56test "hmac md5" {
57 var out: [crypto.Md5.digest_size]u8 = undefined;
58 HmacMd5.hash(out[0..], "", "");
59 htest.assertEqual("74e6f7298a9c2d168935f58c001bad88", out[0..]);
60
61 HmacMd5.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");
62 htest.assertEqual("80070713463e7749b90c2dc24911e275", out[0..]);
63}
64
65test "hmac sha1" {
66 var out: [crypto.Sha1.digest_size]u8 = undefined;
67 HmacSha1.hash(out[0..], "", "");
68 htest.assertEqual("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", out[0..]);
69
70 HmacSha1.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");
71 htest.assertEqual("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", out[0..]);
72}
73
74test "hmac sha256" {
75 var out: [crypto.Sha256.digest_size]u8 = undefined;
76 HmacSha256.hash(out[0..], "", "");
77 htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);
78
79 HmacSha256.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");
80 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
81}
std/crypto/index.zig+6
...@@ -19,10 +19,16 @@ pub const Blake2s256 = blake2.Blake2s256;...@@ -19,10 +19,16 @@ pub const Blake2s256 = blake2.Blake2s256;
19pub const Blake2b384 = blake2.Blake2b384;19pub const Blake2b384 = blake2.Blake2b384;
20pub const Blake2b512 = blake2.Blake2b512;20pub const Blake2b512 = blake2.Blake2b512;
2121
22const hmac = @import("hmac.zig");
23pub const HmacMd5 = hmac.HmacMd5;
24pub const HmacSha1 = hmac.Sha1;
25pub const HmacSha256 = hmac.Sha256;
26
22test "crypto" {27test "crypto" {
23 _ = @import("md5.zig");28 _ = @import("md5.zig");
24 _ = @import("sha1.zig");29 _ = @import("sha1.zig");
25 _ = @import("sha2.zig");30 _ = @import("sha2.zig");
26 _ = @import("sha3.zig");31 _ = @import("sha3.zig");
27 _ = @import("blake2.zig");32 _ = @import("blake2.zig");
33 _ = @import("hmac.zig");
28}34}
std/crypto/md5.zig+10-1
...@@ -59,7 +59,7 @@ pub const Md5 = struct {...@@ -59,7 +59,7 @@ pub const Md5 = struct {
59 }59 }
6060
61 // Full middle blocks.61 // Full middle blocks.
62 while (off + 64 < b.len) : (off += 64) {62 while (off + 64 <= b.len) : (off += 64) {
63 d.round(b[off..off + 64]);63 d.round(b[off..off + 64]);
64 }64 }
6565
...@@ -253,3 +253,12 @@ test "md5 streaming" {...@@ -253,3 +253,12 @@ test "md5 streaming" {
253253
254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
255}255}
256
257test "md5 aligned final" {
258 var block = []u8 {0} ** Md5.block_size;
259 var out: [Md5.digest_size]u8 = undefined;
260
261 var h = Md5.init();
262 h.update(block);
263 h.final(out[0..]);
264}
std/crypto/sha1.zig+10-1
...@@ -60,7 +60,7 @@ pub const Sha1 = struct {...@@ -60,7 +60,7 @@ pub const Sha1 = struct {
60 }60 }
6161
62 // Full middle blocks.62 // Full middle blocks.
63 while (off + 64 < b.len) : (off += 64) {63 while (off + 64 <= b.len) : (off += 64) {
64 d.round(b[off..off + 64]);64 d.round(b[off..off + 64]);
65 }65 }
6666
...@@ -284,3 +284,12 @@ test "sha1 streaming" {...@@ -284,3 +284,12 @@ test "sha1 streaming" {
284 h.final(out[0..]);284 h.final(out[0..]);
285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
286}286}
287
288test "sha1 aligned final" {
289 var block = []u8 {0} ** Sha1.block_size;
290 var out: [Sha1.digest_size]u8 = undefined;
291
292 var h = Sha1.init();
293 h.update(block);
294 h.final(out[0..]);
295}
std/crypto/sha2.zig+20-2
...@@ -105,7 +105,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { return struct {...@@ -105,7 +105,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { return struct {
105 }105 }
106106
107 // Full middle blocks.107 // Full middle blocks.
108 while (off + 64 < b.len) : (off += 64) {108 while (off + 64 <= b.len) : (off += 64) {
109 d.round(b[off..off + 64]);109 d.round(b[off..off + 64]);
110 }110 }
111111
...@@ -319,6 +319,15 @@ test "sha256 streaming" {...@@ -319,6 +319,15 @@ test "sha256 streaming" {
319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
320}320}
321321
322test "sha256 aligned final" {
323 var block = []u8 {0} ** Sha256.block_size;
324 var out: [Sha256.digest_size]u8 = undefined;
325
326 var h = Sha256.init();
327 h.update(block);
328 h.final(out[0..]);
329}
330
322331
323/////////////////////332/////////////////////
324// Sha384 + Sha512333// Sha384 + Sha512
...@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {...@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {
420 }429 }
421430
422 // Full middle blocks.431 // Full middle blocks.
423 while (off + 128 < b.len) : (off += 128) {432 while (off + 128 <= b.len) : (off += 128) {
424 d.round(b[off..off + 128]);433 d.round(b[off..off + 128]);
425 }434 }
426435
...@@ -669,3 +678,12 @@ test "sha512 streaming" {...@@ -669,3 +678,12 @@ test "sha512 streaming" {
669 h.final(out[0..]);678 h.final(out[0..]);
670 htest.assertEqual(h2, out[0..]);679 htest.assertEqual(h2, out[0..]);
671}680}
681
682test "sha512 aligned final" {
683 var block = []u8 {0} ** Sha512.block_size;
684 var out: [Sha512.digest_size]u8 = undefined;
685
686 var h = Sha512.init();
687 h.update(block);
688 h.final(out[0..]);
689}
std/crypto/sha3.zig+18
...@@ -217,6 +217,15 @@ test "sha3-256 streaming" {...@@ -217,6 +217,15 @@ test "sha3-256 streaming" {
217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);
218}218}
219219
220test "sha3-256 aligned final" {
221 var block = []u8 {0} ** Sha3_256.block_size;
222 var out: [Sha3_256.digest_size]u8 = undefined;
223
224 var h = Sha3_256.init();
225 h.update(block);
226 h.final(out[0..]);
227}
228
220test "sha3-384 single" {229test "sha3-384 single" {
221 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";230 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
222 htest.assertEqualHash(Sha3_384, h1 , "");231 htest.assertEqualHash(Sha3_384, h1 , "");
...@@ -278,3 +287,12 @@ test "sha3-512 streaming" {...@@ -278,3 +287,12 @@ test "sha3-512 streaming" {
278 h.final(out[0..]);287 h.final(out[0..]);
279 htest.assertEqual(h2, out[0..]);288 htest.assertEqual(h2, out[0..]);
280}289}
290
291test "sha3-512 aligned final" {
292 var block = []u8 {0} ** Sha3_512.block_size;
293 var out: [Sha3_512.digest_size]u8 = undefined;
294
295 var h = Sha3_512.init();
296 h.update(block);
297 h.final(out[0..]);
298}
std/endian.zig deleted-25
...@@ -1,25 +0,0 @@
1const mem = @import("mem.zig");
2const builtin = @import("builtin");
3
4pub fn swapIfLe(comptime T: type, x: T) T {
5 return swapIf(builtin.Endian.Little, T, x);
6}
7
8pub fn swapIfBe(comptime T: type, x: T) T {
9 return swapIf(builtin.Endian.Big, T, x);
10}
11
12pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) T {
13 return if (builtin.endian == endian) swap(T, x) else x;
14}
15
16pub fn swap(comptime T: type, x: T) T {
17 var buf: [@sizeOf(T)]u8 = undefined;
18 mem.writeInt(buf[0..], x, builtin.Endian.Little);
19 return mem.readInt(buf, T, builtin.Endian.Big);
20}
21
22test "swap" {
23 const debug = @import("debug/index.zig");
24 debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE);
25}
std/event.zig created+235
...@@ -0,0 +1,235 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const event = this;
5const mem = std.mem;
6const posix = std.os.posix;
7
8pub const TcpServer = struct {
9 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
10
11 loop: &Loop,
12 sockfd: i32,
13 accept_coro: ?promise,
14 listen_address: std.net.Address,
15
16 waiting_for_emfile_node: PromiseNode,
17
18 const PromiseNode = std.LinkedList(promise).Node;
19
20 pub fn init(loop: &Loop) !TcpServer {
21 const sockfd = try std.os.posixSocket(posix.AF_INET,
22 posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
23 posix.PROTO_tcp);
24 errdefer std.os.close(sockfd);
25
26 // TODO can't initialize handler coroutine here because we need well defined copy elision
27 return TcpServer {
28 .loop = loop,
29 .sockfd = sockfd,
30 .accept_coro = null,
31 .handleRequestFn = undefined,
32 .waiting_for_emfile_node = undefined,
33 .listen_address = undefined,
34 };
35 }
36
37 pub fn listen(self: &TcpServer, address: &const std.net.Address,
38 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
39 {
40 self.handleRequestFn = handleRequestFn;
41
42 try std.os.posixBind(self.sockfd, &address.os_addr);
43 try std.os.posixListen(self.sockfd, posix.SOMAXCONN);
44 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
45
46 self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self);
47 errdefer cancel ??self.accept_coro;
48
49 try self.loop.addFd(self.sockfd, ??self.accept_coro);
50 errdefer self.loop.removeFd(self.sockfd);
51
52 }
53
54 pub fn deinit(self: &TcpServer) void {
55 self.loop.removeFd(self.sockfd);
56 if (self.accept_coro) |accept_coro| cancel accept_coro;
57 std.os.close(self.sockfd);
58 }
59
60 pub async fn handler(self: &TcpServer) void {
61 while (true) {
62 var accepted_addr: std.net.Address = undefined;
63 if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
64 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
65 {
66 var socket = std.os.File.openHandle(accepted_fd);
67 _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
68 error.OutOfMemory => {
69 socket.close();
70 continue;
71 },
72 };
73 } else |err| switch (err) {
74 error.WouldBlock => {
75 suspend; // we will get resumed by epoll_wait in the event loop
76 continue;
77 },
78 error.ProcessFdQuotaExceeded => {
79 errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
80 suspend |p| {
81 self.waiting_for_emfile_node = PromiseNode.init(p);
82 std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
83 }
84 continue;
85 },
86 error.ConnectionAborted,
87 error.FileDescriptorClosed => continue,
88
89 error.PageFault => unreachable,
90 error.InvalidSyscall => unreachable,
91 error.FileDescriptorNotASocket => unreachable,
92 error.OperationNotSupported => unreachable,
93
94 error.SystemFdQuotaExceeded,
95 error.SystemResources,
96 error.ProtocolFailure,
97 error.BlockedByFirewall,
98 error.Unexpected => {
99 @panic("TODO handle this error");
100 },
101 }
102 }
103 }
104};
105
106pub const Loop = struct {
107 allocator: &mem.Allocator,
108 epollfd: i32,
109 keep_running: bool,
110
111 fn init(allocator: &mem.Allocator) !Loop {
112 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
113 return Loop {
114 .keep_running = true,
115 .allocator = allocator,
116 .epollfd = epollfd,
117 };
118 }
119
120 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
121 var ev = std.os.linux.epoll_event {
122 .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,
123 .data = std.os.linux.epoll_data {
124 .ptr = @ptrToInt(prom),
125 },
126 };
127 try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
128 }
129
130 pub fn removeFd(self: &Loop, fd: i32) void {
131 std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
132 }
133
134 async fn waitFd(self: &Loop, fd: i32) !void {
135 defer self.removeFd(fd);
136 suspend |p| {
137 try self.addFd(fd, p);
138 }
139 }
140
141 pub fn stop(self: &Loop) void {
142 // TODO make atomic
143 self.keep_running = false;
144 // TODO activate an fd in the epoll set
145 }
146
147 pub fn run(self: &Loop) void {
148 while (self.keep_running) {
149 var events: [16]std.os.linux.epoll_event = undefined;
150 const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1);
151 for (events[0..count]) |ev| {
152 const p = @intToPtr(promise, ev.data.ptr);
153 resume p;
154 }
155 }
156 }
157};
158
159pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
160 var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733
161
162 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);
163 errdefer std.os.close(sockfd);
164
165 try std.os.posixConnectAsync(sockfd, &address.os_addr);
166 try await try async loop.waitFd(sockfd);
167 try std.os.posixGetSockOptConnectError(sockfd);
168
169 return std.os.File.openHandle(sockfd);
170}
171
172test "listen on a port, send bytes, receive bytes" {
173 if (builtin.os != builtin.Os.linux) {
174 // TODO build abstractions for other operating systems
175 return;
176 }
177 const MyServer = struct {
178 tcp_server: TcpServer,
179
180 const Self = this;
181
182 async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,
183 _socket: &const std.os.File) void
184 {
185 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
186 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
187 defer socket.close();
188 const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
189 error.OutOfMemory => @panic("unable to handle connection: out of memory"),
190 };
191 (await next_handler) catch |err| {
192 std.debug.panic("unable to handle connection: {}\n", err);
193 };
194 suspend |p| { cancel p; }
195 }
196
197 async fn errorableHandler(self: &Self, _addr: &const std.net.Address,
198 _socket: &const std.os.File) !void
199 {
200 const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
201 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
202
203 var adapter = std.io.FileOutStream.init(&socket);
204 var stream = &adapter.stream;
205 try stream.print("hello from server\n");
206 }
207 };
208
209 const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable;
210 const addr = std.net.Address.initIp4(ip4addr, 0);
211
212 var loop = try Loop.init(std.debug.global_allocator);
213 var server = MyServer {
214 .tcp_server = try TcpServer.init(&loop),
215 };
216 defer server.tcp_server.deinit();
217 try server.tcp_server.listen(addr, MyServer.handler);
218
219 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address);
220 defer cancel p;
221 loop.run();
222}
223
224async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void {
225 errdefer @panic("test failure");
226
227 var socket_file = try await try async event.connect(loop, address);
228 defer socket_file.close();
229
230 var buf: [512]u8 = undefined;
231 const amt_read = try socket_file.read(buf[0..]);
232 const msg = buf[0..amt_read];
233 assert(mem.eql(u8, msg, "hello from server\n"));
234 loop.stop();
235}
std/fmt/index.zig+1-1
...@@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned...@@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
465 return x;465 return x;
466}466}
467467
468fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {468pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
469 const value = switch (c) {469 const value = switch (c) {
470 '0' ... '9' => c - '0',470 '0' ... '9' => c - '0',
471 'A' ... 'Z' => c - 'A' + 10,471 'A' ... 'Z' => c - 'A' + 10,
std/hash/adler.zig created+112
...@@ -0,0 +1,112 @@
1// Adler32 checksum.
2//
3// https://tools.ietf.org/html/rfc1950#section-9
4// https://github.com/madler/zlib/blob/master/adler32.c
5
6const std = @import("../index.zig");
7const debug = std.debug;
8
9pub const Adler32 = struct {
10 const base = 65521;
11 const nmax = 5552;
12
13 adler: u32,
14
15 pub fn init() Adler32 {
16 return Adler32 {
17 .adler = 1,
18 };
19 }
20
21 // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
22 // buffer inputs and should be much quicker.
23 pub fn update(self: &Adler32, input: []const u8) void {
24 var s1 = self.adler & 0xffff;
25 var s2 = (self.adler >> 16) & 0xffff;
26
27 if (input.len == 1) {
28 s1 +%= input[0];
29 if (s1 >= base) {
30 s1 -= base;
31 }
32 s2 +%= s1;
33 if (s2 >= base) {
34 s2 -= base;
35 }
36 }
37 else if (input.len < 16) {
38 for (input) |b| {
39 s1 +%= b;
40 s2 +%= s1;
41 }
42 if (s1 >= base) {
43 s1 -= base;
44 }
45
46 s2 %= base;
47 }
48 else {
49 var i: usize = 0;
50 while (i + nmax <= input.len) : (i += nmax) {
51 const n = nmax / 16; // note: 16 | nmax
52
53 var rounds: usize = 0;
54 while (rounds < n) : (rounds += 1) {
55 comptime var j: usize = 0;
56 inline while (j < 16) : (j += 1) {
57 s1 +%= input[i + n * j];
58 s2 +%= s1;
59 }
60 }
61 }
62
63 if (i < input.len) {
64 while (i + 16 <= input.len) : (i += 16) {
65 comptime var j: usize = 0;
66 inline while (j < 16) : (j += 1) {
67 s1 +%= input[i + j];
68 s2 +%= s1;
69 }
70 }
71 while (i < input.len) : (i += 1) {
72 s1 +%= input[i];
73 s2 +%= s1;
74 }
75
76 s1 %= base;
77 s2 %= base;
78 }
79 }
80
81 self.adler = s1 | (s2 << 16);
82 }
83
84 pub fn final(self: &Adler32) u32 {
85 return self.adler;
86 }
87
88 pub fn hash(input: []const u8) u32 {
89 var c = Adler32.init();
90 c.update(input);
91 return c.final();
92 }
93};
94
95test "adler32 sanity" {
96 debug.assert(Adler32.hash("a") == 0x620062);
97 debug.assert(Adler32.hash("example") == 0xbc002ed);
98}
99
100test "adler32 long" {
101 const long1 = []u8 {1} ** 1024;
102 debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
103
104 const long2 = []u8 {1} ** 1025;
105 debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
106}
107
108test "adler32 very long" {
109 const long = []u8 {1} ** 5553;
110 debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
111}
112
std/hash/crc.zig created+180
...@@ -0,0 +1,180 @@
1// There are two implementations of CRC32 implemented with the following key characteristics:
2//
3// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
4//
5// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
6// still moderately fast just slow relative to the slicing approach.
7
8const std = @import("../index.zig");
9const debug = std.debug;
10
11pub const Polynomial = struct {
12 const IEEE = 0xedb88320;
13 const Castagnoli = 0x82f63b78;
14 const Koopman = 0xeb31d82e;
15};
16
17// IEEE is by far the most common CRC and so is aliased by default.
18pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);
19
20// slicing-by-8 crc32 implementation.
21pub fn Crc32WithPoly(comptime poly: u32) type {
22 return struct {
23 const Self = this;
24 const lookup_tables = comptime block: {
25 @setEvalBranchQuota(20000);
26 var tables: [8][256]u32 = undefined;
27
28 for (tables[0]) |*e, i| {
29 var crc = u32(i);
30 var j: usize = 0; while (j < 8) : (j += 1) {
31 if (crc & 1 == 1) {
32 crc = (crc >> 1) ^ poly;
33 } else {
34 crc = (crc >> 1);
35 }
36 }
37 *e = crc;
38 }
39
40 var i: usize = 0;
41 while (i < 256) : (i += 1) {
42 var crc = tables[0][i];
43 var j: usize = 1; while (j < 8) : (j += 1) {
44 const index = @truncate(u8, crc);
45 crc = tables[0][index] ^ (crc >> 8);
46 tables[j][i] = crc;
47 }
48 }
49
50 break :block tables;
51 };
52
53 crc: u32,
54
55 pub fn init() Self {
56 return Self {
57 .crc = 0xffffffff,
58 };
59 }
60
61 pub fn update(self: &Self, input: []const u8) void {
62 var i: usize = 0;
63 while (i + 8 <= input.len) : (i += 8) {
64 const p = input[i..i+8];
65
66 // Unrolling this way gives ~50Mb/s increase
67 self.crc ^= (u32(p[0]) << 0);
68 self.crc ^= (u32(p[1]) << 8);
69 self.crc ^= (u32(p[2]) << 16);
70 self.crc ^= (u32(p[3]) << 24);
71
72 self.crc =
73 lookup_tables[0][p[7]] ^
74 lookup_tables[1][p[6]] ^
75 lookup_tables[2][p[5]] ^
76 lookup_tables[3][p[4]] ^
77 lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
78 lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
79 lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
80 lookup_tables[7][@truncate(u8, self.crc >> 0)];
81 }
82
83 while (i < input.len) : (i += 1) {
84 const index = @truncate(u8, self.crc) ^ input[i];
85 self.crc = (self.crc >> 8) ^ lookup_tables[0][index];
86 }
87 }
88
89 pub fn final(self: &Self) u32 {
90 return ~self.crc;
91 }
92
93 pub fn hash(input: []const u8) u32 {
94 var c = Self.init();
95 c.update(input);
96 return c.final();
97 }
98 };
99}
100
101test "crc32 ieee" {
102 const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);
103
104 debug.assert(Crc32Ieee.hash("") == 0x00000000);
105 debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
106 debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
107}
108
109test "crc32 castagnoli" {
110 const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);
111
112 debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
113 debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
114 debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
115}
116
117// half-byte lookup table implementation.
118pub fn Crc32SmallWithPoly(comptime poly: u32) type {
119 return struct {
120 const Self = this;
121 const lookup_table = comptime block: {
122 var table: [16]u32 = undefined;
123
124 for (table) |*e, i| {
125 var crc = u32(i * 16);
126 var j: usize = 0; while (j < 8) : (j += 1) {
127 if (crc & 1 == 1) {
128 crc = (crc >> 1) ^ poly;
129 } else {
130 crc = (crc >> 1);
131 }
132 }
133 *e = crc;
134 }
135
136 break :block table;
137 };
138
139 crc: u32,
140
141 pub fn init() Self {
142 return Self {
143 .crc = 0xffffffff,
144 };
145 }
146
147 pub fn update(self: &Self, input: []const u8) void {
148 for (input) |b| {
149 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 0))] ^ (self.crc >> 4);
150 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 4))] ^ (self.crc >> 4);
151 }
152 }
153
154 pub fn final(self: &Self) u32 {
155 return ~self.crc;
156 }
157
158 pub fn hash(input: []const u8) u32 {
159 var c = Self.init();
160 c.update(input);
161 return c.final();
162 }
163 };
164}
165
166test "small crc32 ieee" {
167 const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);
168
169 debug.assert(Crc32Ieee.hash("") == 0x00000000);
170 debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
171 debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
172}
173
174test "small crc32 castagnoli" {
175 const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);
176
177 debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
178 debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
179 debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
180}
std/hash/fnv.zig created+60
...@@ -0,0 +1,60 @@
1// FNV1a - Fowler-Noll-Vo hash function
2//
3// FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties.
4//
5// https://tools.ietf.org/html/draft-eastlake-fnv-14
6
7const std = @import("../index.zig");
8const debug = std.debug;
9
10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5);
11pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
12pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d);
13
14fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
15 return struct {
16 const Self = this;
17
18 value: T,
19
20 pub fn init() Self {
21 return Self {
22 .value = offset,
23 };
24 }
25
26 pub fn update(self: &Self, input: []const u8) void {
27 for (input) |b| {
28 self.value ^= b;
29 self.value *%= prime;
30 }
31 }
32
33 pub fn final(self: &Self) T {
34 return self.value;
35 }
36
37 pub fn hash(input: []const u8) T {
38 var c = Self.init();
39 c.update(input);
40 return c.final();
41 }
42 };
43}
44
45test "fnv1a-32" {
46 debug.assert(Fnv1a_32.hash("") == 0x811c9dc5);
47 debug.assert(Fnv1a_32.hash("a") == 0xe40c292c);
48 debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968);
49}
50
51test "fnv1a-64" {
52 debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325);
53 debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c);
54 debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8);
55}
56
57test "fnv1a-128" {
58 debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d);
59 debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964);
60}
std/hash/index.zig created+22
...@@ -0,0 +1,22 @@
1const adler = @import("adler.zig");
2pub const Adler32 = adler.Adler32;
3
4// pub for polynomials + generic crc32 construction
5pub const crc = @import("crc.zig");
6pub const Crc32 = crc.Crc32;
7
8const fnv = @import("fnv.zig");
9pub const Fnv1a_32 = fnv.Fnv1a_32;
10pub const Fnv1a_64 = fnv.Fnv1a_64;
11pub const Fnv1a_128 = fnv.Fnv1a_128;
12
13const siphash = @import("siphash.zig");
14pub const SipHash64 = siphash.SipHash64;
15pub const SipHash128 = siphash.SipHash128;
16
17test "hash" {
18 _ = @import("adler.zig");
19 _ = @import("crc.zig");
20 _ = @import("fnv.zig");
21 _ = @import("siphash.zig");
22}
std/hash/siphash.zig created+320
...@@ -0,0 +1,320 @@
1// Siphash
2//
3// SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance
4// against hash flooding DoS attacks.
5//
6// https://131002.net/siphash/
7
8const std = @import("../index.zig");
9const debug = std.debug;
10const math = std.math;
11const mem = std.mem;
12
13const Endian = @import("builtin").Endian;
14
15pub fn SipHash64(comptime c_rounds: usize, comptime d_rounds: usize) type {
16 return SipHash(u64, c_rounds, d_rounds);
17}
18
19pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type {
20 return SipHash(u128, c_rounds, d_rounds);
21}
22
23fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type {
24 debug.assert(T == u64 or T == u128);
25 debug.assert(c_rounds > 0 and d_rounds > 0);
26
27 return struct {
28 const Self = this;
29 const digest_size = 64;
30 const block_size = 64;
31
32 v0: u64,
33 v1: u64,
34 v2: u64,
35 v3: u64,
36
37 // streaming cache
38 buf: [8]u8,
39 buf_len: usize,
40 msg_len: u8,
41
42 pub fn init(key: []const u8) Self {
43 debug.assert(key.len >= 16);
44
45 const k0 = mem.readInt(key[0..8], u64, Endian.Little);
46 const k1 = mem.readInt(key[8..16], u64, Endian.Little);
47
48 var d = Self {
49 .v0 = k0 ^ 0x736f6d6570736575,
50 .v1 = k1 ^ 0x646f72616e646f6d,
51 .v2 = k0 ^ 0x6c7967656e657261,
52 .v3 = k1 ^ 0x7465646279746573,
53
54 .buf = undefined,
55 .buf_len = 0,
56 .msg_len = 0,
57 };
58
59 if (T == u128) {
60 d.v1 ^= 0xee;
61 }
62
63 return d;
64 }
65
66 pub fn update(d: &Self, b: []const u8) void {
67 var off: usize = 0;
68
69 // Partial from previous.
70 if (d.buf_len != 0 and d.buf_len + b.len > 8) {
71 off += 8 - d.buf_len;
72 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
73 d.round(d.buf[0..]);
74 d.buf_len = 0;
75 }
76
77 // Full middle blocks.
78 while (off + 8 <= b.len) : (off += 8) {
79 d.round(b[off..off + 8]);
80 }
81
82 // Remainder for next pass.
83 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
84 d.buf_len += u8(b[off..].len);
85 d.msg_len +%= @truncate(u8, b.len);
86 }
87
88 pub fn final(d: &Self) T {
89 // Padding
90 mem.set(u8, d.buf[d.buf_len..], 0);
91 d.buf[7] = d.msg_len;
92 d.round(d.buf[0..]);
93
94 if (T == u128) {
95 d.v2 ^= 0xee;
96 } else {
97 d.v2 ^= 0xff;
98 }
99
100 comptime var i: usize = 0;
101 inline while (i < d_rounds) : (i += 1) {
102 @inlineCall(sipRound, d);
103 }
104
105 const b1 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3;
106 if (T == u64) {
107 return b1;
108 }
109
110 d.v1 ^= 0xdd;
111
112 comptime var j: usize = 0;
113 inline while (j < d_rounds) : (j += 1) {
114 @inlineCall(sipRound, d);
115 }
116
117 const b2 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3;
118 return (u128(b2) << 64) | b1;
119 }
120
121 fn round(d: &Self, b: []const u8) void {
122 debug.assert(b.len == 8);
123
124 const m = mem.readInt(b[0..], u64, Endian.Little);
125 d.v3 ^= m;
126
127 comptime var i: usize = 0;
128 inline while (i < c_rounds) : (i += 1) {
129 @inlineCall(sipRound, d);
130 }
131
132 d.v0 ^= m;
133 }
134
135 fn sipRound(d: &Self) void {
136 d.v0 +%= d.v1;
137 d.v1 = math.rotl(u64, d.v1, u64(13));
138 d.v1 ^= d.v0;
139 d.v0 = math.rotl(u64, d.v0, u64(32));
140 d.v2 +%= d.v3;
141 d.v3 = math.rotl(u64, d.v3, u64(16));
142 d.v3 ^= d.v2;
143 d.v0 +%= d.v3;
144 d.v3 = math.rotl(u64, d.v3, u64(21));
145 d.v3 ^= d.v0;
146 d.v2 +%= d.v1;
147 d.v1 = math.rotl(u64, d.v1, u64(17));
148 d.v1 ^= d.v2;
149 d.v2 = math.rotl(u64, d.v2, u64(32));
150 }
151
152 pub fn hash(key: []const u8, input: []const u8) T {
153 var c = Self.init(key);
154 c.update(input);
155 return c.final();
156 }
157 };
158}
159
160// Test vectors from reference implementation.
161// https://github.com/veorq/SipHash/blob/master/vectors.h
162const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
163
164test "siphash64-2-4 sanity" {
165 const vectors = [][]const u8 {
166 "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
167 "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
168 "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
169 "\x2d\x7e\xfb\xd7\x96\x66\x67\x85",
170 "\xb7\x87\x71\x27\xe0\x94\x27\xcf",
171 "\x8d\xa6\x99\xcd\x64\x55\x76\x18",
172 "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb",
173 "\x37\xd1\x01\x8b\xf5\x00\x02\xab",
174 "\x62\x24\x93\x9a\x79\xf5\xf5\x93",
175 "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e",
176 "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a",
177 "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4",
178 "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75",
179 "\x90\x3d\x84\xc0\x27\x56\xea\x14",
180 "\xee\xf2\x7a\x8e\x90\xca\x23\xf7",
181 "\xe5\x45\xbe\x49\x61\xca\x29\xa1",
182 "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f",
183 "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69",
184 "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b",
185 "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb",
186 "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe",
187 "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0",
188 "\x88\x3e\xa3\xe3\x95\x67\x53\x93",
189 "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8",
190 "\x94\xaf\x49\xf6\xc6\x50\xad\xb8",
191 "\xea\xb8\x85\x8a\xde\x92\xe1\xbc",
192 "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17",
193 "\xad\xcf\x6b\x07\x63\x61\x2e\x2f",
194 "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde",
195 "\x71\x65\x95\x87\x66\x50\xa2\xa6",
196 "\x28\xef\x49\x5c\x53\xa3\x87\xad",
197 "\x42\xc3\x41\xd8\xfa\x92\xd8\x32",
198 "\xce\x7c\xf2\x72\x2f\x51\x27\x71",
199 "\xe3\x78\x59\xf9\x46\x23\xf3\xa7",
200 "\x38\x12\x05\xbb\x1a\xb0\xe0\x12",
201 "\xae\x97\xa1\x0f\xd4\x34\xe0\x15",
202 "\xb4\xa3\x15\x08\xbe\xff\x4d\x31",
203 "\x81\x39\x62\x29\xf0\x90\x79\x02",
204 "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca",
205 "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a",
206 "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e",
207 "\x92\x59\x58\xfc\xd6\x42\x0c\xad",
208 "\xa9\x15\xc2\x9b\xc8\x06\x73\x18",
209 "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4",
210 "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9",
211 "\x87\x57\x75\x19\x04\x8f\x53\xa9",
212 "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb",
213 "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0",
214 "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6",
215 "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7",
216 "\x72\xfe\x52\x97\x5a\x43\x64\xee",
217 "\x5a\x16\x45\xb2\x76\xd5\x92\xa1",
218 "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a",
219 "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81",
220 "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f",
221 "\x99\x24\xa4\x3c\xc1\x31\x57\x24",
222 "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7",
223 "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea",
224 "\x13\x50\x79\xa3\x23\x1c\xe6\x60",
225 "\x93\x2b\x28\x46\xe4\xd7\x06\x66",
226 "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c",
227 "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f",
228 "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5",
229 "\x72\x45\x06\xeb\x4c\x32\x8a\x95",
230 };
231
232 const siphash = SipHash64(2, 4);
233
234 var buffer: [64]u8 = undefined;
235 for (vectors) |vector, i| {
236 buffer[i] = u8(i);
237
238 const expected = mem.readInt(vector, u64, Endian.Little);
239 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
240 }
241}
242
243test "siphash128-2-4 sanity" {
244 const vectors = [][]const u8 {
245 "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
246 "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
247 "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
248 "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51",
249 "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79",
250 "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27",
251 "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e",
252 "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39",
253 "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4",
254 "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed",
255 "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba",
256 "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18",
257 "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25",
258 "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7",
259 "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02",
260 "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9",
261 "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77",
262 "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40",
263 "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23",
264 "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1",
265 "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb",
266 "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12",
267 "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae",
268 "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c",
269 "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad",
270 "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f",
271 "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66",
272 "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94",
273 "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4",
274 "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7",
275 "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87",
276 "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35",
277 "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68",
278 "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf",
279 "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde",
280 "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8",
281 "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11",
282 "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b",
283 "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5",
284 "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9",
285 "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8",
286 "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb",
287 "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b",
288 "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89",
289 "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42",
290 "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c",
291 "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02",
292 "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b",
293 "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16",
294 "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03",
295 "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f",
296 "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38",
297 "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c",
298 "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e",
299 "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87",
300 "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda",
301 "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36",
302 "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e",
303 "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d",
304 "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59",
305 "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40",
306 "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a",
307 "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd",
308 "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c",
309 };
310
311 const siphash = SipHash128(2, 4);
312
313 var buffer: [64]u8 = undefined;
314 for (vectors) |vector, i| {
315 buffer[i] = u8(i);
316
317 const expected = mem.readInt(vector, u128, Endian.Little);
318 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
319 }
320}
std/hash_map.zig+5-1
...@@ -114,6 +114,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -114,6 +114,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
114 }114 }
115115
116 pub fn remove(hm: &Self, key: K) ?&Entry {116 pub fn remove(hm: &Self, key: K) ?&Entry {
117 if (hm.entries.len == 0) return null;
117 hm.incrementModificationCount();118 hm.incrementModificationCount();
118 const start_index = hm.keyToIndex(key);119 const start_index = hm.keyToIndex(key);
119 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {120 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
...@@ -236,7 +237,10 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -236,7 +237,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
236}237}
237238
238test "basic hash map usage" {239test "basic hash map usage" {
239 var map = HashMap(i32, i32, hash_i32, eql_i32).init(debug.global_allocator);240 var direct_allocator = std.heap.DirectAllocator.init();
241 defer direct_allocator.deinit();
242
243 var map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
240 defer map.deinit();244 defer map.deinit();
241245
242 assert((map.put(1, 11) catch unreachable) == null);246 assert((map.put(1, 11) catch unreachable) == null);
std/index.zig+7-5
...@@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig");...@@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig");
17pub const dwarf = @import("dwarf.zig");17pub const dwarf = @import("dwarf.zig");
18pub const elf = @import("elf.zig");18pub const elf = @import("elf.zig");
19pub const empty_import = @import("empty.zig");19pub const empty_import = @import("empty.zig");
20pub const endian = @import("endian.zig");20pub const event = @import("event.zig");
21pub const fmt = @import("fmt/index.zig");21pub const fmt = @import("fmt/index.zig");
22pub const hash = @import("hash/index.zig");
22pub const heap = @import("heap.zig");23pub const heap = @import("heap.zig");
23pub const io = @import("io.zig");24pub const io = @import("io.zig");
24pub const macho = @import("macho.zig");25pub const macho = @import("macho.zig");
...@@ -26,7 +27,7 @@ pub const math = @import("math/index.zig");...@@ -26,7 +27,7 @@ pub const math = @import("math/index.zig");
26pub const mem = @import("mem.zig");27pub const mem = @import("mem.zig");
27pub const net = @import("net.zig");28pub const net = @import("net.zig");
28pub const os = @import("os/index.zig");29pub const os = @import("os/index.zig");
29pub const rand = @import("rand.zig");30pub const rand = @import("rand/index.zig");
30pub const sort = @import("sort.zig");31pub const sort = @import("sort.zig");
31pub const unicode = @import("unicode.zig");32pub const unicode = @import("unicode.zig");
32pub const zig = @import("zig/index.zig");33pub const zig = @import("zig/index.zig");
...@@ -49,16 +50,17 @@ test "std" {...@@ -49,16 +50,17 @@ test "std" {
49 _ = @import("dwarf.zig");50 _ = @import("dwarf.zig");
50 _ = @import("elf.zig");51 _ = @import("elf.zig");
51 _ = @import("empty.zig");52 _ = @import("empty.zig");
52 _ = @import("endian.zig");53 _ = @import("event.zig");
53 _ = @import("fmt/index.zig");54 _ = @import("fmt/index.zig");
55 _ = @import("hash/index.zig");
54 _ = @import("io.zig");56 _ = @import("io.zig");
55 _ = @import("macho.zig");57 _ = @import("macho.zig");
56 _ = @import("math/index.zig");58 _ = @import("math/index.zig");
57 _ = @import("mem.zig");59 _ = @import("mem.zig");
58 _ = @import("heap.zig");
59 _ = @import("net.zig");60 _ = @import("net.zig");
61 _ = @import("heap.zig");
60 _ = @import("os/index.zig");62 _ = @import("os/index.zig");
61 _ = @import("rand.zig");63 _ = @import("rand/index.zig");
62 _ = @import("sort.zig");64 _ = @import("sort.zig");
63 _ = @import("unicode.zig");65 _ = @import("unicode.zig");
64 _ = @import("zig/index.zig");66 _ = @import("zig/index.zig");
std/io.zig+26-4
...@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {
144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
145 /// read from the stream so far are lost.145 /// read from the stream so far are lost.
146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
147 try buf.resize(0);147 try buffer.resize(0);
148148
149 while (true) {149 while (true) {
150 var byte: u8 = try self.readByte();150 var byte: u8 = try self.readByte();
...@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {...@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {
153 return;153 return;
154 }154 }
155155
156 if (buf.len() == max_size) {156 if (buffer.len() == max_size) {
157 return error.StreamTooLong;157 return error.StreamTooLong;
158 }158 }
159159
160 try buf.appendByte(byte);160 try buffer.appendByte(byte);
161 }161 }
162 }162 }
163163
...@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {
171 var buf = Buffer.initNull(allocator);171 var buf = Buffer.initNull(allocator);
172 defer buf.deinit();172 defer buf.deinit();
173173
174 try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);174 try self.readUntilDelimiterBuffer(&buf, delimiter, max_size);
175 return buf.toOwnedSlice();175 return buf.toOwnedSlice();
176 }176 }
177177
...@@ -478,3 +478,25 @@ test "import io tests" {...@@ -478,3 +478,25 @@ test "import io tests" {
478 }478 }
479}479}
480480
481pub fn readLine(buf: []u8) !usize {
482 var stdin = getStdIn() catch return error.StdInUnavailable;
483 var adapter = FileInStream.init(&stdin);
484 var stream = &adapter.stream;
485 var index: usize = 0;
486 while (true) {
487 const byte = stream.readByte() catch return error.EndOfFile;
488 switch (byte) {
489 '\r' => {
490 // trash the following \n
491 _ = stream.readByte() catch return error.EndOfFile;
492 return index;
493 },
494 '\n' => return index,
495 else => {
496 if (index == buf.len) return error.InputTooLong;
497 buf[index] = byte;
498 index += 1;
499 },
500 }
501 }
502}
std/io_test.zig+3-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const io = std.io;2const io = std.io;
3const allocator = std.debug.global_allocator;3const allocator = std.debug.global_allocator;
4const Rand = std.rand.Rand;4const DefaultPrng = std.rand.DefaultPrng;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const mem = std.mem;6const mem = std.mem;
7const os = std.os;7const os = std.os;
...@@ -9,8 +9,8 @@ const builtin = @import("builtin");...@@ -9,8 +9,8 @@ const builtin = @import("builtin");
99
10test "write a file, read it, then delete it" {10test "write a file, read it, then delete it" {
11 var data: [1024]u8 = undefined;11 var data: [1024]u8 = undefined;
12 var rng = Rand.init(1234);12 var prng = DefaultPrng.init(1234);
13 rng.fillBytes(data[0..]);13 prng.random.bytes(data[0..]);
14 const tmp_file_name = "temp_test_file.txt";14 const tmp_file_name = "temp_test_file.txt";
15 {15 {
16 var file = try os.File.openWrite(allocator, tmp_file_name);16 var file = try os.File.openWrite(allocator, tmp_file_name);
std/linked_list.zig+1
...@@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
161 }161 }
162162
163 list.len -= 1;163 list.len -= 1;
164 assert(list.len == 0 or (list.first != null and list.last != null));
164 }165 }
165166
166 /// Remove and return the last node in the list.167 /// Remove and return the last node in the list.
std/math/atan2.zig+1-1
...@@ -22,7 +22,7 @@ const std = @import("../index.zig");...@@ -22,7 +22,7 @@ const std = @import("../index.zig");
22const math = std.math;22const math = std.math;
23const assert = std.debug.assert;23const assert = std.debug.assert;
2424
25fn atan2(comptime T: type, x: T, y: T) T {25pub fn atan2(comptime T: type, x: T, y: T) T {
26 return switch (T) {26 return switch (T) {
27 f32 => atan2_32(x, y),27 f32 => atan2_32(x, y),
28 f64 => atan2_64(x, y),28 f64 => atan2_64(x, y),
std/math/index.zig+15-2
...@@ -515,15 +515,28 @@ test "math.negateCast" {...@@ -515,15 +515,28 @@ test "math.negateCast" {
515515
516/// Cast an integer to a different integer type. If the value doesn't fit, 516/// Cast an integer to a different integer type. If the value doesn't fit,
517/// return an error.517/// return an error.
518pub fn cast(comptime T: type, x: var) !T {518pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
519 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer519 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
520 if (x > @maxValue(T)) {520 comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Int); // must pass an integer
521 if (@maxValue(@typeOf(x)) > @maxValue(T) and x > @maxValue(T)) {
522 return error.Overflow;
523 } else if (@minValue(@typeOf(x)) < @minValue(T) and x < @minValue(T)) {
521 return error.Overflow;524 return error.Overflow;
522 } else {525 } else {
523 return T(x);526 return T(x);
524 }527 }
525}528}
526529
530test "math.cast" {
531 if (cast(u8, u32(300))) |_| @panic("fail") else |err| assert(err == error.Overflow);
532 if (cast(i8, i32(-200))) |_| @panic("fail") else |err| assert(err == error.Overflow);
533 if (cast(u8, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow);
534 if (cast(u64, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow);
535
536 assert((try cast(u8, u32(255))) == u8(255));
537 assert(@typeOf(try cast(u8, u32(255))) == u8);
538}
539
527pub fn floorPowerOfTwo(comptime T: type, value: T) T {540pub fn floorPowerOfTwo(comptime T: type, value: T) T {
528 var x = value;541 var x = value;
529542
std/mem.zig+26
...@@ -3,6 +3,7 @@ const debug = std.debug;...@@ -3,6 +3,7 @@ const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const math = std.math;4const math = std.math;
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const mem = this;
67
7pub const Allocator = struct {8pub const Allocator = struct {
8 const Error = error {OutOfMemory};9 const Error = error {OutOfMemory};
...@@ -550,3 +551,28 @@ test "std.mem.rotate" {...@@ -550,3 +551,28 @@ test "std.mem.rotate" {
550551
551 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));552 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
552}553}
554
555// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
556// endian-casting the pointer and then dereferencing
557
558pub fn endianSwapIfLe(comptime T: type, x: T) T {
559 return endianSwapIf(builtin.Endian.Little, T, x);
560}
561
562pub fn endianSwapIfBe(comptime T: type, x: T) T {
563 return endianSwapIf(builtin.Endian.Big, T, x);
564}
565
566pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T {
567 return if (builtin.endian == endian) endianSwap(T, x) else x;
568}
569
570pub fn endianSwap(comptime T: type, x: T) T {
571 var buf: [@sizeOf(T)]u8 = undefined;
572 mem.writeInt(buf[0..], x, builtin.Endian.Little);
573 return mem.readInt(buf, T, builtin.Endian.Big);
574}
575
576test "std.mem.endianSwap" {
577 assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
578}
std/net.zig+121-162
...@@ -1,143 +1,120 @@...@@ -1,143 +1,120 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const linux = std.os.linux;2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const endian = std.endian;4const net = this;
5const posix = std.os.posix;
6const mem = std.mem;
57
6// TODO don't trust this file, it bit rotted. start over8pub const TmpWinAddr = struct {
79 family: u8,
8const Connection = struct {10 data: [14]u8,
9 socket_fd: i32,
10
11 pub fn send(c: Connection, buf: []const u8) !usize {
12 const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
13 const send_err = linux.getErrno(send_ret);
14 switch (send_err) {
15 0 => return send_ret,
16 linux.EINVAL => unreachable,
17 linux.EFAULT => unreachable,
18 linux.ECONNRESET => return error.ConnectionReset,
19 linux.EINTR => return error.SigInterrupt,
20 // TODO there are more possible errors
21 else => return error.Unexpected,
22 }
23 }
24
25 pub fn recv(c: Connection, buf: []u8) ![]u8 {
26 const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
27 const recv_err = linux.getErrno(recv_ret);
28 switch (recv_err) {
29 0 => return buf[0..recv_ret],
30 linux.EINVAL => unreachable,
31 linux.EFAULT => unreachable,
32 linux.ENOTSOCK => return error.NotSocket,
33 linux.EINTR => return error.SigInterrupt,
34 linux.ENOMEM => return error.OutOfMemory,
35 linux.ECONNREFUSED => return error.ConnectionRefused,
36 linux.EBADF => return error.BadFd,
37 // TODO more error values
38 else => return error.Unexpected,
39 }
40 }
41
42 pub fn close(c: Connection) !void {
43 switch (linux.getErrno(linux.close(c.socket_fd))) {
44 0 => return,
45 linux.EBADF => unreachable,
46 linux.EINTR => return error.SigInterrupt,
47 linux.EIO => return error.Io,
48 else => return error.Unexpected,
49 }
50 }
51};11};
5212
53const Address = struct {13pub const OsAddress = switch (builtin.os) {
54 family: u16,14 builtin.Os.windows => TmpWinAddr,
55 scope_id: u32,15 else => posix.sockaddr,
56 addr: [16]u8,
57 sort_key: i32,
58};16};
5917
60pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {18pub const Address = struct {
61 if (hostname.len == 0) {19 os_addr: OsAddress,
6220
63 unreachable; // TODO21 pub fn initIp4(ip4: u32, port: u16) Address {
22 return Address {
23 .os_addr = posix.sockaddr {
24 .in = posix.sockaddr_in {
25 .family = posix.AF_INET,
26 .port = std.mem.endianSwapIfLe(u16, port),
27 .addr = ip4,
28 .zero = []u8{0} ** 8,
29 },
30 },
31 };
64 }32 }
6533
66 unreachable; // TODO34 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
67}35 return Address {
36 .family = posix.AF_INET6,
37 .os_addr = posix.sockaddr {
38 .in6 = posix.sockaddr_in6 {
39 .family = posix.AF_INET6,
40 .port = std.mem.endianSwapIfLe(u16, port),
41 .flowinfo = 0,
42 .addr = ip6.addr,
43 .scope_id = ip6.scope_id,
44 },
45 },
46 };
47 }
6848
69pub fn connectAddr(addr: &Address, port: u16) !Connection {49 pub fn initPosix(addr: &const posix.sockaddr) Address {
70 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);50 return Address {
71 const socket_err = linux.getErrno(socket_ret);51 .os_addr = *addr,
72 if (socket_err > 0) {52 };
73 // TODO figure out possible errors from socket()
74 return error.Unexpected;
75 }53 }
76 const socket_fd = i32(socket_ret);
7754
78 const connect_ret = if (addr.family == linux.AF_INET) x: {55 pub fn format(self: &const Address, out_stream: var) !void {
79 var os_addr: linux.sockaddr_in = undefined;56 switch (self.os_addr.in.family) {
80 os_addr.family = addr.family;57 posix.AF_INET => {
81 os_addr.port = endian.swapIfLe(u16, port);58 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
82 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);59 const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
83 @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));60 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
84 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));61 },
85 } else if (addr.family == linux.AF_INET6) x: {62 posix.AF_INET6 => {
86 var os_addr: linux.sockaddr_in6 = undefined;63 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
87 os_addr.family = addr.family;64 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
88 os_addr.port = endian.swapIfLe(u16, port);
89 os_addr.flowinfo = 0;
90 os_addr.scope_id = addr.scope_id;
91 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
92 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
93 } else {
94 unreachable;
95 };
96 const connect_err = linux.getErrno(connect_ret);
97 if (connect_err > 0) {
98 switch (connect_err) {
99 linux.ETIMEDOUT => return error.TimedOut,
100 else => {
101 // TODO figure out possible errors from connect()
102 return error.Unexpected;
103 },65 },
66 else => try out_stream.write("(unrecognized address family)"),
104 }67 }
105 }68 }
69};
10670
107 return Connection {71pub fn parseIp4(buf: []const u8) !u32 {
108 .socket_fd = socket_fd,72 var result: u32 = undefined;
109 };73 const out_ptr = ([]u8)((&result)[0..1]);
110}
111
112pub fn connect(hostname: []const u8, port: u16) !Connection {
113 var addrs_buf: [1]Address = undefined;
114 const addrs_slice = try lookup(hostname, addrs_buf[0..]);
115 const main_addr = &addrs_slice[0];
116
117 return connectAddr(main_addr, port);
118}
11974
120pub fn parseIpLiteral(buf: []const u8) !Address {75 var x: u8 = 0;
76 var index: u8 = 0;
77 var saw_any_digits = false;
78 for (buf) |c| {
79 if (c == '.') {
80 if (!saw_any_digits) {
81 return error.InvalidCharacter;
82 }
83 if (index == 3) {
84 return error.InvalidEnd;
85 }
86 out_ptr[index] = x;
87 index += 1;
88 x = 0;
89 saw_any_digits = false;
90 } else if (c >= '0' and c <= '9') {
91 saw_any_digits = true;
92 const digit = c - '0';
93 if (@mulWithOverflow(u8, x, 10, &x)) {
94 return error.Overflow;
95 }
96 if (@addWithOverflow(u8, x, digit, &x)) {
97 return error.Overflow;
98 }
99 } else {
100 return error.InvalidCharacter;
101 }
102 }
103 if (index == 3 and saw_any_digits) {
104 out_ptr[index] = x;
105 return result;
106 }
121107
122 return error.InvalidIpLiteral;108 return error.Incomplete;
123}109}
124110
125fn hexDigit(c: u8) u8 {111pub const Ip6Addr = struct {
126 // TODO use switch with range112 scope_id: u32,
127 if ('0' <= c and c <= '9') {113 addr: [16]u8,
128 return c - '0';114};
129 } else if ('A' <= c and c <= 'Z') {
130 return c - 'A' + 10;
131 } else if ('a' <= c and c <= 'z') {
132 return c - 'a' + 10;
133 } else {
134 return @maxValue(u8);
135 }
136}
137115
138fn parseIp6(buf: []const u8) !Address {116pub fn parseIp6(buf: []const u8) !Ip6Addr {
139 var result: Address = undefined;117 var result: Ip6Addr = undefined;
140 result.family = linux.AF_INET6;
141 result.scope_id = 0;118 result.scope_id = 0;
142 const ip_slice = result.addr[0..];119 const ip_slice = result.addr[0..];
143120
...@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {...@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {
156 return error.Overflow;133 return error.Overflow;
157 }134 }
158 } else {135 } else {
159 return error.InvalidChar;136 return error.InvalidCharacter;
160 }137 }
161 } else if (c == ':') {138 } else if (c == ':') {
162 if (!saw_any_digits) {139 if (!saw_any_digits) {
163 return error.InvalidChar;140 return error.InvalidCharacter;
164 }141 }
165 if (index == 14) {142 if (index == 14) {
166 return error.JunkAtEnd;143 return error.InvalidEnd;
167 }144 }
168 ip_slice[index] = @truncate(u8, x >> 8);145 ip_slice[index] = @truncate(u8, x >> 8);
169 index += 1;146 index += 1;
...@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {...@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {
174 saw_any_digits = false;151 saw_any_digits = false;
175 } else if (c == '%') {152 } else if (c == '%') {
176 if (!saw_any_digits) {153 if (!saw_any_digits) {
177 return error.InvalidChar;154 return error.InvalidCharacter;
178 }155 }
179 if (index == 14) {156 if (index == 14) {
180 ip_slice[index] = @truncate(u8, x >> 8);157 ip_slice[index] = @truncate(u8, x >> 8);
...@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {...@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {
185 scope_id = true;162 scope_id = true;
186 saw_any_digits = false;163 saw_any_digits = false;
187 } else {164 } else {
188 const digit = hexDigit(c);165 const digit = try std.fmt.charToDigit(c, 16);
189 if (digit == @maxValue(u8)) {
190 return error.InvalidChar;
191 }
192 if (@mulWithOverflow(u16, x, 16, &x)) {166 if (@mulWithOverflow(u16, x, 16, &x)) {
193 return error.Overflow;167 return error.Overflow;
194 }168 }
...@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {...@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {
216 return error.Incomplete;190 return error.Incomplete;
217}191}
218192
219fn parseIp4(buf: []const u8) !u32 {193test "std.net.parseIp4" {
220 var result: u32 = undefined;194 assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
221 const out_ptr = ([]u8)((&result)[0..1]);
222195
223 var x: u8 = 0;196 testParseIp4Fail("256.0.0.1", error.Overflow);
224 var index: u8 = 0;197 testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
225 var saw_any_digits = false;198 testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
226 for (buf) |c| {199 testParseIp4Fail("127.0.0.", error.Incomplete);
227 if (c == '.') {200 testParseIp4Fail("100..0.1", error.InvalidCharacter);
228 if (!saw_any_digits) {201}
229 return error.InvalidChar;202
230 }203fn testParseIp4Fail(buf: []const u8, expected_err: error) void {
231 if (index == 3) {204 if (parseIp4(buf)) |_| {
232 return error.JunkAtEnd;205 @panic("expected error");
233 }206 } else |e| {
234 out_ptr[index] = x;207 assert(e == expected_err);
235 index += 1;
236 x = 0;
237 saw_any_digits = false;
238 } else if (c >= '0' and c <= '9') {
239 saw_any_digits = true;
240 const digit = c - '0';
241 if (@mulWithOverflow(u8, x, 10, &x)) {
242 return error.Overflow;
243 }
244 if (@addWithOverflow(u8, x, digit, &x)) {
245 return error.Overflow;
246 }
247 } else {
248 return error.InvalidChar;
249 }
250 }
251 if (index == 3 and saw_any_digits) {
252 out_ptr[index] = x;
253 return result;
254 }208 }
209}
255210
256 return error.Incomplete;211test "std.net.parseIp6" {
212 const addr = try parseIp6("FF01:0:0:0:0:0:0:FB");
213 assert(addr.addr[0] == 0xff);
214 assert(addr.addr[1] == 0x01);
215 assert(addr.addr[2] == 0x00);
257}216}
std/os/child_process.zig-35
...@@ -13,8 +13,6 @@ const builtin = @import("builtin");...@@ -13,8 +13,6 @@ const builtin = @import("builtin");
13const Os = builtin.Os;13const Os = builtin.Os;
14const LinkedList = std.LinkedList;14const LinkedList = std.LinkedList;
1515
16var children_nodes = LinkedList(&ChildProcess).init();
17
18const is_windows = builtin.os == Os.windows;16const is_windows = builtin.os == Os.windows;
1917
20pub const ChildProcess = struct {18pub const ChildProcess = struct {
...@@ -296,8 +294,6 @@ pub const ChildProcess = struct {...@@ -296,8 +294,6 @@ pub const ChildProcess = struct {
296 }294 }
297295
298 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {296 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
299 children_nodes.remove(&self.llnode);
300
301 defer {297 defer {
302 os.close(self.err_pipe[0]);298 os.close(self.err_pipe[0]);
303 os.close(self.err_pipe[1]);299 os.close(self.err_pipe[1]);
...@@ -427,9 +423,6 @@ pub const ChildProcess = struct {...@@ -427,9 +423,6 @@ pub const ChildProcess = struct {
427 self.llnode = LinkedList(&ChildProcess).Node.init(self);423 self.llnode = LinkedList(&ChildProcess).Node.init(self);
428 self.term = null;424 self.term = null;
429425
430 // TODO make this atomic so it works even with threads
431 children_nodes.prepend(&self.llnode);
432
433 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }426 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
434 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }427 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
435 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }428 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
...@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {...@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {
773 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;766 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;
774 return mem.readInt(bytes[0..], ErrInt, builtin.endian);767 return mem.readInt(bytes[0..], ErrInt, builtin.endian);
775}768}
776
777extern fn sigchld_handler(_: i32) void {
778 while (true) {
779 var status: i32 = undefined;
780 const pid_result = posix.waitpid(-1, &status, posix.WNOHANG);
781 if (pid_result == 0) {
782 return;
783 }
784 const err = posix.getErrno(pid_result);
785 if (err > 0) {
786 if (err == posix.ECHILD) {
787 return;
788 }
789 unreachable;
790 }
791 handleTerm(i32(pid_result), status);
792 }
793}
794
795fn handleTerm(pid: i32, status: i32) void {
796 var it = children_nodes.first;
797 while (it) |node| : (it = node.next) {
798 if (node.data.pid == pid) {
799 node.data.handleWaitResult(status);
800 return;
801 }
802 }
803}
std/os/darwin.zig+35
...@@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks...@@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks
56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
5858
59pub const O_ACCMODE = 3;
60pub const O_ALERT = 536870912;
61pub const O_ASYNC = 64;
62pub const O_DIRECTORY = 1048576;
63pub const O_DP_GETRAWENCRYPTED = 1;
64pub const O_DP_GETRAWUNENCRYPTED = 2;
65pub const O_DSYNC = 4194304;
66pub const O_FSYNC = O_SYNC;
67pub const O_NOCTTY = 131072;
68pub const O_POPUP = 2147483648;
69pub const O_SYNC = 128;
70
59pub const SEEK_SET = 0x0;71pub const SEEK_SET = 0x0;
60pub const SEEK_CUR = 0x1;72pub const SEEK_CUR = 0x1;
61pub const SEEK_END = 0x2;73pub const SEEK_END = 0x2;
6274
75pub const DT_UNKNOWN = 0;
76pub const DT_FIFO = 1;
77pub const DT_CHR = 2;
78pub const DT_DIR = 4;
79pub const DT_BLK = 6;
80pub const DT_REG = 8;
81pub const DT_LNK = 10;
82pub const DT_SOCK = 12;
83pub const DT_WHT = 14;
84
63pub const SIG_BLOCK = 1; /// block specified signal set85pub const SIG_BLOCK = 1; /// block specified signal set
64pub const SIG_UNBLOCK = 2; /// unblock specified signal set86pub const SIG_UNBLOCK = 2; /// unblock specified signal set
65pub const SIG_SETMASK = 3; /// set specified signal set87pub const SIG_SETMASK = 3; /// set specified signal set
...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {
192 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));214 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
193}215}
194216
217
218pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
219 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
220}
221
195pub fn mkdir(path: &const u8, mode: u32) usize {222pub fn mkdir(path: &const u8, mode: u32) usize {
196 return errnoWrap(c.mkdir(path, mode));223 return errnoWrap(c.mkdir(path, mode));
197}224}
...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {
204 return errnoWrap(c.rename(old, new));231 return errnoWrap(c.rename(old, new));
205}232}
206233
234pub fn rmdir(path: &const u8) usize {
235 return errnoWrap(c.rmdir(path));
236}
237
207pub fn chdir(path: &const u8) usize {238pub fn chdir(path: &const u8) usize {
208 return errnoWrap(c.chdir(path));239 return errnoWrap(c.chdir(path));
209}240}
...@@ -268,6 +299,10 @@ pub const empty_sigset = sigset_t(0);...@@ -268,6 +299,10 @@ pub const empty_sigset = sigset_t(0);
268299
269pub const timespec = c.timespec;300pub const timespec = c.timespec;
270pub const Stat = c.Stat;301pub const Stat = c.Stat;
302pub const dirent = c.dirent;
303
304pub const sa_family_t = c.sa_family_t;
305pub const sockaddr = c.sockaddr;
271306
272/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.307/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
273pub const Sigaction = struct {308pub const Sigaction = struct {
std/os/file.zig+1-1
...@@ -233,7 +233,7 @@ pub const File = struct {...@@ -233,7 +233,7 @@ pub const File = struct {
233 Unexpected,233 Unexpected,
234 };234 };
235235
236 fn mode(self: &File) ModeError!FileMode {236 fn mode(self: &File) ModeError!os.FileMode {
237 if (is_posix) {237 if (is_posix) {
238 var stat: posix.Stat = undefined;238 var stat: posix.Stat = undefined;
239 const err = posix.getErrno(posix.fstat(self.handle, &stat));239 const err = posix.getErrno(posix.fstat(self.handle, &stat));
std/os/index.zig+605-33
...@@ -4,6 +4,19 @@ const Os = builtin.Os;...@@ -4,6 +4,19 @@ const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;4const is_windows = builtin.os == Os.windows;
5const os = this;5const os = this;
66
7test "std.os" {
8 _ = @import("child_process.zig");
9 _ = @import("darwin.zig");
10 _ = @import("darwin_errno.zig");
11 _ = @import("get_user_id.zig");
12 _ = @import("linux/errno.zig");
13 _ = @import("linux/index.zig");
14 _ = @import("linux/x86_64.zig");
15 _ = @import("path.zig");
16 _ = @import("test.zig");
17 _ = @import("windows/index.zig");
18}
19
7pub const windows = @import("windows/index.zig");20pub const windows = @import("windows/index.zig");
8pub const darwin = @import("darwin.zig");21pub const darwin = @import("darwin.zig");
9pub const linux = @import("linux/index.zig");22pub const linux = @import("linux/index.zig");
...@@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {...@@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {
14 Os.zen => zen,27 Os.zen => zen,
15 else => @compileError("Unsupported OS"),28 else => @compileError("Unsupported OS"),
16};29};
30pub const net = @import("net.zig");
1731
18pub const ChildProcess = @import("child_process.zig").ChildProcess;32pub const ChildProcess = @import("child_process.zig").ChildProcess;
19pub const path = @import("path.zig");33pub const path = @import("path.zig");
...@@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {...@@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {
173 }187 }
174}188}
175189
190/// When a file descriptor is closed on linux, it pops the first
191/// node from this queue and resumes it.
192/// Async functions which get the EMFILE error code can suspend,
193/// putting their coroutine handle into this list.
194/// TODO make this an atomic linked list
195pub var emfile_promise_queue = std.LinkedList(promise).init();
196
176/// Closes the file handle. Keeps trying if it gets interrupted by a signal.197/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
177pub fn close(handle: FileHandle) void {198pub fn close(handle: FileHandle) void {
178 if (is_windows) {199 if (is_windows) {
...@@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {...@@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {
180 } else {201 } else {
181 while (true) {202 while (true) {
182 const err = posix.getErrno(posix.close(handle));203 const err = posix.getErrno(posix.close(handle));
183 if (err == posix.EINTR) {204 switch (err) {
184 continue;205 posix.EINTR => continue,
185 } else {206 else => {
186 return;207 if (emfile_promise_queue.popFirst()) |p| resume p.data;
208 return;
209 },
187 }210 }
188 }211 }
189 }212 }
...@@ -1050,15 +1073,16 @@ const DeleteTreeError = error {...@@ -1050,15 +1073,16 @@ const DeleteTreeError = error {
1050};1073};
1051pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {1074pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
1052 start_over: while (true) {1075 start_over: while (true) {
1076 var got_access_denied = false;
1053 // First, try deleting the item as a file. This way we don't follow sym links.1077 // First, try deleting the item as a file. This way we don't follow sym links.
1054 if (deleteFile(allocator, full_path)) {1078 if (deleteFile(allocator, full_path)) {
1055 return;1079 return;
1056 } else |err| switch (err) {1080 } else |err| switch (err) {
1057 error.FileNotFound => return,1081 error.FileNotFound => return,
1058 error.IsDir => {},1082 error.IsDir => {},
1083 error.AccessDenied => got_access_denied = true,
10591084
1060 error.OutOfMemory,1085 error.OutOfMemory,
1061 error.AccessDenied,
1062 error.SymLinkLoop,1086 error.SymLinkLoop,
1063 error.NameTooLong,1087 error.NameTooLong,
1064 error.SystemResources,1088 error.SystemResources,
...@@ -1071,7 +1095,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1071,7 +1095,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1071 }1095 }
1072 {1096 {
1073 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {1097 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
1074 error.NotDir => continue :start_over,1098 error.NotDir => {
1099 if (got_access_denied) {
1100 return error.AccessDenied;
1101 }
1102 continue :start_over;
1103 },
10751104
1076 error.OutOfMemory,1105 error.OutOfMemory,
1077 error.AccessDenied,1106 error.AccessDenied,
...@@ -1109,18 +1138,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1109,18 +1138,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1109}1138}
11101139
1111pub const Dir = struct {1140pub const Dir = struct {
1112 // See man getdents
1113 fd: i32,1141 fd: i32,
1142 darwin_seek: darwin_seek_t,
1114 allocator: &Allocator,1143 allocator: &Allocator,
1115 buf: []u8,1144 buf: []u8,
1116 index: usize,1145 index: usize,
1117 end_index: usize,1146 end_index: usize,
11181147
1119 const LinuxEntry = extern struct {1148 const darwin_seek_t = switch (builtin.os) {
1120 d_ino: usize,1149 Os.macosx, Os.ios => i64,
1121 d_off: usize,1150 else => void,
1122 d_reclen: u16,
1123 d_name: u8, // field address is the address of first byte of name
1124 };1151 };
11251152
1126 pub const Entry = struct {1153 pub const Entry = struct {
...@@ -1135,15 +1162,26 @@ pub const Dir = struct {...@@ -1135,15 +1162,26 @@ pub const Dir = struct {
1135 SymLink,1162 SymLink,
1136 File,1163 File,
1137 UnixDomainSocket,1164 UnixDomainSocket,
1165 Whiteout,
1138 Unknown,1166 Unknown,
1139 };1167 };
1140 };1168 };
11411169
1142 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {1170 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
1143 const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0);1171 const fd = switch (builtin.os) {
1172 Os.windows => @compileError("TODO support Dir.open for windows"),
1173 Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
1174 Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
1175 else => @compileError("Dir.open is not supported for this platform"),
1176 };
1177 const darwin_seek_init = switch (builtin.os) {
1178 Os.macosx, Os.ios => 0,
1179 else => {},
1180 };
1144 return Dir {1181 return Dir {
1145 .allocator = allocator,1182 .allocator = allocator,
1146 .fd = fd,1183 .fd = fd,
1184 .darwin_seek = darwin_seek_init,
1147 .index = 0,1185 .index = 0,
1148 .end_index = 0,1186 .end_index = 0,
1149 .buf = []u8{},1187 .buf = []u8{},
...@@ -1158,6 +1196,76 @@ pub const Dir = struct {...@@ -1158,6 +1196,76 @@ pub const Dir = struct {
1158 /// Memory such as file names referenced in this returned entry becomes invalid1196 /// Memory such as file names referenced in this returned entry becomes invalid
1159 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.1197 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1160 pub fn next(self: &Dir) !?Entry {1198 pub fn next(self: &Dir) !?Entry {
1199 switch (builtin.os) {
1200 Os.linux => return self.nextLinux(),
1201 Os.macosx, Os.ios => return self.nextDarwin(),
1202 Os.windows => return self.nextWindows(),
1203 else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
1204 }
1205 }
1206
1207 fn nextDarwin(self: &Dir) !?Entry {
1208 start_over: while (true) {
1209 if (self.index >= self.end_index) {
1210 if (self.buf.len == 0) {
1211 self.buf = try self.allocator.alloc(u8, page_size);
1212 }
1213
1214 while (true) {
1215 const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len,
1216 &self.darwin_seek);
1217 const err = posix.getErrno(result);
1218 if (err > 0) {
1219 switch (err) {
1220 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1221 posix.EINVAL => {
1222 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1223 continue;
1224 },
1225 else => return unexpectedErrorPosix(err),
1226 }
1227 }
1228 if (result == 0)
1229 return null;
1230 self.index = 0;
1231 self.end_index = result;
1232 break;
1233 }
1234 }
1235 const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1236 const next_index = self.index + darwin_entry.d_reclen;
1237 self.index = next_index;
1238
1239 const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen];
1240
1241 // skip . and .. entries
1242 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1243 continue :start_over;
1244 }
1245
1246 const entry_kind = switch (darwin_entry.d_type) {
1247 posix.DT_BLK => Entry.Kind.BlockDevice,
1248 posix.DT_CHR => Entry.Kind.CharacterDevice,
1249 posix.DT_DIR => Entry.Kind.Directory,
1250 posix.DT_FIFO => Entry.Kind.NamedPipe,
1251 posix.DT_LNK => Entry.Kind.SymLink,
1252 posix.DT_REG => Entry.Kind.File,
1253 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1254 posix.DT_WHT => Entry.Kind.Whiteout,
1255 else => Entry.Kind.Unknown,
1256 };
1257 return Entry {
1258 .name = name,
1259 .kind = entry_kind,
1260 };
1261 }
1262 }
1263
1264 fn nextWindows(self: &Dir) !?Entry {
1265 @compileError("TODO support Dir.next for windows");
1266 }
1267
1268 fn nextLinux(self: &Dir) !?Entry {
1161 start_over: while (true) {1269 start_over: while (true) {
1162 if (self.index >= self.end_index) {1270 if (self.index >= self.end_index) {
1163 if (self.buf.len == 0) {1271 if (self.buf.len == 0) {
...@@ -1166,7 +1274,7 @@ pub const Dir = struct {...@@ -1166,7 +1274,7 @@ pub const Dir = struct {
11661274
1167 while (true) {1275 while (true) {
1168 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);1276 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
1169 const err = linux.getErrno(result);1277 const err = posix.getErrno(result);
1170 if (err > 0) {1278 if (err > 0) {
1171 switch (err) {1279 switch (err) {
1172 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,1280 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
...@@ -1184,7 +1292,7 @@ pub const Dir = struct {...@@ -1184,7 +1292,7 @@ pub const Dir = struct {
1184 break;1292 break;
1185 }1293 }
1186 }1294 }
1187 const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);1295 const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1188 const next_index = self.index + linux_entry.d_reclen;1296 const next_index = self.index + linux_entry.d_reclen;
1189 self.index = next_index;1297 self.index = next_index;
11901298
...@@ -1668,39 +1776,29 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const...@@ -1668,39 +1776,29 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
1668 assert(it.next(debug.global_allocator) == null);1776 assert(it.next(debug.global_allocator) == null);
1669}1777}
16701778
1671test "std.os" {
1672 _ = @import("child_process.zig");
1673 _ = @import("darwin_errno.zig");
1674 _ = @import("darwin.zig");
1675 _ = @import("get_user_id.zig");
1676 _ = @import("linux/errno.zig");
1677 //_ = @import("linux_i386.zig");
1678 _ = @import("linux/x86_64.zig");
1679 _ = @import("linux/index.zig");
1680 _ = @import("path.zig");
1681 _ = @import("windows/index.zig");
1682}
1683
1684
1685// TODO make this a build variable that you can set1779// TODO make this a build variable that you can set
1686const unexpected_error_tracing = false;1780const unexpected_error_tracing = false;
1781const UnexpectedError = error {
1782 /// The Operating System returned an undocumented error code.
1783 Unexpected,
1784};
16871785
1688/// Call this when you made a syscall or something that sets errno1786/// Call this when you made a syscall or something that sets errno
1689/// and you get an unexpected error.1787/// and you get an unexpected error.
1690pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {1788pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
1691 if (unexpected_error_tracing) {1789 if (unexpected_error_tracing) {
1692 debug.warn("unexpected errno: {}\n", errno);1790 debug.warn("unexpected errno: {}\n", errno);
1693 debug.dumpStackTrace();1791 debug.dumpCurrentStackTrace(null);
1694 }1792 }
1695 return error.Unexpected;1793 return error.Unexpected;
1696}1794}
16971795
1698/// Call this when you made a windows DLL call or something that does SetLastError1796/// Call this when you made a windows DLL call or something that does SetLastError
1699/// and you get an unexpected error.1797/// and you get an unexpected error.
1700pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {1798pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
1701 if (unexpected_error_tracing) {1799 if (unexpected_error_tracing) {
1702 debug.warn("unexpected GetLastError(): {}\n", err);1800 debug.warn("unexpected GetLastError(): {}\n", err);
1703 debug.dumpStackTrace();1801 debug.dumpCurrentStackTrace(null);
1704 }1802 }
1705 return error.Unexpected;1803 return error.Unexpected;
1706}1804}
...@@ -1812,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool {...@@ -1812,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool {
1812 }1910 }
1813 }1911 }
1814}1912}
1913
1914pub const PosixSocketError = error {
1915 /// Permission to create a socket of the specified type and/or
1916 /// pro‐tocol is denied.
1917 PermissionDenied,
1918
1919 /// The implementation does not support the specified address family.
1920 AddressFamilyNotSupported,
1921
1922 /// Unknown protocol, or protocol family not available.
1923 ProtocolFamilyNotAvailable,
1924
1925 /// The per-process limit on the number of open file descriptors has been reached.
1926 ProcessFdQuotaExceeded,
1927
1928 /// The system-wide limit on the total number of open files has been reached.
1929 SystemFdQuotaExceeded,
1930
1931 /// Insufficient memory is available. The socket cannot be created until sufficient
1932 /// resources are freed.
1933 SystemResources,
1934
1935 /// The protocol type or the specified protocol is not supported within this domain.
1936 ProtocolNotSupported,
1937};
1938
1939pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
1940 const rc = posix.socket(domain, socket_type, protocol);
1941 const err = posix.getErrno(rc);
1942 switch (err) {
1943 0 => return i32(rc),
1944 posix.EACCES => return PosixSocketError.PermissionDenied,
1945 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
1946 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
1947 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
1948 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
1949 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
1950 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
1951 else => return unexpectedErrorPosix(err),
1952 }
1953}
1954
1955pub const PosixBindError = error {
1956 /// The address is protected, and the user is not the superuser.
1957 /// For UNIX domain sockets: Search permission is denied on a component
1958 /// of the path prefix.
1959 AccessDenied,
1960
1961 /// The given address is already in use, or in the case of Internet domain sockets,
1962 /// The port number was specified as zero in the socket
1963 /// address structure, but, upon attempting to bind to an ephemeral port, it was
1964 /// determined that all port numbers in the ephemeral port range are currently in
1965 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
1966 AddressInUse,
1967
1968 /// sockfd is not a valid file descriptor.
1969 InvalidFileDescriptor,
1970
1971 /// The socket is already bound to an address, or addrlen is wrong, or addr is not
1972 /// a valid address for this socket's domain.
1973 InvalidSocketOrAddress,
1974
1975 /// The file descriptor sockfd does not refer to a socket.
1976 FileDescriptorNotASocket,
1977
1978 /// A nonexistent interface was requested or the requested address was not local.
1979 AddressNotAvailable,
1980
1981 /// addr points outside the user's accessible address space.
1982 PageFault,
1983
1984 /// Too many symbolic links were encountered in resolving addr.
1985 SymLinkLoop,
1986
1987 /// addr is too long.
1988 NameTooLong,
1989
1990 /// A component in the directory prefix of the socket pathname does not exist.
1991 FileNotFound,
1992
1993 /// Insufficient kernel memory was available.
1994 SystemResources,
1995
1996 /// A component of the path prefix is not a directory.
1997 NotDir,
1998
1999 /// The socket inode would reside on a read-only filesystem.
2000 ReadOnlyFileSystem,
2001
2002 Unexpected,
2003};
2004
2005/// addr is `&const T` where T is one of the sockaddr
2006pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
2007 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
2008 const err = posix.getErrno(rc);
2009 switch (err) {
2010 0 => return,
2011 posix.EACCES => return PosixBindError.AccessDenied,
2012 posix.EADDRINUSE => return PosixBindError.AddressInUse,
2013 posix.EBADF => return PosixBindError.InvalidFileDescriptor,
2014 posix.EINVAL => return PosixBindError.InvalidSocketOrAddress,
2015 posix.ENOTSOCK => return PosixBindError.FileDescriptorNotASocket,
2016 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
2017 posix.EFAULT => return PosixBindError.PageFault,
2018 posix.ELOOP => return PosixBindError.SymLinkLoop,
2019 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
2020 posix.ENOENT => return PosixBindError.FileNotFound,
2021 posix.ENOMEM => return PosixBindError.SystemResources,
2022 posix.ENOTDIR => return PosixBindError.NotDir,
2023 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
2024 else => return unexpectedErrorPosix(err),
2025 }
2026}
2027
2028const PosixListenError = error {
2029 /// Another socket is already listening on the same port.
2030 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2031 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
2032 /// was determined that all port numbers in the ephemeral port range are currently in
2033 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2034 AddressInUse,
2035
2036 /// The argument sockfd is not a valid file descriptor.
2037 InvalidFileDescriptor,
2038
2039 /// The file descriptor sockfd does not refer to a socket.
2040 FileDescriptorNotASocket,
2041
2042 /// The socket is not of a type that supports the listen() operation.
2043 OperationNotSupported,
2044
2045 Unexpected,
2046};
2047
2048pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2049 const rc = posix.listen(sockfd, backlog);
2050 const err = posix.getErrno(rc);
2051 switch (err) {
2052 0 => return,
2053 posix.EADDRINUSE => return PosixListenError.AddressInUse,
2054 posix.EBADF => return PosixListenError.InvalidFileDescriptor,
2055 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
2056 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
2057 else => return unexpectedErrorPosix(err),
2058 }
2059}
2060
2061pub const PosixAcceptError = error {
2062 /// The socket is marked nonblocking and no connections are present to be accepted.
2063 WouldBlock,
2064
2065 /// sockfd is not an open file descriptor.
2066 FileDescriptorClosed,
2067
2068 ConnectionAborted,
2069
2070 /// The addr argument is not in a writable part of the user address space.
2071 PageFault,
2072
2073 /// Socket is not listening for connections, or addrlen is invalid (e.g., is negative),
2074 /// or invalid value in flags.
2075 InvalidSyscall,
2076
2077 /// The per-process limit on the number of open file descriptors has been reached.
2078 ProcessFdQuotaExceeded,
2079
2080 /// The system-wide limit on the total number of open files has been reached.
2081 SystemFdQuotaExceeded,
2082
2083 /// Not enough free memory. This often means that the memory allocation is limited
2084 /// by the socket buffer limits, not by the system memory.
2085 SystemResources,
2086
2087 /// The file descriptor sockfd does not refer to a socket.
2088 FileDescriptorNotASocket,
2089
2090 /// The referenced socket is not of type SOCK_STREAM.
2091 OperationNotSupported,
2092
2093 ProtocolFailure,
2094
2095 /// Firewall rules forbid connection.
2096 BlockedByFirewall,
2097
2098 Unexpected,
2099};
2100
2101pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2102 while (true) {
2103 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2104 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2105 const err = posix.getErrno(rc);
2106 switch (err) {
2107 0 => return i32(rc),
2108 posix.EINTR => continue,
2109 else => return unexpectedErrorPosix(err),
2110
2111 posix.EAGAIN => return PosixAcceptError.WouldBlock,
2112 posix.EBADF => return PosixAcceptError.FileDescriptorClosed,
2113 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2114 posix.EFAULT => return PosixAcceptError.PageFault,
2115 posix.EINVAL => return PosixAcceptError.InvalidSyscall,
2116 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2117 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2118 posix.ENOBUFS, posix.ENOMEM => return PosixAcceptError.SystemResources,
2119 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2120 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2121 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2122 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2123 }
2124 }
2125}
2126
2127pub const LinuxEpollCreateError = error {
2128 /// Invalid value specified in flags.
2129 InvalidSyscall,
2130
2131 /// The per-user limit on the number of epoll instances imposed by
2132 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2133 /// details.
2134 /// Or, The per-process limit on the number of open file descriptors has been reached.
2135 ProcessFdQuotaExceeded,
2136
2137 /// The system-wide limit on the total number of open files has been reached.
2138 SystemFdQuotaExceeded,
2139
2140 /// There was insufficient memory to create the kernel object.
2141 SystemResources,
2142
2143 Unexpected,
2144};
2145
2146pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2147 const rc = posix.epoll_create1(flags);
2148 const err = posix.getErrno(rc);
2149 switch (err) {
2150 0 => return i32(rc),
2151 else => return unexpectedErrorPosix(err),
2152
2153 posix.EINVAL => return LinuxEpollCreateError.InvalidSyscall,
2154 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
2155 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
2156 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
2157 }
2158}
2159
2160pub const LinuxEpollCtlError = error {
2161 /// epfd or fd is not a valid file descriptor.
2162 InvalidFileDescriptor,
2163
2164 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2165 /// with this epoll instance.
2166 FileDescriptorAlreadyPresentInSet,
2167
2168 /// epfd is not an epoll file descriptor, or fd is the same as epfd, or the requested
2169 /// operation op is not supported by this interface, or
2170 /// An invalid event type was specified along with EPOLLEXCLUSIVE in events, or
2171 /// op was EPOLL_CTL_MOD and events included EPOLLEXCLUSIVE, or
2172 /// op was EPOLL_CTL_MOD and the EPOLLEXCLUSIVE flag has previously been applied to
2173 /// this epfd, fd pair, or
2174 /// EPOLLEXCLUSIVE was specified in event and fd refers to an epoll instance.
2175 InvalidSyscall,
2176
2177 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
2178 /// circular loop of epoll instances monitoring one another.
2179 OperationCausesCircularLoop,
2180
2181 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
2182 /// instance.
2183 FileDescriptorNotRegistered,
2184
2185 /// There was insufficient memory to handle the requested op control operation.
2186 SystemResources,
2187
2188 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
2189 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
2190 /// See epoll(7) for further details.
2191 UserResourceLimitReached,
2192
2193 /// The target file fd does not support epoll. This error can occur if fd refers to,
2194 /// for example, a regular file or a directory.
2195 FileDescriptorIncompatibleWithEpoll,
2196
2197 Unexpected,
2198};
2199
2200pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) LinuxEpollCtlError!void {
2201 const rc = posix.epoll_ctl(epfd, op, fd, event);
2202 const err = posix.getErrno(rc);
2203 switch (err) {
2204 0 => return,
2205 else => return unexpectedErrorPosix(err),
2206
2207 posix.EBADF => return LinuxEpollCtlError.InvalidFileDescriptor,
2208 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
2209 posix.EINVAL => return LinuxEpollCtlError.InvalidSyscall,
2210 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
2211 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
2212 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
2213 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
2214 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
2215 }
2216}
2217
2218pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2219 while (true) {
2220 const rc = posix.epoll_wait(epfd, events.ptr, u32(events.len), timeout);
2221 const err = posix.getErrno(rc);
2222 switch (err) {
2223 0 => return rc,
2224 posix.EINTR => continue,
2225 posix.EBADF => unreachable,
2226 posix.EFAULT => unreachable,
2227 posix.EINVAL => unreachable,
2228 else => unreachable,
2229 }
2230 }
2231}
2232
2233pub const PosixGetSockNameError = error {
2234 /// Insufficient resources were available in the system to perform the operation.
2235 SystemResources,
2236
2237 Unexpected,
2238};
2239
2240pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2241 var addr: posix.sockaddr = undefined;
2242 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
2243 const rc = posix.getsockname(sockfd, &addr, &addrlen);
2244 const err = posix.getErrno(rc);
2245 switch (err) {
2246 0 => return addr,
2247 else => return unexpectedErrorPosix(err),
2248
2249 posix.EBADF => unreachable,
2250 posix.EFAULT => unreachable,
2251 posix.EINVAL => unreachable,
2252 posix.ENOTSOCK => unreachable,
2253 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2254 }
2255}
2256
2257pub const PosixConnectError = error {
2258 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2259 /// file, or search permission is denied for one of the directories in the path prefix.
2260 /// or
2261 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2262 /// the connection request failed because of a local firewall rule.
2263 PermissionDenied,
2264
2265 /// Local address is already in use.
2266 AddressInUse,
2267
2268 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2269 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2270 /// in the ephemeral port range are currently in use. See the discussion of
2271 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2272 AddressNotAvailable,
2273
2274 /// The passed address didn't have the correct address family in its sa_family field.
2275 AddressFamilyNotSupported,
2276
2277 /// Insufficient entries in the routing cache.
2278 SystemResources,
2279
2280 /// A connect() on a stream socket found no one listening on the remote address.
2281 ConnectionRefused,
2282
2283 /// Network is unreachable.
2284 NetworkUnreachable,
2285
2286 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2287 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2288 ConnectionTimedOut,
2289
2290 Unexpected,
2291};
2292
2293pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2294 while (true) {
2295 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2296 const err = posix.getErrno(rc);
2297 switch (err) {
2298 0 => return,
2299 else => return unexpectedErrorPosix(err),
2300
2301 posix.EACCES => return PosixConnectError.PermissionDenied,
2302 posix.EPERM => return PosixConnectError.PermissionDenied,
2303 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2304 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2305 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2306 posix.EAGAIN => return PosixConnectError.SystemResources,
2307 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2308 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2309 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2310 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2311 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2312 posix.EINTR => continue,
2313 posix.EISCONN => unreachable, // The socket is already connected.
2314 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2315 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2316 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2317 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2318 }
2319 }
2320}
2321
2322/// Same as posixConnect except it is for blocking socket file descriptors.
2323/// It expects to receive EINPROGRESS.
2324pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2325 while (true) {
2326 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2327 const err = posix.getErrno(rc);
2328 switch (err) {
2329 0, posix.EINPROGRESS => return,
2330 else => return unexpectedErrorPosix(err),
2331
2332 posix.EACCES => return PosixConnectError.PermissionDenied,
2333 posix.EPERM => return PosixConnectError.PermissionDenied,
2334 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2335 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2336 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2337 posix.EAGAIN => return PosixConnectError.SystemResources,
2338 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2339 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2340 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2341 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2342 posix.EINTR => continue,
2343 posix.EISCONN => unreachable, // The socket is already connected.
2344 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2345 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2346 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2347 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2348 }
2349 }
2350}
2351
2352pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2353 var err_code: i32 = undefined;
2354 var size: u32 = @sizeOf(i32);
2355 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast(&u8, &err_code), &size);
2356 assert(size == 4);
2357 const err = posix.getErrno(rc);
2358 switch (err) {
2359 0 => switch (err_code) {
2360 0 => return,
2361 else => return unexpectedErrorPosix(err),
2362
2363 posix.EACCES => return PosixConnectError.PermissionDenied,
2364 posix.EPERM => return PosixConnectError.PermissionDenied,
2365 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2366 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2367 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2368 posix.EAGAIN => return PosixConnectError.SystemResources,
2369 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2370 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2371 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2372 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2373 posix.EISCONN => unreachable, // The socket is already connected.
2374 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2375 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2376 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2377 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2378 },
2379 else => return unexpectedErrorPosix(err),
2380 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2381 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2382 posix.EINVAL => unreachable,
2383 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2384 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2385 }
2386}
std/os/linux/i386.zig deleted-505
...@@ -1,505 +0,0 @@
1const std = @import("../../index.zig");
2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;
5
6pub const SYS_restart_syscall = 0;
7pub const SYS_exit = 1;
8pub const SYS_fork = 2;
9pub const SYS_read = 3;
10pub const SYS_write = 4;
11pub const SYS_open = 5;
12pub const SYS_close = 6;
13pub const SYS_waitpid = 7;
14pub const SYS_creat = 8;
15pub const SYS_link = 9;
16pub const SYS_unlink = 10;
17pub const SYS_execve = 11;
18pub const SYS_chdir = 12;
19pub const SYS_time = 13;
20pub const SYS_mknod = 14;
21pub const SYS_chmod = 15;
22pub const SYS_lchown = 16;
23pub const SYS_break = 17;
24pub const SYS_oldstat = 18;
25pub const SYS_lseek = 19;
26pub const SYS_getpid = 20;
27pub const SYS_mount = 21;
28pub const SYS_umount = 22;
29pub const SYS_setuid = 23;
30pub const SYS_getuid = 24;
31pub const SYS_stime = 25;
32pub const SYS_ptrace = 26;
33pub const SYS_alarm = 27;
34pub const SYS_oldfstat = 28;
35pub const SYS_pause = 29;
36pub const SYS_utime = 30;
37pub const SYS_stty = 31;
38pub const SYS_gtty = 32;
39pub const SYS_access = 33;
40pub const SYS_nice = 34;
41pub const SYS_ftime = 35;
42pub const SYS_sync = 36;
43pub const SYS_kill = 37;
44pub const SYS_rename = 38;
45pub const SYS_mkdir = 39;
46pub const SYS_rmdir = 40;
47pub const SYS_dup = 41;
48pub const SYS_pipe = 42;
49pub const SYS_times = 43;
50pub const SYS_prof = 44;
51pub const SYS_brk = 45;
52pub const SYS_setgid = 46;
53pub const SYS_getgid = 47;
54pub const SYS_signal = 48;
55pub const SYS_geteuid = 49;
56pub const SYS_getegid = 50;
57pub const SYS_acct = 51;
58pub const SYS_umount2 = 52;
59pub const SYS_lock = 53;
60pub const SYS_ioctl = 54;
61pub const SYS_fcntl = 55;
62pub const SYS_mpx = 56;
63pub const SYS_setpgid = 57;
64pub const SYS_ulimit = 58;
65pub const SYS_oldolduname = 59;
66pub const SYS_umask = 60;
67pub const SYS_chroot = 61;
68pub const SYS_ustat = 62;
69pub const SYS_dup2 = 63;
70pub const SYS_getppid = 64;
71pub const SYS_getpgrp = 65;
72pub const SYS_setsid = 66;
73pub const SYS_sigaction = 67;
74pub const SYS_sgetmask = 68;
75pub const SYS_ssetmask = 69;
76pub const SYS_setreuid = 70;
77pub const SYS_setregid = 71;
78pub const SYS_sigsuspend = 72;
79pub const SYS_sigpending = 73;
80pub const SYS_sethostname = 74;
81pub const SYS_setrlimit = 75;
82pub const SYS_getrlimit = 76;
83pub const SYS_getrusage = 77;
84pub const SYS_gettimeofday = 78;
85pub const SYS_settimeofday = 79;
86pub const SYS_getgroups = 80;
87pub const SYS_setgroups = 81;
88pub const SYS_select = 82;
89pub const SYS_symlink = 83;
90pub const SYS_oldlstat = 84;
91pub const SYS_readlink = 85;
92pub const SYS_uselib = 86;
93pub const SYS_swapon = 87;
94pub const SYS_reboot = 88;
95pub const SYS_readdir = 89;
96pub const SYS_mmap = 90;
97pub const SYS_munmap = 91;
98pub const SYS_truncate = 92;
99pub const SYS_ftruncate = 93;
100pub const SYS_fchmod = 94;
101pub const SYS_fchown = 95;
102pub const SYS_getpriority = 96;
103pub const SYS_setpriority = 97;
104pub const SYS_profil = 98;
105pub const SYS_statfs = 99;
106pub const SYS_fstatfs = 100;
107pub const SYS_ioperm = 101;
108pub const SYS_socketcall = 102;
109pub const SYS_syslog = 103;
110pub const SYS_setitimer = 104;
111pub const SYS_getitimer = 105;
112pub const SYS_stat = 106;
113pub const SYS_lstat = 107;
114pub const SYS_fstat = 108;
115pub const SYS_olduname = 109;
116pub const SYS_iopl = 110;
117pub const SYS_vhangup = 111;
118pub const SYS_idle = 112;
119pub const SYS_vm86old = 113;
120pub const SYS_wait4 = 114;
121pub const SYS_swapoff = 115;
122pub const SYS_sysinfo = 116;
123pub const SYS_ipc = 117;
124pub const SYS_fsync = 118;
125pub const SYS_sigreturn = 119;
126pub const SYS_clone = 120;
127pub const SYS_setdomainname = 121;
128pub const SYS_uname = 122;
129pub const SYS_modify_ldt = 123;
130pub const SYS_adjtimex = 124;
131pub const SYS_mprotect = 125;
132pub const SYS_sigprocmask = 126;
133pub const SYS_create_module = 127;
134pub const SYS_init_module = 128;
135pub const SYS_delete_module = 129;
136pub const SYS_get_kernel_syms = 130;
137pub const SYS_quotactl = 131;
138pub const SYS_getpgid = 132;
139pub const SYS_fchdir = 133;
140pub const SYS_bdflush = 134;
141pub const SYS_sysfs = 135;
142pub const SYS_personality = 136;
143pub const SYS_afs_syscall = 137;
144pub const SYS_setfsuid = 138;
145pub const SYS_setfsgid = 139;
146pub const SYS__llseek = 140;
147pub const SYS_getdents = 141;
148pub const SYS__newselect = 142;
149pub const SYS_flock = 143;
150pub const SYS_msync = 144;
151pub const SYS_readv = 145;
152pub const SYS_writev = 146;
153pub const SYS_getsid = 147;
154pub const SYS_fdatasync = 148;
155pub const SYS__sysctl = 149;
156pub const SYS_mlock = 150;
157pub const SYS_munlock = 151;
158pub const SYS_mlockall = 152;
159pub const SYS_munlockall = 153;
160pub const SYS_sched_setparam = 154;
161pub const SYS_sched_getparam = 155;
162pub const SYS_sched_setscheduler = 156;
163pub const SYS_sched_getscheduler = 157;
164pub const SYS_sched_yield = 158;
165pub const SYS_sched_get_priority_max = 159;
166pub const SYS_sched_get_priority_min = 160;
167pub const SYS_sched_rr_get_interval = 161;
168pub const SYS_nanosleep = 162;
169pub const SYS_mremap = 163;
170pub const SYS_setresuid = 164;
171pub const SYS_getresuid = 165;
172pub const SYS_vm86 = 166;
173pub const SYS_query_module = 167;
174pub const SYS_poll = 168;
175pub const SYS_nfsservctl = 169;
176pub const SYS_setresgid = 170;
177pub const SYS_getresgid = 171;
178pub const SYS_prctl = 172;
179pub const SYS_rt_sigreturn = 173;
180pub const SYS_rt_sigaction = 174;
181pub const SYS_rt_sigprocmask = 175;
182pub const SYS_rt_sigpending = 176;
183pub const SYS_rt_sigtimedwait = 177;
184pub const SYS_rt_sigqueueinfo = 178;
185pub const SYS_rt_sigsuspend = 179;
186pub const SYS_pread64 = 180;
187pub const SYS_pwrite64 = 181;
188pub const SYS_chown = 182;
189pub const SYS_getcwd = 183;
190pub const SYS_capget = 184;
191pub const SYS_capset = 185;
192pub const SYS_sigaltstack = 186;
193pub const SYS_sendfile = 187;
194pub const SYS_getpmsg = 188;
195pub const SYS_putpmsg = 189;
196pub const SYS_vfork = 190;
197pub const SYS_ugetrlimit = 191;
198pub const SYS_mmap2 = 192;
199pub const SYS_truncate64 = 193;
200pub const SYS_ftruncate64 = 194;
201pub const SYS_stat64 = 195;
202pub const SYS_lstat64 = 196;
203pub const SYS_fstat64 = 197;
204pub const SYS_lchown32 = 198;
205pub const SYS_getuid32 = 199;
206pub const SYS_getgid32 = 200;
207pub const SYS_geteuid32 = 201;
208pub const SYS_getegid32 = 202;
209pub const SYS_setreuid32 = 203;
210pub const SYS_setregid32 = 204;
211pub const SYS_getgroups32 = 205;
212pub const SYS_setgroups32 = 206;
213pub const SYS_fchown32 = 207;
214pub const SYS_setresuid32 = 208;
215pub const SYS_getresuid32 = 209;
216pub const SYS_setresgid32 = 210;
217pub const SYS_getresgid32 = 211;
218pub const SYS_chown32 = 212;
219pub const SYS_setuid32 = 213;
220pub const SYS_setgid32 = 214;
221pub const SYS_setfsuid32 = 215;
222pub const SYS_setfsgid32 = 216;
223pub const SYS_pivot_root = 217;
224pub const SYS_mincore = 218;
225pub const SYS_madvise = 219;
226pub const SYS_madvise1 = 219;
227pub const SYS_getdents64 = 220;
228pub const SYS_fcntl64 = 221;
229pub const SYS_gettid = 224;
230pub const SYS_readahead = 225;
231pub const SYS_setxattr = 226;
232pub const SYS_lsetxattr = 227;
233pub const SYS_fsetxattr = 228;
234pub const SYS_getxattr = 229;
235pub const SYS_lgetxattr = 230;
236pub const SYS_fgetxattr = 231;
237pub const SYS_listxattr = 232;
238pub const SYS_llistxattr = 233;
239pub const SYS_flistxattr = 234;
240pub const SYS_removexattr = 235;
241pub const SYS_lremovexattr = 236;
242pub const SYS_fremovexattr = 237;
243pub const SYS_tkill = 238;
244pub const SYS_sendfile64 = 239;
245pub const SYS_futex = 240;
246pub const SYS_sched_setaffinity = 241;
247pub const SYS_sched_getaffinity = 242;
248pub const SYS_set_thread_area = 243;
249pub const SYS_get_thread_area = 244;
250pub const SYS_io_setup = 245;
251pub const SYS_io_destroy = 246;
252pub const SYS_io_getevents = 247;
253pub const SYS_io_submit = 248;
254pub const SYS_io_cancel = 249;
255pub const SYS_fadvise64 = 250;
256pub const SYS_exit_group = 252;
257pub const SYS_lookup_dcookie = 253;
258pub const SYS_epoll_create = 254;
259pub const SYS_epoll_ctl = 255;
260pub const SYS_epoll_wait = 256;
261pub const SYS_remap_file_pages = 257;
262pub const SYS_set_tid_address = 258;
263pub const SYS_timer_create = 259;
264pub const SYS_timer_settime = SYS_timer_create+1;
265pub const SYS_timer_gettime = SYS_timer_create+2;
266pub const SYS_timer_getoverrun = SYS_timer_create+3;
267pub const SYS_timer_delete = SYS_timer_create+4;
268pub const SYS_clock_settime = SYS_timer_create+5;
269pub const SYS_clock_gettime = SYS_timer_create+6;
270pub const SYS_clock_getres = SYS_timer_create+7;
271pub const SYS_clock_nanosleep = SYS_timer_create+8;
272pub const SYS_statfs64 = 268;
273pub const SYS_fstatfs64 = 269;
274pub const SYS_tgkill = 270;
275pub const SYS_utimes = 271;
276pub const SYS_fadvise64_64 = 272;
277pub const SYS_vserver = 273;
278pub const SYS_mbind = 274;
279pub const SYS_get_mempolicy = 275;
280pub const SYS_set_mempolicy = 276;
281pub const SYS_mq_open = 277;
282pub const SYS_mq_unlink = SYS_mq_open+1;
283pub const SYS_mq_timedsend = SYS_mq_open+2;
284pub const SYS_mq_timedreceive = SYS_mq_open+3;
285pub const SYS_mq_notify = SYS_mq_open+4;
286pub const SYS_mq_getsetattr = SYS_mq_open+5;
287pub const SYS_kexec_load = 283;
288pub const SYS_waitid = 284;
289pub const SYS_add_key = 286;
290pub const SYS_request_key = 287;
291pub const SYS_keyctl = 288;
292pub const SYS_ioprio_set = 289;
293pub const SYS_ioprio_get = 290;
294pub const SYS_inotify_init = 291;
295pub const SYS_inotify_add_watch = 292;
296pub const SYS_inotify_rm_watch = 293;
297pub const SYS_migrate_pages = 294;
298pub const SYS_openat = 295;
299pub const SYS_mkdirat = 296;
300pub const SYS_mknodat = 297;
301pub const SYS_fchownat = 298;
302pub const SYS_futimesat = 299;
303pub const SYS_fstatat64 = 300;
304pub const SYS_unlinkat = 301;
305pub const SYS_renameat = 302;
306pub const SYS_linkat = 303;
307pub const SYS_symlinkat = 304;
308pub const SYS_readlinkat = 305;
309pub const SYS_fchmodat = 306;
310pub const SYS_faccessat = 307;
311pub const SYS_pselect6 = 308;
312pub const SYS_ppoll = 309;
313pub const SYS_unshare = 310;
314pub const SYS_set_robust_list = 311;
315pub const SYS_get_robust_list = 312;
316pub const SYS_splice = 313;
317pub const SYS_sync_file_range = 314;
318pub const SYS_tee = 315;
319pub const SYS_vmsplice = 316;
320pub const SYS_move_pages = 317;
321pub const SYS_getcpu = 318;
322pub const SYS_epoll_pwait = 319;
323pub const SYS_utimensat = 320;
324pub const SYS_signalfd = 321;
325pub const SYS_timerfd_create = 322;
326pub const SYS_eventfd = 323;
327pub const SYS_fallocate = 324;
328pub const SYS_timerfd_settime = 325;
329pub const SYS_timerfd_gettime = 326;
330pub const SYS_signalfd4 = 327;
331pub const SYS_eventfd2 = 328;
332pub const SYS_epoll_create1 = 329;
333pub const SYS_dup3 = 330;
334pub const SYS_pipe2 = 331;
335pub const SYS_inotify_init1 = 332;
336pub const SYS_preadv = 333;
337pub const SYS_pwritev = 334;
338pub const SYS_rt_tgsigqueueinfo = 335;
339pub const SYS_perf_event_open = 336;
340pub const SYS_recvmmsg = 337;
341pub const SYS_fanotify_init = 338;
342pub const SYS_fanotify_mark = 339;
343pub const SYS_prlimit64 = 340;
344pub const SYS_name_to_handle_at = 341;
345pub const SYS_open_by_handle_at = 342;
346pub const SYS_clock_adjtime = 343;
347pub const SYS_syncfs = 344;
348pub const SYS_sendmmsg = 345;
349pub const SYS_setns = 346;
350pub const SYS_process_vm_readv = 347;
351pub const SYS_process_vm_writev = 348;
352pub const SYS_kcmp = 349;
353pub const SYS_finit_module = 350;
354pub const SYS_sched_setattr = 351;
355pub const SYS_sched_getattr = 352;
356pub const SYS_renameat2 = 353;
357pub const SYS_seccomp = 354;
358pub const SYS_getrandom = 355;
359pub const SYS_memfd_create = 356;
360pub const SYS_bpf = 357;
361pub const SYS_execveat = 358;
362pub const SYS_socket = 359;
363pub const SYS_socketpair = 360;
364pub const SYS_bind = 361;
365pub const SYS_connect = 362;
366pub const SYS_listen = 363;
367pub const SYS_accept4 = 364;
368pub const SYS_getsockopt = 365;
369pub const SYS_setsockopt = 366;
370pub const SYS_getsockname = 367;
371pub const SYS_getpeername = 368;
372pub const SYS_sendto = 369;
373pub const SYS_sendmsg = 370;
374pub const SYS_recvfrom = 371;
375pub const SYS_recvmsg = 372;
376pub const SYS_shutdown = 373;
377pub const SYS_userfaultfd = 374;
378pub const SYS_membarrier = 375;
379pub const SYS_mlock2 = 376;
380
381
382pub const O_CREAT = 0o100;
383pub const O_EXCL = 0o200;
384pub const O_NOCTTY = 0o400;
385pub const O_TRUNC = 0o1000;
386pub const O_APPEND = 0o2000;
387pub const O_NONBLOCK = 0o4000;
388pub const O_DSYNC = 0o10000;
389pub const O_SYNC = 0o4010000;
390pub const O_RSYNC = 0o4010000;
391pub const O_DIRECTORY = 0o200000;
392pub const O_NOFOLLOW = 0o400000;
393pub const O_CLOEXEC = 0o2000000;
394
395pub const O_ASYNC = 0o20000;
396pub const O_DIRECT = 0o40000;
397pub const O_LARGEFILE = 0o100000;
398pub const O_NOATIME = 0o1000000;
399pub const O_PATH = 0o10000000;
400pub const O_TMPFILE = 0o20200000;
401pub const O_NDELAY = O_NONBLOCK;
402
403pub const F_DUPFD = 0;
404pub const F_GETFD = 1;
405pub const F_SETFD = 2;
406pub const F_GETFL = 3;
407pub const F_SETFL = 4;
408
409pub const F_SETOWN = 8;
410pub const F_GETOWN = 9;
411pub const F_SETSIG = 10;
412pub const F_GETSIG = 11;
413
414pub const F_GETLK = 12;
415pub const F_SETLK = 13;
416pub const F_SETLKW = 14;
417
418pub const F_SETOWN_EX = 15;
419pub const F_GETOWN_EX = 16;
420
421pub const F_GETOWNER_UIDS = 17;
422
423pub inline fn syscall0(number: usize) usize {
424 return asm volatile ("int $0x80"
425 : [ret] "={eax}" (-> usize)
426 : [number] "{eax}" (number));
427}
428
429pub inline fn syscall1(number: usize, arg1: usize) usize {
430 return asm volatile ("int $0x80"
431 : [ret] "={eax}" (-> usize)
432 : [number] "{eax}" (number),
433 [arg1] "{ebx}" (arg1));
434}
435
436pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
437 return asm volatile ("int $0x80"
438 : [ret] "={eax}" (-> usize)
439 : [number] "{eax}" (number),
440 [arg1] "{ebx}" (arg1),
441 [arg2] "{ecx}" (arg2));
442}
443
444pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
445 return asm volatile ("int $0x80"
446 : [ret] "={eax}" (-> usize)
447 : [number] "{eax}" (number),
448 [arg1] "{ebx}" (arg1),
449 [arg2] "{ecx}" (arg2),
450 [arg3] "{edx}" (arg3));
451}
452
453pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
454 return asm volatile ("int $0x80"
455 : [ret] "={eax}" (-> usize)
456 : [number] "{eax}" (number),
457 [arg1] "{ebx}" (arg1),
458 [arg2] "{ecx}" (arg2),
459 [arg3] "{edx}" (arg3),
460 [arg4] "{esi}" (arg4));
461}
462
463pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize,
464 arg4: usize, arg5: usize) usize
465{
466 return asm volatile ("int $0x80"
467 : [ret] "={eax}" (-> usize)
468 : [number] "{eax}" (number),
469 [arg1] "{ebx}" (arg1),
470 [arg2] "{ecx}" (arg2),
471 [arg3] "{edx}" (arg3),
472 [arg4] "{esi}" (arg4),
473 [arg5] "{edi}" (arg5));
474}
475
476pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize,
477 arg4: usize, arg5: usize, arg6: usize) usize
478{
479 return asm volatile ("int $0x80"
480 : [ret] "={eax}" (-> usize)
481 : [number] "{eax}" (number),
482 [arg1] "{ebx}" (arg1),
483 [arg2] "{ecx}" (arg2),
484 [arg3] "{edx}" (arg3),
485 [arg4] "{esi}" (arg4),
486 [arg5] "{edi}" (arg5),
487 [arg6] "{ebp}" (arg6));
488}
489
490pub nakedcc fn restore() void {
491 asm volatile (
492 \\popl %%eax
493 \\movl $119, %%eax
494 \\int $0x80
495 :
496 :
497 : "rcx", "r11");
498}
499
500pub nakedcc fn restore_rt() void {
501 asm volatile ("int $0x80"
502 :
503 : [number] "{eax}" (usize(SYS_rt_sigreturn))
504 : "rcx", "r11");
505}
std/os/linux/index.zig+602-150
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("../../index.zig");1const std = @import("../../index.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const arch = switch (builtin.arch) {4pub use switch (builtin.arch) {
5 builtin.Arch.x86_64 => @import("x86_64.zig"),5 builtin.Arch.x86_64 => @import("x86_64.zig"),
6 builtin.Arch.i386 => @import("i386.zig"),6 builtin.Arch.i386 => @import("i386.zig"),
7 else => @compileError("unsupported arch"),7 else => @compileError("unsupported arch"),
...@@ -93,27 +93,6 @@ pub const O_RDONLY = 0o0;...@@ -93,27 +93,6 @@ pub const O_RDONLY = 0o0;
93pub const O_WRONLY = 0o1;93pub const O_WRONLY = 0o1;
94pub const O_RDWR = 0o2;94pub const O_RDWR = 0o2;
9595
96pub const O_CREAT = arch.O_CREAT;
97pub const O_EXCL = arch.O_EXCL;
98pub const O_NOCTTY = arch.O_NOCTTY;
99pub const O_TRUNC = arch.O_TRUNC;
100pub const O_APPEND = arch.O_APPEND;
101pub const O_NONBLOCK = arch.O_NONBLOCK;
102pub const O_DSYNC = arch.O_DSYNC;
103pub const O_SYNC = arch.O_SYNC;
104pub const O_RSYNC = arch.O_RSYNC;
105pub const O_DIRECTORY = arch.O_DIRECTORY;
106pub const O_NOFOLLOW = arch.O_NOFOLLOW;
107pub const O_CLOEXEC = arch.O_CLOEXEC;
108
109pub const O_ASYNC = arch.O_ASYNC;
110pub const O_DIRECT = arch.O_DIRECT;
111pub const O_LARGEFILE = arch.O_LARGEFILE;
112pub const O_NOATIME = arch.O_NOATIME;
113pub const O_PATH = arch.O_PATH;
114pub const O_TMPFILE = arch.O_TMPFILE;
115pub const O_NDELAY = arch.O_NDELAY;
116
117pub const SEEK_SET = 0;96pub const SEEK_SET = 0;
118pub const SEEK_CUR = 1;97pub const SEEK_CUR = 1;
119pub const SEEK_END = 2;98pub const SEEK_END = 2;
...@@ -122,17 +101,6 @@ pub const SIG_BLOCK = 0;...@@ -122,17 +101,6 @@ pub const SIG_BLOCK = 0;
122pub const SIG_UNBLOCK = 1;101pub const SIG_UNBLOCK = 1;
123pub const SIG_SETMASK = 2;102pub const SIG_SETMASK = 2;
124103
125pub const SOCK_STREAM = 1;
126pub const SOCK_DGRAM = 2;
127pub const SOCK_RAW = 3;
128pub const SOCK_RDM = 4;
129pub const SOCK_SEQPACKET = 5;
130pub const SOCK_DCCP = 6;
131pub const SOCK_PACKET = 10;
132pub const SOCK_CLOEXEC = 0o2000000;
133pub const SOCK_NONBLOCK = 0o4000;
134
135
136pub const PROTO_ip = 0o000;104pub const PROTO_ip = 0o000;
137pub const PROTO_icmp = 0o001;105pub const PROTO_icmp = 0o001;
138pub const PROTO_igmp = 0o002;106pub const PROTO_igmp = 0o002;
...@@ -170,6 +138,20 @@ pub const PROTO_encap = 0o142;...@@ -170,6 +138,20 @@ pub const PROTO_encap = 0o142;
170pub const PROTO_pim = 0o147;138pub const PROTO_pim = 0o147;
171pub const PROTO_raw = 0o377;139pub const PROTO_raw = 0o377;
172140
141pub const SHUT_RD = 0;
142pub const SHUT_WR = 1;
143pub const SHUT_RDWR = 2;
144
145pub const SOCK_STREAM = 1;
146pub const SOCK_DGRAM = 2;
147pub const SOCK_RAW = 3;
148pub const SOCK_RDM = 4;
149pub const SOCK_SEQPACKET = 5;
150pub const SOCK_DCCP = 6;
151pub const SOCK_PACKET = 10;
152pub const SOCK_CLOEXEC = 0o2000000;
153pub const SOCK_NONBLOCK = 0o4000;
154
173pub const PF_UNSPEC = 0;155pub const PF_UNSPEC = 0;
174pub const PF_LOCAL = 1;156pub const PF_LOCAL = 1;
175pub const PF_UNIX = PF_LOCAL;157pub const PF_UNIX = PF_LOCAL;
...@@ -214,7 +196,10 @@ pub const PF_CAIF = 37;...@@ -214,7 +196,10 @@ pub const PF_CAIF = 37;
214pub const PF_ALG = 38;196pub const PF_ALG = 38;
215pub const PF_NFC = 39;197pub const PF_NFC = 39;
216pub const PF_VSOCK = 40;198pub const PF_VSOCK = 40;
217pub const PF_MAX = 41;199pub const PF_KCM = 41;
200pub const PF_QIPCRTR = 42;
201pub const PF_SMC = 43;
202pub const PF_MAX = 44;
218203
219pub const AF_UNSPEC = PF_UNSPEC;204pub const AF_UNSPEC = PF_UNSPEC;
220pub const AF_LOCAL = PF_LOCAL;205pub const AF_LOCAL = PF_LOCAL;
...@@ -260,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;...@@ -260,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;
260pub const AF_ALG = PF_ALG;245pub const AF_ALG = PF_ALG;
261pub const AF_NFC = PF_NFC;246pub const AF_NFC = PF_NFC;
262pub const AF_VSOCK = PF_VSOCK;247pub const AF_VSOCK = PF_VSOCK;
248pub const AF_KCM = PF_KCM;
249pub const AF_QIPCRTR = PF_QIPCRTR;
250pub const AF_SMC = PF_SMC;
263pub const AF_MAX = PF_MAX;251pub const AF_MAX = PF_MAX;
264252
253pub const SO_DEBUG = 1;
254pub const SO_REUSEADDR = 2;
255pub const SO_TYPE = 3;
256pub const SO_ERROR = 4;
257pub const SO_DONTROUTE = 5;
258pub const SO_BROADCAST = 6;
259pub const SO_SNDBUF = 7;
260pub const SO_RCVBUF = 8;
261pub const SO_KEEPALIVE = 9;
262pub const SO_OOBINLINE = 10;
263pub const SO_NO_CHECK = 11;
264pub const SO_PRIORITY = 12;
265pub const SO_LINGER = 13;
266pub const SO_BSDCOMPAT = 14;
267pub const SO_REUSEPORT = 15;
268pub const SO_PASSCRED = 16;
269pub const SO_PEERCRED = 17;
270pub const SO_RCVLOWAT = 18;
271pub const SO_SNDLOWAT = 19;
272pub const SO_RCVTIMEO = 20;
273pub const SO_SNDTIMEO = 21;
274pub const SO_ACCEPTCONN = 30;
275pub const SO_SNDBUFFORCE = 32;
276pub const SO_RCVBUFFORCE = 33;
277pub const SO_PROTOCOL = 38;
278pub const SO_DOMAIN = 39;
279
280pub const SO_SECURITY_AUTHENTICATION = 22;
281pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
282pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
283
284pub const SO_BINDTODEVICE = 25;
285
286pub const SO_ATTACH_FILTER = 26;
287pub const SO_DETACH_FILTER = 27;
288pub const SO_GET_FILTER = SO_ATTACH_FILTER;
289
290pub const SO_PEERNAME = 28;
291pub const SO_TIMESTAMP = 29;
292pub const SCM_TIMESTAMP = SO_TIMESTAMP;
293
294pub const SO_PEERSEC = 31;
295pub const SO_PASSSEC = 34;
296pub const SO_TIMESTAMPNS = 35;
297pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
298pub const SO_MARK = 36;
299pub const SO_TIMESTAMPING = 37;
300pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
301pub const SO_RXQ_OVFL = 40;
302pub const SO_WIFI_STATUS = 41;
303pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
304pub const SO_PEEK_OFF = 42;
305pub const SO_NOFCS = 43;
306pub const SO_LOCK_FILTER = 44;
307pub const SO_SELECT_ERR_QUEUE = 45;
308pub const SO_BUSY_POLL = 46;
309pub const SO_MAX_PACING_RATE = 47;
310pub const SO_BPF_EXTENSIONS = 48;
311pub const SO_INCOMING_CPU = 49;
312pub const SO_ATTACH_BPF = 50;
313pub const SO_DETACH_BPF = SO_DETACH_FILTER;
314pub const SO_ATTACH_REUSEPORT_CBPF = 51;
315pub const SO_ATTACH_REUSEPORT_EBPF = 52;
316pub const SO_CNX_ADVICE = 53;
317pub const SCM_TIMESTAMPING_OPT_STATS = 54;
318pub const SO_MEMINFO = 55;
319pub const SO_INCOMING_NAPI_ID = 56;
320pub const SO_COOKIE = 57;
321pub const SCM_TIMESTAMPING_PKTINFO = 58;
322pub const SO_PEERGROUPS = 59;
323pub const SO_ZEROCOPY = 60;
324
325pub const SOL_SOCKET = 1;
326
327pub const SOL_IP = 0;
328pub const SOL_IPV6 = 41;
329pub const SOL_ICMPV6 = 58;
330
331pub const SOL_RAW = 255;
332pub const SOL_DECNET = 261;
333pub const SOL_X25 = 262;
334pub const SOL_PACKET = 263;
335pub const SOL_ATM = 264;
336pub const SOL_AAL = 265;
337pub const SOL_IRDA = 266;
338pub const SOL_NETBEUI = 267;
339pub const SOL_LLC = 268;
340pub const SOL_DCCP = 269;
341pub const SOL_NETLINK = 270;
342pub const SOL_TIPC = 271;
343pub const SOL_RXRPC = 272;
344pub const SOL_PPPOL2TP = 273;
345pub const SOL_BLUETOOTH = 274;
346pub const SOL_PNPIPE = 275;
347pub const SOL_RDS = 276;
348pub const SOL_IUCV = 277;
349pub const SOL_CAIF = 278;
350pub const SOL_ALG = 279;
351pub const SOL_NFC = 280;
352pub const SOL_KCM = 281;
353pub const SOL_TLS = 282;
354
355pub const SOMAXCONN = 128;
356
357pub const MSG_OOB = 0x0001;
358pub const MSG_PEEK = 0x0002;
359pub const MSG_DONTROUTE = 0x0004;
360pub const MSG_CTRUNC = 0x0008;
361pub const MSG_PROXY = 0x0010;
362pub const MSG_TRUNC = 0x0020;
363pub const MSG_DONTWAIT = 0x0040;
364pub const MSG_EOR = 0x0080;
365pub const MSG_WAITALL = 0x0100;
366pub const MSG_FIN = 0x0200;
367pub const MSG_SYN = 0x0400;
368pub const MSG_CONFIRM = 0x0800;
369pub const MSG_RST = 0x1000;
370pub const MSG_ERRQUEUE = 0x2000;
371pub const MSG_NOSIGNAL = 0x4000;
372pub const MSG_MORE = 0x8000;
373pub const MSG_WAITFORONE = 0x10000;
374pub const MSG_BATCH = 0x40000;
375pub const MSG_ZEROCOPY = 0x4000000;
376pub const MSG_FASTOPEN = 0x20000000;
377pub const MSG_CMSG_CLOEXEC = 0x40000000;
378
265pub const DT_UNKNOWN = 0;379pub const DT_UNKNOWN = 0;
266pub const DT_FIFO = 1;380pub const DT_FIFO = 1;
267pub const DT_CHR = 2;381pub const DT_CHR = 2;
...@@ -364,6 +478,126 @@ pub const CLOCK_BOOTTIME_ALARM = 9;...@@ -364,6 +478,126 @@ pub const CLOCK_BOOTTIME_ALARM = 9;
364pub const CLOCK_SGI_CYCLE = 10;478pub const CLOCK_SGI_CYCLE = 10;
365pub const CLOCK_TAI = 11;479pub const CLOCK_TAI = 11;
366480
481pub const CSIGNAL = 0x000000ff;
482pub const CLONE_VM = 0x00000100;
483pub const CLONE_FS = 0x00000200;
484pub const CLONE_FILES = 0x00000400;
485pub const CLONE_SIGHAND = 0x00000800;
486pub const CLONE_PTRACE = 0x00002000;
487pub const CLONE_VFORK = 0x00004000;
488pub const CLONE_PARENT = 0x00008000;
489pub const CLONE_THREAD = 0x00010000;
490pub const CLONE_NEWNS = 0x00020000;
491pub const CLONE_SYSVSEM = 0x00040000;
492pub const CLONE_SETTLS = 0x00080000;
493pub const CLONE_PARENT_SETTID = 0x00100000;
494pub const CLONE_CHILD_CLEARTID = 0x00200000;
495pub const CLONE_DETACHED = 0x00400000;
496pub const CLONE_UNTRACED = 0x00800000;
497pub const CLONE_CHILD_SETTID = 0x01000000;
498pub const CLONE_NEWCGROUP = 0x02000000;
499pub const CLONE_NEWUTS = 0x04000000;
500pub const CLONE_NEWIPC = 0x08000000;
501pub const CLONE_NEWUSER = 0x10000000;
502pub const CLONE_NEWPID = 0x20000000;
503pub const CLONE_NEWNET = 0x40000000;
504pub const CLONE_IO = 0x80000000;
505
506pub const MS_RDONLY = 1;
507pub const MS_NOSUID = 2;
508pub const MS_NODEV = 4;
509pub const MS_NOEXEC = 8;
510pub const MS_SYNCHRONOUS = 16;
511pub const MS_REMOUNT = 32;
512pub const MS_MANDLOCK = 64;
513pub const MS_DIRSYNC = 128;
514pub const MS_NOATIME = 1024;
515pub const MS_NODIRATIME = 2048;
516pub const MS_BIND = 4096;
517pub const MS_MOVE = 8192;
518pub const MS_REC = 16384;
519pub const MS_SILENT = 32768;
520pub const MS_POSIXACL = (1<<16);
521pub const MS_UNBINDABLE = (1<<17);
522pub const MS_PRIVATE = (1<<18);
523pub const MS_SLAVE = (1<<19);
524pub const MS_SHARED = (1<<20);
525pub const MS_RELATIME = (1<<21);
526pub const MS_KERNMOUNT = (1<<22);
527pub const MS_I_VERSION = (1<<23);
528pub const MS_STRICTATIME = (1<<24);
529pub const MS_LAZYTIME = (1<<25);
530pub const MS_NOREMOTELOCK = (1<<27);
531pub const MS_NOSEC = (1<<28);
532pub const MS_BORN = (1<<29);
533pub const MS_ACTIVE = (1<<30);
534pub const MS_NOUSER = (1<<31);
535
536pub const MS_RMT_MASK = (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME);
537
538pub const MS_MGC_VAL = 0xc0ed0000;
539pub const MS_MGC_MSK = 0xffff0000;
540
541pub const MNT_FORCE = 1;
542pub const MNT_DETACH = 2;
543pub const MNT_EXPIRE = 4;
544pub const UMOUNT_NOFOLLOW = 8;
545
546
547pub const S_IFMT = 0o170000;
548
549pub const S_IFDIR = 0o040000;
550pub const S_IFCHR = 0o020000;
551pub const S_IFBLK = 0o060000;
552pub const S_IFREG = 0o100000;
553pub const S_IFIFO = 0o010000;
554pub const S_IFLNK = 0o120000;
555pub const S_IFSOCK = 0o140000;
556
557pub const S_ISUID = 0o4000;
558pub const S_ISGID = 0o2000;
559pub const S_ISVTX = 0o1000;
560pub const S_IRUSR = 0o400;
561pub const S_IWUSR = 0o200;
562pub const S_IXUSR = 0o100;
563pub const S_IRWXU = 0o700;
564pub const S_IRGRP = 0o040;
565pub const S_IWGRP = 0o020;
566pub const S_IXGRP = 0o010;
567pub const S_IRWXG = 0o070;
568pub const S_IROTH = 0o004;
569pub const S_IWOTH = 0o002;
570pub const S_IXOTH = 0o001;
571pub const S_IRWXO = 0o007;
572
573pub fn S_ISREG(m: u32) bool {
574 return m & S_IFMT == S_IFREG;
575}
576
577pub fn S_ISDIR(m: u32) bool {
578 return m & S_IFMT == S_IFDIR;
579}
580
581pub fn S_ISCHR(m: u32) bool {
582 return m & S_IFMT == S_IFCHR;
583}
584
585pub fn S_ISBLK(m: u32) bool {
586 return m & S_IFMT == S_IFBLK;
587}
588
589pub fn S_ISFIFO(m: u32) bool {
590 return m & S_IFMT == S_IFIFO;
591}
592
593pub fn S_ISLNK(m: u32) bool {
594 return m & S_IFMT == S_IFLNK;
595}
596
597pub fn S_ISSOCK(m: u32) bool {
598 return m & S_IFMT == S_IFSOCK;
599}
600
367pub const TFD_NONBLOCK = O_NONBLOCK;601pub const TFD_NONBLOCK = O_NONBLOCK;
368pub const TFD_CLOEXEC = O_CLOEXEC;602pub const TFD_CLOEXEC = O_CLOEXEC;
369603
...@@ -394,65 +628,81 @@ pub fn getErrno(r: usize) usize {...@@ -394,65 +628,81 @@ pub fn getErrno(r: usize) usize {
394}628}
395629
396pub fn dup2(old: i32, new: i32) usize {630pub fn dup2(old: i32, new: i32) usize {
397 return arch.syscall2(arch.SYS_dup2, usize(old), usize(new));631 return syscall2(SYS_dup2, usize(old), usize(new));
398}632}
399633
400pub fn chdir(path: &const u8) usize {634pub fn chdir(path: &const u8) usize {
401 return arch.syscall1(arch.SYS_chdir, @ptrToInt(path));635 return syscall1(SYS_chdir, @ptrToInt(path));
636}
637
638pub fn chroot(path: &const u8) usize {
639 return syscall1(SYS_chroot, @ptrToInt(path));
402}640}
403641
404pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {642pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {
405 return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));643 return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
406}644}
407645
408pub fn fork() usize {646pub fn fork() usize {
409 return arch.syscall0(arch.SYS_fork);647 return syscall0(SYS_fork);
410}648}
411649
412pub fn getcwd(buf: &u8, size: usize) usize {650pub fn getcwd(buf: &u8, size: usize) usize {
413 return arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size);651 return syscall2(SYS_getcwd, @ptrToInt(buf), size);
414}652}
415653
416pub fn getdents(fd: i32, dirp: &u8, count: usize) usize {654pub fn getdents(fd: i32, dirp: &u8, count: usize) usize {
417 return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count);655 return syscall3(SYS_getdents, usize(fd), @ptrToInt(dirp), count);
418}656}
419657
420pub fn isatty(fd: i32) bool {658pub fn isatty(fd: i32) bool {
421 var wsz: winsize = undefined;659 var wsz: winsize = undefined;
422 return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;660 return syscall3(SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
423}661}
424662
425pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) usize {663pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) usize {
426 return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);664 return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
427}665}
428666
429pub fn mkdir(path: &const u8, mode: u32) usize {667pub fn mkdir(path: &const u8, mode: u32) usize {
430 return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode);668 return syscall2(SYS_mkdir, @ptrToInt(path), mode);
669}
670
671pub fn mount(special: &const u8, dir: &const u8, fstype: &const u8, flags: usize, data: usize) usize {
672 return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
673}
674
675pub fn umount(special: &const u8) usize {
676 return syscall2(SYS_umount2, @ptrToInt(special), 0);
677}
678
679pub fn umount2(special: &const u8, flags: u32) usize {
680 return syscall2(SYS_umount2, @ptrToInt(special), flags);
431}681}
432682
433pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {683pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {
434 return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),684 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
435 @bitCast(usize, offset));685 @bitCast(usize, offset));
436}686}
437687
438pub fn munmap(address: &u8, length: usize) usize {688pub fn munmap(address: &u8, length: usize) usize {
439 return arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length);689 return syscall2(SYS_munmap, @ptrToInt(address), length);
440}690}
441691
442pub fn read(fd: i32, buf: &u8, count: usize) usize {692pub fn read(fd: i32, buf: &u8, count: usize) usize {
443 return arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count);693 return syscall3(SYS_read, usize(fd), @ptrToInt(buf), count);
444}694}
445695
446pub fn rmdir(path: &const u8) usize {696pub fn rmdir(path: &const u8) usize {
447 return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path));697 return syscall1(SYS_rmdir, @ptrToInt(path));
448}698}
449699
450pub fn symlink(existing: &const u8, new: &const u8) usize {700pub fn symlink(existing: &const u8, new: &const u8) usize {
451 return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new));701 return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
452}702}
453703
454pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {704pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {
455 return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset);705 return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
456}706}
457707
458pub fn pipe(fd: &[2]i32) usize {708pub fn pipe(fd: &[2]i32) usize {
...@@ -460,84 +710,136 @@ pub fn pipe(fd: &[2]i32) usize {...@@ -460,84 +710,136 @@ pub fn pipe(fd: &[2]i32) usize {
460}710}
461711
462pub fn pipe2(fd: &[2]i32, flags: usize) usize {712pub fn pipe2(fd: &[2]i32, flags: usize) usize {
463 return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags);713 return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
464}714}
465715
466pub fn write(fd: i32, buf: &const u8, count: usize) usize {716pub fn write(fd: i32, buf: &const u8, count: usize) usize {
467 return arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count);717 return syscall3(SYS_write, usize(fd), @ptrToInt(buf), count);
468}718}
469719
470pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) usize {720pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) usize {
471 return arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset);721 return syscall4(SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset);
472}722}
473723
474pub fn rename(old: &const u8, new: &const u8) usize {724pub fn rename(old: &const u8, new: &const u8) usize {
475 return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new));725 return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new));
476}726}
477727
478pub fn open(path: &const u8, flags: u32, perm: usize) usize {728pub fn open(path: &const u8, flags: u32, perm: usize) usize {
479 return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm);729 return syscall3(SYS_open, @ptrToInt(path), flags, perm);
480}730}
481731
482pub fn create(path: &const u8, perm: usize) usize {732pub fn create(path: &const u8, perm: usize) usize {
483 return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm);733 return syscall2(SYS_creat, @ptrToInt(path), perm);
484}734}
485735
486pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) usize {736pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) usize {
487 return arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode);737 return syscall4(SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode);
488}738}
489739
490pub fn close(fd: i32) usize {740pub fn close(fd: i32) usize {
491 return arch.syscall1(arch.SYS_close, usize(fd));741 return syscall1(SYS_close, usize(fd));
492}742}
493743
494pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {744pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
495 return arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos);745 return syscall3(SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos);
496}746}
497747
498pub fn exit(status: i32) noreturn {748pub fn exit(status: i32) noreturn {
499 _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));749 _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
500 unreachable;750 unreachable;
501}751}
502752
503pub fn getrandom(buf: &u8, count: usize, flags: u32) usize {753pub fn getrandom(buf: &u8, count: usize, flags: u32) usize {
504 return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags));754 return syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags));
505}755}
506756
507pub fn kill(pid: i32, sig: i32) usize {757pub fn kill(pid: i32, sig: i32) usize {
508 return arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig));758 return syscall2(SYS_kill, @bitCast(usize, isize(pid)), usize(sig));
509}759}
510760
511pub fn unlink(path: &const u8) usize {761pub fn unlink(path: &const u8) usize {
512 return arch.syscall1(arch.SYS_unlink, @ptrToInt(path));762 return syscall1(SYS_unlink, @ptrToInt(path));
513}763}
514764
515pub fn waitpid(pid: i32, status: &i32, options: i32) usize {765pub fn waitpid(pid: i32, status: &i32, options: i32) usize {
516 return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);766 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
517}767}
518768
519pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {769pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
520 return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));770 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
521}771}
522772
523pub fn setuid(uid: u32) usize {773pub fn setuid(uid: u32) usize {
524 return arch.syscall1(arch.SYS_setuid, uid);774 return syscall1(SYS_setuid, uid);
525}775}
526776
527pub fn setgid(gid: u32) usize {777pub fn setgid(gid: u32) usize {
528 return arch.syscall1(arch.SYS_setgid, gid);778 return syscall1(SYS_setgid, gid);
529}779}
530780
531pub fn setreuid(ruid: u32, euid: u32) usize {781pub fn setreuid(ruid: u32, euid: u32) usize {
532 return arch.syscall2(arch.SYS_setreuid, ruid, euid);782 return syscall2(SYS_setreuid, ruid, euid);
533}783}
534784
535pub fn setregid(rgid: u32, egid: u32) usize {785pub fn setregid(rgid: u32, egid: u32) usize {
536 return arch.syscall2(arch.SYS_setregid, rgid, egid);786 return syscall2(SYS_setregid, rgid, egid);
787}
788
789pub fn getuid() u32 {
790 return u32(syscall0(SYS_getuid));
791}
792
793pub fn getgid() u32 {
794 return u32(syscall0(SYS_getgid));
795}
796
797pub fn geteuid() u32 {
798 return u32(syscall0(SYS_geteuid));
799}
800
801pub fn getegid() u32 {
802 return u32(syscall0(SYS_getegid));
803}
804
805pub fn seteuid(euid: u32) usize {
806 return syscall1(SYS_seteuid, euid);
807}
808
809pub fn setegid(egid: u32) usize {
810 return syscall1(SYS_setegid, egid);
811}
812
813pub fn getresuid(ruid: &u32, euid: &u32, suid: &u32) usize {
814 return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
815}
816
817pub fn getresgid(rgid: &u32, egid: &u32, sgid: &u32) usize {
818 return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
819}
820
821pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
822 return syscall3(SYS_setresuid, ruid, euid, suid);
823}
824
825pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
826 return syscall3(SYS_setresgid, rgid, egid, sgid);
827}
828
829pub fn getgroups(size: usize, list: &u32) usize {
830 return syscall2(SYS_getgroups, size, @ptrToInt(list));
831}
832
833pub fn setgroups(size: usize, list: &const u32) usize {
834 return syscall2(SYS_setgroups, size, @ptrToInt(list));
835}
836
837pub fn getpid() i32 {
838 return @bitCast(i32, u32(syscall0(SYS_getpid)));
537}839}
538840
539pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {841pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {
540 return arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);842 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);
541}843}
542844
543pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {845pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
...@@ -548,11 +850,11 @@ pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigacti...@@ -548,11 +850,11 @@ pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigacti
548 .handler = act.handler,850 .handler = act.handler,
549 .flags = act.flags | SA_RESTORER,851 .flags = act.flags | SA_RESTORER,
550 .mask = undefined,852 .mask = undefined,
551 .restorer = @ptrCast(extern fn()void, arch.restore_rt),853 .restorer = @ptrCast(extern fn()void, restore_rt),
552 };854 };
553 var ksa_old: k_sigaction = undefined;855 var ksa_old: k_sigaction = undefined;
554 @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);856 @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);
555 const result = arch.syscall4(arch.SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));857 const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
556 const err = getErrno(result);858 const err = getErrno(result);
557 if (err != 0) {859 if (err != 0) {
558 return result;860 return result;
...@@ -592,22 +894,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;...@@ -592,22 +894,22 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;
592pub fn raise(sig: i32) usize {894pub fn raise(sig: i32) usize {
593 var set: sigset_t = undefined;895 var set: sigset_t = undefined;
594 blockAppSignals(&set);896 blockAppSignals(&set);
595 const tid = i32(arch.syscall0(arch.SYS_gettid));897 const tid = i32(syscall0(SYS_gettid));
596 const ret = arch.syscall2(arch.SYS_tkill, usize(tid), usize(sig));898 const ret = syscall2(SYS_tkill, usize(tid), usize(sig));
597 restoreSignals(&set);899 restoreSignals(&set);
598 return ret;900 return ret;
599}901}
600902
601fn blockAllSignals(set: &sigset_t) void {903fn blockAllSignals(set: &sigset_t) void {
602 _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8);904 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8);
603}905}
604906
605fn blockAppSignals(set: &sigset_t) void {907fn blockAppSignals(set: &sigset_t) void {
606 _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8);908 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8);
607}909}
608910
609fn restoreSignals(set: &sigset_t) void {911fn restoreSignals(set: &sigset_t) void {
610 _ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8);912 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8);
611}913}
612914
613pub fn sigaddset(set: &sigset_t, sig: u6) void {915pub fn sigaddset(set: &sigset_t, sig: u6) void {
...@@ -620,30 +922,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {...@@ -620,30 +922,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {
620 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;922 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
621}923}
622924
623925pub const in_port_t = u16;
624pub const sa_family_t = u16;926pub const sa_family_t = u16;
625pub const socklen_t = u32;927pub const socklen_t = u32;
626pub const in_addr = u32;
627pub const in6_addr = [16]u8;
628928
629pub const sockaddr = extern struct {929pub const sockaddr = extern union {
630 family: sa_family_t,930 in: sockaddr_in,
631 port: u16,931 in6: sockaddr_in6,
632 data: [12]u8,
633};932};
634933
635pub const sockaddr_in = extern struct {934pub const sockaddr_in = extern struct {
636 family: sa_family_t,935 family: sa_family_t,
637 port: u16,936 port: in_port_t,
638 addr: in_addr,937 addr: u32,
639 zero: [8]u8,938 zero: [8]u8,
640};939};
641940
642pub const sockaddr_in6 = extern struct {941pub const sockaddr_in6 = extern struct {
643 family: sa_family_t,942 family: sa_family_t,
644 port: u16,943 port: in_port_t,
645 flowinfo: u32,944 flowinfo: u32,
646 addr: in6_addr,945 addr: [16]u8,
647 scope_id: u32,946 scope_id: u32,
648};947};
649948
...@@ -653,61 +952,61 @@ pub const iovec = extern struct {...@@ -653,61 +952,61 @@ pub const iovec = extern struct {
653};952};
654953
655pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {954pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
656 return arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len));955 return syscall3(SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len));
657}956}
658957
659pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {958pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
660 return arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));959 return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
661}960}
662961
663pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize {962pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
664 return arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol));963 return syscall3(SYS_socket, domain, socket_type, protocol);
665}964}
666965
667pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {966pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize {
668 return arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));967 return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen));
669}968}
670969
671pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize {970pub fn getsockopt(fd: i32, level: u32, optname: u32, 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));971 return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
673}972}
674973
675pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) usize {974pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
676 return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);975 return syscall3(SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
677}976}
678977
679pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) usize {978pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
680 return arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len));979 return syscall3(SYS_connect, usize(fd), @ptrToInt(addr), usize(len));
681}980}
682981
683pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) usize {982pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {
684 return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);983 return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
685}984}
686985
687pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,986pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
688 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize987 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize
689{988{
690 return arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));989 return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
691}990}
692991
693pub fn shutdown(fd: i32, how: i32) usize {992pub fn shutdown(fd: i32, how: i32) usize {
694 return arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how));993 return syscall2(SYS_shutdown, usize(fd), usize(how));
695}994}
696995
697pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {996pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
698 return arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len));997 return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
699}998}
700999
701pub fn listen(fd: i32, backlog: i32) usize {1000pub fn listen(fd: i32, backlog: u32) usize {
702 return arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog));1001 return syscall2(SYS_listen, usize(fd), backlog);
703}1002}
7041003
705pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {1004pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {
706 return arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen));1005 return syscall6(SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen));
707}1006}
7081007
709pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {1008pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
710 return arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]));1009 return syscall4(SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]));
711}1010}
7121011
713pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {1012pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
...@@ -715,52 +1014,86 @@ pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {...@@ -715,52 +1014,86 @@ pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
715}1014}
7161015
717pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) usize {1016pub 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);1017 return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
719}1018}
720
721// error NameTooLong;
722// error SystemResources;
723// error Io;
724//
725// pub fn if_nametoindex(name: []u8) !u32 {
726// var ifr: ifreq = undefined;
727//
728// if (name.len >= ifr.ifr_name.len) {
729// return error.NameTooLong;
730// }
731//
732// const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
733// const socket_err = getErrno(socket_ret);
734// if (socket_err > 0) {
735// return error.SystemResources;
736// }
737// const socket_fd = i32(socket_ret);
738// @memcpy(&ifr.ifr_name[0], &name[0], name.len);
739// ifr.ifr_name[name.len] = 0;
740// const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr);
741// close(socket_fd);
742// const ioctl_err = getErrno(ioctl_ret);
743// if (ioctl_err > 0) {
744// return error.Io;
745// }
746// return ifr.ifr_ifindex;
747// }
748
749pub const Stat = arch.Stat;
750pub const timespec = arch.timespec;
7511019
752pub fn fstat(fd: i32, stat_buf: &Stat) usize {1020pub fn fstat(fd: i32, stat_buf: &Stat) usize {
753 return arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf));1021 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
1022}
1023
1024pub fn stat(pathname: &const u8, statbuf: &Stat) usize {
1025 return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf));
1026}
1027
1028pub fn lstat(pathname: &const u8, statbuf: &Stat) usize {
1029 return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf));
1030}
1031
1032pub fn listxattr(path: &const u8, list: &u8, size: usize) usize {
1033 return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
1034}
1035
1036pub fn llistxattr(path: &const u8, list: &u8, size: usize) usize {
1037 return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
1038}
1039
1040pub fn flistxattr(fd: usize, list: &u8, size: usize) usize {
1041 return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
1042}
1043
1044pub fn getxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize {
1045 return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1046}
1047
1048pub fn lgetxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize {
1049 return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1050}
1051
1052pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize {
1053 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
1054}
1055
1056pub fn setxattr(path: &const u8, name: &const u8, value: &const void,
1057 size: usize, flags: usize) usize {
1058
1059 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1060 size, flags);
754}1061}
7551062
756pub const epoll_data = extern union {1063pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void,
1064 size: usize, flags: usize) usize {
1065
1066 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1067 size, flags);
1068}
1069
1070pub fn fsetxattr(fd: usize, name: &const u8, value: &const void,
1071 size: usize, flags: usize) usize {
1072
1073 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value),
1074 size, flags);
1075}
1076
1077pub fn removexattr(path: &const u8, name: &const u8) usize {
1078 return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
1079}
1080
1081pub fn lremovexattr(path: &const u8, name: &const u8) usize {
1082 return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
1083}
1084
1085pub fn fremovexattr(fd: usize, name: &const u8) usize {
1086 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
1087}
1088
1089pub const epoll_data = packed union {
757 ptr: usize,1090 ptr: usize,
758 fd: i32,1091 fd: i32,
759 @"u32": u32,1092 @"u32": u32,
760 @"u64": u64,1093 @"u64": u64,
761};1094};
7621095
763pub const epoll_event = extern struct {1096pub const epoll_event = packed struct {
764 events: u32,1097 events: u32,
765 data: epoll_data,1098 data: epoll_data,
766};1099};
...@@ -770,19 +1103,19 @@ pub fn epoll_create() usize {...@@ -770,19 +1103,19 @@ pub fn epoll_create() usize {
770}1103}
7711104
772pub fn epoll_create1(flags: usize) usize {1105pub fn epoll_create1(flags: usize) usize {
773 return arch.syscall1(arch.SYS_epoll_create1, flags);1106 return syscall1(SYS_epoll_create1, flags);
774}1107}
7751108
776pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) usize {1109pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: &epoll_event) usize {
777 return arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));1110 return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
778}1111}
7791112
780pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: u32, timeout: i32) usize {1113pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: u32, timeout: i32) usize {
781 return arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout));1114 return syscall4(SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout));
782}1115}
7831116
784pub fn timerfd_create(clockid: i32, flags: u32) usize {1117pub fn timerfd_create(clockid: i32, flags: u32) usize {
785 return arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags));1118 return syscall2(SYS_timerfd_create, usize(clockid), usize(flags));
786}1119}
7871120
788pub const itimerspec = extern struct {1121pub const itimerspec = extern struct {
...@@ -791,11 +1124,130 @@ pub const itimerspec = extern struct {...@@ -791,11 +1124,130 @@ pub const itimerspec = extern struct {
791};1124};
7921125
793pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {1126pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {
794 return arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value));1127 return syscall2(SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value));
795}1128}
7961129
797pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) usize {1130pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) usize {
798 return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));1131 return syscall4(SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
1132}
1133
1134pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1135pub const _LINUX_CAPABILITY_U32S_1 = 1;
1136
1137pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1138pub const _LINUX_CAPABILITY_U32S_2 = 2;
1139
1140pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1141pub const _LINUX_CAPABILITY_U32S_3 = 2;
1142
1143pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1144pub const VFS_CAP_REVISION_SHIFT = 24;
1145pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1146pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
1147
1148pub const VFS_CAP_REVISION_1 = 0x01000000;
1149pub const VFS_CAP_U32_1 = 1;
1150pub const XATTR_CAPS_SZ_1 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_1);
1151
1152pub const VFS_CAP_REVISION_2 = 0x02000000;
1153pub const VFS_CAP_U32_2 = 2;
1154pub const XATTR_CAPS_SZ_2 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_2);
1155
1156pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1157pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1158pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
1159
1160pub const vfs_cap_data = extern struct {
1161 //all of these are mandated as little endian
1162 //when on disk.
1163 const Data = struct {
1164 permitted: u32,
1165 inheritable: u32,
1166 };
1167
1168 magic_etc: u32,
1169 data: [VFS_CAP_U32]Data,
1170};
1171
1172
1173pub const CAP_CHOWN = 0;
1174pub const CAP_DAC_OVERRIDE = 1;
1175pub const CAP_DAC_READ_SEARCH = 2;
1176pub const CAP_FOWNER = 3;
1177pub const CAP_FSETID = 4;
1178pub const CAP_KILL = 5;
1179pub const CAP_SETGID = 6;
1180pub const CAP_SETUID = 7;
1181pub const CAP_SETPCAP = 8;
1182pub const CAP_LINUX_IMMUTABLE = 9;
1183pub const CAP_NET_BIND_SERVICE = 10;
1184pub const CAP_NET_BROADCAST = 11;
1185pub const CAP_NET_ADMIN = 12;
1186pub const CAP_NET_RAW = 13;
1187pub const CAP_IPC_LOCK = 14;
1188pub const CAP_IPC_OWNER = 15;
1189pub const CAP_SYS_MODULE = 16;
1190pub const CAP_SYS_RAWIO = 17;
1191pub const CAP_SYS_CHROOT = 18;
1192pub const CAP_SYS_PTRACE = 19;
1193pub const CAP_SYS_PACCT = 20;
1194pub const CAP_SYS_ADMIN = 21;
1195pub const CAP_SYS_BOOT = 22;
1196pub const CAP_SYS_NICE = 23;
1197pub const CAP_SYS_RESOURCE = 24;
1198pub const CAP_SYS_TIME = 25;
1199pub const CAP_SYS_TTY_CONFIG = 26;
1200pub const CAP_MKNOD = 27;
1201pub const CAP_LEASE = 28;
1202pub const CAP_AUDIT_WRITE = 29;
1203pub const CAP_AUDIT_CONTROL = 30;
1204pub const CAP_SETFCAP = 31;
1205pub const CAP_MAC_OVERRIDE = 32;
1206pub const CAP_MAC_ADMIN = 33;
1207pub const CAP_SYSLOG = 34;
1208pub const CAP_WAKE_ALARM = 35;
1209pub const CAP_BLOCK_SUSPEND = 36;
1210pub const CAP_AUDIT_READ = 37;
1211pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1212
1213pub fn cap_valid(u8: x) bool {
1214 return x >= 0 and x <= CAP_LAST_CAP;
1215}
1216
1217pub fn CAP_TO_MASK(cap: u8) u32 {
1218 return u32(1) << u5(cap & 31);
1219}
1220
1221pub fn CAP_TO_INDEX(cap: u8) u8 {
1222 return cap >> 5;
1223}
1224
1225pub const cap_t = extern struct {
1226 hdrp: &cap_user_header_t,
1227 datap: &cap_user_data_t,
1228};
1229
1230pub const cap_user_header_t = extern struct {
1231 version: u32,
1232 pid: usize,
1233};
1234
1235pub const cap_user_data_t = extern struct {
1236 effective: u32,
1237 permitted: u32,
1238 inheritable: u32,
1239};
1240
1241pub fn unshare(flags: usize) usize {
1242 return syscall1(SYS_unshare, usize(flags));
1243}
1244
1245pub fn capget(hdrp: &cap_user_header_t, datap: &cap_user_data_t) usize {
1246 return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
1247}
1248
1249pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize {
1250 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
799}1251}
8001252
801test "import linux test" {1253test "import linux test" {
std/os/linux/x86_64.zig+8
...@@ -488,3 +488,11 @@ pub const timespec = extern struct {...@@ -488,3 +488,11 @@ pub const timespec = extern struct {
488 tv_sec: isize,488 tv_sec: isize,
489 tv_nsec: isize,489 tv_nsec: isize,
490};490};
491
492pub const dirent = extern struct {
493 d_ino: usize,
494 d_off: usize,
495 d_reclen: u16,
496 d_name: u8, // field address is the address of first byte of name
497};
498
std/os/test.zig created+25
...@@ -0,0 +1,25 @@
1const std = @import("../index.zig");
2const os = std.os;
3const assert = std.debug.assert;
4const io = std.io;
5
6const a = std.debug.global_allocator;
7
8const builtin = @import("builtin");
9
10test "makePath, put some files in it, deleteTree" {
11 if (builtin.os == builtin.Os.windows) {
12 // TODO implement os.Dir for windows
13 // https://github.com/zig-lang/zig/issues/709
14 return;
15 }
16 try os.makePath(a, "os_test_tmp/b/c");
17 try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
18 try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
19 try os.deleteTree(a, "os_test_tmp");
20 if (os.Dir.open(a, "os_test_tmp")) |dir| {
21 @panic("expected error");
22 } else |err| {
23 assert(err == error.PathNotFound);
24 }
25}
std/rand.zig deleted-240
...@@ -1,240 +0,0 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const rand_test = @import("rand_test.zig");
5const mem = std.mem;
6const math = std.math;
7
8pub const MT19937_32 = MersenneTwister(
9 u32, 624, 397, 31,
10 0x9908B0DF,
11 11, 0xFFFFFFFF,
12 7, 0x9D2C5680,
13 15, 0xEFC60000,
14 18, 1812433253);
15
16pub const MT19937_64 = MersenneTwister(
17 u64, 312, 156, 31,
18 0xB5026F5AA96619E9,
19 29, 0x5555555555555555,
20 17, 0x71D67FFFEDA60000,
21 37, 0xFFF7EEE000000000,
22 43, 6364136223846793005);
23
24/// Use `init` to initialize this state.
25pub const Rand = struct {
26 const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32;
27
28 rng: Rng,
29
30 /// Initialize random state with the given seed.
31 pub fn init(seed: usize) Rand {
32 return Rand {
33 .rng = Rng.init(seed),
34 };
35 }
36
37 /// Get an integer or boolean with random bits.
38 pub fn scalar(r: &Rand, comptime T: type) T {
39 if (T == usize) {
40 return r.rng.get();
41 } else if (T == bool) {
42 return (r.rng.get() & 0b1) == 0;
43 } else {
44 var result: [@sizeOf(T)]u8 = undefined;
45 r.fillBytes(result[0..]);
46 return mem.readInt(result, T, builtin.Endian.Little);
47 }
48 }
49
50 /// Fill `buf` with randomness.
51 pub fn fillBytes(r: &Rand, buf: []u8) void {
52 var bytes_left = buf.len;
53 while (bytes_left >= @sizeOf(usize)) {
54 mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little);
55 bytes_left -= @sizeOf(usize);
56 }
57 if (bytes_left > 0) {
58 var rand_val_array: [@sizeOf(usize)]u8 = undefined;
59 mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little);
60 while (bytes_left > 0) {
61 buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
62 bytes_left -= 1;
63 }
64 }
65 }
66
67 /// Get a random unsigned integer with even distribution between `start`
68 /// inclusive and `end` exclusive.
69 pub fn range(r: &Rand, comptime T: type, start: T, end: T) T {
70 assert(start <= end);
71 if (T.is_signed) {
72 const uint = @IntType(false, T.bit_count);
73 if (start >= 0 and end >= 0) {
74 return T(r.range(uint, uint(start), uint(end)));
75 } else if (start < 0 and end < 0) {
76 // Can't overflow because the range is over signed ints
77 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
78 } else if (start < 0 and end >= 0) {
79 const end_uint = uint(end);
80 const total_range = math.absCast(start) + end_uint;
81 const value = r.range(uint, 0, total_range);
82 const result = if (value < end_uint) x: {
83 break :x T(value);
84 } else if (value == end_uint) x: {
85 break :x start;
86 } else x: {
87 // Can't overflow because the range is over signed ints
88 break :x math.negateCast(value - end_uint) catch unreachable;
89 };
90 return result;
91 } else {
92 unreachable;
93 }
94 } else {
95 const total_range = end - start;
96 const leftover = @maxValue(T) % total_range;
97 const upper_bound = @maxValue(T) - leftover;
98 var rand_val_array: [@sizeOf(T)]u8 = undefined;
99
100 while (true) {
101 r.fillBytes(rand_val_array[0..]);
102 const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
103 if (rand_val < upper_bound) {
104 return start + (rand_val % total_range);
105 }
106 }
107 }
108 }
109
110 /// Get a floating point value in the range 0.0..1.0.
111 pub fn float(r: &Rand, comptime T: type) T {
112 // TODO Implement this way instead:
113 // const int = @int_type(false, @sizeOf(T) * 8);
114 // const mask = ((1 << @float_mantissa_bit_count(T)) - 1);
115 // const rand_bits = r.rng.scalar(int) & mask;
116 // return @float_compose(T, false, 0, rand_bits) - 1.0
117 const int_type = @IntType(false, @sizeOf(T) * 8);
118 const precision = if (T == f32)
119 16777216
120 else if (T == f64)
121 9007199254740992
122 else
123 @compileError("unknown floating point type")
124 ;
125 return T(r.range(int_type, 0, precision)) / T(precision);
126 }
127};
128
129fn MersenneTwister(
130 comptime int: type, comptime n: usize, comptime m: usize, comptime r: int,
131 comptime a: int,
132 comptime u: math.Log2Int(int), comptime d: int,
133 comptime s: math.Log2Int(int), comptime b: int,
134 comptime t: math.Log2Int(int), comptime c: int,
135 comptime l: math.Log2Int(int), comptime f: int) type
136{
137 return struct {
138 const Self = this;
139
140 array: [n]int,
141 index: usize,
142
143 pub fn init(seed: int) Self {
144 var mt = Self {
145 .array = undefined,
146 .index = n,
147 };
148
149 var prev_value = seed;
150 mt.array[0] = prev_value;
151 var i: usize = 1;
152 while (i < n) : (i += 1) {
153 prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));
154 mt.array[i] = prev_value;
155 }
156 return mt;
157 }
158
159 pub fn get(mt: &Self) int {
160 const mag01 = []int{0, a};
161 const LM: int = (1 << r) - 1;
162 const UM = ~LM;
163
164 if (mt.index >= n) {
165 var i: usize = 0;
166
167 while (i < n - m) : (i += 1) {
168 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
169 mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
170 }
171
172 while (i < n - 1) : (i += 1) {
173 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
174 mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
175
176 }
177 const x = (mt.array[i] & UM) | (mt.array[0] & LM);
178 mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
179
180 mt.index = 0;
181 }
182
183 var x = mt.array[mt.index];
184 mt.index += 1;
185
186 x ^= ((x >> u) & d);
187 x ^= ((x << s) & b);
188 x ^= ((x << t) & c);
189 x ^= (x >> l);
190
191 return x;
192 }
193 };
194}
195
196test "rand float 32" {
197 var r = Rand.init(42);
198 var i: usize = 0;
199 while (i < 1000) : (i += 1) {
200 const val = r.float(f32);
201 assert(val >= 0.0);
202 assert(val < 1.0);
203 }
204}
205
206test "rand.MT19937_64" {
207 var rng = MT19937_64.init(rand_test.mt64_seed);
208 for (rand_test.mt64_data) |value| {
209 assert(value == rng.get());
210 }
211}
212
213test "rand.MT19937_32" {
214 var rng = MT19937_32.init(rand_test.mt32_seed);
215 for (rand_test.mt32_data) |value| {
216 assert(value == rng.get());
217 }
218}
219
220test "rand.Rand.range" {
221 var r = Rand.init(42);
222 testRange(&r, -4, 3);
223 testRange(&r, -4, -1);
224 testRange(&r, 10, 14);
225}
226
227fn testRange(r: &Rand, start: i32, end: i32) void {
228 const count = usize(end - start);
229 var values_buffer = []bool{false} ** 20;
230 const values = values_buffer[0..count];
231 var i: usize = 0;
232 while (i < count) {
233 const value = r.range(i32, start, end);
234 const index = usize(value - start);
235 if (!values[index]) {
236 i += 1;
237 values[index] = true;
238 }
239 }
240}
std/rand/index.zig created+652
...@@ -0,0 +1,652 @@
1// The engines provided here should be initialized from an external source. For now, getRandomBytes
2// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.
4//
5// ```
6// var buf: [8]u8 = undefined;
7// try std.os.getRandomBytes(buf[0..]);
8// const seed = mem.readInt(buf[0..8], u64, builtin.Endian.Little);
9//
10// var r = DefaultPrng.init(seed);
11//
12// const s = r.random.scalar(u64);
13// ```
14//
15// TODO(tiehuis): Benchmark these against other reference implementations.
16
17const std = @import("../index.zig");
18const builtin = @import("builtin");
19const assert = std.debug.assert;
20const mem = std.mem;
21const math = std.math;
22
23// When you need fast unbiased random numbers
24pub const DefaultPrng = Xoroshiro128;
25
26// When you need cryptographically secure random numbers
27pub const DefaultCsprng = Isaac64;
28
29pub const Random = struct {
30 fillFn: fn(r: &Random, buf: []u8) void,
31
32 /// Read random bytes into the specified buffer until fill.
33 pub fn bytes(r: &Random, buf: []u8) void {
34 r.fillFn(r, buf);
35 }
36
37 /// Return a random integer/boolean type.
38 pub fn scalar(r: &Random, comptime T: type) T {
39 var rand_bytes: [@sizeOf(T)]u8 = undefined;
40 r.bytes(rand_bytes[0..]);
41
42 if (T == bool) {
43 return rand_bytes[0] & 0b1 == 0;
44 } else {
45 // NOTE: Cannot @bitCast array to integer type.
46 return mem.readInt(rand_bytes, T, builtin.Endian.Little);
47 }
48 }
49
50 /// Get a random unsigned integer with even distribution between `start`
51 /// inclusive and `end` exclusive.
52 pub fn range(r: &Random, comptime T: type, start: T, end: T) T {
53 assert(start <= end);
54 if (T.is_signed) {
55 const uint = @IntType(false, T.bit_count);
56 if (start >= 0 and end >= 0) {
57 return T(r.range(uint, uint(start), uint(end)));
58 } else if (start < 0 and end < 0) {
59 // Can't overflow because the range is over signed ints
60 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
61 } else if (start < 0 and end >= 0) {
62 const end_uint = uint(end);
63 const total_range = math.absCast(start) + end_uint;
64 const value = r.range(uint, 0, total_range);
65 const result = if (value < end_uint) x: {
66 break :x T(value);
67 } else if (value == end_uint) x: {
68 break :x start;
69 } else x: {
70 // Can't overflow because the range is over signed ints
71 break :x math.negateCast(value - end_uint) catch unreachable;
72 };
73 return result;
74 } else {
75 unreachable;
76 }
77 } else {
78 const total_range = end - start;
79 const leftover = @maxValue(T) % total_range;
80 const upper_bound = @maxValue(T) - leftover;
81 var rand_val_array: [@sizeOf(T)]u8 = undefined;
82
83 while (true) {
84 r.bytes(rand_val_array[0..]);
85 const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
86 if (rand_val < upper_bound) {
87 return start + (rand_val % total_range);
88 }
89 }
90 }
91 }
92
93 /// Return a floating point value evenly distributed in the range [0, 1).
94 pub fn float(r: &Random, comptime T: type) T {
95 // Generate a uniform value between [1, 2) and scale down to [0, 1).
96 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
97 switch (T) {
98 f32 => {
99 const s = r.scalar(u32);
100 const repr = (0x7f << 23) | (s >> 9);
101 return @bitCast(f32, repr) - 1.0;
102 },
103 f64 => {
104 const s = r.scalar(u64);
105 const repr = (0x3ff << 52) | (s >> 12);
106 return @bitCast(f64, repr) - 1.0;
107 },
108 else => @compileError("unknown floating point type"),
109 }
110 }
111
112 /// Return a floating point value normally distributed in the range [0, 1].
113 pub fn floatNorm(r: &Random, comptime T: type) T {
114 // TODO(tiehuis): See https://www.doornik.com/research/ziggurat.pdf
115 @compileError("floatNorm is unimplemented");
116 }
117
118 /// Return a exponentially distributed float between (0, @maxValue(f64))
119 pub fn floatExp(r: &Random, comptime T: type) T {
120 @compileError("floatExp is unimplemented");
121 }
122
123 /// Shuffle a slice into a random order.
124 pub fn shuffle(r: &Random, comptime T: type, buf: []T) void {
125 if (buf.len < 2) {
126 return;
127 }
128
129 var i: usize = 0;
130 while (i < buf.len - 1) : (i += 1) {
131 const j = r.range(usize, i, buf.len);
132 mem.swap(T, &buf[i], &buf[j]);
133 }
134 }
135};
136
137// Generator to extend 64-bit seed values into longer sequences.
138//
139// The number of cycles is thus limited to 64-bits regardless of the engine, but this
140// is still plenty for practical purposes.
141const SplitMix64 = struct {
142 s: u64,
143
144 pub fn init(seed: u64) SplitMix64 {
145 return SplitMix64 { .s = seed };
146 }
147
148 pub fn next(self: &SplitMix64) u64 {
149 self.s +%= 0x9e3779b97f4a7c15;
150
151 var z = self.s;
152 z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
153 z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
154 return z ^ (z >> 31);
155 }
156};
157
158test "splitmix64 sequence" {
159 var r = SplitMix64.init(0xaeecf86f7878dd75);
160
161 const seq = []const u64 {
162 0x5dbd39db0178eb44,
163 0xa9900fb66b397da3,
164 0x5c1a28b1aeebcf5c,
165 0x64a963238f776912,
166 0xc6d4177b21d1c0ab,
167 0xb2cbdbdb5ea35394,
168 };
169
170 for (seq) |s| {
171 std.debug.assert(s == r.next());
172 }
173}
174
175// PCG32 - http://www.pcg-random.org/
176//
177// PRNG
178pub const Pcg = struct {
179 const default_multiplier = 6364136223846793005;
180
181 random: Random,
182
183 s: u64,
184 i: u64,
185
186 pub fn init(init_s: u64) Pcg {
187 var pcg = Pcg {
188 .random = Random { .fillFn = fill },
189 .s = undefined,
190 .i = undefined,
191 };
192
193 pcg.seed(init_s);
194 return pcg;
195 }
196
197 fn next(self: &Pcg) u32 {
198 const l = self.s;
199 self.s = l *% default_multiplier +% (self.i | 1);
200
201 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
202 const rot = u32(l >> 59);
203
204 return (xor_s >> u5(rot)) | (xor_s << u5((0 -% rot) & 31));
205 }
206
207 fn seed(self: &Pcg, init_s: u64) void {
208 // Pcg requires 128-bits of seed.
209 var gen = SplitMix64.init(init_s);
210 self.seedTwo(gen.next(), gen.next());
211 }
212
213 fn seedTwo(self: &Pcg, init_s: u64, init_i: u64) void {
214 self.s = 0;
215 self.i = (init_s << 1) | 1;
216 self.s = self.s *% default_multiplier +% self.i;
217 self.s +%= init_i;
218 self.s = self.s *% default_multiplier +% self.i;
219 }
220
221 fn fill(r: &Random, buf: []u8) void {
222 const self = @fieldParentPtr(Pcg, "random", r);
223
224 var i: usize = 0;
225 const aligned_len = buf.len - (buf.len & 7);
226
227 // Complete 4 byte segments.
228 while (i < aligned_len) : (i += 4) {
229 var n = self.next();
230 comptime var j: usize = 0;
231 inline while (j < 4) : (j += 1) {
232 buf[i + j] = @truncate(u8, n);
233 n >>= 8;
234 }
235 }
236
237 // Remaining. (cuts the stream)
238 if (i != buf.len) {
239 var n = self.next();
240 while (i < buf.len) : (i += 1) {
241 buf[i] = @truncate(u8, n);
242 n >>= 4;
243 }
244 }
245 }
246};
247
248test "pcg sequence" {
249 var r = Pcg.init(0);
250 const s0: u64 = 0x9394bf54ce5d79de;
251 const s1: u64 = 0x84e9c579ef59bbf7;
252 r.seedTwo(s0, s1);
253
254 const seq = []const u32 {
255 2881561918,
256 3063928540,
257 1199791034,
258 2487695858,
259 1479648952,
260 3247963454,
261 };
262
263 for (seq) |s| {
264 std.debug.assert(s == r.next());
265 }
266}
267
268// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
269//
270// PRNG
271pub const Xoroshiro128 = struct {
272 random: Random,
273
274 s: [2]u64,
275
276 pub fn init(init_s: u64) Xoroshiro128 {
277 var x = Xoroshiro128 {
278 .random = Random { .fillFn = fill },
279 .s = undefined,
280 };
281
282 x.seed(init_s);
283 return x;
284 }
285
286 fn next(self: &Xoroshiro128) u64 {
287 const s0 = self.s[0];
288 var s1 = self.s[1];
289 const r = s0 +% s1;
290
291 s1 ^= s0;
292 self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
293 self.s[1] = math.rotl(u64, s1, u8(36));
294
295 return r;
296 }
297
298 // Skip 2^64 places ahead in the sequence
299 fn jump(self: &Xoroshiro128) void {
300 var s0: u64 = 0;
301 var s1: u64 = 0;
302
303 const table = []const u64 {
304 0xbeac0467eba5facb,
305 0xd86b048b86aa9922
306 };
307
308 inline for (table) |entry| {
309 var b: usize = 0;
310 while (b < 64) : (b += 1) {
311 if ((entry & (u64(1) << u6(b))) != 0) {
312 s0 ^= self.s[0];
313 s1 ^= self.s[1];
314 }
315 _ = self.next();
316 }
317 }
318
319 self.s[0] = s0;
320 self.s[1] = s1;
321 }
322
323 fn seed(self: &Xoroshiro128, init_s: u64) void {
324 // Xoroshiro requires 128-bits of seed.
325 var gen = SplitMix64.init(init_s);
326
327 self.s[0] = gen.next();
328 self.s[1] = gen.next();
329 }
330
331 fn fill(r: &Random, buf: []u8) void {
332 const self = @fieldParentPtr(Xoroshiro128, "random", r);
333
334 var i: usize = 0;
335 const aligned_len = buf.len - (buf.len & 7);
336
337 // Complete 8 byte segments.
338 while (i < aligned_len) : (i += 8) {
339 var n = self.next();
340 comptime var j: usize = 0;
341 inline while (j < 8) : (j += 1) {
342 buf[i + j] = @truncate(u8, n);
343 n >>= 8;
344 }
345 }
346
347 // Remaining. (cuts the stream)
348 if (i != buf.len) {
349 var n = self.next();
350 while (i < buf.len) : (i += 1) {
351 buf[i] = @truncate(u8, n);
352 n >>= 8;
353 }
354 }
355 }
356};
357
358test "xoroshiro sequence" {
359 var r = Xoroshiro128.init(0);
360 r.s[0] = 0xaeecf86f7878dd75;
361 r.s[1] = 0x01cd153642e72622;
362
363 const seq1 = []const u64 {
364 0xb0ba0da5bb600397,
365 0x18a08afde614dccc,
366 0xa2635b956a31b929,
367 0xabe633c971efa045,
368 0x9ac19f9706ca3cac,
369 0xf62b426578c1e3fb,
370 };
371
372 for (seq1) |s| {
373 std.debug.assert(s == r.next());
374 }
375
376
377 r.jump();
378
379 const seq2 = []const u64 {
380 0x95344a13556d3e22,
381 0xb4fb32dafa4d00df,
382 0xb2011d9ccdcfe2dd,
383 0x05679a9b2119b908,
384 0xa860a1da7c9cd8a0,
385 0x658a96efe3f86550,
386 };
387
388 for (seq2) |s| {
389 std.debug.assert(s == r.next());
390 }
391}
392
393// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
394//
395// CSPRNG
396//
397// Follows the general idea of the implementation from here with a few shortcuts.
398// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
399pub const Isaac64 = struct {
400 random: Random,
401
402 r: [256]u64,
403 m: [256]u64,
404 a: u64,
405 b: u64,
406 c: u64,
407 i: usize,
408
409 pub fn init(init_s: u64) Isaac64 {
410 var isaac = Isaac64 {
411 .random = Random { .fillFn = fill },
412 .r = undefined,
413 .m = undefined,
414 .a = undefined,
415 .b = undefined,
416 .c = undefined,
417 .i = undefined,
418 };
419
420 // seed == 0 => same result as the unseeded reference implementation
421 isaac.seed(init_s, 1);
422 return isaac;
423 }
424
425 fn step(self: &Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
426 const x = self.m[base + m1];
427 self.a = mix +% self.m[base + m2];
428
429 const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
430 self.m[base + m1] = y;
431
432 self.b = x +% self.m[(y >> 11) % self.m.len];
433 self.r[self.r.len - 1 - base - m1] = self.b;
434 }
435
436 fn refill(self: &Isaac64) void {
437 const midpoint = self.r.len / 2;
438
439 self.c +%= 1;
440 self.b +%= self.c;
441
442 {
443 var i: usize = 0;
444 while (i < midpoint) : (i += 4) {
445 self.step( ~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
446 self.step( self.a ^ (self.a >> 5) , i + 1, 0, midpoint);
447 self.step( self.a ^ (self.a << 12) , i + 2, 0, midpoint);
448 self.step( self.a ^ (self.a >> 33) , i + 3, 0, midpoint);
449 }
450 }
451
452 {
453 var i: usize = 0;
454 while (i < midpoint) : (i += 4) {
455 self.step( ~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
456 self.step( self.a ^ (self.a >> 5) , i + 1, midpoint, 0);
457 self.step( self.a ^ (self.a << 12) , i + 2, midpoint, 0);
458 self.step( self.a ^ (self.a >> 33) , i + 3, midpoint, 0);
459 }
460 }
461
462 self.i = 0;
463 }
464
465 fn next(self: &Isaac64) u64 {
466 if (self.i >= self.r.len) {
467 self.refill();
468 }
469
470 const value = self.r[self.i];
471 self.i += 1;
472 return value;
473 }
474
475 fn seed(self: &Isaac64, init_s: u64, comptime rounds: usize) void {
476 // We ignore the multi-pass requirement since we don't currently expose full access to
477 // seeding the self.m array completely.
478 mem.set(u64, self.m[0..], 0);
479 self.m[0] = init_s;
480
481 // prescrambled golden ratio constants
482 var a = []const u64 {
483 0x647c4677a2884b7c,
484 0xb9f8b322c73ac862,
485 0x8c0ea5053d4712a0,
486 0xb29b2e824a595524,
487 0x82f053db8355e0ce,
488 0x48fe4a0fa5a09315,
489 0xae985bf2cbfc89ed,
490 0x98f5704f6c44c0ab,
491 };
492
493 comptime var i: usize = 0;
494 inline while (i < rounds) : (i += 1) {
495 var j: usize = 0;
496 while (j < self.m.len) : (j += 8) {
497 comptime var x1: usize = 0;
498 inline while (x1 < 8) : (x1 += 1) {
499 a[x1] +%= self.m[j + x1];
500 }
501
502 a[0] -%= a[4]; a[5] ^= a[7] >> 9; a[7] +%= a[0];
503 a[1] -%= a[5]; a[6] ^= a[0] << 9; a[0] +%= a[1];
504 a[2] -%= a[6]; a[7] ^= a[1] >> 23; a[1] +%= a[2];
505 a[3] -%= a[7]; a[0] ^= a[2] << 15; a[2] +%= a[3];
506 a[4] -%= a[0]; a[1] ^= a[3] >> 14; a[3] +%= a[4];
507 a[5] -%= a[1]; a[2] ^= a[4] << 20; a[4] +%= a[5];
508 a[6] -%= a[2]; a[3] ^= a[5] >> 17; a[5] +%= a[6];
509 a[7] -%= a[3]; a[4] ^= a[6] << 14; a[6] +%= a[7];
510
511 comptime var x2: usize = 0;
512 inline while (x2 < 8) : (x2 += 1) {
513 self.m[j + x2] = a[x2];
514 }
515 }
516 }
517
518 mem.set(u64, self.r[0..], 0);
519 self.a = 0;
520 self.b = 0;
521 self.c = 0;
522 self.i = self.r.len; // trigger refill on first value
523 }
524
525 fn fill(r: &Random, buf: []u8) void {
526 const self = @fieldParentPtr(Isaac64, "random", r);
527
528 var i: usize = 0;
529 const aligned_len = buf.len - (buf.len & 7);
530
531 // Fill complete 64-byte segments
532 while (i < aligned_len) : (i += 8) {
533 var n = self.next();
534 comptime var j: usize = 0;
535 inline while (j < 8) : (j += 1) {
536 buf[i + j] = @truncate(u8, n);
537 n >>= 8;
538 }
539 }
540
541 // Fill trailing, ignoring excess (cut the stream).
542 if (i != buf.len) {
543 var n = self.next();
544 while (i < buf.len) : (i += 1) {
545 buf[i] = @truncate(u8, n);
546 n >>= 8;
547 }
548 }
549 }
550};
551
552test "isaac64 sequence" {
553 var r = Isaac64.init(0);
554
555 // from reference implementation
556 const seq = []const u64 {
557 0xf67dfba498e4937c,
558 0x84a5066a9204f380,
559 0xfee34bd5f5514dbb,
560 0x4d1664739b8f80d6,
561 0x8607459ab52a14aa,
562 0x0e78bc5a98529e49,
563 0xfe5332822ad13777,
564 0x556c27525e33d01a,
565 0x08643ca615f3149f,
566 0xd0771faf3cb04714,
567 0x30e86f68a37b008d,
568 0x3074ebc0488a3adf,
569 0x270645ea7a2790bc,
570 0x5601a0a8d3763c6a,
571 0x2f83071f53f325dd,
572 0xb9090f3d42d2d2ea,
573 };
574
575 for (seq) |s| {
576 std.debug.assert(s == r.next());
577 }
578}
579
580// Actual Random helper function tests, pcg engine is assumed correct.
581test "Random float" {
582 var prng = DefaultPrng.init(0);
583
584 var i: usize = 0;
585 while (i < 1000) : (i += 1) {
586 const val1 = prng.random.float(f32);
587 std.debug.assert(val1 >= 0.0);
588 std.debug.assert(val1 < 1.0);
589
590 const val2 = prng.random.float(f64);
591 std.debug.assert(val2 >= 0.0);
592 std.debug.assert(val2 < 1.0);
593 }
594}
595
596test "Random scalar" {
597 var prng = DefaultPrng.init(0);
598 const s = prng .random.scalar(u64);
599}
600
601test "Random bytes" {
602 var prng = DefaultPrng.init(0);
603 var buf: [2048]u8 = undefined;
604 prng.random.bytes(buf[0..]);
605}
606
607test "Random shuffle" {
608 var prng = DefaultPrng.init(0);
609
610 var seq = []const u8 { 0, 1, 2, 3, 4 };
611 var seen = []bool {false} ** 5;
612
613 var i: usize = 0;
614 while (i < 1000) : (i += 1) {
615 prng.random.shuffle(u8, seq[0..]);
616 seen[seq[0]] = true;
617 std.debug.assert(sumArray(seq[0..]) == 10);
618 }
619
620 // we should see every entry at the head at least once
621 for (seen) |e| {
622 std.debug.assert(e == true);
623 }
624}
625
626fn sumArray(s: []const u8) u32 {
627 var r: u32 = 0;
628 for (s) |e| r += e;
629 return r;
630}
631
632test "Random range" {
633 var prng = DefaultPrng.init(0);
634 testRange(&prng.random, -4, 3);
635 testRange(&prng.random, -4, -1);
636 testRange(&prng.random, 10, 14);
637}
638
639fn testRange(r: &Random, start: i32, end: i32) void {
640 const count = usize(end - start);
641 var values_buffer = []bool{false} ** 20;
642 const values = values_buffer[0..count];
643 var i: usize = 0;
644 while (i < count) {
645 const value = r.range(i32, start, end);
646 const index = usize(value - start);
647 if (!values[index]) {
648 i += 1;
649 values[index] = true;
650 }
651 }
652}
std/rand_test.zig deleted-507
...@@ -1,507 +0,0 @@
1pub const mt64_seed = 0xb334e49d0977c37e;
2pub const mt64_data = []u64 {
3 0x2ad1a63fab6d25a9, 0xb7143aba12569814, 0xc1b60d8d49e53e8, 0x5652adfc8da656dc,
4 0x43e3beb6d9e484a9, 0x17b09b71e9418ff7, 0x541646292686cfa4, 0x260457071268ecfc,
5 0x1627af31774e1dc1, 0x362a49b34ed75bb3, 0x7acf72002fe0f733, 0x3aaaf2e7b9409452,
6 0x9cfc2d9908115c2, 0x6e81a7f16ae613e9, 0xfc4da89c04acf3c7, 0x6984b6adb4feb9ae,
7 0x6a128b334e27b03d, 0xcc45a2b02937871a, 0xe585b229e00b2283, 0x7a92c0664a6f678a,
8 0x972735011bdc0744, 0xb494e743d658a084, 0x1eda3c4e7b1b2d0c, 0x4c7adb3831d87332,
9 0x12f8c7355f5ec631, 0xfc2bcb6be7d60eba, 0x74b95b47895f8687, 0x171de6fe92b97f5a,
10 0x86383730f52719ac, 0xe4e43ce0f61274f6, 0x514f7e072d96f19c, 0xabef324fbc6cb7fe,
11 0x7534b945b742f14f, 0x47f9efe33265adbe, 0x7bcab027a0abf16b, 0x3312a2b34225bff7,
12 0xb61455ce8c2e3e0b, 0x2b81008deeee4d94, 0x743b0b2b4974c7b6, 0xfc219101fd665f7d,
13 0x863d78891cbfe5e5, 0x7531bb1839181778, 0xf614359a65356e72, 0xfcdd1f6e3f250bdd,
14 0x528e10bd536eed5b, 0x9f69386ac60cd618, 0xbf5f242706817f01, 0x8e7da8070072cf64,
15 0xaa318b622da0667f, 0xc9580540fb7efd66, 0xb5d996deccd02e0e, 0x81c6a799ea3f5a41,
16 0xe6b896f4e21a8550, 0xde5206f177a24ceb, 0x53343e81639ec0b6, 0x5a6edb63d08be9f6,
17 0x3602c2892f7da1b9, 0xda84f4259841bdea, 0x5880e169a7746e45, 0x57cddb5ffd3c2423,
18 0x28fe1166fe7b8595, 0x92136c9decb42243, 0xa8c4199818ca7d62, 0x5042cd96f62854dd,
19 0x22b2d38c3f21f8d0, 0x73a2bfccf1b5f7bb, 0xaba3718f40b6984e, 0x9c1f5dc3e399f5f0,
20 0x9cf463f95369c149, 0xa7546d69e4232e18, 0x9ea57317d19ab7fc, 0xfb13c83d830731fb,
21 0x635a123eaa099259, 0x9a2fe7d0ba6e3c5c, 0x40b903cd0d0d3b4e, 0xc8210eb2d2e941cb,
22 0xd2582d4b1e016484, 0x1d048030875af39c, 0xb51c31a6c193d76f, 0x5ce9b801b8d61626,
23 0x2bae30455cbb0022, 0xba54df5998b2443f, 0x927abb9342c9a90a, 0xc431eb7df3e06727,
24 0x726f885d3da88d5, 0x7d85ff1ca4260280, 0xaf3fecf8f019817, 0x31d39105d6fc4fe8,
25 0x262d9842dbafd4bd, 0x54c28a2876e62e39, 0x95a986e24e214dde, 0xbf677a1abd2e553,
26 0x48ac890ff787b2b6, 0x2890ec1c67c539f4, 0x7ce88bf3975882c3, 0x88ef340414a29c88,
27 0xe30de9c88a00805b, 0xe772225e3ee6c68a, 0xa3a7d0921c5d5816, 0x8354957227b1663f,
28 0xb5b65ded7c747cbc, 0x93b4a12ff2e8fcea, 0x6359579c3c438b3c, 0x45b2c12e9722f2bd,
29 0x659a604414f19e1, 0x4ec9a149d4219ca5, 0xd830290dd6aebe2b, 0xabc7874a6b4827f8,
30 0xc91be5dd875847e7, 0x5b761d39f3f96aee, 0x5749dffad692b6c8, 0x86c94840cbd249d2,
31 0x411a466e886ad7, 0x27dca1f51aebb9a0, 0x1cceb093fbab7a42, 0x7140c2d6706e927c,
32 0x6881fdb87299a92f, 0xa81a28de171f3c47, 0x8fa9a1b3bb5dfb2a, 0xae076853e3e0abde,
33 0xe76572308ecd6b54, 0x6cd926c2e2760d8a, 0xdf080266cfbe3dc3, 0xb99b961999765d7b,
34 0xadb5d4e2b896ddf1, 0x8d3aaf4c83c83c56, 0x9b66e4f6eb65bef7, 0x7a81c3bf785eb1df,
35 0xc53f02b3e8c38647, 0xcdfeb25ee787759d, 0xead5e734d64ab5f6, 0x7930d87af1072499,
36 0xf30690a71d88ad6e, 0x73c347923c84728a, 0x3f2b588221003fe4, 0xe747052d0b453af2,
37 0xabe6fa70539b5edf, 0x4db6d1530d628c2, 0x4ec929af434eb1b0, 0x15afbe39886181ff,
38 0xa9141b9c89a07b80, 0x7d33f966c6232057, 0x8ddcb412f34a491d, 0xa74472b8ecc1e2f2,
39 0x34d745de1cb7de2e, 0x6cf67091309e5e93, 0xfb25004efa59450a, 0x3355947066522286,
40 0x5a8cffdf079dac21, 0x419445d6e6825887, 0x6e9c064f84381dcf, 0xbbcaf462a3a8ad76,
41 0x75836c68d6c1a13e, 0xf38141565d5c3759, 0x8c65989142ffa802, 0x106067ec26e6463,
42 0xadfac5e3a80de9c2, 0xc48b16e2df25b9f2, 0xa3257889c33669e6, 0x5bc760d4d65a1745,
43 0x303cd31fead81139, 0xfb97f78cade31e1d, 0xb888b8e05820a469, 0x7ebb8e44d47f54d9,
44 0xce76cdbb5ecdc529, 0xb1eb29949a099d52, 0xb6affc1b240a7eb3, 0x22977eac542906f1,
45 0x9b105b391ff729df, 0x83371186b2834968, 0xd5b893f382ea9e90, 0x5d17aa80a1fd4854,
46 0xe8ed8525eb29210c, 0xc789f3cd36c4dae3, 0x556e50a5f46b73fb, 0xef1d129b523dff77,
47 0x851de0f53f6707f9, 0x8deeeadfb1fa8bfc, 0x3d8c89c0e08c4f2e, 0xecfaaea537123333,
48 0x5bc9053d2dfd7669, 0x408c5bb2e880a9a2, 0x495726b3f3248219, 0x2b23cca4a6ea1ccc,
49 0x1df3663045092d61, 0xaf977a46e965e45b, 0x43a2facfff7f97e, 0x9b7714344c7b51e,
50 0x35643b24efb0559a, 0x502820785dc1af13, 0xbf82d2775b46433d, 0x1db626f2e16ca66,
51 0x744b031447c1e27d, 0x99e79898612f4606, 0xda02a728d234821f, 0xcf00c6fbb637a6e9,
52 0x242f2963196fd8b, 0x7aed8efc2dd562bb, 0x6204fb5d3dc6208a, 0x3e84861182fc7f6,
53 0xd14c4ee5aeef5c7a, 0x3749fbef94378dc1, 0x8fe710ec5cfc8566, 0xf43d7e495d5384d7,
54 0x8ff6396f1f1ce7c4, 0xf1252a6b6f86b42c, 0xddbbd098d6dca83f, 0x4e228724a227232a,
55 0x92a5a52ba2b24fa8, 0xdfc172b03fde669c, 0x34ee55adf7f0711c, 0x21d181e79b8000bc,
56 0xc788b1f48b37b693, 0x544fc4cfed0e0f92, 0xafca0c6de41789cc, 0xbb37bb5107ef97f8,
57 0xb9d62bf1dc0f6c95, 0xc78b5a36110dfb1, 0x1d615b658f39657e, 0x2bb2cd04cabcc360,
58 0xe563488ece6362f0, 0x213b56ce006fecc6, 0xc38207089fed0270, 0xa33199ff4a51d095,
59 0x1802ad28fb1896b1, 0xbead8f18c164a332, 0xceb5149101aa450f, 0x39ad89851ee8b62a,
60 0x317229aafabf37c4, 0xee68b8b9bf3520b3, 0xe4db499288350f04, 0xf8ea27feddb0ae7a,
61 0xa17235067b489c42, 0xbf4a570245f95d78, 0x8065c67e1d1537ab, 0xbd9357fb1b30aee5,
62 0xc224166ebeb24c42, 0xf9baf8ccd01b53bf, 0x5c13775c3fea8038, 0x4ea66f6d650ce62d,
63 0x470592ed81c140f2, 0xc2d0eb6f7999321f, 0x85d762f20290dc0c, 0x9f7d0d13936f6e78,
64 0x41f1fd2d20f2d62d, 0x891cb19ce1af2c2f, 0xe7ff34c3b29c3719, 0x246743f43126c69c,
65 0xea4b2da3195ebab9, 0x4831e4de995187dc, 0x7fb8969bbee45ce5, 0xe35b483da73c44ed,
66 0xf89158ca9af36227, 0x9fc7f34a35469a7a, 0xd02483ebca6564e7, 0xca00da156aaeda03,
67 0x303d1514646822f1, 0x226832ae582b8eac, 0xf772d719e413504e, 0x87603b928c068ab1,
68 0x4dc1552230e9b883, 0xef8c5e9db946fc87, 0x935581290bf7a4ee, 0xca632d2c7674bf2,
69 0xd8a3933b80d39efd, 0xf026574d0ffee6fb, 0xe4412d0dcd2fe94f, 0x668916490a2983ec,
70 0x73b1fe84a995718, 0x729bedefe21cc0e7, 0xd3a770f1c683b98f, 0x5d597a96323a10c2,
71 0xfbb7834bbf5fed23, 0xf3546c805a42ccdd, 0x9ef3e2164bb31a0c, 0x388363ce6c6c2253,
72 0x8120f4a949f017cb, 0x925a61942bbd3d10, 0xa03182d8599c0521, 0x2412e23004b40ebb,
73 0x35010a126bf2aecc, 0x21147869a1a84ca7, 0x53cba503b6127b98, 0x10c89dd62ab3591c,
74 0xf4c7f84faaf9f5f1, 0x8b4a37a2e844b97b, 0x23ddeb236a0bd9af, 0x4fd51d7207f49e62,
75 0x6cdab447c27706b2, 0x9e8f54b9a2d1a790, 0x191aed85d4d77087, 0xf74ecf5015265af6,
76 0x45925e25404922a1, 0xcf5467a0f5b42b98, 0x73590809c85c728c, 0xc16beeda74a1a1b8,
77 0xc3bbe7999803dd6a, 0x1a368bb32eec184, 0xafad2d86b7bb574f, 0xdc7c7b8960dc921a,
78 0xd9b68d854f5e0ae1, 0xe9e1a6a16efe0bea, 0x304a15bd6ca1cb14, 0x713ce3144e0af4b9,
79 0xc50eb410981be1d2, 0xb0fba6119bf7a300, 0x7a107296731fd314, 0xdd764898a90042b3,
80 0x8a69973262da3bc8, 0x29c6b9d048596c44, 0x62581bd20da76f1b, 0x4d1a3941d6d3e4bb,
81 0x19c447306245055, 0xb2978afcd04ba357, 0x7c01cdefcfe24432, 0xc4b268314411deae,
82 0x5ba56d49da714765, 0x33299186ac6dfd09, 0xede087aec096ef0d, 0xf758da2c7bcf9ddb,
83 0x5ea6c40d56824cdd, 0x121ff879d6ba905b, 0xb5fed0c42b616f5c, 0x21029cdc347de152,
84 0xb251d93f4cd7bf4a, 0xaedcb2dc6402cf13, 0x840e5e0d96e89407, 0x6a92fd328efcc6ef,
85 0xc63f5d8f6fcadcbd, 0x405bd64d1621128e, 0xe1318888172f58ed, 0x1009c9764d49da2b,
86 0x4bc0592cbfdf9f91, 0x972f0e080dfecd02, 0xa1cb961958eeb6aa, 0x6ee6467ad8c20aca,
87 0xb3f1c738390d6a83, 0x6504eb7ac498650d, 0xdf7dda67f198f59f, 0x72615652e56a82c3,
88 0x85e0fa2dfb51755a, 0x98b1f92a3d2ad940, 0xce81d51d875c0045, 0x437004d0be0a4d69,
89 0x64065895526f896c, 0xe1e1fea920785d49, 0x7d507ffd56fda19a, 0x17309b625cecb42,
90 0x67b6d83f0fd0f572, 0x5178665a5bcd38f4, 0x3c49fda2d35a8606, 0x7f058d2cb0ad351c,
91 0xfb95691559245416, 0xc991b857662b1b9f, 0x9e6d0f4e19774f96, 0x26cc7502212ca578,
92 0x3466110f03225e49, 0x2ae4958375eab9f3, 0x939a8d94c8871191, 0xa27356548ac6b28d,
93 0xacf86d43ec3aa030, 0xe0d16c7fa0b13a8c, 0x408ec2b2f8da531b, 0xde72494115ee4e83,
94 0xd26d7f79a02c5b1e, 0x2b6f835520c97f6a, 0x1f30f008b109ae7d, 0x698dbf9acaa222f1,
95 0xbd55de40838376d5, 0xebe53822cec7eb80, 0x7ce900793008d2bc, 0x494fc7d10e8331bb,
96 0x53509b90bdb7d588, 0x62aa920e9554b2f2, 0xe103098542011b6f, 0xeb722b9523d68af8,
97 0xb71b1a6ea2c6591b, 0x97cd7da55c940270, 0x8ab70184427e45dc, 0x6cb6907427808465,
98 0xf69232a42dbe7475, 0xbc9816d429fa8909, 0xef1e74244539d41b, 0x5569b6d10440d5c,
99 0x7dda6817985c8ef5, 0xb270ed19cc8161b3, 0x87d80b66c8a15db0, 0x96966684c3ba47fb,
100 0x996669bc87aff3bf, 0x17c015383c793f2, 0xa4b5de41fc69f61a, 0x14a0eb4e3055742f,
101 0x5f0da5a7a2b8bc79, 0x5fe0353728aac023, 0x1554daf4abe92eed, 0x545722dac774b6a4,
102 0x733fc54174f2e0d1, 0x3478ef85dd994316, 0x58ba2ac090ef7575, 0xa66b9b0cbc77b6e2,
103 0xdc78cab5c708a3ee, 0x97a30c27be510f61, 0xb95d0b06fc0910b6, 0xdc80bdc42f79a25f,
104 0x5cadc438e65b3070, 0x6263df49ce691b9c, 0xa7ce160daa64416b, 0xa4f8bfedb57288c1,
105 0xa51714e187bbcfe9, 0xe25df4e9fc44644c, 0xeaf1854b3116ce11, 0xde1b8f810991a604,
106 0xd4fc2e365e99be4b, 0x8d1b0d2799527e06, 0x7cac59eaf46baba, 0x4fa63c74d2dabaf1,
107 0x4f6c5d5e676733a6, 0x7ab7ddb9c1b789b7, 0x5d9beb4877a37034, 0x5e96bc9de3985bcb,
108 0x72bab4dcb75b3228, 0xfa40f33c4d799e1f, 0x73e6f61a69984a6b, 0x7499c9af466cf22f,
109 0x42fab9136bfa64dd, 0xd5e8e39513b6fffd, 0x8eda1fd5ad8cd51d, 0x95338744859dff44,
110 0x4f0c5e5ae768c729, 0x5bc92c60495ae348, 0xcbb48c170ac21168, 0x8374aa2440eeb138,
111 0x70b663d6f6d70ca9, 0x11264ca6dd79e5a0, 0xf058a2c156974514, 0x36820eefc435ba63,
112 0xd7b69f3d0c0c27a1, 0xe1a2eddf3b41d205, 0x80508ec93b038bc8, 0xd7e0429bd511ff37,
113 0x7bf55a4e87e183b8, 0x4cb370ce7edb4bea, 0x26fbd0b31dcef45b, 0xf7acbd6781419fa6,
114 0xf7849659f05c90c, 0xb686271ea57a47c6, 0x16f3f839dbfb4e1b, 0x906872b08b2c61a,
115 0xc30c86d0a0203c15, 0xdaf238a6aa4fc9f7, 0x2399aa09ad2c069a, 0xf133c3aca703f545,
116 0x868a10304a1c98ba, 0x60ef0607f46f7e90, 0xe4e69f26931e11a5, 0x487b8f6bd6d92941,
117 0xd10cb2971798c0c7, 0x7126d81aa4bd0106, 0xcb620311dc84ab82, 0x26f8734a7a356bb2,
118 0xcf9b9eeb02ee978c, 0x8a9ff0285d4d6b30, 0xe30e3b957e2cc7f8, 0x7c15a09e4d275809,
119 0xdf723ae1dda5d167, 0xac212e4f6264bba2, 0xe3d60920ed983308, 0x91b403cbc91e290c,
120 0xcdb905b012aff7c7, 0xb5ee73d45f900897, 0xafacc7cd7f5d52e7, 0xa8653272621165d6,
121 0x90e2efc485ddd0d1, 0x56ef1ca9097b1a96, 0xc7a20f85777eb0a, 0xf4cec0271a50eae9,
122 0x21acd76442024973, 0x19a46be82a4abdbe, 0x1bc12e0b8bf41fbb, 0x3766fe3d8e5119f2,
123 0x7fea355c4c18e8ad, 0xd08b496a24fb8017, 0xe1a7cfaa0877aa2, 0xd37ad9e2a2a3fa96,
124 0xaa362ba0e696f679, 0x7e7de89142c3aca5, 0x2dedb0842a3575b8, 0xb74c1e1d9082fe5b,
125 0xb1ae74323699140f, 0x73623f80c727a6ea, 0x132ed204b0f10441, 0xc3e6ebe8ffc252bf,
126 0x5f15cffb8286dce0, 0x66dab32df780fa8f, 0xeb00da7b25ea99e4, 0x113ad2448fafb671,
127 0xee065c10a8f1924f, 0x2fcb7367cc01fe5, 0x484338f5c2d0aacd, 0xecfacd785e42d7a6,
128 0x11513f845de8af3a, 0xd11be6b29054de0d, 0x2536e5d2856af9b7, 0x60ab519760acd4c4,
129 0x6bfe010250a831ac, 0xb28a93e44b53b21b, 0x281cf9b233858583, 0x4ca6139abc79a710,
130 0x5717d33616d77a95, 0x9ba52d2b7dfe71b5, 0x32e1c543476aa17d, 0xae242cc75806b7fa,
131 0xa1415cb8fde770da, 0x3956c67542dc004d, 0x3a6f51518fdd20ce, 0x448c848f6c936d93,
132 0x8fec38ff51bb5fab, 0x7463816cfc0754ac, 0x83b38e531ba39e73, 0xf9fc84dcf4f8c93e,
133 0xdf20dbe8b91c3d6f, 0xec65939ac9516f9a, 0x888346f6c1aaa94a, 0xe42cabb108f60d95,
134 0x39bb2e46b0599fa9, 0x529335ed75acba9e, 0x6a8767c5d00776c4, 0x8243346104fe61a5,
135 0x7a2bd0339b3e9bac, 0xb68ccdf14473f4ba, 0xa06f389531ab553a, 0xc7c6f074fc2882d3,
136 0x50a5fd6e6d0df962, 0xd7c0000d194139b7, 0x5ae27ef4033f873d, 0x4e7abe8a6d3570f8,
137 0x27011ccd3885e709, 0x3dae53f7b7a8924a, 0xa9086c9b2b86fb71, 0xa3f9e534a399e62c,
138 0x9f2f0379f9a33ec6, 0xceb51af95d4472bd, 0x15aa534182f8465, 0x96373b9cd28a627b,
139 0x9fdce0ad99d41907, 0x2755bb0f52b8c239, 0x2f2e241b6aa7d243, 0xf040afbacb2f6001,
140 0x552267c5f8b4c1b0, 0x22bfb3f0b58f9e48, 0x6bff8de368dbee3a, 0x652025c63d4069ce,
141 0x743eb697b25f9c90, 0x8a3742c9dbf67b1c, 0xaf3bcfc260d7e69, 0x491facaa59b7e1d,
142 0xd07d0761e6535fcd, 0x79ef09d9d3859232, 0xe0e0a013317d9207, 0x4b94baecf6fe4b4e,
143 0x574576ed054cfc38, 0x90e90edd1a26f0aa, 0x616d32a371af78c6, 0x392cea9c34ffb0a8,
144 0x692a6e730c33ac6f, 0x9e4b92ef425b78a6, 0x291d4c962d2f3e7c, 0x5f0f8ebb67f308fc,
145 0xc1a0faf70ec747a3, 0x641da9550cd89392, 0x6adbe38115f09648, 0x3a51980fb324da0d,
146 0xee894f2b5c17a380, 0x58788fa693f767c9, 0xc9f490ff5d88c4c0, 0x2ca6e8b204aa3070,
147 0x7693837d7910c40c, 0x9240e04f16051720, 0xab773072d922faa2, 0xacb6892db8362872,
148 0x5ac8b4d130613c0e, 0x65cd5ac259c653cb, 0x9647e0276864f3f8, 0xe207c57ee9237a53,
149 0xe41f2663482a8fdb, 0xf605931fce8b95bd, 0x5b0247a9009255d2, 0xae949df3ab5a4ab5,
150 0xc0e912dacbb72c42, 0x4226971e6351f33a, 0xd98d41f9f0fdb6c3, 0x64bf6a0af66782d5,
151 0xb4ca689b3959bf46, 0xb4cbf621b4970922, 0xe9f27469c2412fe6, 0xb529d406d27c785e,
152 0xf33be21f2672ec78, 0x34b3c4c4603656cd, 0x4a7efe099a0ae9d1, 0xa6ad5b909667945b,
153 0xe20850e47ab440f7, 0x68739e1b4fa069e5, 0x4c191300a9207cf4, 0x9b613a1a38160c98,
154 0x2cc631eb015081c9, 0x52af80aad7b676f4, 0x904b38943300ca8f, 0x50a515c0d302620f,
155 0x52ae95b8a0c1f36c, 0x6a62ab87786774e2, 0x17ea45367ad58985, 0x92959c57166aa21b,
156 0x2a9d91bd1a9716b4, 0x552c2f8528220174, 0xd665856c96b47d17, 0x14c6cba13b6dca3b,
157 0x865f1c93ec9000d0, 0x23dda8b5e161910e, 0xc191ac4342717953, 0x6783fdb95e098f1d,
158 0x1a4c26a5cad1e8ee, 0xde96e2a1e33e3046, 0xa57e65bedcf9047e, 0xa1cdef163fe7f80c,
159 0xeb0abcc13feeb7b2, 0xaa158c61b0e44470, 0x98dc901679caf85b, 0x954046758f8d2e96,
160 0x56db5e99c5d8c68, 0x7bb8d36962a4ac81, 0x2e301b4ecb03821, 0x121c1b2df70f0e1c,
161 0x3fbdad1e8faa0543, 0x6efb222398a2f88b, 0x65760de4d96338e0, 0x15b2c58a67fb43fa,
162 0x22f1532c89367d77, 0x1f726ffdad411d9e, 0x42572b54dcedf3ba, 0x3f8e0f6e9f0bbb7b,
163 0x4b0e705c86571a1c, 0xf8c9b04f8bd75117, 0x67ed2e9e4545557, 0x57e8853f681bbf8c,
164 0x6f99d1fd5fdbf582, 0xd2aa9bd48ad692e2, 0x2efc88bddecfe616, 0x8e9779a1e119abf4,
165 0x52dfee4722a20b75, 0x79465be3aea146d6, 0x588997dbcbd5f005, 0x79bda8bcc5d4c650,
166 0x2384e131ed3b5330, 0x229cb1d89738aa26, 0x1526d1a020a96507, 0xc7b6ac961a740cb9,
167 0xe78cec14478c4f71, 0xaba61cfd8f1e2a71, 0x24123c8a37ae66f3, 0xbad8b07709aa215d,
168 0x7896fa53fd2418e7, 0x72265842e8c4f955, 0x9f6331fd80527661, 0x7c649eeddb382c9d,
169 0xd3b0708dd6b5ae84, 0xeda51f244551e15, 0xb7822c860b93dd44, 0xdf9afcc3c9cac88f,
170 0x9244b9816573be70, 0xf3d103887cc4ce2d, 0xb3295c2e5bcb0218, 0x85243b7a2e0af441,
171 0xbffd3df508d06098, 0x4908b967f6765c12, 0x8886ac94c0dabb, 0x9c7865af133eb6c0,
172 0x5946fee66e64d7b2, 0x7737bc5af713087f, 0xbec815a80782dd5d, 0xe7672cfe0f7945fb,
173 0xe1f80b6df5beece1, 0x5b749d3a22450fd6, 0xaf34a567bf838668, 0xa72a177d20943ceb,
174 0x257c45c1601c4922, 0x3d7c68f6fe36ce59, 0x1b8ef47186e06c96, 0x8040426656154c17,
175 0xc15f74f980647bda, 0x36389393336a78be, 0x15d174ed5536afe2, 0x51e702e8adb61f63,
176 0xc9c95ca3f1c08f30, 0x6653094c8531c93a, 0xf7be5dfc2eb3b5b, 0xb5e21ec5c63850b0,
177 0x9ab5f082e01021a5, 0x75c4ca38d7678fb1, 0xb20bd13e05e5bd67, 0x3378133e631fbaee,
178 0x17cb3686511aeb6e, 0x4c0dea4c80ec7bc, 0x21fe874bf5509300, 0xece4f84e34d52e54,
179 0x3f2649803ca9918b, 0xdb493adeac5c60f5, 0x7c02a1d153afedd, 0x2d08ceda0fef7967,
180 0x6a32e018e432b0ea, 0x86479f3ea38ad57e, 0x84e3e04f1e5877be, 0x41b898cb02772049,
181 0xd6dded3714d71084, 0x9df5b2f3a0ab275d, 0xd5ab652dfa73ee0a, 0x4633e03fa37d6edb,
182 0x226314b8c4b937ff, 0x45d66a00ab031188, 0xb93ce1cfbcd1eaa0, 0xf88e0756f7e7c1c1,
183 0xf3611966fed51e03, 0x81235048c662d9f7, 0xcc8275f866147b4f, 0xd3b3ca0f5033a863,
184 0x970212eb8c2b3429, 0xec848dd58f3449d6, 0xa1d527af824d09f2, 0x60bd5e91448b9cf4,
185 0x1210ddfac603aa88, 0xcbf4270f3407e25a, 0x212955fec55466a0, 0x3afeaef4c9ccc793,
186 0xdd114286ec304817, 0x849e6ae3c2cf794f, 0x71c08228d6a05310, 0x177e77779d155b11,
187 0xdc59148f219a9c04, 0xb0702a7802d5276d, 0x56085d6761aee015, 0x3f79ce06bcfb4f3,
188 0x459a1f917f8f3e0, 0xe4ea5635e8bcd512, 0xa88e99b63f135a39, 0x95bd628d77d39446,
189 0xe6432158ef4c7d98, 0xb349cd3d1c74369e, 0x25b1a32db58efb0a, 0xc2add3a44cecc0b5,
190 0x5d676629f23010b5, 0x9890b3a62599408e, 0xef68ea8144d97805, 0x429e0fda34046a85,
191 0x7723d9043053bf52, 0xbb78842d9b67ae91, 0x9155ef932192e6a3, 0xdb523ea403d39f6b,
192 0xdb8fa1eee23ea58, 0x7c735492524a3448, 0xc580cb82e81505, 0xb0be6a006414841c,
193 0xdec2e763b5cedaa5, 0x8da58bb23638af5f, 0xb0e6b33f6736e7d0, 0x8146bbcd3dd4df61,
194 0x978080148a8989bb, 0x7f8119caa3308095, 0x4e88c318ea0604f3, 0x6ee5262f16b3cf83,
195 0xc44395c7a578ace9, 0x92016ee635de27e1, 0xb8dc5ceb36e67fd2, 0x95c851d65bd35f8c,
196 0xbe393620503c49fa, 0x42af183b92eac923, 0xfef0e660435135ce, 0x262d67d480451ed1,
197 0x590f92e1ee0502b3, 0x18825c97d49e3700, 0x2cd8c30a848c9acf, 0x1025c7747fda0115,
198 0x54109f23e82590aa, 0x93917bf1f8325981, 0xda674b183fa0e3cf, 0x2a0b2467eb8aefc5,
199 0xb0085eb83468793c, 0x607cabb2c9d3a81b, 0xe7a6b6013804d665, 0x67629a769c1efede,
200 0x2830ab6ef6d10166, 0xffd02b0655332bd4, 0x19bd056c3117568f, 0x385a834785662c6f,
201 0x938b5d56bd5f7248, 0x969afe82dd4829c8, 0xf455d4ace41c797d, 0x23d9cd67eff27512,
202 0x2b0c7037ecb322e2, 0x73df193328258bda, 0x5d7ee05cf2054f93, 0xdabfbd5b46b61cea,
203 0xcea02d82546b96de, 0x2245d5e74d5f60ae, 0x842ca45f8ef2a44, 0x7505cc4e1c3060d8,
204 0x869146ac8e68565e, 0x22ea711fb30e73e3, 0x53cd64736898a0c0, 0xfa88458b920684df,
205 0xc3ae23f451e0616f, 0xe2dd69393141ff32, 0x98863ab129bcd866, 0x8c9756a40dd5b834,
206 0x2eeeef78c36fede5, 0xe84d2eb23e22153b, 0xb0ccc2f7ac541d78, 0x151faba0f513acfa,
207 0x4300e3cea0260717, 0xaba308c6d857d2d0, 0x5eb25dd325256c6a, 0x3342627b68038da4,
208 0x70d7d75526da35, 0x80ff3f5ea2ac3cf1, 0xe7434f2f026394b0, 0xa7c5ff17f7d2cb07,
209 0xdfed0bb33a06ff78, 0x485cc64d38ce2596, 0x88db8580147aa8fc, 0xf52a5111d693b973,
210 0xeeaa031c02b370a8, 0xbb3b1678222d0e81, 0x27b569f2a6630939, 0x2b301fa3e50efeb8,
211 0x4dbc1f85bf3f8972, 0xb37e4f2cb75a825b, 0x3c8848e0f1777cc7, 0x8fae2e6938ba00aa,
212 0xfb4674b50884992c, 0x2b765005b85b7388, 0xaaf0007fb9662ce5, 0x684bd59009a4ad65,
213 0x221ffead3d73ab35, 0xccfe6d02d46856b5, 0x54d3323359e1b114, 0xcb412202ed42f097,
214 0x15d63df422771b9b, 0x71852bca1581d14f, 0xf30dcbb6cf891e63, 0x478fb1eed3cc5a10,
215 0x849a3b52bc5bb196, 0x4c1a98dbc546dd81, 0x846dc8c2258ec4f8, 0xbd4da447c7340bd0,
216 0x8f1ee1d6a85b9db0, 0x123ebfa8aaec07f2, 0xae34948e375d4477, 0xd466a4177842d8e4,
217 0xd5108efeb19cac6, 0x3266f7db8f133bdb, 0xe69af4e5d8d767e4, 0xea0efc0331df64a2,
218 0xb879052746ed72ed, 0x2c8233cc84de4144, 0xdcd5dda825186731, 0xb9e3b679d268f34c,
219 0x7ce12e2fa95bda8b, 0xa34afd12e611a4c1, 0x6043d06ee7619f90, 0xca3a3d4813c0addf,
220 0x6e97a61d1e4b3c4f, 0x8cdeae467a4bb292, 0xf08a6c69e70076b5, 0x97aa5c3180d3edbe,
221 0xc39813e1573904d5, 0x42577549d026e8c8, 0xaf5827ffe259b62a, 0x9e1d48596c4f0b24,
222 0xab9dd230ba8efb64, 0x81769493b85868d4, 0x715b45c5e3952245, 0x84735e138d228f35,
223 0xf4f987da7d19c74d, 0x1bdc77979baf29b, 0x785b3640158e0278, 0x77fc9d00681bcdd,
224 0xb5980cc490dcab93, 0x9062c158196b8244, 0xc16af5418cc97c4a, 0xdd4a4e9e8e00e524,
225 0x870b554b629277f1, 0xf90ff72bb54322c0, 0xd4c273bc2199823, 0xeebc75970d438466,
226 0xe4cad67413074a53, 0x6eccde71bd09dc0c, 0x14278b0ca6b910b4, 0x6e8895f17cdb933c,
227 0xa0b3987821416e11, 0x71b7d24b81fa769f, 0x1d3b1a805b885a58, 0x1bc737b1719736a,
228 0xea4d1dbb8823037, 0xe50ce48c8469adbd, 0x34c2d5e6c41a888e, 0x446a756eb06dc3a4,
229 0xbac5ed8a8f90262, 0x7f1b76e0c707ab9d, 0xb31323309b94a12e, 0xf58269b9852f986e,
230 0x3b74c2b338c244fc, 0x879b46f23a4deae4, 0x3f2591e34cdce1c9, 0x73c6f81eb560ed5c,
231 0xd2aa923c7a5c18a9, 0x7170c1f7621cace9, 0xa18b327b11b951a, 0x2b36315510f56370,
232 0x5cfed2f703dfc0bb, 0x1e43b99175054c07, 0x392dfa3210e8013b, 0x65e0c5c0454ee693,
233 0x2a795f6f493349db, 0x17995ebdfe848db0, 0xf23174b823a52cf7, 0xaac6ef104bfd396e,
234 0xfa0f5b29156eeccd, 0x9ccb3590a6e88c1a, 0x2edae0b1b80aafab, 0x1e1e92baae39aa30,
235 0x24475af89cec7f33, 0xacdbeceaadb9936c, 0x7725948da8586e93, 0xcc05595e17947215,
236 0x1f3cbde17a508faa, 0x2795f58ff5c8919b, 0x309658d1748f30d3, 0xe90c11962e5ed4bb,
237 0xc22b876286d32e27, 0x495c8b667c6ea3dd, 0x84263045f7d6eab5, 0xf8d3a9ab1494a315,
238 0xabc42cf769a21d9d, 0x3fef7fb40bdf3a81, 0xfd35336e188925a3, 0xd472bdaf277ab26d,
239 0x4949e8ff51da2307, 0xbec86dce960ff3b, 0x1aa1ce4f70256b10, 0xd52986ff8cd700ea,
240 0x364d8efc0f5afad6, 0xca3d1958f57a9050, 0x17a0a2ec122dc677, 0x7992695be3363fd6,
241 0x5c66a265e0607da8, 0x7250114e050bb917, 0x30cd3a70bc7b723d, 0x7b77433392b3fbf8,
242 0x295bb7bf46318b38, 0xdb15025af2a71c65, 0x26a82b21ef67f50c, 0x14a5573d4fc798c1,
243 0xd8cad4642ec68e5e, 0x9276d7f60142822c, 0xf7b8efc27522e52f, 0xd0a3f36f6d340bed,
244 0x341260fb11765c02, 0xcd1d394d796702cc, 0x7d483ef031eb3346, 0x74eaab49374576c1,
245 0xa073bea32a71a273, 0xd65ce2552993b5cf, 0x8670afe77caaeb16, 0xb607f1455d072a47,
246 0x30ed96be92809559, 0xa58380a503c23c9c, 0x916aa68fb957a30d, 0x30c5a675bf19738c,
247 0xd4cbad34e4e4b886, 0xd6cb83061f2b0ebf, 0xceddb4040f535fa9, 0x778c586927b1e247,
248 0xe4bb5c4b6e0f3c3d, 0x3e857d671db80667, 0x2b909dd8725f1fa2, 0x558ffd0772db7841,
249 0x710f9638d3edb2c4, 0x21a4ccee53d46556, 0xf76e8e4737b9628b, 0x71cd157f23581c71,
250 0x68d8fded9b66efd6, 0x7d9f5e182c0b9457, 0x2140757748a217ff, 0xdd1e5365520b77a4,
251 0x644d8e4b2f30dcfa, 0xa1de42f4e9791564, 0x70e148ababfe9f86, 0xb97f463e0ac7daec,
252 0x82844f729d9fa554, 0x5c8475e84470c924, 0x3a83de748eac32fd, 0x68725fbc9c202c5b,
253};
254
255pub const mt32_seed = 0x7dc0d160;
256pub const mt32_data = []u32 {
257 0x59327332, 0x200858fa, 0xab53c028, 0x5c442427,
258 0xd8be0287, 0x3b69d304, 0x15fdf62f, 0x59b8ecd,
259 0x6d7ab30c, 0x3a3dd6f1, 0xc1b9773e, 0xa12fb017,
260 0xa805b5c1, 0x4a313ba5, 0xd82c790c, 0x8de311f2,
261 0xe7cb23dd, 0x784b2efb, 0x9743487c, 0x73e2f2fb,
262 0x1a7ac286, 0xaef90d, 0x6c0a4514, 0xae1d83aa,
263 0x412fcca1, 0x3acd2d28, 0xde78292f, 0x13237756,
264 0xdd6cdeba, 0x44ae4df9, 0x3e9902eb, 0x39e1cf20,
265 0x62f561b9, 0x6cbdf531, 0x4a000673, 0xb1c82daa,
266 0x896156ca, 0x75e410f2, 0x9c69e72c, 0x396b42bb,
267 0x25c97ec0, 0xe12173f1, 0x8dcd42e5, 0x82aac3e3,
268 0xcdc1c84d, 0x13509c0c, 0x46a696d2, 0xb89ad987,
269 0x92da5e7f, 0xaa87d8a9, 0xe433ff57, 0x80a7ee49,
270 0xd387cfcc, 0x7dc47d92, 0x21516140, 0x989ca465,
271 0xf2a8e002, 0x73b99ddb, 0x2204108f, 0x27e84890,
272 0x371c81c0, 0x9f581854, 0xc0841c35, 0x770f6804,
273 0x87c55f4e, 0xd29516bb, 0x2b6d6bde, 0x5541f6ee,
274 0x1ec9b182, 0x7d599729, 0x4f4b9a14, 0x6f8c8562,
275 0x2d5151aa, 0xb54f5bc, 0xa252452b, 0x2a4266da,
276 0x25a6b75d, 0x2d11106e, 0xc5d77943, 0xb10b6e0b,
277 0xeb5cae4a, 0x43a0dd53, 0xa40bea1f, 0x63e632c2,
278 0xf420b6ce, 0x8b080233, 0x7f70ae87, 0xf460f0d6,
279 0x147c7e74, 0x710692ea, 0xa0a7d8fb, 0xe7f05808,
280 0xa6173aaf, 0xae608de0, 0x8702036, 0xbf1bfc7b,
281 0xf14cd548, 0xbbc7553d, 0x5358dd1d, 0xcc0c1fe5,
282 0xfab6f78d, 0x9365c118, 0xf64216a3, 0xb4bdcf1b,
283 0xc90b8a7a, 0x8b7b78a, 0x4c7b6854, 0xba7b5628,
284 0xdd728c15, 0xcb1f8905, 0xa63e2342, 0xa78822,
285 0xbda61b18, 0x160a59fa, 0xeccf473b, 0xc5a445b5,
286 0x7aa86430, 0x362e0d7c, 0x8006a0cb, 0x8b11586f,
287 0x6677bba9, 0x6208cf27, 0xeec9b5, 0x3dfedfc9,
288 0x886cc0e8, 0x32ed77ca, 0x43525faf, 0x9786354a,
289 0x1a2eb378, 0xf0e6b168, 0x49064b09, 0x8ab39681,
290 0x7b6655fc, 0x35adb168, 0xc417d430, 0x2784288a,
291 0xea17836, 0xc85006e7, 0x673dfdc3, 0x42765688,
292 0xc2b9251, 0x840a45b, 0xcac98e2f, 0x1a6f9777,
293 0x34959b23, 0xf0dcec81, 0xcaa2c6c8, 0x1cf93061,
294 0x787e598d, 0xd5d9e31e, 0x14e08791, 0xd9d9d782,
295 0xef162f23, 0x238f4113, 0x23f42107, 0x6ed5cc3f,
296 0xa55e5a7c, 0x4650595, 0x5217da8b, 0x6eeaacdc,
297 0xb453d7b1, 0xfa1ff004, 0xb9d17f74, 0x2bd6a53e,
298 0xe4c2d9dd, 0xed66375e, 0xf8215568, 0x9bcadbb3,
299 0x9c4f9d51, 0xff68312, 0x82308422, 0x83e990b0,
300 0x38b6135b, 0x70e2aa13, 0xa30065d2, 0x6396a00,
301 0x77d423bc, 0xa93abf0a, 0xc7bb8c31, 0x5d7bd3d3,
302 0x6a374f2e, 0xe4b5bc88, 0x39f6e512, 0xd6aea995,
303 0x878c1bfa, 0x4636014d, 0x9caa2c09, 0x7ac4758b,
304 0xbd3b957e, 0x518c2fd6, 0xea009a2e, 0x542bf419,
305 0x59090006, 0xb1d94703, 0xe0d9eefc, 0xe7fccb17,
306 0x40111951, 0xf2560485, 0xb50ce9e1, 0xd7a1ee51,
307 0x28dffa99, 0x41d12275, 0xdd89a365, 0xf22eda29,
308 0x104f94ee, 0xe669983b, 0x6346a250, 0x86326fc5,
309 0xb7f347df, 0x3849a39f, 0xf433929a, 0xeea5155,
310 0x4cf9b778, 0x6bd7926a, 0xcda9496, 0xf430d7a2,
311 0x41637670, 0xaf3bbad6, 0xeb66e44e, 0x2499605d,
312 0x9988920d, 0xf9d652ef, 0x67aa80c0, 0x505073c9,
313 0x85cd418f, 0x9f83fb65, 0xf50b3eac, 0x812ba6bd,
314 0x74d61788, 0x86d64f3b, 0xb1f8fc1c, 0x3e2af667,
315 0x4d118a2, 0xd028ffa9, 0x32e88a44, 0x4ed9ba35,
316 0xea3c7030, 0xffe44aaf, 0x5e39c467, 0xeabcfebb,
317 0x53e656ec, 0xced701d0, 0x31020b02, 0x4b4c1dc5,
318 0x8744885c, 0xa8e93656, 0x3ef457e5, 0x272bde23,
319 0xe541477c, 0x3ad3ac04, 0x63eaa692, 0x81055cf9,
320 0x3ff5f782, 0xa8efe6bc, 0x15f37656, 0xaaaebf1d,
321 0xf73d461a, 0xe8b2c0b5, 0x5035ff48, 0x3a95e34b,
322 0x6f21d94f, 0x6f6d1f96, 0xdaf79f37, 0x826f69f3,
323 0x209a00b8, 0x2ad1b2f2, 0x2c64fb45, 0xcf8bf26e,
324 0x9befcff2, 0xc08f6951, 0x96d98205, 0xa267dcb5,
325 0xbc43ec5, 0xee6a7e1c, 0x49224eae, 0x14e820e,
326 0xbb340212, 0x68ed572c, 0x45e9e623, 0x1297f3af,
327 0x49a98ed2, 0xddd34ae8, 0x211838ab, 0x47e7652d,
328 0xb40430c6, 0xc8d3bd7, 0x4352356e, 0xf0e5cac9,
329 0x21880df4, 0xc16b343a, 0xd9ed7350, 0x17fe1f65,
330 0x6637192e, 0xd81c93aa, 0x7d6e17d2, 0xd407b13f,
331 0x425da072, 0x380d423d, 0x6ce57b22, 0x7b17ed17,
332 0x95fbf626, 0x768303d6, 0x76ab6b3e, 0x591491e3,
333 0x259f79ab, 0xd4babeaf, 0x9c7de2f8, 0x4fe6cb58,
334 0xf43680a9, 0x651a1266, 0x730ea3c8, 0x9188d4c5,
335 0x12d01e34, 0x47afb2e9, 0xb4b76d35, 0x5e5164bc,
336 0xc864fc46, 0x5d018aa7, 0x17fac975, 0x5a775fbd,
337 0x40e6fa14, 0x7a00b683, 0x99e4e102, 0x2f933b90,
338 0x474e14ba, 0xde1b0754, 0xe84aba2b, 0xb386cd43,
339 0x17ca77c9, 0x7b4f38ef, 0x803ea1a8, 0x93553947,
340 0x806c8224, 0x2608451e, 0x63157fe3, 0xaf53930e,
341 0x5dfe8c16, 0x65592bda, 0x7086eb3f, 0x838e6a50,
342 0xa27836d9, 0xf2f16d92, 0xdc0a981, 0xfbf8f915,
343 0x2caea00d, 0x86bb3e18, 0x6d94c209, 0x3bbbeb6c,
344 0x114d68f4, 0xc271e48f, 0xa3350dc1, 0xb8d55eb4,
345 0x68be5ee1, 0xbf22ef29, 0xd6e0aa54, 0x48f7219,
346 0x21aca253, 0xfbf07910, 0xfcdd61a8, 0x118a09b,
347 0x3f2bbde6, 0x46eea63f, 0xdb51ed16, 0xf8a9fc36,
348 0x31614dc0, 0xdd84f54d, 0xd2b66065, 0xdae0af99,
349 0x6d071a51, 0xbdbac46c, 0x15deee25, 0xf792e64c,
350 0x910194e8, 0xfc989a8f, 0x919727fd, 0x6f93a56c,
351 0x2df36e9a, 0xd395b948, 0xb026b54a, 0xf0938a5,
352 0xe9c64399, 0xb5cda15b, 0xb7b8dd41, 0x7146f944,
353 0x8d41ce2f, 0x47c74099, 0x2e5a8e5f, 0x28f7a19c,
354 0xef7a8ef9, 0x6a763eb9, 0xf13a3ec4, 0x9f352360,
355 0x42317561, 0x6c6a0ca5, 0x5e40b472, 0x3ddaadd4,
356 0x2f5d14eb, 0x5dd49aeb, 0xc89edb24, 0xa2da269b,
357 0x5cf0a38b, 0x8e2f435c, 0x40970e54, 0xa2cb730e,
358 0xf9d8c301, 0x8ef29fb1, 0xf08b1840, 0x7d45e4a2,
359 0xa0fe4ce1, 0x939a21c4, 0xfdeebfea, 0x4c661550,
360 0xdd304d1c, 0x3cdb078d, 0x94ae8db2, 0x4f6b4287,
361 0xffe64fa8, 0x50384bb0, 0x16cf5ed3, 0xa91a8fec,
362 0xdb8ebb1, 0x59c2898b, 0xd587edc9, 0xdec2e75a,
363 0x496ccdd2, 0x897db91d, 0xf8ea5149, 0x6bed4bad,
364 0xce76e472, 0x43c7f976, 0xb055dc01, 0x7ffd5671,
365 0xe193b86a, 0xe288ce11, 0x514d531e, 0xa42fa47e,
366 0xe7c0e194, 0xffc059ba, 0x26548e36, 0xe1f10d92,
367 0x3ef5d95e, 0xa6e69282, 0xffacb09e, 0xf4a16ff5,
368 0x9b7f03bd, 0x588c54b4, 0xc2b6eaa1, 0x2d83acdc,
369 0x7fdbb606, 0x2b160650, 0x9923e57e, 0x32bd23bd,
370 0x50cd6d4c, 0x205d901f, 0x810a9935, 0x27ce6e7a,
371 0xe0c6c66, 0xac06c99c, 0x4326aa9b, 0xe1af1e90,
372 0xe358c8b1, 0x2f601c2a, 0xefca77e7, 0x1a7ed2f8,
373 0x8ad2e191, 0xe5520809, 0x27084438, 0xe4d8e782,
374 0x5e8a4038, 0x87bba694, 0x65f07eba, 0x616f8f07,
375 0xc5565d9, 0x555955e4, 0xf41c2caa, 0xb085fbf5,
376 0xa5f9d9ff, 0x418fa0df, 0xec5a576d, 0x7fc332ab,
377 0x7683ed33, 0x968ef54b, 0x834d598d, 0x6833f356,
378 0x59dc7e7f, 0x779661dc, 0x58942dd4, 0x80387aab,
379 0xf6dac9e5, 0xe043be04, 0x2ae4f872, 0x881f8d01,
380 0x82cfd69d, 0x931f4648, 0x2a76ab31, 0xa3f1dd7c,
381 0xd7f4826a, 0xe74918da, 0xe4c98636, 0x441164f,
382 0x15a0e9aa, 0xce7480ad, 0xba39076b, 0x233aa8d,
383 0x6c32f0e6, 0x169c62bf, 0xa2cd17f6, 0xb5590084,
384 0xb2036f00, 0x18315935, 0x11e9c9c7, 0x25c77861,
385 0x41596cda, 0x635e5e02, 0x8f396cc, 0x4cd00d8d,
386 0xd665597e, 0x90f891ef, 0x547b93ee, 0x376959c1,
387 0xdc5fa80, 0x9b4797a6, 0x53673041, 0x25ab117a,
388 0x7b8b8292, 0xf4e99584, 0x5139da98, 0x30e2afeb,
389 0xff2664b9, 0x591eb6f0, 0x9e87e602, 0xf5e26193,
390 0x61831f07, 0xabc139f9, 0x984eda0a, 0xaea1b8da,
391 0x65c7410d, 0x2b84800d, 0x1d3cfec3, 0xd05cb8a1,
392 0x4529641b, 0x7d6712e6, 0xc38cbde7, 0xacad7787,
393 0xd8482f3a, 0xa5662eaa, 0x24836ee9, 0xf3b5cc97,
394 0x50a581ae, 0xff6004b6, 0x650fc547, 0x161898b1,
395 0xa7593447, 0x325827dd, 0xf1844a1a, 0x7eb56de2,
396 0x89882452, 0xfebb49a, 0xfe86ae9c, 0x7dba98b1,
397 0x1d65adb5, 0xb71acffa, 0x861215af, 0xc0f1496,
398 0x70967c72, 0x3803d127, 0x6c8fdd84, 0xe40991f1,
399 0x1343e3a, 0xf57b4e73, 0x25f34f76, 0xaebcdee8,
400 0x8752d71f, 0xfc710e54, 0x34f3af44, 0xfa7dea4e,
401 0x477d4d83, 0x42640ff1, 0x2c5c31ce, 0xa82de5e4,
402 0xcc813271, 0x4d40bf86, 0x4e416095, 0xb5ac332c,
403 0xd2d44703, 0xe4c5ef57, 0xde193a29, 0xbf3e7974,
404 0xbb313d75, 0x8dc973d5, 0x301b2657, 0x44dc5064,
405 0x8c58c633, 0x83424c74, 0xb7cbf7ac, 0xa04238c2,
406 0x6ceabd59, 0xd25e6fd0, 0x3409167, 0x42d6ef80,
407 0x1f47c437, 0xdb21e45f, 0x2fd48e29, 0x9498cfb7,
408 0xc9e4cb12, 0xc6dcf0df, 0xa1633c39, 0x1b349670,
409 0xf76d4a64, 0x15ecd8dd, 0x777bb76d, 0xc46008e7,
410 0x23d94e44, 0x78aa07de, 0x2eeac782, 0x3757b114,
411 0x2b22de2a, 0x37726519, 0xf107546d, 0xe9847f74,
412 0x449a4ea6, 0x2e31fa5a, 0xd719ea88, 0xb2115c87,
413 0xfa6b7231, 0xf72fc9ff, 0xcd22bc37, 0x9080778a,
414 0x93430a21, 0x97c24360, 0x6e5b1a76, 0x5e8baa7c,
415 0x300c94f8, 0x2843d9da, 0xdceac0ae, 0xeeed885,
416 0x1898ffd0, 0xa3bbee3c, 0xc16f8fd7, 0x82992b68,
417 0x39c153b6, 0x1b3ba4c8, 0x41e7c3ac, 0xcdf8f06a,
418 0xd40b8ae6, 0x4982b6c2, 0xb32f7437, 0x22ed3691,
419 0x16579a2a, 0xff9de457, 0xc421e8e4, 0x17c8f6cb,
420 0xa5c4a8da, 0x49bd8afa, 0xe2be081c, 0x95170f28,
421 0xd679fbdf, 0xcf39d563, 0x4e2d2ee9, 0x39471096,
422 0x3918bef0, 0x279b7679, 0xa5281a0f, 0x49481d6f,
423 0x11f95ee1, 0xd9df649f, 0x2993eb27, 0x48ad815f,
424 0x99cf306d, 0xca9457e4, 0xc27c51d2, 0xc2a838ec,
425 0x537faf4c, 0x55dccddf, 0x8df5aeb8, 0xabb317ca,
426 0xfc1bcf6b, 0x669c2b1b, 0x719b62d5, 0x6b9325cf,
427 0xc123d0d3, 0x2ddc6ace, 0x27fdc30a, 0xd3f93cd8,
428 0x704f5486, 0xd3f448ec, 0xbbd1e32c, 0x3bcd4c0b,
429 0x86f8166, 0x957db888, 0x899b6a5e, 0x270dc8b7,
430 0xff16222e, 0x51e139a8, 0x3d8b4b9f, 0x68d20818,
431 0xa639ad00, 0x4c2e0fd2, 0xb4949cdc, 0x2ab6eb32,
432 0xdd0c67ad, 0xd2208cbe, 0xcd17a0bc, 0xacc541f7,
433 0xfa9e714f, 0x316d31a7, 0xed79fa91, 0xb5c0e980,
434 0x412ecc9b, 0x9815753, 0xd0df1f43, 0x8e37dbb9,
435 0xe640df75, 0x379c2fb6, 0xc7ed26a4, 0xc5190400,
436 0x1cc81b53, 0xcb0b0cd5, 0x360f061b, 0x6d90284e,
437 0x83c05bd0, 0xbd80bae9, 0xd584ef12, 0x228a46ec,
438 0x657c4fbe, 0x5ca1043c, 0x852aca0f, 0x31ce950,
439 0x33ee2cd8, 0x3cdecbf7, 0x787ef08c, 0xea610ee,
440 0x47c1db89, 0x90eeda11, 0x74f8d429, 0x51d3a4c5,
441 0x3135b401, 0x2e14783c, 0xb9af855c, 0xb66348d9,
442 0xa3a47387, 0x6eb72af1, 0x7bb56088, 0xc664542d,
443 0x7ed96b8, 0x995870a8, 0x385b1fd6, 0xa430680d,
444 0x98a883ec, 0x2497a389, 0x7a880627, 0x8350ba9d,
445 0x4cb35c33, 0x30bf6b14, 0x8695a469, 0x9a81e44b,
446 0x8bb27c9a, 0xbfb6a4dd, 0xbae7cf6e, 0x4ebccc87,
447 0xb712ed3d, 0x31e90365, 0xcc1fa63f, 0x32b93df6,
448 0xbad4c7bc, 0xb2570e17, 0x73fa21be, 0x5c02a8d2,
449 0x94446d75, 0x7265f3ad, 0xd58487a2, 0x919b7a07,
450 0xbe2d0e05, 0xd36ccf4f, 0x6d5c66d7, 0x8448522f,
451 0x8409c294, 0x6f1c7af7, 0x173a13bc, 0x1b3e4a0b,
452 0x705b941b, 0x77eb584f, 0x85b68458, 0x8e3ad1ac,
453 0x4aa99702, 0x7ae1b24c, 0x899ba29c, 0x860a3711,
454 0xabe53a4f, 0x37870133, 0x1ed7cb89, 0xea539762,
455 0x4ba64130, 0x48517a2d, 0xce0a869d, 0x937ba48,
456 0xd0f234c4, 0xf9b2cf26, 0xc3c311f0, 0x153d09a9,
457 0x404d3af9, 0x9f7edbc1, 0xbdcecded, 0x97969ba8,
458 0x3379437, 0xadd3c893, 0x7c024639, 0x459390b,
459 0xcb7c7320, 0xa5c63725, 0x65907e3e, 0xbf70583b,
460 0xcebb601b, 0x4edfb286, 0x9350336f, 0xdfb4be76,
461 0x88b56f39, 0x9937d7f9, 0xa12a286d, 0x34f141c,
462 0xa2e75c15, 0xd69a7060, 0x931340c3, 0x22447f25,
463 0xe8aed82c, 0xd76a9ae7, 0xc967288, 0xe572facd,
464 0xbe82b0ee, 0x10f5dce1, 0x4f03ee35, 0x2340b923,
465 0xf4fb6bd0, 0x64adbf01, 0x3d277a0a, 0x39e76f2c,
466 0xe3c024d9, 0x57869c82, 0x743b7826, 0xf66f1574,
467 0xc93965c, 0xf86a552, 0x13557069, 0x9e0845de,
468 0xaee084f9, 0x5eafaedb, 0xc06f5f3, 0x9051f6ea,
469 0x98fceda2, 0x2af2f8cc, 0x6c41b5a8, 0xc1af74de,
470 0x57302276, 0x253923c9, 0xd79996b3, 0x8ecb3141,
471 0x641387cc, 0xf87a4101, 0x96a50c76, 0xbcf24a11,
472 0x87b6bb6, 0x58ee501b, 0xaa859695, 0xb2eed107,
473 0x554173f0, 0xb12ec0e6, 0x57785c1b, 0x53685c9a,
474 0x114c3163, 0x9383cf19, 0x31fd7cdf, 0xaeb8225c,
475 0x58774fe7, 0x54700ad4, 0xad418726, 0xf055b71c,
476 0x7d31237f, 0xdd97cad5, 0xcdd5325e, 0x42f2acf4,
477 0x4bed262b, 0x7a8faaf2, 0x2b1eafdd, 0xa1b806ac,
478 0x26965c6e, 0xb41b7168, 0x15e2e70b, 0x7daa8e13,
479 0x6198aa5a, 0xc9b8b94c, 0x339b5754, 0xcd3b285c,
480 0xffd1486c, 0xf224979a, 0xafb89ec5, 0x222058c,
481 0xcb4814d0, 0x2b0e7c7d, 0x9eb25b84, 0x271564b0,
482 0xbb72e076, 0x48251020, 0x18008023, 0x48d10005,
483 0x4a452eaa, 0xb2365308, 0x19cdb632, 0x1fd56d04,
484 0xffa5ff2a, 0xaba89e42, 0x388fc17d, 0xea61c00f,
485 0x5156273d, 0x776f1a56, 0x8d539d28, 0x289c01cb,
486 0x857aa71f, 0x348e411f, 0xc9eb3c91, 0x67a61079,
487 0xe4276a0f, 0x45bdc15f, 0x8e0a698e, 0xbdefc310,
488 0x82377ba6, 0x3bfbf404, 0xcbf22c79, 0x35f501bc,
489 0xb16044a7, 0xeffdb8, 0xdbac383d, 0x7816663f,
490 0x18f5a318, 0x3d04f1cb, 0x735da9b4, 0x75e339a1,
491 0x5b6c55f, 0x1c18887e, 0xf698e14f, 0x338a6da1,
492 0xdac85699, 0x1aca7768, 0x8eb0fa7a, 0xc98fa71d,
493 0x3b794408, 0x92913041, 0xf8dc8827, 0x1cf706e9,
494 0x3aeee292, 0x321dbaa8, 0xee1eb8d1, 0x23554be9,
495 0x811c7804, 0xf0f4de6b, 0xd457e382, 0xeda56795,
496 0xeffdfc71, 0xf2a52829, 0xa7460732, 0x2c1321c0,
497 0x2f734db0, 0xf04ecb0b, 0xec7d777e, 0x43c54317,
498 0xccaa74cd, 0xfe49dd9d, 0x4c509829, 0x278f9bd7,
499 0x581dc500, 0x4ad38c2e, 0xcbee1047, 0x13302c1c,
500 0xbc0cb734, 0xc1c8f234, 0x1df52b35, 0xd8815548,
501 0x319edefb, 0x437cebe5, 0x3dcb6026, 0xe9d4f93f,
502 0xb2661154, 0xeb8c15a0, 0xb008505, 0x5f869981,
503 0xf5588ca4, 0xd6929c5b, 0xa3dd13d1, 0xdc863314,
504 0x891a454f, 0x91737e49, 0x5064d4d8, 0x2fd32675,
505 0xadefe9b1, 0xdde32b11, 0x741bbd6, 0x3b4363a9,
506 0xb121d9e8, 0x916ca61d, 0x38c0af15, 0x5e3dfd72,
507};
std/sort.zig+78-78
...@@ -67,7 +67,7 @@ const Iterator = struct {...@@ -67,7 +67,7 @@ const Iterator = struct {
67 self.numerator -= self.denominator;67 self.numerator -= self.denominator;
68 self.decimal += 1;68 self.decimal += 1;
69 }69 }
70 70
71 return Range {.start = start, .end = self.decimal};71 return Range {.start = start, .end = self.decimal};
72 }72 }
7373
...@@ -82,7 +82,7 @@ const Iterator = struct {...@@ -82,7 +82,7 @@ const Iterator = struct {
82 self.numerator_step -= self.denominator;82 self.numerator_step -= self.denominator;
83 self.decimal_step += 1;83 self.decimal_step += 1;
84 }84 }
85 85
86 return (self.decimal_step < self.size);86 return (self.decimal_step < self.size);
87 }87 }
8888
...@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
219 var B1 = iterator.nextRange();219 var B1 = iterator.nextRange();
220 var A2 = iterator.nextRange();220 var A2 = iterator.nextRange();
221 var B2 = iterator.nextRange();221 var B2 = iterator.nextRange();
222 222
223 if (lessThan(items[B1.end - 1], items[A1.start])) {223 if (lessThan(items[B1.end - 1], items[A1.start])) {
224 // the two ranges are in reverse order, so copy them in reverse order into the cache224 // the two ranges are in reverse order, so copy them in reverse order into the cache
225 mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]);225 mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]);
...@@ -230,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -230,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
230 } else {230 } else {
231 // if A1, B1, A2, and B2 are all in order, skip doing anything else231 // if A1, B1, A2, and B2 are all in order, skip doing anything else
232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;
233 233
234 // copy A1 and B1 into the cache in the same order234 // copy A1 and B1 into the cache in the same order
235 mem.copy(T, cache[0..], items[A1.start..A1.end]);235 mem.copy(T, cache[0..], items[A1.start..A1.end]);
236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);
237 }237 }
238 A1 = Range.init(A1.start, B1.end);238 A1 = Range.init(A1.start, B1.end);
239 239
240 // merge A2 and B2 into the cache240 // merge A2 and B2 into the cache
241 if (lessThan(items[B2.end - 1], items[A2.start])) {241 if (lessThan(items[B2.end - 1], items[A2.start])) {
242 // the two ranges are in reverse order, so copy them in reverse order into the cache242 // the two ranges are in reverse order, so copy them in reverse order into the cache
...@@ -251,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -251,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);
252 }252 }
253 A2 = Range.init(A2.start, B2.end);253 A2 = Range.init(A2.start, B2.end);
254 254
255 // merge A1 and A2 from the cache into the items255 // merge A1 and A2 from the cache into the items
256 const A3 = Range.init(0, A1.length());256 const A3 = Range.init(0, A1.length());
257 const B3 = Range.init(A1.length(), A1.length() + A2.length());257 const B3 = Range.init(A1.length(), A1.length() + A2.length());
258 258
259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {
260 // the two ranges are in reverse order, so copy them in reverse order into the items260 // the two ranges are in reverse order, so copy them in reverse order into the items
261 mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]);261 mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]);
...@@ -269,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -269,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);
270 }270 }
271 }271 }
272 272
273 // we merged two levels at the same time, so we're done with this level already273 // we merged two levels at the same time, so we're done with this level already
274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275 _ = iterator.nextLevel();275 _ = iterator.nextLevel();
276 276
277 } else {277 } else {
278 iterator.begin();278 iterator.begin();
279 while (!iterator.finished()) {279 while (!iterator.finished()) {
280 var A = iterator.nextRange();280 var A = iterator.nextRange();
281 var B = iterator.nextRange();281 var B = iterator.nextRange();
282 282
283 if (lessThan(items[B.end - 1], items[A.start])) {283 if (lessThan(items[B.end - 1], items[A.start])) {
284 // the two ranges are in reverse order, so a simple rotation should fix it284 // the two ranges are in reverse order, so a simple rotation should fix it
285 mem.rotate(T, items[A.start..B.end], A.length());285 mem.rotate(T, items[A.start..B.end], A.length());
...@@ -301,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -301,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer
302 // 7. sort the second internal buffer if it exists302 // 7. sort the second internal buffer if it exists
303 // 8. redistribute the two internal buffers back into the items303 // 8. redistribute the two internal buffers back into the items
304 304
305 var block_size: usize = math.sqrt(iterator.length());305 var block_size: usize = math.sqrt(iterator.length());
306 var buffer_size = iterator.length()/block_size + 1;306 var buffer_size = iterator.length()/block_size + 1;
307 307
308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
310 var A: Range = undefined;310 var A: Range = undefined;
...@@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
322322
323 var buffer1 = Range.init(0, 0);323 var buffer1 = Range.init(0, 0);
324 var buffer2 = Range.init(0, 0);324 var buffer2 = Range.init(0, 0);
325 325
326 // find two internal buffers of size 'buffer_size' each326 // find two internal buffers of size 'buffer_size' each
327 find = buffer_size + buffer_size;327 find = buffer_size + buffer_size;
328 var find_separately = false;328 var find_separately = false;
329 329
330 if (block_size <= cache.len) {330 if (block_size <= cache.len) {
331 // if every A block fits into the cache then we won't need the second internal buffer,331 // if every A block fits into the cache then we won't need the second internal buffer,
332 // so we really only need to find 'buffer_size' unique values332 // so we really only need to find 'buffer_size' unique values
...@@ -336,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -336,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
336 find = buffer_size;336 find = buffer_size;
337 find_separately = true;337 find_separately = true;
338 }338 }
339 339
340 // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each),340 // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each),
341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,
342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get
343 343
344 // in the case where it couldn't find a single buffer of at least √A unique values,344 // in the case where it couldn't find a single buffer of at least √A unique values,
345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)
346 iterator.begin();346 iterator.begin();
347 while (!iterator.finished()) {347 while (!iterator.finished()) {
348 A = iterator.nextRange();348 A = iterator.nextRange();
349 B = iterator.nextRange();349 B = iterator.nextRange();
350 350
351 // just store information about where the values will be pulled from and to,351 // just store information about where the values will be pulled from and to,
352 // as well as how many values there are, to create the two internal buffers352 // as well as how many values there are, to create the two internal buffers
353 353
354 // check A for the number of unique values we need to fill an internal buffer354 // check A for the number of unique values we need to fill an internal buffer
355 // these values will be pulled out to the start of A355 // these values will be pulled out to the start of A
356 last = A.start;356 last = A.start;
...@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
360 if (index == A.end) break;360 if (index == A.end) break;
361 }361 }
362 index = last;362 index = last;
363 363
364 if (count >= buffer_size) {364 if (count >= buffer_size) {
365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
366 pull[pull_index] = Pull {366 pull[pull_index] = Pull {
...@@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
370 .to = A.start,370 .to = A.start,
371 };371 };
372 pull_index = 1;372 pull_index = 1;
373 373
374 if (count == buffer_size + buffer_size) {374 if (count == buffer_size + buffer_size) {
375 // we were able to find a single contiguous section containing 2√A unique values,375 // we were able to find a single contiguous section containing 2√A unique values,
376 // so this section can be used to contain both of the internal buffers we'll need376 // so this section can be used to contain both of the internal buffers we'll need
...@@ -405,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -405,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
405 .to = A.start,405 .to = A.start,
406 };406 };
407 }407 }
408 408
409 // check B for the number of unique values we need to fill an internal buffer409 // check B for the number of unique values we need to fill an internal buffer
410 // these values will be pulled out to the end of B410 // these values will be pulled out to the end of B
411 last = B.end - 1;411 last = B.end - 1;
...@@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
415 if (index == B.start) break;415 if (index == B.start) break;
416 }416 }
417 index = last;417 index = last;
418 418
419 if (count >= buffer_size) {419 if (count >= buffer_size) {
420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
421 pull[pull_index] = Pull {421 pull[pull_index] = Pull {
...@@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
425 .to = B.end,425 .to = B.end,
426 };426 };
427 pull_index = 1;427 pull_index = 1;
428 428
429 if (count == buffer_size + buffer_size) {429 if (count == buffer_size + buffer_size) {
430 // we were able to find a single contiguous section containing 2√A unique values,430 // we were able to find a single contiguous section containing 2√A unique values,
431 // so this section can be used to contain both of the internal buffers we'll need431 // so this section can be used to contain both of the internal buffers we'll need
...@@ -449,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -449,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,
450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2
451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;
452 452
453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!
454 buffer2 = Range.init(B.end - count, B.end);454 buffer2 = Range.init(B.end - count, B.end);
455 break;455 break;
...@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
465 };465 };
466 }466 }
467 }467 }
468 468
469 // pull out the two ranges so we can use them as internal buffers469 // pull out the two ranges so we can use them as internal buffers
470 pull_index = 0;470 pull_index = 0;
471 while (pull_index < 2) : (pull_index += 1) {471 while (pull_index < 2) : (pull_index += 1) {
472 const length = pull[pull_index].count;472 const length = pull[pull_index].count;
473 473
474 if (pull[pull_index].to < pull[pull_index].from) {474 if (pull[pull_index].to < pull[pull_index].from) {
475 // we're pulling the values out to the left, which means the start of an A subarray475 // we're pulling the values out to the left, which means the start of an A subarray
476 index = pull[pull_index].from;476 index = pull[pull_index].from;
...@@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
493 }493 }
494 }494 }
495 }495 }
496 496
497 // adjust block_size and buffer_size based on the values we were able to pull out497 // adjust block_size and buffer_size based on the values we were able to pull out
498 buffer_size = buffer1.length();498 buffer_size = buffer1.length();
499 block_size = iterator.length()/buffer_size + 1;499 block_size = iterator.length()/buffer_size + 1;
500 500
501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502 // so this was originally here to test the math for adjusting block_size above502 // so this was originally here to test the math for adjusting block_size above
503 // assert((iterator.length() + 1)/block_size <= buffer_size);503 // assert((iterator.length() + 1)/block_size <= buffer_size);
504 504
505 // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort!505 // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort!
506 iterator.begin();506 iterator.begin();
507 while (!iterator.finished()) {507 while (!iterator.finished()) {
508 A = iterator.nextRange();508 A = iterator.nextRange();
509 B = iterator.nextRange();509 B = iterator.nextRange();
510 510
511 // remove any parts of A or B that are being used by the internal buffers511 // remove any parts of A or B that are being used by the internal buffers
512 start = A.start;512 start = A.start;
513 if (start == pull[0].range.start) {513 if (start == pull[0].range.start) {
514 if (pull[0].from > pull[0].to) {514 if (pull[0].from > pull[0].to) {
515 A.start += pull[0].count;515 A.start += pull[0].count;
516 516
517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge
518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,
519 // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal519 // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal
...@@ -532,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -532,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
532 if (B.length() == 0) continue;532 if (B.length() == 0) continue;
533 }533 }
534 }534 }
535 535
536 if (lessThan(items[B.end - 1], items[A.start])) {536 if (lessThan(items[B.end - 1], items[A.start])) {
537 // the two ranges are in reverse order, so a simple rotation should fix it537 // the two ranges are in reverse order, so a simple rotation should fix it
538 mem.rotate(T, items[A.start..B.end], A.length());538 mem.rotate(T, items[A.start..B.end], A.length());
539 } else if (lessThan(items[A.end], items[A.end - 1])) {539 } else if (lessThan(items[A.end], items[A.end - 1])) {
540 // these two ranges weren't already in order, so we'll need to merge them!540 // these two ranges weren't already in order, so we'll need to merge them!
541 var findA: usize = undefined;541 var findA: usize = undefined;
542 542
543 // break the remainder of A into blocks. firstA is the uneven-sized first A block543 // break the remainder of A into blocks. firstA is the uneven-sized first A block
544 var blockA = Range.init(A.start, A.end);544 var blockA = Range.init(A.start, A.end);
545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);
546 546
547 // swap the first value of each A block with the value in buffer1547 // swap the first value of each A block with the value in buffer1
548 var indexA = buffer1.start;548 var indexA = buffer1.start;
549 index = firstA.end;549 index = firstA.end;
550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
551 mem.swap(T, &items[indexA], &items[index]);551 mem.swap(T, &items[indexA], &items[index]);
552 }552 }
553 553
554 // start rolling the A blocks through the B blocks!554 // start rolling the A blocks through the B blocks!
555 // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well555 // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well
556 var lastA = firstA;556 var lastA = firstA;
...@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));
559 blockA.start += firstA.length();559 blockA.start += firstA.length();
560 indexA = buffer1.start;560 indexA = buffer1.start;
561 561
562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it
563 // otherwise, if the second buffer is available, block swap the contents into that563 // otherwise, if the second buffer is available, block swap the contents into that
564 if (lastA.length() <= cache.len) {564 if (lastA.length() <= cache.len) {
...@@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
566 } else if (buffer2.length() > 0) {566 } else if (buffer2.length() > 0) {
567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());
568 }568 }
569 569
570 if (blockA.length() > 0) {570 if (blockA.length() > 0) {
571 while (true) {571 while (true) {
572 // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block,572 // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block,
...@@ -575,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -575,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
575 // figure out where to split the previous B block, and rotate it at the split575 // figure out where to split the previous B block, and rotate it at the split
576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);
577 const B_remaining = lastB.end - B_split;577 const B_remaining = lastB.end - B_split;
578 578
579 // swap the minimum A block to the beginning of the rolling A blocks579 // swap the minimum A block to the beginning of the rolling A blocks
580 var minA = blockA.start;580 var minA = blockA.start;
581 findA = minA + block_size;581 findA = minA + block_size;
...@@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
585 }585 }
586 }586 }
587 blockSwap(T, items, blockA.start, minA, block_size);587 blockSwap(T, items, blockA.start, minA, block_size);
588 588
589 // swap the first item of the previous A block back with its original value, which is stored in buffer1589 // swap the first item of the previous A block back with its original value, which is stored in buffer1
590 mem.swap(T, &items[blockA.start], &items[indexA]);590 mem.swap(T, &items[blockA.start], &items[indexA]);
591 indexA += 1;591 indexA += 1;
592 592
593 // locally merge the previous A block with the B values that follow it593 // locally merge the previous A block with the B values that follow it
594 // if lastA fits into the external cache we'll use that (with MergeExternal),594 // if lastA fits into the external cache we'll use that (with MergeExternal),
595 // or if the second internal buffer exists we'll use that (with MergeInternal),595 // or if the second internal buffer exists we'll use that (with MergeInternal),
596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)
597 597
598 if (lastA.length() <= cache.len) {598 if (lastA.length() <= cache.len) {
599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);
600 } else if (buffer2.length() > 0) {600 } else if (buffer2.length() > 0) {
...@@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
602 } else {602 } else {
603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);
604 }604 }
605 605
606 if (buffer2.length() > 0 or block_size <= cache.len) {606 if (buffer2.length() > 0 or block_size <= cache.len) {
607 // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway607 // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway
608 if (block_size <= cache.len) {608 if (block_size <= cache.len) {
...@@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
610 } else {610 } else {
611 blockSwap(T, items, blockA.start, buffer2.start, block_size);611 blockSwap(T, items, blockA.start, buffer2.start, block_size);
612 }612 }
613 613
614 // this is equivalent to rotating, but faster614 // this is equivalent to rotating, but faster
615 // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it615 // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it
616 // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs616 // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs
...@@ -619,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -619,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation
620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);
621 }621 }
622 622
623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split
624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);
625 lastB = Range.init(lastA.end, lastA.end + B_remaining);625 lastB = Range.init(lastA.end, lastA.end + B_remaining);
626 626
627 // if there are no more A blocks remaining, this step is finished!627 // if there are no more A blocks remaining, this step is finished!
628 blockA.start += block_size;628 blockA.start += block_size;
629 if (blockA.length() == 0)629 if (blockA.length() == 0)
630 break;630 break;
631 631
632 } else if (blockB.length() < block_size) {632 } else if (blockB.length() < block_size) {
633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634 // the cache is disabled here since it might contain the contents of the previous A block634 // the cache is disabled here since it might contain the contents of the previous A block
635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);
636 636
637 lastB = Range.init(blockA.start, blockA.start + blockB.length());637 lastB = Range.init(blockA.start, blockA.start + blockB.length());
638 blockA.start += blockB.length();638 blockA.start += blockB.length();
639 blockA.end += blockB.length();639 blockA.end += blockB.length();
...@@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
642 // roll the leftmost A block to the end by swapping it with the next B block642 // roll the leftmost A block to the end by swapping it with the next B block
643 blockSwap(T, items, blockA.start, blockB.start, block_size);643 blockSwap(T, items, blockA.start, blockB.start, block_size);
644 lastB = Range.init(blockA.start, blockA.start + block_size);644 lastB = Range.init(blockA.start, blockA.start + block_size);
645 645
646 blockA.start += block_size;646 blockA.start += block_size;
647 blockA.end += block_size;647 blockA.end += block_size;
648 blockB.start += block_size;648 blockB.start += block_size;
649 649
650 if (blockB.end > B.end - block_size) {650 if (blockB.end > B.end - block_size) {
651 blockB.end = B.end;651 blockB.end = B.end;
652 } else {652 } else {
...@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
655 }655 }
656 }656 }
657 }657 }
658 658
659 // merge the last A block with the remaining B values659 // merge the last A block with the remaining B values
660 if (lastA.length() <= cache.len) {660 if (lastA.length() <= cache.len) {
661 mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]);661 mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]);
...@@ -666,14 +666,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -666,14 +666,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
666 }666 }
667 }667 }
668 }668 }
669 669
670 // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up670 // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up
671 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer671 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer
672 672
673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,
674 // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here674 // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here
675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);
676 676
677 pull_index = 0;677 pull_index = 0;
678 while (pull_index < 2) : (pull_index += 1) {678 while (pull_index < 2) : (pull_index += 1) {
679 var unique = pull[pull_index].count * 2;679 var unique = pull[pull_index].count * 2;
...@@ -702,7 +702,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -702,7 +702,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
702 }702 }
703 }703 }
704 }704 }
705 705
706 // double the size of each A and B subarray that will be merged in the next level706 // double the size of each A and B subarray that will be merged in the next level
707 if (!iterator.nextLevel()) break;707 if (!iterator.nextLevel()) break;
708 }708 }
...@@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
711// merge operation without a buffer711// merge operation without a buffer
712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {
713 if (A_arg.length() == 0 or B_arg.length() == 0) return;713 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714 714
715 // this just repeatedly binary searches into B and rotates A into position.715 // this just repeatedly binary searches into B and rotates A into position.
716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
717 // but I decided to stick with this because it had better situational performance717 // but I decided to stick with this because it had better situational performance
718 // 718 //
719 // (Hwang and Lin is designed for merging subarrays of very different sizes,719 // (Hwang and Lin is designed for merging subarrays of very different sizes,
720 // but WikiSort almost always uses subarrays that are roughly the same size)720 // but WikiSort almost always uses subarrays that are roughly the same size)
721 // 721 //
722 // normally this is incredibly suboptimal, but this function is only called722 // normally this is incredibly suboptimal, but this function is only called
723 // when none of the A or B blocks in any subarray contained 2√A unique values,723 // when none of the A or B blocks in any subarray contained 2√A unique values,
724 // which places a hard limit on the number of times this will ACTUALLY need724 // which places a hard limit on the number of times this will ACTUALLY need
725 // to binary search and rotate.725 // to binary search and rotate.
726 // 726 //
727 // according to my analysis the worst case is √A rotations performed on √A items727 // according to my analysis the worst case is √A rotations performed on √A items
728 // once the constant factors are removed, which ends up being O(n)728 // once the constant factors are removed, which ends up being O(n)
729 // 729 //
730 // again, this is NOT a general-purpose solution – it only works well in this case!730 // again, this is NOT a general-purpose solution – it only works well in this case!
731 // kind of like how the O(n^2) insertion sort is used in some places731 // kind of like how the O(n^2) insertion sort is used in some places
732732
733 var A = *A_arg;733 var A = *A_arg;
734 var B = *B_arg;734 var B = *B_arg;
735 735
736 while (true) {736 while (true) {
737 // find the first place in B where the first item in A needs to be inserted737 // find the first place in B where the first item in A needs to be inserted
738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);
739 739
740 // rotate A into place740 // rotate A into place
741 const amount = mid - A.end;741 const amount = mid - A.end;
742 mem.rotate(T, items[A.start..mid], A.length());742 mem.rotate(T, items[A.start..mid], A.length());
743 if (B.end == mid) break;743 if (B.end == mid) break;
744 744
745 // calculate the new A and B ranges745 // calculate the new A and B ranges
746 B.start = mid;746 B.start = mid;
747 A = Range.init(A.start + amount, B.start);747 A = Range.init(A.start + amount, B.start);
...@@ -757,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -757,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
757 var A_count: usize = 0;757 var A_count: usize = 0;
758 var B_count: usize = 0;758 var B_count: usize = 0;
759 var insert: usize = 0;759 var insert: usize = 0;
760 760
761 if (B.length() > 0 and A.length() > 0) {761 if (B.length() > 0 and A.length() > 0) {
762 while (true) {762 while (true) {
763 if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) {763 if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) {
...@@ -773,7 +773,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -773,7 +773,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
773 }773 }
774 }774 }
775 }775 }
776 776
777 // swap the remainder of A into the final array777 // swap the remainder of A into the final array
778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);
779}779}
...@@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s...@@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
791 if (range.length() == 0) return range.start;791 if (range.length() == 0) return range.start;
792 const skip = math.max(range.length()/unique, usize(1));792 const skip = math.max(range.length()/unique, usize(1));
793 793
794 var index = range.start + skip;794 var index = range.start + skip;
795 while (lessThan(items[index - 1], value)) : (index += skip) {795 while (lessThan(items[index - 1], value)) : (index += skip) {
796 if (index >= range.end - skip) {796 if (index >= range.end - skip) {
797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);
798 }798 }
799 }799 }
800 800
801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802}802}
803803
804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
805 if (range.length() == 0) return range.start;805 if (range.length() == 0) return range.start;
806 const skip = math.max(range.length()/unique, usize(1));806 const skip = math.max(range.length()/unique, usize(1));
807 807
808 var index = range.end - skip;808 var index = range.end - skip;
809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
810 if (index < range.start + skip) {810 if (index < range.start + skip) {
811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);
812 }812 }
813 }813 }
814 814
815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816}816}
817817
818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
819 if (range.length() == 0) return range.start;819 if (range.length() == 0) return range.start;
820 const skip = math.max(range.length()/unique, usize(1));820 const skip = math.max(range.length()/unique, usize(1));
821 821
822 var index = range.start + skip;822 var index = range.start + skip;
823 while (!lessThan(value, items[index - 1])) : (index += skip) {823 while (!lessThan(value, items[index - 1])) : (index += skip) {
824 if (index >= range.end - skip) {824 if (index >= range.end - skip) {
825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);
826 }826 }
827 }827 }
828 828
829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830}830}
831831
832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
833 if (range.length() == 0) return range.start;833 if (range.length() == 0) return range.start;
834 const skip = math.max(range.length()/unique, usize(1));834 const skip = math.max(range.length()/unique, usize(1));
835 835
836 var index = range.end - skip;836 var index = range.end - skip;
837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
838 if (index < range.start + skip) {838 if (index < range.start + skip) {
839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);
840 }840 }
841 }841 }
842 842
843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844}844}
845845
...@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less...@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
885 const A_last = A.end;885 const A_last = A.end;
886 const B_last = B.end;886 const B_last = B.end;
887 var insert_index: usize = 0;887 var insert_index: usize = 0;
888 888
889 while (true) {889 while (true) {
890 if (!lessThan(from[B_index], from[A_index])) {890 if (!lessThan(from[B_index], from[A_index])) {
891 into[insert_index] = from[A_index];891 into[insert_index] = from[A_index];
...@@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
916 var insert_index: usize = A.start;916 var insert_index: usize = A.start;
917 const A_last = A.length();917 const A_last = A.length();
918 const B_last = B.end;918 const B_last = B.end;
919 919
920 if (B.length() > 0 and A.length() > 0) {920 if (B.length() > 0 and A.length() > 0) {
921 while (true) {921 while (true) {
922 if (!lessThan(items[B_index], cache[A_index])) {922 if (!lessThan(items[B_index], cache[A_index])) {
...@@ -932,7 +932,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -932,7 +932,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
932 }932 }
933 }933 }
934 }934 }
935 935
936 // copy the remainder of A into the final array936 // copy the remainder of A into the final array
937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938}938}
...@@ -1081,17 +1081,17 @@ test "another sort case" {...@@ -1081,17 +1081,17 @@ test "another sort case" {
1081}1081}
10821082
1083test "sort fuzz testing" {1083test "sort fuzz testing" {
1084 var rng = std.rand.Rand.init(0x12345678);1084 var prng = std.rand.DefaultPrng.init(0x12345678);
1085 const test_case_count = 10;1085 const test_case_count = 10;
1086 var i: usize = 0;1086 var i: usize = 0;
1087 while (i < test_case_count) : (i += 1) {1087 while (i < test_case_count) : (i += 1) {
1088 fuzzTest(&rng);1088 fuzzTest(&prng.random);
1089 }1089 }
1090}1090}
10911091
1092var fixed_buffer_mem: [100 * 1024]u8 = undefined;1092var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10931093
1094fn fuzzTest(rng: &std.rand.Rand) void {1094fn fuzzTest(rng: &std.rand.Random) void {
1095 const array_size = rng.range(usize, 0, 1000);1095 const array_size = rng.range(usize, 0, 1000);
1096 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1096 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1097 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;1097 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;
std/special/build_file_template.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) !void {3pub fn build(b: &Builder) void {
4 const mode = b.standardReleaseOptions();4 const mode = b.standardReleaseOptions();
5 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");5 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");
6 exe.setBuildMode(mode);6 exe.setBuildMode(mode);
std/special/builtin.zig+25-8
...@@ -14,26 +14,43 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn...@@ -14,26 +14,43 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn
14 }14 }
15}15}
1616
17// Note that memset does not return `dest`, like the libc API.17export fn memset(dest: ?&u8, c: u8, n: usize) ?&u8 {
18// The semantics of memset is dictated by the corresponding
19// LLVM intrinsics, not by the libc API.
20export fn memset(dest: ?&u8, c: u8, n: usize) void {
21 @setRuntimeSafety(false);18 @setRuntimeSafety(false);
2219
23 var index: usize = 0;20 var index: usize = 0;
24 while (index != n) : (index += 1)21 while (index != n) : (index += 1)
25 (??dest)[index] = c;22 (??dest)[index] = c;
23
24 return dest;
26}25}
2726
28// Note that memcpy does not return `dest`, like the libc API.27export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) ?&u8 {
29// The semantics of memcpy is dictated by the corresponding
30// LLVM intrinsics, not by the libc API.
31export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) void {
32 @setRuntimeSafety(false);28 @setRuntimeSafety(false);
3329
34 var index: usize = 0;30 var index: usize = 0;
35 while (index != n) : (index += 1)31 while (index != n) : (index += 1)
36 (??dest)[index] = (??src)[index];32 (??dest)[index] = (??src)[index];
33
34 return dest;
35}
36
37export fn memmove(dest: ?&u8, src: ?&const u8, n: usize) ?&u8 {
38 @setRuntimeSafety(false);
39
40 if (@ptrToInt(dest) < @ptrToInt(src)) {
41 var index: usize = 0;
42 while (index != n) : (index += 1) {
43 (??dest)[index] = (??src)[index];
44 }
45 } else {
46 var index = n;
47 while (index != 0) {
48 index -= 1;
49 (??dest)[index] = (??src)[index];
50 }
51 }
52
53 return dest;
37}54}
3855
39comptime {56comptime {
std/zig/ast.zig+1470-100
...@@ -11,34 +11,108 @@ pub const Node = struct {...@@ -11,34 +11,108 @@ pub const Node = struct {
11 pub const Id = enum {11 pub const Id = enum {
12 Root,12 Root,
13 VarDecl,13 VarDecl,
14 Use,
15 ErrorSetDecl,
16 ContainerDecl,
17 StructField,
18 UnionTag,
19 EnumTag,
14 Identifier,20 Identifier,
21 AsyncAttribute,
15 FnProto,22 FnProto,
16 ParamDecl,23 ParamDecl,
17 Block,24 Block,
25 Defer,
26 Comptime,
27 Payload,
28 PointerPayload,
29 PointerIndexPayload,
30 Else,
31 Switch,
32 SwitchCase,
33 SwitchElse,
34 While,
35 For,
36 If,
18 InfixOp,37 InfixOp,
19 PrefixOp,38 PrefixOp,
39 SuffixOp,
40 GroupedExpression,
41 ControlFlowExpression,
42 Suspend,
43 FieldInitializer,
20 IntegerLiteral,44 IntegerLiteral,
21 FloatLiteral,45 FloatLiteral,
22 StringLiteral,46 StringLiteral,
47 MultilineStringLiteral,
48 CharLiteral,
49 BoolLiteral,
50 NullLiteral,
51 UndefinedLiteral,
52 ThisLiteral,
53 Asm,
54 AsmInput,
55 AsmOutput,
56 Unreachable,
57 ErrorType,
58 VarType,
23 BuiltinCall,59 BuiltinCall,
24 LineComment,60 LineComment,
61 TestDecl,
25 };62 };
2663
27 pub fn iterate(base: &Node, index: usize) ?&Node {64 pub fn iterate(base: &Node, index: usize) ?&Node {
28 return switch (base.id) {65 return switch (base.id) {
29 Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),66 Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),
30 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),67 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),
68 Id.Use => @fieldParentPtr(NodeUse, "base", base).iterate(index),
69 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).iterate(index),
70 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).iterate(index),
71 Id.StructField => @fieldParentPtr(NodeStructField, "base", base).iterate(index),
72 Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).iterate(index),
73 Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).iterate(index),
31 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),74 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),
75 Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).iterate(index),
32 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),76 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
33 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),77 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
34 Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),78 Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
79 Id.Defer => @fieldParentPtr(NodeDefer, "base", base).iterate(index),
80 Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).iterate(index),
81 Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index),
82 Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).iterate(index),
83 Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).iterate(index),
84 Id.Else => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
85 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
86 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
87 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index),
88 Id.While => @fieldParentPtr(NodeWhile, "base", base).iterate(index),
89 Id.For => @fieldParentPtr(NodeFor, "base", base).iterate(index),
90 Id.If => @fieldParentPtr(NodeIf, "base", base).iterate(index),
35 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),91 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
36 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),92 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
93 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
94 Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).iterate(index),
95 Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).iterate(index),
96 Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).iterate(index),
97 Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).iterate(index),
37 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),98 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
38 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),99 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
39 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),100 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
101 Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).iterate(index),
102 Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).iterate(index),
103 Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).iterate(index),
104 Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).iterate(index),
105 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
106 Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).iterate(index),
107 Id.Asm => @fieldParentPtr(NodeAsm, "base", base).iterate(index),
108 Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).iterate(index),
109 Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).iterate(index),
110 Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).iterate(index),
111 Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index),
112 Id.VarType => @fieldParentPtr(NodeVarType, "base", base).iterate(index),
40 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),113 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
41 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),114 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
115 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
42 };116 };
43 }117 }
44118
...@@ -46,17 +120,54 @@ pub const Node = struct {...@@ -46,17 +120,54 @@ pub const Node = struct {
46 return switch (base.id) {120 return switch (base.id) {
47 Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),121 Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),
48 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),122 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),
123 Id.Use => @fieldParentPtr(NodeUse, "base", base).firstToken(),
124 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).firstToken(),
125 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).firstToken(),
126 Id.StructField => @fieldParentPtr(NodeStructField, "base", base).firstToken(),
127 Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).firstToken(),
128 Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).firstToken(),
49 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(),129 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(),
130 Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).firstToken(),
50 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),131 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
51 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),132 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
52 Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),133 Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
134 Id.Defer => @fieldParentPtr(NodeDefer, "base", base).firstToken(),
135 Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).firstToken(),
136 Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(),
137 Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).firstToken(),
138 Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).firstToken(),
139 Id.Else => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
140 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
141 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
142 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
143 Id.While => @fieldParentPtr(NodeWhile, "base", base).firstToken(),
144 Id.For => @fieldParentPtr(NodeFor, "base", base).firstToken(),
145 Id.If => @fieldParentPtr(NodeIf, "base", base).firstToken(),
53 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),146 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
54 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),147 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
148 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
149 Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).firstToken(),
150 Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).firstToken(),
151 Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).firstToken(),
152 Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).firstToken(),
55 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),153 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
56 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),154 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
57 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),155 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
156 Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).firstToken(),
157 Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).firstToken(),
158 Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).firstToken(),
159 Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).firstToken(),
160 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
161 Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).firstToken(),
162 Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).firstToken(),
163 Id.Asm => @fieldParentPtr(NodeAsm, "base", base).firstToken(),
164 Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).firstToken(),
165 Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).firstToken(),
166 Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(),
167 Id.VarType => @fieldParentPtr(NodeVarType, "base", base).firstToken(),
58 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),168 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
59 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),169 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
170 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
60 };171 };
61 }172 }
62173
...@@ -64,17 +175,54 @@ pub const Node = struct {...@@ -64,17 +175,54 @@ pub const Node = struct {
64 return switch (base.id) {175 return switch (base.id) {
65 Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),176 Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),
66 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),177 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),
178 Id.Use => @fieldParentPtr(NodeUse, "base", base).lastToken(),
179 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).lastToken(),
180 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).lastToken(),
181 Id.StructField => @fieldParentPtr(NodeStructField, "base", base).lastToken(),
182 Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).lastToken(),
183 Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).lastToken(),
67 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(),184 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(),
185 Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).lastToken(),
68 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),186 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
69 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),187 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
70 Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),188 Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
189 Id.Defer => @fieldParentPtr(NodeDefer, "base", base).lastToken(),
190 Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).lastToken(),
191 Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(),
192 Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).lastToken(),
193 Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).lastToken(),
194 Id.Else => @fieldParentPtr(NodeElse, "base", base).lastToken(),
195 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
196 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
197 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(),
198 Id.While => @fieldParentPtr(NodeWhile, "base", base).lastToken(),
199 Id.For => @fieldParentPtr(NodeFor, "base", base).lastToken(),
200 Id.If => @fieldParentPtr(NodeIf, "base", base).lastToken(),
71 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),201 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
72 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),202 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
203 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
204 Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).lastToken(),
205 Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).lastToken(),
206 Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).lastToken(),
207 Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).lastToken(),
73 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),208 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
74 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),209 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
75 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),210 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
211 Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).lastToken(),
212 Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).lastToken(),
213 Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).lastToken(),
214 Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).lastToken(),
215 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
216 Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).lastToken(),
217 Id.Asm => @fieldParentPtr(NodeAsm, "base", base).lastToken(),
218 Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).lastToken(),
219 Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).lastToken(),
220 Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).lastToken(),
221 Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(),
222 Id.VarType => @fieldParentPtr(NodeVarType, "base", base).lastToken(),
76 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),223 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
77 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),224 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
225 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
78 };226 };
79 }227 }
80};228};
...@@ -148,6 +296,190 @@ pub const NodeVarDecl = struct {...@@ -148,6 +296,190 @@ pub const NodeVarDecl = struct {
148 }296 }
149};297};
150298
299pub const NodeUse = struct {
300 base: Node,
301 visib_token: ?Token,
302 expr: &Node,
303 semicolon_token: Token,
304
305 pub fn iterate(self: &NodeUse, index: usize) ?&Node {
306 var i = index;
307
308 if (i < 1) return self.expr;
309 i -= 1;
310
311 return null;
312 }
313
314 pub fn firstToken(self: &NodeUse) Token {
315 if (self.visib_token) |visib_token| return visib_token;
316 return self.expr.firstToken();
317 }
318
319 pub fn lastToken(self: &NodeUse) Token {
320 return self.semicolon_token;
321 }
322};
323
324pub const NodeErrorSetDecl = struct {
325 base: Node,
326 error_token: Token,
327 decls: ArrayList(&NodeIdentifier),
328 rbrace_token: Token,
329
330 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
331 var i = index;
332
333 if (i < self.decls.len) return &self.decls.at(i).base;
334 i -= self.decls.len;
335
336 return null;
337 }
338
339 pub fn firstToken(self: &NodeErrorSetDecl) Token {
340 return self.error_token;
341 }
342
343 pub fn lastToken(self: &NodeErrorSetDecl) Token {
344 return self.rbrace_token;
345 }
346};
347
348pub const NodeContainerDecl = struct {
349 base: Node,
350 ltoken: Token,
351 layout: Layout,
352 kind: Kind,
353 init_arg_expr: InitArg,
354 fields_and_decls: ArrayList(&Node),
355 rbrace_token: Token,
356
357 const Layout = enum {
358 Auto,
359 Extern,
360 Packed,
361 };
362
363 const Kind = enum {
364 Struct,
365 Enum,
366 Union,
367 };
368
369 const InitArg = union(enum) {
370 None,
371 Enum,
372 Type: &Node,
373 };
374
375 pub fn iterate(self: &NodeContainerDecl, index: usize) ?&Node {
376 var i = index;
377
378 switch (self.init_arg_expr) {
379 InitArg.Type => |t| {
380 if (i < 1) return t;
381 i -= 1;
382 },
383 InitArg.None,
384 InitArg.Enum => { }
385 }
386
387 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
388 i -= self.fields_and_decls.len;
389
390 return null;
391 }
392
393 pub fn firstToken(self: &NodeContainerDecl) Token {
394 return self.ltoken;
395 }
396
397 pub fn lastToken(self: &NodeContainerDecl) Token {
398 return self.rbrace_token;
399 }
400};
401
402pub const NodeStructField = struct {
403 base: Node,
404 name_token: Token,
405 type_expr: &Node,
406
407 pub fn iterate(self: &NodeStructField, index: usize) ?&Node {
408 var i = index;
409
410 if (i < 1) return self.type_expr;
411 i -= 1;
412
413 return null;
414 }
415
416 pub fn firstToken(self: &NodeStructField) Token {
417 return self.name_token;
418 }
419
420 pub fn lastToken(self: &NodeStructField) Token {
421 return self.type_expr.lastToken();
422 }
423};
424
425pub const NodeUnionTag = struct {
426 base: Node,
427 name_token: Token,
428 type_expr: ?&Node,
429
430 pub fn iterate(self: &NodeUnionTag, index: usize) ?&Node {
431 var i = index;
432
433 if (self.type_expr) |type_expr| {
434 if (i < 1) return type_expr;
435 i -= 1;
436 }
437
438 return null;
439 }
440
441 pub fn firstToken(self: &NodeUnionTag) Token {
442 return self.name_token;
443 }
444
445 pub fn lastToken(self: &NodeUnionTag) Token {
446 if (self.type_expr) |type_expr| {
447 return type_expr.lastToken();
448 }
449
450 return self.name_token;
451 }
452};
453
454pub const NodeEnumTag = struct {
455 base: Node,
456 name_token: Token,
457 value: ?&Node,
458
459 pub fn iterate(self: &NodeEnumTag, index: usize) ?&Node {
460 var i = index;
461
462 if (self.value) |value| {
463 if (i < 1) return value;
464 i -= 1;
465 }
466
467 return null;
468 }
469
470 pub fn firstToken(self: &NodeEnumTag) Token {
471 return self.name_token;
472 }
473
474 pub fn lastToken(self: &NodeEnumTag) Token {
475 if (self.value) |value| {
476 return value.lastToken();
477 }
478
479 return self.name_token;
480 }
481};
482
151pub const NodeIdentifier = struct {483pub const NodeIdentifier = struct {
152 base: Node,484 base: Node,
153 name_token: Token,485 name_token: Token,
...@@ -165,6 +497,36 @@ pub const NodeIdentifier = struct {...@@ -165,6 +497,36 @@ pub const NodeIdentifier = struct {
165 }497 }
166};498};
167499
500pub const NodeAsyncAttribute = struct {
501 base: Node,
502 async_token: Token,
503 allocator_type: ?&Node,
504 rangle_bracket: ?Token,
505
506 pub fn iterate(self: &NodeAsyncAttribute, index: usize) ?&Node {
507 var i = index;
508
509 if (self.allocator_type) |allocator_type| {
510 if (i < 1) return allocator_type;
511 i -= 1;
512 }
513
514 return null;
515 }
516
517 pub fn firstToken(self: &NodeAsyncAttribute) Token {
518 return self.async_token;
519 }
520
521 pub fn lastToken(self: &NodeAsyncAttribute) Token {
522 if (self.rangle_bracket) |rangle_bracket| {
523 return rangle_bracket;
524 }
525
526 return self.async_token;
527 }
528};
529
168pub const NodeFnProto = struct {530pub const NodeFnProto = struct {
169 base: Node,531 base: Node,
170 visib_token: ?Token,532 visib_token: ?Token,
...@@ -176,13 +538,13 @@ pub const NodeFnProto = struct {...@@ -176,13 +538,13 @@ pub const NodeFnProto = struct {
176 extern_token: ?Token,538 extern_token: ?Token,
177 inline_token: ?Token,539 inline_token: ?Token,
178 cc_token: ?Token,540 cc_token: ?Token,
541 async_attr: ?&NodeAsyncAttribute,
179 body_node: ?&Node,542 body_node: ?&Node,
180 lib_name: ?&Node, // populated if this is an extern declaration543 lib_name: ?&Node, // populated if this is an extern declaration
181 align_expr: ?&Node, // populated if align(A) is present544 align_expr: ?&Node, // populated if align(A) is present
182545
183 pub const ReturnType = union(enum) {546 pub const ReturnType = union(enum) {
184 Explicit: &Node,547 Explicit: &Node,
185 Infer: Token,
186 InferErrorSet: &Node,548 InferErrorSet: &Node,
187 };549 };
188550
...@@ -204,7 +566,6 @@ pub const NodeFnProto = struct {...@@ -204,7 +566,6 @@ pub const NodeFnProto = struct {
204 if (i < 1) return node;566 if (i < 1) return node;
205 i -= 1;567 i -= 1;
206 },568 },
207 ReturnType.Infer => {},
208 }569 }
209570
210 if (self.align_expr) |align_expr| {571 if (self.align_expr) |align_expr| {
...@@ -238,7 +599,6 @@ pub const NodeFnProto = struct {...@@ -238,7 +599,6 @@ pub const NodeFnProto = struct {
238 // TODO allow this and next prong to share bodies since the types are the same599 // TODO allow this and next prong to share bodies since the types are the same
239 ReturnType.Explicit => |node| return node.lastToken(),600 ReturnType.Explicit => |node| return node.lastToken(),
240 ReturnType.InferErrorSet => |node| return node.lastToken(),601 ReturnType.InferErrorSet => |node| return node.lastToken(),
241 ReturnType.Infer => |token| return token,
242 }602 }
243 }603 }
244};604};
...@@ -275,9 +635,10 @@ pub const NodeParamDecl = struct {...@@ -275,9 +635,10 @@ pub const NodeParamDecl = struct {
275635
276pub const NodeBlock = struct {636pub const NodeBlock = struct {
277 base: Node,637 base: Node,
278 begin_token: Token,638 label: ?Token,
279 end_token: Token,639 lbrace: Token,
280 statements: ArrayList(&Node),640 statements: ArrayList(&Node),
641 rbrace: Token,
281642
282 pub fn iterate(self: &NodeBlock, index: usize) ?&Node {643 pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
283 var i = index;644 var i = index;
...@@ -289,190 +650,1199 @@ pub const NodeBlock = struct {...@@ -289,190 +650,1199 @@ pub const NodeBlock = struct {
289 }650 }
290651
291 pub fn firstToken(self: &NodeBlock) Token {652 pub fn firstToken(self: &NodeBlock) Token {
292 return self.begin_token;653 if (self.label) |label| {
654 return label;
655 }
656
657 return self.lbrace;
293 }658 }
294659
295 pub fn lastToken(self: &NodeBlock) Token {660 pub fn lastToken(self: &NodeBlock) Token {
296 return self.end_token;661 return self.rbrace;
297 }662 }
298};663};
299664
300pub const NodeInfixOp = struct {665pub const NodeDefer = struct {
301 base: Node,666 base: Node,
302 op_token: Token,667 defer_token: Token,
303 lhs: &Node,668 kind: Kind,
304 op: InfixOp,669 expr: &Node,
305 rhs: &Node,
306670
307 const InfixOp = enum {671 const Kind = enum {
308 EqualEqual,672 Error,
309 BangEqual,673 Unconditional,
310 Period,
311 };674 };
312675
313 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {676 pub fn iterate(self: &NodeDefer, index: usize) ?&Node {
314 var i = index;677 var i = index;
315678
316 if (i < 1) return self.lhs;679 if (i < 1) return self.expr;
317 i -= 1;680 i -= 1;
318681
319 switch (self.op) {682 return null;
320 InfixOp.EqualEqual,683 }
321 InfixOp.BangEqual,
322 InfixOp.Period => {},
323 }
324684
325 if (i < 1) return self.rhs;685 pub fn firstToken(self: &NodeDefer) Token {
686 return self.defer_token;
687 }
688
689 pub fn lastToken(self: &NodeDefer) Token {
690 return self.expr.lastToken();
691 }
692};
693
694pub const NodeComptime = struct {
695 base: Node,
696 comptime_token: Token,
697 expr: &Node,
698
699 pub fn iterate(self: &NodeComptime, index: usize) ?&Node {
700 var i = index;
701
702 if (i < 1) return self.expr;
326 i -= 1;703 i -= 1;
327704
328 return null;705 return null;
329 }706 }
330707
331 pub fn firstToken(self: &NodeInfixOp) Token {708 pub fn firstToken(self: &NodeComptime) Token {
332 return self.lhs.firstToken();709 return self.comptime_token;
333 }710 }
334711
335 pub fn lastToken(self: &NodeInfixOp) Token {712 pub fn lastToken(self: &NodeComptime) Token {
336 return self.rhs.lastToken();713 return self.expr.lastToken();
337 }714 }
338};715};
339716
340pub const NodePrefixOp = struct {717pub const NodePayload = struct {
341 base: Node,718 base: Node,
342 op_token: Token,719 lpipe: Token,
343 op: PrefixOp,720 error_symbol: &NodeIdentifier,
344 rhs: &Node,721 rpipe: Token,
345
346 const PrefixOp = union(enum) {
347 Return,
348 Try,
349 AddrOf: AddrOfInfo,
350 };
351 const AddrOfInfo = struct {
352 align_expr: ?&Node,
353 bit_offset_start_token: ?Token,
354 bit_offset_end_token: ?Token,
355 const_token: ?Token,
356 volatile_token: ?Token,
357 };
358722
359 pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {723 pub fn iterate(self: &NodePayload, index: usize) ?&Node {
360 var i = index;724 var i = index;
361725
362 switch (self.op) {726 if (i < 1) return &self.error_symbol.base;
363 PrefixOp.Return,
364 PrefixOp.Try => {},
365 PrefixOp.AddrOf => |addr_of_info| {
366 if (addr_of_info.align_expr) |align_expr| {
367 if (i < 1) return align_expr;
368 i -= 1;
369 }
370 },
371 }
372
373 if (i < 1) return self.rhs;
374 i -= 1;727 i -= 1;
375728
376 return null;729 return null;
377 }730 }
378731
379 pub fn firstToken(self: &NodePrefixOp) Token {732 pub fn firstToken(self: &NodePayload) Token {
380 return self.op_token;733 return self.lpipe;
381 }734 }
382735
383 pub fn lastToken(self: &NodePrefixOp) Token {736 pub fn lastToken(self: &NodePayload) Token {
384 return self.rhs.lastToken();737 return self.rpipe;
385 }738 }
386};739};
387740
388pub const NodeIntegerLiteral = struct {741pub const NodePointerPayload = struct {
389 base: Node,742 base: Node,
390 token: Token,743 lpipe: Token,
744 is_ptr: bool,
745 value_symbol: &NodeIdentifier,
746 rpipe: Token,
747
748 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
749 var i = index;
750
751 if (i < 1) return &self.value_symbol.base;
752 i -= 1;
391753
392 pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node {
393 return null;754 return null;
394 }755 }
395756
396 pub fn firstToken(self: &NodeIntegerLiteral) Token {757 pub fn firstToken(self: &NodePointerPayload) Token {
397 return self.token;758 return self.lpipe;
398 }759 }
399760
400 pub fn lastToken(self: &NodeIntegerLiteral) Token {761 pub fn lastToken(self: &NodePointerPayload) Token {
401 return self.token;762 return self.rpipe;
402 }763 }
403};764};
404765
405pub const NodeFloatLiteral = struct {766pub const NodePointerIndexPayload = struct {
406 base: Node,767 base: Node,
407 token: Token,768 lpipe: Token,
769 is_ptr: bool,
770 value_symbol: &NodeIdentifier,
771 index_symbol: ?&NodeIdentifier,
772 rpipe: Token,
773
774 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
775 var i = index;
776
777 if (i < 1) return &self.value_symbol.base;
778 i -= 1;
779
780 if (self.index_symbol) |index_symbol| {
781 if (i < 1) return &index_symbol.base;
782 i -= 1;
783 }
408784
409 pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node {
410 return null;785 return null;
411 }786 }
412787
413 pub fn firstToken(self: &NodeFloatLiteral) Token {788 pub fn firstToken(self: &NodePointerIndexPayload) Token {
414 return self.token;789 return self.lpipe;
415 }790 }
416791
417 pub fn lastToken(self: &NodeFloatLiteral) Token {792 pub fn lastToken(self: &NodePointerIndexPayload) Token {
418 return self.token;793 return self.rpipe;
419 }794 }
420};795};
421796
422pub const NodeBuiltinCall = struct {797pub const NodeElse = struct {
423 base: Node,798 base: Node,
424 builtin_token: Token,799 else_token: Token,
425 params: ArrayList(&Node),800 payload: ?&NodePayload,
426 rparen_token: Token,801 body: &Node,
427802
428 pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node {803 pub fn iterate(self: &NodeElse, index: usize) ?&Node {
429 var i = index;804 var i = index;
430805
431 if (i < self.params.len) return self.params.at(i);806 if (self.payload) |payload| {
432 i -= self.params.len;807 if (i < 1) return &payload.base;
808 i -= 1;
809 }
810
811 if (i < 1) return self.body;
812 i -= 1;
433813
434 return null;814 return null;
435 }815 }
436816
437 pub fn firstToken(self: &NodeBuiltinCall) Token {817 pub fn firstToken(self: &NodeElse) Token {
438 return self.builtin_token;818 return self.else_token;
439 }819 }
440820
441 pub fn lastToken(self: &NodeBuiltinCall) Token {821 pub fn lastToken(self: &NodeElse) Token {
442 return self.rparen_token;822 return self.body.lastToken();
443 }823 }
444};824};
445825
446pub const NodeStringLiteral = struct {826pub const NodeSwitch = struct {
447 base: Node,827 base: Node,
448 token: Token,828 switch_token: Token,
829 expr: &Node,
830 cases: ArrayList(&NodeSwitchCase),
831 rbrace: Token,
832
833 pub fn iterate(self: &NodeSwitch, index: usize) ?&Node {
834 var i = index;
835
836 if (i < 1) return self.expr;
837 i -= 1;
838
839 if (i < self.cases.len) return &self.cases.at(i).base;
840 i -= self.cases.len;
449841
450 pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
451 return null;842 return null;
452 }843 }
453844
454 pub fn firstToken(self: &NodeStringLiteral) Token {845 pub fn firstToken(self: &NodeSwitch) Token {
455 return self.token;846 return self.switch_token;
456 }847 }
457848
458 pub fn lastToken(self: &NodeStringLiteral) Token {849 pub fn lastToken(self: &NodeSwitch) Token {
459 return self.token;850 return self.rbrace;
460 }851 }
461};852};
462853
463pub const NodeLineComment = struct {854pub const NodeSwitchCase = struct {
464 base: Node,855 base: Node,
465 lines: ArrayList(Token),856 items: ArrayList(&Node),
857 payload: ?&NodePointerPayload,
858 expr: &Node,
859
860 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
861 var i = index;
862
863 if (i < self.items.len) return self.items.at(i);
864 i -= self.items.len;
865
866 if (self.payload) |payload| {
867 if (i < 1) return &payload.base;
868 i -= 1;
869 }
870
871 if (i < 1) return self.expr;
872 i -= 1;
466873
467 pub fn iterate(self: &NodeLineComment, index: usize) ?&Node {
468 return null;874 return null;
469 }875 }
470876
471 pub fn firstToken(self: &NodeLineComment) Token {877 pub fn firstToken(self: &NodeSwitchCase) Token {
472 return self.lines.at(0);878 return self.items.at(0).firstToken();
473 }879 }
474880
475 pub fn lastToken(self: &NodeLineComment) Token {881 pub fn lastToken(self: &NodeSwitchCase) Token {
882 return self.expr.lastToken();
883 }
884};
885
886pub const NodeSwitchElse = struct {
887 base: Node,
888 token: Token,
889
890 pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node {
891 return null;
892 }
893
894 pub fn firstToken(self: &NodeSwitchElse) Token {
895 return self.token;
896 }
897
898 pub fn lastToken(self: &NodeSwitchElse) Token {
899 return self.token;
900 }
901};
902
903pub const NodeWhile = struct {
904 base: Node,
905 label: ?Token,
906 inline_token: ?Token,
907 while_token: Token,
908 condition: &Node,
909 payload: ?&NodePointerPayload,
910 continue_expr: ?&Node,
911 body: &Node,
912 @"else": ?&NodeElse,
913
914 pub fn iterate(self: &NodeWhile, index: usize) ?&Node {
915 var i = index;
916
917 if (i < 1) return self.condition;
918 i -= 1;
919
920 if (self.payload) |payload| {
921 if (i < 1) return &payload.base;
922 i -= 1;
923 }
924
925 if (self.continue_expr) |continue_expr| {
926 if (i < 1) return continue_expr;
927 i -= 1;
928 }
929
930 if (i < 1) return self.body;
931 i -= 1;
932
933 if (self.@"else") |@"else"| {
934 if (i < 1) return &@"else".base;
935 i -= 1;
936 }
937
938 return null;
939 }
940
941 pub fn firstToken(self: &NodeWhile) Token {
942 if (self.label) |label| {
943 return label;
944 }
945
946 if (self.inline_token) |inline_token| {
947 return inline_token;
948 }
949
950 return self.while_token;
951 }
952
953 pub fn lastToken(self: &NodeWhile) Token {
954 if (self.@"else") |@"else"| {
955 return @"else".body.lastToken();
956 }
957
958 return self.body.lastToken();
959 }
960};
961
962pub const NodeFor = struct {
963 base: Node,
964 label: ?Token,
965 inline_token: ?Token,
966 for_token: Token,
967 array_expr: &Node,
968 payload: ?&NodePointerIndexPayload,
969 body: &Node,
970 @"else": ?&NodeElse,
971
972 pub fn iterate(self: &NodeFor, index: usize) ?&Node {
973 var i = index;
974
975 if (i < 1) return self.array_expr;
976 i -= 1;
977
978 if (self.payload) |payload| {
979 if (i < 1) return &payload.base;
980 i -= 1;
981 }
982
983 if (i < 1) return self.body;
984 i -= 1;
985
986 if (self.@"else") |@"else"| {
987 if (i < 1) return &@"else".base;
988 i -= 1;
989 }
990
991 return null;
992 }
993
994 pub fn firstToken(self: &NodeFor) Token {
995 if (self.label) |label| {
996 return label;
997 }
998
999 if (self.inline_token) |inline_token| {
1000 return inline_token;
1001 }
1002
1003 return self.for_token;
1004 }
1005
1006 pub fn lastToken(self: &NodeFor) Token {
1007 if (self.@"else") |@"else"| {
1008 return @"else".body.lastToken();
1009 }
1010
1011 return self.body.lastToken();
1012 }
1013};
1014
1015pub const NodeIf = struct {
1016 base: Node,
1017 if_token: Token,
1018 condition: &Node,
1019 payload: ?&NodePointerPayload,
1020 body: &Node,
1021 @"else": ?&NodeElse,
1022
1023 pub fn iterate(self: &NodeIf, index: usize) ?&Node {
1024 var i = index;
1025
1026 if (i < 1) return self.condition;
1027 i -= 1;
1028
1029 if (self.payload) |payload| {
1030 if (i < 1) return &payload.base;
1031 i -= 1;
1032 }
1033
1034 if (i < 1) return self.body;
1035 i -= 1;
1036
1037 if (self.@"else") |@"else"| {
1038 if (i < 1) return &@"else".base;
1039 i -= 1;
1040 }
1041
1042 return null;
1043 }
1044
1045 pub fn firstToken(self: &NodeIf) Token {
1046 return self.if_token;
1047 }
1048
1049 pub fn lastToken(self: &NodeIf) Token {
1050 if (self.@"else") |@"else"| {
1051 return @"else".body.lastToken();
1052 }
1053
1054 return self.body.lastToken();
1055 }
1056};
1057
1058pub const NodeInfixOp = struct {
1059 base: Node,
1060 op_token: Token,
1061 lhs: &Node,
1062 op: InfixOp,
1063 rhs: &Node,
1064
1065 const InfixOp = union(enum) {
1066 Add,
1067 AddWrap,
1068 ArrayCat,
1069 ArrayMult,
1070 Assign,
1071 AssignBitAnd,
1072 AssignBitOr,
1073 AssignBitShiftLeft,
1074 AssignBitShiftRight,
1075 AssignBitXor,
1076 AssignDiv,
1077 AssignMinus,
1078 AssignMinusWrap,
1079 AssignMod,
1080 AssignPlus,
1081 AssignPlusWrap,
1082 AssignTimes,
1083 AssignTimesWarp,
1084 BangEqual,
1085 BitAnd,
1086 BitOr,
1087 BitShiftLeft,
1088 BitShiftRight,
1089 BitXor,
1090 BoolAnd,
1091 BoolOr,
1092 Catch: ?&NodePayload,
1093 Div,
1094 EqualEqual,
1095 ErrorUnion,
1096 GreaterOrEqual,
1097 GreaterThan,
1098 LessOrEqual,
1099 LessThan,
1100 MergeErrorSets,
1101 Mod,
1102 Mult,
1103 MultWrap,
1104 Period,
1105 Range,
1106 Sub,
1107 SubWrap,
1108 UnwrapMaybe,
1109 };
1110
1111 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
1112 var i = index;
1113
1114 if (i < 1) return self.lhs;
1115 i -= 1;
1116
1117 switch (self.op) {
1118 InfixOp.Catch => |maybe_payload| {
1119 if (maybe_payload) |payload| {
1120 if (i < 1) return &payload.base;
1121 i -= 1;
1122 }
1123 },
1124
1125 InfixOp.Add,
1126 InfixOp.AddWrap,
1127 InfixOp.ArrayCat,
1128 InfixOp.ArrayMult,
1129 InfixOp.Assign,
1130 InfixOp.AssignBitAnd,
1131 InfixOp.AssignBitOr,
1132 InfixOp.AssignBitShiftLeft,
1133 InfixOp.AssignBitShiftRight,
1134 InfixOp.AssignBitXor,
1135 InfixOp.AssignDiv,
1136 InfixOp.AssignMinus,
1137 InfixOp.AssignMinusWrap,
1138 InfixOp.AssignMod,
1139 InfixOp.AssignPlus,
1140 InfixOp.AssignPlusWrap,
1141 InfixOp.AssignTimes,
1142 InfixOp.AssignTimesWarp,
1143 InfixOp.BangEqual,
1144 InfixOp.BitAnd,
1145 InfixOp.BitOr,
1146 InfixOp.BitShiftLeft,
1147 InfixOp.BitShiftRight,
1148 InfixOp.BitXor,
1149 InfixOp.BoolAnd,
1150 InfixOp.BoolOr,
1151 InfixOp.Div,
1152 InfixOp.EqualEqual,
1153 InfixOp.ErrorUnion,
1154 InfixOp.GreaterOrEqual,
1155 InfixOp.GreaterThan,
1156 InfixOp.LessOrEqual,
1157 InfixOp.LessThan,
1158 InfixOp.MergeErrorSets,
1159 InfixOp.Mod,
1160 InfixOp.Mult,
1161 InfixOp.MultWrap,
1162 InfixOp.Period,
1163 InfixOp.Range,
1164 InfixOp.Sub,
1165 InfixOp.SubWrap,
1166 InfixOp.UnwrapMaybe => {},
1167 }
1168
1169 if (i < 1) return self.rhs;
1170 i -= 1;
1171
1172 return null;
1173 }
1174
1175 pub fn firstToken(self: &NodeInfixOp) Token {
1176 return self.lhs.firstToken();
1177 }
1178
1179 pub fn lastToken(self: &NodeInfixOp) Token {
1180 return self.rhs.lastToken();
1181 }
1182};
1183
1184pub const NodePrefixOp = struct {
1185 base: Node,
1186 op_token: Token,
1187 op: PrefixOp,
1188 rhs: &Node,
1189
1190 const PrefixOp = union(enum) {
1191 AddrOf: AddrOfInfo,
1192 ArrayType: &Node,
1193 Await,
1194 BitNot,
1195 BoolNot,
1196 Cancel,
1197 Deref,
1198 MaybeType,
1199 Negation,
1200 NegationWrap,
1201 Resume,
1202 SliceType: AddrOfInfo,
1203 Try,
1204 UnwrapMaybe,
1205 };
1206
1207 const AddrOfInfo = struct {
1208 align_expr: ?&Node,
1209 bit_offset_start_token: ?Token,
1210 bit_offset_end_token: ?Token,
1211 const_token: ?Token,
1212 volatile_token: ?Token,
1213 };
1214
1215 pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {
1216 var i = index;
1217
1218 switch (self.op) {
1219 PrefixOp.SliceType => |addr_of_info| {
1220 if (addr_of_info.align_expr) |align_expr| {
1221 if (i < 1) return align_expr;
1222 i -= 1;
1223 }
1224 },
1225 PrefixOp.AddrOf => |addr_of_info| {
1226 if (addr_of_info.align_expr) |align_expr| {
1227 if (i < 1) return align_expr;
1228 i -= 1;
1229 }
1230 },
1231 PrefixOp.ArrayType => |size_expr| {
1232 if (i < 1) return size_expr;
1233 i -= 1;
1234 },
1235 PrefixOp.Await,
1236 PrefixOp.BitNot,
1237 PrefixOp.BoolNot,
1238 PrefixOp.Cancel,
1239 PrefixOp.Deref,
1240 PrefixOp.MaybeType,
1241 PrefixOp.Negation,
1242 PrefixOp.NegationWrap,
1243 PrefixOp.Try,
1244 PrefixOp.Resume,
1245 PrefixOp.UnwrapMaybe => {},
1246 }
1247
1248 if (i < 1) return self.rhs;
1249 i -= 1;
1250
1251 return null;
1252 }
1253
1254 pub fn firstToken(self: &NodePrefixOp) Token {
1255 return self.op_token;
1256 }
1257
1258 pub fn lastToken(self: &NodePrefixOp) Token {
1259 return self.rhs.lastToken();
1260 }
1261};
1262
1263pub const NodeFieldInitializer = struct {
1264 base: Node,
1265 period_token: Token,
1266 name_token: Token,
1267 expr: &Node,
1268
1269 pub fn iterate(self: &NodeFieldInitializer, index: usize) ?&Node {
1270 var i = index;
1271
1272 if (i < 1) return self.expr;
1273 i -= 1;
1274
1275 return null;
1276 }
1277
1278 pub fn firstToken(self: &NodeFieldInitializer) Token {
1279 return self.period_token;
1280 }
1281
1282 pub fn lastToken(self: &NodeFieldInitializer) Token {
1283 return self.expr.lastToken();
1284 }
1285};
1286
1287pub const NodeSuffixOp = struct {
1288 base: Node,
1289 lhs: &Node,
1290 op: SuffixOp,
1291 rtoken: Token,
1292
1293 const SuffixOp = union(enum) {
1294 Call: CallInfo,
1295 ArrayAccess: &Node,
1296 Slice: SliceRange,
1297 ArrayInitializer: ArrayList(&Node),
1298 StructInitializer: ArrayList(&NodeFieldInitializer),
1299 };
1300
1301 const CallInfo = struct {
1302 params: ArrayList(&Node),
1303 async_attr: ?&NodeAsyncAttribute,
1304 };
1305
1306 const SliceRange = struct {
1307 start: &Node,
1308 end: ?&Node,
1309 };
1310
1311 pub fn iterate(self: &NodeSuffixOp, index: usize) ?&Node {
1312 var i = index;
1313
1314 if (i < 1) return self.lhs;
1315 i -= 1;
1316
1317 switch (self.op) {
1318 SuffixOp.Call => |call_info| {
1319 if (i < call_info.params.len) return call_info.params.at(i);
1320 i -= call_info.params.len;
1321 },
1322 SuffixOp.ArrayAccess => |index_expr| {
1323 if (i < 1) return index_expr;
1324 i -= 1;
1325 },
1326 SuffixOp.Slice => |range| {
1327 if (i < 1) return range.start;
1328 i -= 1;
1329
1330 if (range.end) |end| {
1331 if (i < 1) return end;
1332 i -= 1;
1333 }
1334 },
1335 SuffixOp.ArrayInitializer => |exprs| {
1336 if (i < exprs.len) return exprs.at(i);
1337 i -= exprs.len;
1338 },
1339 SuffixOp.StructInitializer => |fields| {
1340 if (i < fields.len) return &fields.at(i).base;
1341 i -= fields.len;
1342 },
1343 }
1344
1345 return null;
1346 }
1347
1348 pub fn firstToken(self: &NodeSuffixOp) Token {
1349 return self.lhs.firstToken();
1350 }
1351
1352 pub fn lastToken(self: &NodeSuffixOp) Token {
1353 return self.rtoken;
1354 }
1355};
1356
1357pub const NodeGroupedExpression = struct {
1358 base: Node,
1359 lparen: Token,
1360 expr: &Node,
1361 rparen: Token,
1362
1363 pub fn iterate(self: &NodeGroupedExpression, index: usize) ?&Node {
1364 var i = index;
1365
1366 if (i < 1) return self.expr;
1367 i -= 1;
1368
1369 return null;
1370 }
1371
1372 pub fn firstToken(self: &NodeGroupedExpression) Token {
1373 return self.lparen;
1374 }
1375
1376 pub fn lastToken(self: &NodeGroupedExpression) Token {
1377 return self.rparen;
1378 }
1379};
1380
1381pub const NodeControlFlowExpression = struct {
1382 base: Node,
1383 ltoken: Token,
1384 kind: Kind,
1385 rhs: ?&Node,
1386
1387 const Kind = union(enum) {
1388 Break: ?Token,
1389 Continue: ?Token,
1390 Return,
1391 };
1392
1393 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
1394 var i = index;
1395
1396 if (self.rhs) |rhs| {
1397 if (i < 1) return rhs;
1398 i -= 1;
1399 }
1400
1401 return null;
1402 }
1403
1404 pub fn firstToken(self: &NodeControlFlowExpression) Token {
1405 return self.ltoken;
1406 }
1407
1408 pub fn lastToken(self: &NodeControlFlowExpression) Token {
1409 if (self.rhs) |rhs| {
1410 return rhs.lastToken();
1411 }
1412
1413 switch (self.kind) {
1414 Kind.Break => |maybe_blk_token| {
1415 if (maybe_blk_token) |blk_token| {
1416 return blk_token;
1417 }
1418 },
1419 Kind.Continue => |maybe_blk_token| {
1420 if (maybe_blk_token) |blk_token| {
1421 return blk_token;
1422 }
1423 },
1424 Kind.Return => return self.ltoken,
1425 }
1426
1427 return self.ltoken;
1428 }
1429};
1430
1431pub const NodeSuspend = struct {
1432 base: Node,
1433 suspend_token: Token,
1434 payload: ?&NodePayload,
1435 body: ?&Node,
1436
1437 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
1438 var i = index;
1439
1440 if (self.payload) |payload| {
1441 if (i < 1) return &payload.base;
1442 i -= 1;
1443 }
1444
1445 if (self.body) |body| {
1446 if (i < 1) return body;
1447 i -= 1;
1448 }
1449
1450 return null;
1451 }
1452
1453 pub fn firstToken(self: &NodeSuspend) Token {
1454 return self.suspend_token;
1455 }
1456
1457 pub fn lastToken(self: &NodeSuspend) Token {
1458 if (self.body) |body| {
1459 return body.lastToken();
1460 }
1461
1462 if (self.payload) |payload| {
1463 return payload.lastToken();
1464 }
1465
1466 return self.suspend_token;
1467 }
1468};
1469
1470pub const NodeIntegerLiteral = struct {
1471 base: Node,
1472 token: Token,
1473
1474 pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node {
1475 return null;
1476 }
1477
1478 pub fn firstToken(self: &NodeIntegerLiteral) Token {
1479 return self.token;
1480 }
1481
1482 pub fn lastToken(self: &NodeIntegerLiteral) Token {
1483 return self.token;
1484 }
1485};
1486
1487pub const NodeFloatLiteral = struct {
1488 base: Node,
1489 token: Token,
1490
1491 pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node {
1492 return null;
1493 }
1494
1495 pub fn firstToken(self: &NodeFloatLiteral) Token {
1496 return self.token;
1497 }
1498
1499 pub fn lastToken(self: &NodeFloatLiteral) Token {
1500 return self.token;
1501 }
1502};
1503
1504pub const NodeBuiltinCall = struct {
1505 base: Node,
1506 builtin_token: Token,
1507 params: ArrayList(&Node),
1508 rparen_token: Token,
1509
1510 pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node {
1511 var i = index;
1512
1513 if (i < self.params.len) return self.params.at(i);
1514 i -= self.params.len;
1515
1516 return null;
1517 }
1518
1519 pub fn firstToken(self: &NodeBuiltinCall) Token {
1520 return self.builtin_token;
1521 }
1522
1523 pub fn lastToken(self: &NodeBuiltinCall) Token {
1524 return self.rparen_token;
1525 }
1526};
1527
1528pub const NodeStringLiteral = struct {
1529 base: Node,
1530 token: Token,
1531
1532 pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
1533 return null;
1534 }
1535
1536 pub fn firstToken(self: &NodeStringLiteral) Token {
1537 return self.token;
1538 }
1539
1540 pub fn lastToken(self: &NodeStringLiteral) Token {
1541 return self.token;
1542 }
1543};
1544
1545pub const NodeMultilineStringLiteral = struct {
1546 base: Node,
1547 tokens: ArrayList(Token),
1548
1549 pub fn iterate(self: &NodeMultilineStringLiteral, index: usize) ?&Node {
1550 return null;
1551 }
1552
1553 pub fn firstToken(self: &NodeMultilineStringLiteral) Token {
1554 return self.tokens.at(0);
1555 }
1556
1557 pub fn lastToken(self: &NodeMultilineStringLiteral) Token {
1558 return self.tokens.at(self.tokens.len - 1);
1559 }
1560};
1561
1562pub const NodeCharLiteral = struct {
1563 base: Node,
1564 token: Token,
1565
1566 pub fn iterate(self: &NodeCharLiteral, index: usize) ?&Node {
1567 return null;
1568 }
1569
1570 pub fn firstToken(self: &NodeCharLiteral) Token {
1571 return self.token;
1572 }
1573
1574 pub fn lastToken(self: &NodeCharLiteral) Token {
1575 return self.token;
1576 }
1577};
1578
1579pub const NodeBoolLiteral = struct {
1580 base: Node,
1581 token: Token,
1582
1583 pub fn iterate(self: &NodeBoolLiteral, index: usize) ?&Node {
1584 return null;
1585 }
1586
1587 pub fn firstToken(self: &NodeBoolLiteral) Token {
1588 return self.token;
1589 }
1590
1591 pub fn lastToken(self: &NodeBoolLiteral) Token {
1592 return self.token;
1593 }
1594};
1595
1596pub const NodeNullLiteral = struct {
1597 base: Node,
1598 token: Token,
1599
1600 pub fn iterate(self: &NodeNullLiteral, index: usize) ?&Node {
1601 return null;
1602 }
1603
1604 pub fn firstToken(self: &NodeNullLiteral) Token {
1605 return self.token;
1606 }
1607
1608 pub fn lastToken(self: &NodeNullLiteral) Token {
1609 return self.token;
1610 }
1611};
1612
1613pub const NodeUndefinedLiteral = struct {
1614 base: Node,
1615 token: Token,
1616
1617 pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node {
1618 return null;
1619 }
1620
1621 pub fn firstToken(self: &NodeUndefinedLiteral) Token {
1622 return self.token;
1623 }
1624
1625 pub fn lastToken(self: &NodeUndefinedLiteral) Token {
1626 return self.token;
1627 }
1628};
1629
1630pub const NodeThisLiteral = struct {
1631 base: Node,
1632 token: Token,
1633
1634 pub fn iterate(self: &NodeThisLiteral, index: usize) ?&Node {
1635 return null;
1636 }
1637
1638 pub fn firstToken(self: &NodeThisLiteral) Token {
1639 return self.token;
1640 }
1641
1642 pub fn lastToken(self: &NodeThisLiteral) Token {
1643 return self.token;
1644 }
1645};
1646
1647pub const NodeAsmOutput = struct {
1648 base: Node,
1649 symbolic_name: &NodeIdentifier,
1650 constraint: &NodeStringLiteral,
1651 kind: Kind,
1652
1653 const Kind = union(enum) {
1654 Variable: &NodeIdentifier,
1655 Return: &Node
1656 };
1657
1658 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
1659 var i = index;
1660
1661 if (i < 1) return &self.symbolic_name.base;
1662 i -= 1;
1663
1664 if (i < 1) return &self.constraint.base;
1665 i -= 1;
1666
1667 switch (self.kind) {
1668 Kind.Variable => |variable_name| {
1669 if (i < 1) return &variable_name.base;
1670 i -= 1;
1671 },
1672 Kind.Return => |return_type| {
1673 if (i < 1) return return_type;
1674 i -= 1;
1675 }
1676 }
1677
1678 return null;
1679 }
1680
1681 pub fn firstToken(self: &NodeAsmOutput) Token {
1682 return self.symbolic_name.firstToken();
1683 }
1684
1685 pub fn lastToken(self: &NodeAsmOutput) Token {
1686 return switch (self.kind) {
1687 Kind.Variable => |variable_name| variable_name.lastToken(),
1688 Kind.Return => |return_type| return_type.lastToken(),
1689 };
1690 }
1691};
1692
1693pub const NodeAsmInput = struct {
1694 base: Node,
1695 symbolic_name: &NodeIdentifier,
1696 constraint: &NodeStringLiteral,
1697 expr: &Node,
1698
1699 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
1700 var i = index;
1701
1702 if (i < 1) return &self.symbolic_name.base;
1703 i -= 1;
1704
1705 if (i < 1) return &self.constraint.base;
1706 i -= 1;
1707
1708 if (i < 1) return self.expr;
1709 i -= 1;
1710
1711 return null;
1712 }
1713
1714 pub fn firstToken(self: &NodeAsmInput) Token {
1715 return self.symbolic_name.firstToken();
1716 }
1717
1718 pub fn lastToken(self: &NodeAsmInput) Token {
1719 return self.expr.lastToken();
1720 }
1721};
1722
1723pub const NodeAsm = struct {
1724 base: Node,
1725 asm_token: Token,
1726 is_volatile: bool,
1727 template: Token,
1728 //tokens: ArrayList(AsmToken),
1729 outputs: ArrayList(&NodeAsmOutput),
1730 inputs: ArrayList(&NodeAsmInput),
1731 cloppers: ArrayList(&NodeStringLiteral),
1732 rparen: Token,
1733
1734 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
1735 var i = index;
1736
1737 if (i < self.outputs.len) return &self.outputs.at(index).base;
1738 i -= self.outputs.len;
1739
1740 if (i < self.inputs.len) return &self.inputs.at(index).base;
1741 i -= self.inputs.len;
1742
1743 if (i < self.cloppers.len) return &self.cloppers.at(index).base;
1744 i -= self.cloppers.len;
1745
1746 return null;
1747 }
1748
1749 pub fn firstToken(self: &NodeAsm) Token {
1750 return self.asm_token;
1751 }
1752
1753 pub fn lastToken(self: &NodeAsm) Token {
1754 return self.rparen;
1755 }
1756};
1757
1758pub const NodeUnreachable = struct {
1759 base: Node,
1760 token: Token,
1761
1762 pub fn iterate(self: &NodeUnreachable, index: usize) ?&Node {
1763 return null;
1764 }
1765
1766 pub fn firstToken(self: &NodeUnreachable) Token {
1767 return self.token;
1768 }
1769
1770 pub fn lastToken(self: &NodeUnreachable) Token {
1771 return self.token;
1772 }
1773};
1774
1775pub const NodeErrorType = struct {
1776 base: Node,
1777 token: Token,
1778
1779 pub fn iterate(self: &NodeErrorType, index: usize) ?&Node {
1780 return null;
1781 }
1782
1783 pub fn firstToken(self: &NodeErrorType) Token {
1784 return self.token;
1785 }
1786
1787 pub fn lastToken(self: &NodeErrorType) Token {
1788 return self.token;
1789 }
1790};
1791
1792pub const NodeVarType = struct {
1793 base: Node,
1794 token: Token,
1795
1796 pub fn iterate(self: &NodeVarType, index: usize) ?&Node {
1797 return null;
1798 }
1799
1800 pub fn firstToken(self: &NodeVarType) Token {
1801 return self.token;
1802 }
1803
1804 pub fn lastToken(self: &NodeVarType) Token {
1805 return self.token;
1806 }
1807};
1808
1809pub const NodeLineComment = struct {
1810 base: Node,
1811 lines: ArrayList(Token),
1812
1813 pub fn iterate(self: &NodeLineComment, index: usize) ?&Node {
1814 return null;
1815 }
1816
1817 pub fn firstToken(self: &NodeLineComment) Token {
1818 return self.lines.at(0);
1819 }
1820
1821 pub fn lastToken(self: &NodeLineComment) Token {
476 return self.lines.at(self.lines.len - 1);1822 return self.lines.at(self.lines.len - 1);
477 }1823 }
478};1824};
1825
1826pub const NodeTestDecl = struct {
1827 base: Node,
1828 test_token: Token,
1829 name: &Node,
1830 body_node: &Node,
1831
1832 pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
1833 var i = index;
1834
1835 if (i < 1) return self.body_node;
1836 i -= 1;
1837
1838 return null;
1839 }
1840
1841 pub fn firstToken(self: &NodeTestDecl) Token {
1842 return self.test_token;
1843 }
1844
1845 pub fn lastToken(self: &NodeTestDecl) Token {
1846 return self.body_node.lastToken();
1847 }
1848};
std/zig/parser.zig+4109-485
...@@ -53,20 +53,33 @@ pub const Parser = struct {...@@ -53,20 +53,33 @@ pub const Parser = struct {
53 }53 }
5454
55 const TopLevelDeclCtx = struct {55 const TopLevelDeclCtx = struct {
56 decls: &ArrayList(&ast.Node),
56 visib_token: ?Token,57 visib_token: ?Token,
57 extern_token: ?Token,58 extern_token: ?Token,
59 lib_name: ?&ast.Node,
60 };
61
62 const ContainerExternCtx = struct {
63 dest_ptr: DestPtr,
64 ltoken: Token,
65 layout: ast.NodeContainerDecl.Layout,
58 };66 };
5967
60 const DestPtr = union(enum) {68 const DestPtr = union(enum) {
61 Field: &&ast.Node,69 Field: &&ast.Node,
62 NullableField: &?&ast.Node,70 NullableField: &?&ast.Node,
63 List: &ArrayList(&ast.Node),
6471
65 pub fn store(self: &const DestPtr, value: &ast.Node) !void {72 pub fn store(self: &const DestPtr, value: &ast.Node) void {
66 switch (*self) {73 switch (*self) {
67 DestPtr.Field => |ptr| *ptr = value,74 DestPtr.Field => |ptr| *ptr = value,
68 DestPtr.NullableField => |ptr| *ptr = value,75 DestPtr.NullableField => |ptr| *ptr = value,
69 DestPtr.List => |list| try list.append(value),76 }
77 }
78
79 pub fn get(self: &const DestPtr) &ast.Node {
80 switch (*self) {
81 DestPtr.Field => |ptr| return *ptr,
82 DestPtr.NullableField => |ptr| return ??*ptr,
70 }83 }
71 }84 }
72 };85 };
...@@ -76,21 +89,69 @@ pub const Parser = struct {...@@ -76,21 +89,69 @@ pub const Parser = struct {
76 ptr: &Token,89 ptr: &Token,
77 };90 };
7891
92 const RevertState = struct {
93 parser: Parser,
94 tokenizer: Tokenizer,
95
96 // We expect, that if something is optional, then there is a field,
97 // that needs to be set to null, when we revert.
98 ptr: &?&ast.Node,
99 };
100
101 const ExprListCtx = struct {
102 list: &ArrayList(&ast.Node),
103 end: Token.Id,
104 ptr: &Token,
105 };
106
107 const ElseCtx = struct {
108 payload: ?DestPtr,
109 body: DestPtr,
110 };
111
112 fn ListSave(comptime T: type) type {
113 return struct {
114 list: &ArrayList(T),
115 ptr: &Token,
116 };
117 }
118
119 const LabelCtx = struct {
120 label: ?Token,
121 dest_ptr: DestPtr,
122 };
123
124 const InlineCtx = struct {
125 label: ?Token,
126 inline_token: ?Token,
127 dest_ptr: DestPtr,
128 };
129
130 const LoopCtx = struct {
131 label: ?Token,
132 inline_token: ?Token,
133 loop_token: Token,
134 dest_ptr: DestPtr,
135 };
136
137 const AsyncEndCtx = struct {
138 dest_ptr: DestPtr,
139 attribute: &ast.NodeAsyncAttribute,
140 };
141
79 const State = union(enum) {142 const State = union(enum) {
80 TopLevel,143 TopLevel,
81 TopLevelExtern: ?Token,144 TopLevelExtern: TopLevelDeclCtx,
82 TopLevelDecl: TopLevelDeclCtx,145 TopLevelDecl: TopLevelDeclCtx,
83 Expression: DestPtr,146 ContainerExtern: ContainerExternCtx,
84 ExpectOperand,147 ContainerDecl: &ast.NodeContainerDecl,
85 Operand: &ast.Node,148 SliceOrArrayAccess: &ast.NodeSuffixOp,
86 AfterOperand,
87 InfixOp: &ast.NodeInfixOp,
88 PrefixOp: &ast.NodePrefixOp,
89 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,149 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
90 TypeExpr: DestPtr,
91 VarDecl: &ast.NodeVarDecl,150 VarDecl: &ast.NodeVarDecl,
92 VarDeclAlign: &ast.NodeVarDecl,151 VarDeclAlign: &ast.NodeVarDecl,
93 VarDeclEq: &ast.NodeVarDecl,152 VarDeclEq: &ast.NodeVarDecl,
153 IfToken: @TagType(Token.Id),
154 IfTokenSave: ExpectTokenSave,
94 ExpectToken: @TagType(Token.Id),155 ExpectToken: @TagType(Token.Id),
95 ExpectTokenSave: ExpectTokenSave,156 ExpectTokenSave: ExpectTokenSave,
96 FnProto: &ast.NodeFnProto,157 FnProto: &ast.NodeFnProto,
...@@ -99,10 +160,73 @@ pub const Parser = struct {...@@ -99,10 +160,73 @@ pub const Parser = struct {
99 ParamDecl: &ast.NodeFnProto,160 ParamDecl: &ast.NodeFnProto,
100 ParamDeclComma,161 ParamDeclComma,
101 FnDef: &ast.NodeFnProto,162 FnDef: &ast.NodeFnProto,
163 LabeledExpression: LabelCtx,
164 Inline: InlineCtx,
165 While: LoopCtx,
166 For: LoopCtx,
102 Block: &ast.NodeBlock,167 Block: &ast.NodeBlock,
168 Else: &?&ast.NodeElse,
169 WhileContinueExpr: &?&ast.Node,
103 Statement: &ast.NodeBlock,170 Statement: &ast.NodeBlock,
104 ExprListItemOrEnd: &ArrayList(&ast.Node),171 Semicolon: &const &const ast.Node,
105 ExprListCommaOrEnd: &ArrayList(&ast.Node),172 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
173 AsmInputItems: &ArrayList(&ast.NodeAsmInput),
174 AsmClopperItems: &ArrayList(&ast.NodeStringLiteral),
175 ExprListItemOrEnd: ExprListCtx,
176 ExprListCommaOrEnd: ExprListCtx,
177 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
178 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
179 FieldListCommaOrEnd: &ast.NodeContainerDecl,
180 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
181 SuspendBody: &ast.NodeSuspend,
182 AsyncEnd: AsyncEndCtx,
183 Payload: &?&ast.NodePayload,
184 PointerPayload: &?&ast.NodePointerPayload,
185 PointerIndexPayload: &?&ast.NodePointerIndexPayload,
186 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
187 SwitchCaseItem: &ArrayList(&ast.Node),
188 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
189
190 /// A state that can be appended before any other State. If an error occures,
191 /// the parser will first try looking for the closest optional state. If an
192 /// optional state is found, the parser will revert to the state it was in
193 /// when the optional was added. This will polute the arena allocator with
194 /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes.
195 Optional: RevertState,
196
197 Expression: DestPtr,
198 RangeExpressionBegin: DestPtr,
199 RangeExpressionEnd: DestPtr,
200 AssignmentExpressionBegin: DestPtr,
201 AssignmentExpressionEnd: DestPtr,
202 UnwrapExpressionBegin: DestPtr,
203 UnwrapExpressionEnd: DestPtr,
204 BoolOrExpressionBegin: DestPtr,
205 BoolOrExpressionEnd: DestPtr,
206 BoolAndExpressionBegin: DestPtr,
207 BoolAndExpressionEnd: DestPtr,
208 ComparisonExpressionBegin: DestPtr,
209 ComparisonExpressionEnd: DestPtr,
210 BinaryOrExpressionBegin: DestPtr,
211 BinaryOrExpressionEnd: DestPtr,
212 BinaryXorExpressionBegin: DestPtr,
213 BinaryXorExpressionEnd: DestPtr,
214 BinaryAndExpressionBegin: DestPtr,
215 BinaryAndExpressionEnd: DestPtr,
216 BitShiftExpressionBegin: DestPtr,
217 BitShiftExpressionEnd: DestPtr,
218 AdditionExpressionBegin: DestPtr,
219 AdditionExpressionEnd: DestPtr,
220 MultiplyExpressionBegin: DestPtr,
221 MultiplyExpressionEnd: DestPtr,
222 CurlySuffixExpressionBegin: DestPtr,
223 CurlySuffixExpressionEnd: DestPtr,
224 TypeExprBegin: DestPtr,
225 TypeExprEnd: DestPtr,
226 PrefixOpExpression: DestPtr,
227 SuffixOpExpressionBegin: DestPtr,
228 SuffixOpExpressionEnd: DestPtr,
229 PrimaryExpression: DestPtr,
106 };230 };
107231
108 /// Returns an AST tree, allocated with the parser's allocator.232 /// Returns an AST tree, allocated with the parser's allocator.
...@@ -167,88 +291,199 @@ pub const Parser = struct {...@@ -167,88 +291,199 @@ pub const Parser = struct {
167 State.TopLevel => {291 State.TopLevel => {
168 const token = self.getNextToken();292 const token = self.getNextToken();
169 switch (token.id) {293 switch (token.id) {
170 Token.Id.Keyword_pub, Token.Id.Keyword_export => {294 Token.Id.Keyword_test => {
171 stack.append(State { .TopLevelExtern = token }) catch unreachable;295 stack.append(State.TopLevel) catch unreachable;
296
297 const name_token = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
298 const lbrace = (try self.eatToken(&stack, Token.Id.LBrace)) ?? continue;
299
300 const name = try self.createStringLiteral(arena, name_token);
301 const block = try self.createBlock(arena, (?Token)(null), token);
302 const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, &name.base, block);
303 stack.append(State { .Block = block }) catch unreachable;
172 continue;304 continue;
173 },305 },
174 Token.Id.Eof => {306 Token.Id.Eof => {
175 root_node.eof_token = token;307 root_node.eof_token = token;
176 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};308 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
177 },309 },
310 Token.Id.Keyword_pub, Token.Id.Keyword_export => {
311 stack.append(State.TopLevel) catch unreachable;
312 try stack.append(State {
313 .TopLevelExtern = TopLevelDeclCtx {
314 .decls = &root_node.decls,
315 .visib_token = token,
316 .extern_token = null,
317 .lib_name = null,
318 }
319 });
320 continue;
321 },
322 Token.Id.Keyword_comptime => {
323 const node = try arena.create(ast.NodeComptime);
324 *node = ast.NodeComptime {
325 .base = self.initNode(ast.Node.Id.Comptime),
326 .comptime_token = token,
327 .expr = undefined,
328 };
329 try root_node.decls.append(&node.base);
330 stack.append(State.TopLevel) catch unreachable;
331 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
332 continue;
333 },
178 else => {334 else => {
179 self.putBackToken(token);335 self.putBackToken(token);
180 stack.append(State { .TopLevelExtern = null }) catch unreachable;336 stack.append(State.TopLevel) catch unreachable;
337 try stack.append(State {
338 .TopLevelExtern = TopLevelDeclCtx {
339 .decls = &root_node.decls,
340 .visib_token = null,
341 .extern_token = null,
342 .lib_name = null,
343 }
344 });
181 continue;345 continue;
182 },346 },
183 }347 }
184 },348 },
185 State.TopLevelExtern => |visib_token| {349 State.TopLevelExtern => |ctx| {
186 const token = self.getNextToken();350 const token = self.getNextToken();
187 if (token.id == Token.Id.Keyword_extern) {351 switch (token.id) {
188 stack.append(State {352 Token.Id.Keyword_use => {
189 .TopLevelDecl = TopLevelDeclCtx {353 const node = try arena.create(ast.NodeUse);
190 .visib_token = visib_token,354 *node = ast.NodeUse {
191 .extern_token = token,355 .base = self.initNode(ast.Node.Id.Use),
192 },356 .visib_token = ctx.visib_token,
193 }) catch unreachable;357 .expr = undefined,
194 continue;358 .semicolon_token = undefined,
195 }359 };
196 self.putBackToken(token);360 try ctx.decls.append(&node.base);
197 stack.append(State {361
198 .TopLevelDecl = TopLevelDeclCtx {362 stack.append(State {
199 .visib_token = visib_token,363 .ExpectTokenSave = ExpectTokenSave {
200 .extern_token = null,364 .id = Token.Id.Semicolon,
365 .ptr = &node.semicolon_token,
366 }
367 }) catch unreachable;
368 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
369 continue;
201 },370 },
202 }) catch unreachable;371 Token.Id.Keyword_extern => {
203 continue;372 const lib_name_token = self.getNextToken();
373 const lib_name = blk: {
374 if (lib_name_token.id == Token.Id.StringLiteral) {
375 const res = try self.createStringLiteral(arena, lib_name_token);
376 break :blk &res.base;
377 } else {
378 self.putBackToken(lib_name_token);
379 break :blk null;
380 }
381 };
382
383 stack.append(State {
384 .TopLevelDecl = TopLevelDeclCtx {
385 .decls = ctx.decls,
386 .visib_token = ctx.visib_token,
387 .extern_token = token,
388 .lib_name = lib_name,
389 },
390 }) catch unreachable;
391 continue;
392 },
393 else => {
394 self.putBackToken(token);
395 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
396 continue;
397 }
398 }
204 },399 },
205 State.TopLevelDecl => |ctx| {400 State.TopLevelDecl => |ctx| {
206 const token = self.getNextToken();401 const token = self.getNextToken();
207 switch (token.id) {402 switch (token.id) {
208 Token.Id.Keyword_var, Token.Id.Keyword_const => {403 Token.Id.Keyword_var, Token.Id.Keyword_const => {
209 stack.append(State.TopLevel) catch unreachable;
210 // TODO shouldn't need these casts404 // TODO shouldn't need these casts
211 const var_decl_node = try self.createAttachVarDecl(arena, &root_node.decls, ctx.visib_token,405 const var_decl_node = try self.createAttachVarDecl(arena, ctx.decls, ctx.visib_token,
212 token, (?Token)(null), ctx.extern_token);406 token, (?Token)(null), ctx.extern_token, ctx.lib_name);
213 try stack.append(State { .VarDecl = var_decl_node });407 stack.append(State { .VarDecl = var_decl_node }) catch unreachable;
214 continue;408 continue;
215 },409 },
216 Token.Id.Keyword_fn => {410 Token.Id.Keyword_fn => {
217 stack.append(State.TopLevel) catch unreachable;
218 // TODO shouldn't need these casts411 // TODO shouldn't need these casts
219 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, token,412 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, token,
220 ctx.extern_token, (?Token)(null), ctx.visib_token, (?Token)(null));413 ctx.extern_token, ctx.lib_name, (?Token)(null), ctx.visib_token, (?Token)(null));
221 try stack.append(State { .FnDef = fn_proto });414 stack.append(State { .FnDef = fn_proto }) catch unreachable;
222 try stack.append(State { .FnProto = fn_proto });415 try stack.append(State { .FnProto = fn_proto });
223 continue;416 continue;
224 },417 },
225 Token.Id.StringLiteral => {
226 @panic("TODO extern with string literal");
227 },
228 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {418 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
229 stack.append(State.TopLevel) catch unreachable;
230 const fn_token = try self.eatToken(Token.Id.Keyword_fn);
231 // TODO shouldn't need this cast419 // TODO shouldn't need this cast
232 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, fn_token,420 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined),
233 ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null));421 ctx.extern_token, ctx.lib_name, (?Token)(token), (?Token)(null), (?Token)(null));
234 try stack.append(State { .FnDef = fn_proto });422 stack.append(State { .FnDef = fn_proto }) catch unreachable;
423 try stack.append(State { .FnProto = fn_proto });
424 try stack.append(State {
425 .ExpectTokenSave = ExpectTokenSave {
426 .id = Token.Id.Keyword_fn,
427 .ptr = &fn_proto.fn_token,
428 }
429 });
430 continue;
431 },
432 Token.Id.Keyword_async => {
433 // TODO shouldn't need this cast
434 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined),
435 ctx.extern_token, ctx.lib_name, (?Token)(null), (?Token)(null), (?Token)(null));
436
437 const async_node = try arena.create(ast.NodeAsyncAttribute);
438 *async_node = ast.NodeAsyncAttribute {
439 .base = self.initNode(ast.Node.Id.AsyncAttribute),
440 .async_token = token,
441 .allocator_type = null,
442 .rangle_bracket = null,
443 };
444
445 fn_proto.async_attr = async_node;
446 stack.append(State { .FnDef = fn_proto }) catch unreachable;
235 try stack.append(State { .FnProto = fn_proto });447 try stack.append(State { .FnProto = fn_proto });
448 try stack.append(State {
449 .ExpectTokenSave = ExpectTokenSave {
450 .id = Token.Id.Keyword_fn,
451 .ptr = &fn_proto.fn_token,
452 }
453 });
454
455 const langle_bracket = self.getNextToken();
456 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
457 self.putBackToken(langle_bracket);
458 continue;
459 }
460
461 async_node.rangle_bracket = Token(undefined);
462 try stack.append(State {
463 .ExpectTokenSave = ExpectTokenSave {
464 .id = Token.Id.AngleBracketRight,
465 .ptr = &??async_node.rangle_bracket,
466 }
467 });
468 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
469 continue;
470 },
471 else => {
472 try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id));
236 continue;473 continue;
237 },474 },
238 else => return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id)),
239 }475 }
240 },476 },
241 State.VarDecl => |var_decl| {477 State.VarDecl => |var_decl| {
242 var_decl.name_token = try self.eatToken(Token.Id.Identifier);
243 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;478 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
244479 try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} });
245 const next_token = self.getNextToken();480 try stack.append(State { .IfToken = Token.Id.Colon });
246 if (next_token.id == Token.Id.Colon) {481 try stack.append(State {
247 try stack.append(State { .TypeExpr = DestPtr {.NullableField = &var_decl.type_node} });482 .ExpectTokenSave = ExpectTokenSave {
248 continue;483 .id = Token.Id.Identifier,
249 }484 .ptr = &var_decl.name_token,
250485 }
251 self.putBackToken(next_token);486 });
252 continue;487 continue;
253 },488 },
254 State.VarDeclAlign => |var_decl| {489 State.VarDeclAlign => |var_decl| {
...@@ -256,9 +491,9 @@ pub const Parser = struct {...@@ -256,9 +491,9 @@ pub const Parser = struct {
256491
257 const next_token = self.getNextToken();492 const next_token = self.getNextToken();
258 if (next_token.id == Token.Id.Keyword_align) {493 if (next_token.id == Token.Id.Keyword_align) {
259 _ = try self.eatToken(Token.Id.LParen);
260 try stack.append(State { .ExpectToken = Token.Id.RParen });494 try stack.append(State { .ExpectToken = Token.Id.RParen });
261 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });495 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });
496 try stack.append(State { .ExpectToken = Token.Id.LParen });
262 continue;497 continue;
263 }498 }
264499
...@@ -284,422 +519,2191 @@ pub const Parser = struct {...@@ -284,422 +519,2191 @@ pub const Parser = struct {
284 var_decl.semicolon_token = token;519 var_decl.semicolon_token = token;
285 continue;520 continue;
286 }521 }
287 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));522 try self.parseError(&stack, token, "expected '=' or ';', found {}", @tagName(token.id));
288 },
289 State.ExpectToken => |token_id| {
290 _ = try self.eatToken(token_id);
291 continue;
292 },
293
294 State.ExpectTokenSave => |expect_token_save| {
295 *expect_token_save.ptr = try self.eatToken(expect_token_save.id);
296 continue;523 continue;
297 },524 },
298525
299 State.Expression => |dest_ptr| {526 State.ContainerExtern => |ctx| {
300 // save the dest_ptr for later
301 stack.append(state) catch unreachable;
302 try stack.append(State.ExpectOperand);
303 continue;
304 },
305 State.ExpectOperand => {
306 // we'll either get an operand (like 1 or x),
307 // or a prefix operator (like ~ or return).
308 const token = self.getNextToken();527 const token = self.getNextToken();
309 switch (token.id) {528
310 Token.Id.Keyword_return => {529 const node = try arena.create(ast.NodeContainerDecl);
311 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,530 *node = ast.NodeContainerDecl {
312 ast.NodePrefixOp.PrefixOp.Return) });531 .base = self.initNode(ast.Node.Id.ContainerDecl),
313 try stack.append(State.ExpectOperand);532 .ltoken = ctx.ltoken,
314 continue;533 .layout = ctx.layout,
315 },534 .kind = switch (token.id) {
316 Token.Id.Keyword_try => {535 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
317 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,536 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
318 ast.NodePrefixOp.PrefixOp.Try) });537 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
319 try stack.append(State.ExpectOperand);538 else => {
320 continue;539 try self.parseError(&stack, token, "expected {}, {} or {}, found {}",
321 },540 @tagName(Token.Id.Keyword_struct),
322 Token.Id.Ampersand => {541 @tagName(Token.Id.Keyword_union),
323 const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{542 @tagName(Token.Id.Keyword_enum),
324 .AddrOf = ast.NodePrefixOp.AddrOfInfo {543 @tagName(token.id));
325 .align_expr = null,544 continue;
326 .bit_offset_start_token = null,545 },
327 .bit_offset_end_token = null,
328 .const_token = null,
329 .volatile_token = null,
330 }
331 });
332 try stack.append(State { .PrefixOp = prefix_op });
333 try stack.append(State.ExpectOperand);
334 try stack.append(State { .AddrOfModifiers = &prefix_op.op.AddrOf });
335 continue;
336 },
337 Token.Id.Identifier => {
338 try stack.append(State {
339 .Operand = &(try self.createIdentifier(arena, token)).base
340 });
341 try stack.append(State.AfterOperand);
342 continue;
343 },
344 Token.Id.IntegerLiteral => {
345 try stack.append(State {
346 .Operand = &(try self.createIntegerLiteral(arena, token)).base
347 });
348 try stack.append(State.AfterOperand);
349 continue;
350 },
351 Token.Id.FloatLiteral => {
352 try stack.append(State {
353 .Operand = &(try self.createFloatLiteral(arena, token)).base
354 });
355 try stack.append(State.AfterOperand);
356 continue;
357 },546 },
358 Token.Id.Builtin => {547 .init_arg_expr = undefined,
359 const node = try arena.create(ast.NodeBuiltinCall);548 .fields_and_decls = ArrayList(&ast.Node).init(arena),
360 *node = ast.NodeBuiltinCall {549 .rbrace_token = undefined,
361 .base = self.initNode(ast.Node.Id.BuiltinCall),550 };
362 .builtin_token = token,551 ctx.dest_ptr.store(&node.base);
363 .params = ArrayList(&ast.Node).init(arena),552
364 .rparen_token = undefined,553 stack.append(State { .ContainerDecl = node }) catch unreachable;
365 };554 try stack.append(State { .ExpectToken = Token.Id.LBrace });
366 try stack.append(State {555
367 .Operand = &node.base556 const lparen = self.getNextToken();
368 });557 if (lparen.id != Token.Id.LParen) {
369 try stack.append(State.AfterOperand);558 self.putBackToken(lparen);
370 try stack.append(State {.ExprListItemOrEnd = &node.params });559 node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
371 try stack.append(State {560 continue;
372 .ExpectTokenSave = ExpectTokenSave {561 }
373 .id = Token.Id.LParen,562
374 .ptr = &node.rparen_token,563 try stack.append(State { .ExpectToken = Token.Id.RParen });
375 },564
376 });565 const init_arg_token = self.getNextToken();
377 continue;566 switch (init_arg_token.id) {
567 Token.Id.Keyword_enum => {
568 node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
378 },569 },
379 Token.Id.StringLiteral => {570 else => {
380 const node = try arena.create(ast.NodeStringLiteral);571 self.putBackToken(init_arg_token);
381 *node = ast.NodeStringLiteral {572 node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
382 .base = self.initNode(ast.Node.Id.StringLiteral),
383 .token = token,
384 };
385 try stack.append(State {573 try stack.append(State {
386 .Operand = &node.base574 .Expression = DestPtr {
575 .Field = &node.init_arg_expr.Type
576 }
387 });577 });
388 try stack.append(State.AfterOperand);
389 continue;
390 },578 },
391
392 else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)),
393 }579 }
580 continue;
394 },581 },
395582
396 State.AfterOperand => {583 State.ContainerDecl => |container_decl| {
397 // we'll either get an infix operator (like != or ^),584 const token = self.getNextToken();
398 // or a postfix operator (like () or {}),585
399 // otherwise this expression is done (like on a ; or else).
400 var token = self.getNextToken();
401 switch (token.id) {586 switch (token.id) {
402 Token.Id.EqualEqual => {587 Token.Id.Identifier => {
403 try stack.append(State {588 switch (container_decl.kind) {
404 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.EqualEqual)589 ast.NodeContainerDecl.Kind.Struct => {
405 });590 const node = try arena.create(ast.NodeStructField);
406 try stack.append(State.ExpectOperand);591 *node = ast.NodeStructField {
407 continue;592 .base = self.initNode(ast.Node.Id.StructField),
593 .name_token = token,
594 .type_expr = undefined,
595 };
596 try container_decl.fields_and_decls.append(&node.base);
597
598 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
599 try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
600 try stack.append(State { .ExpectToken = Token.Id.Colon });
601 continue;
602 },
603 ast.NodeContainerDecl.Kind.Union => {
604 const node = try arena.create(ast.NodeUnionTag);
605 *node = ast.NodeUnionTag {
606 .base = self.initNode(ast.Node.Id.UnionTag),
607 .name_token = token,
608 .type_expr = null,
609 };
610 try container_decl.fields_and_decls.append(&node.base);
611
612 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
613
614 const next = self.getNextToken();
615 if (next.id != Token.Id.Colon) {
616 self.putBackToken(next);
617 continue;
618 }
619
620 try stack.append(State { .Expression = DestPtr { .NullableField = &node.type_expr } });
621 continue;
622 },
623 ast.NodeContainerDecl.Kind.Enum => {
624 const node = try arena.create(ast.NodeEnumTag);
625 *node = ast.NodeEnumTag {
626 .base = self.initNode(ast.Node.Id.EnumTag),
627 .name_token = token,
628 .value = null,
629 };
630 try container_decl.fields_and_decls.append(&node.base);
631
632 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
633
634 const next = self.getNextToken();
635 if (next.id != Token.Id.Equal) {
636 self.putBackToken(next);
637 continue;
638 }
639
640 try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } });
641 continue;
642 },
643 }
408 },644 },
409 Token.Id.BangEqual => {645 Token.Id.Keyword_pub, Token.Id.Keyword_export => {
646 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
410 try stack.append(State {647 try stack.append(State {
411 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BangEqual)648 .TopLevelExtern = TopLevelDeclCtx {
649 .decls = &container_decl.fields_and_decls,
650 .visib_token = token,
651 .extern_token = null,
652 .lib_name = null,
653 }
412 });654 });
413 try stack.append(State.ExpectOperand);
414 continue;655 continue;
415 },656 },
416 Token.Id.Period => {657 Token.Id.RBrace => {
417 try stack.append(State {658 container_decl.rbrace_token = token;
418 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period)
419 });
420 try stack.append(State.ExpectOperand);
421 continue;659 continue;
422 },660 },
423 else => {661 else => {
424 // no postfix/infix operator after this operand.
425 self.putBackToken(token);662 self.putBackToken(token);
426 // reduce the stack663 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
427 var expression: &ast.Node = stack.pop().Operand;664 try stack.append(State {
428 while (true) {665 .TopLevelExtern = TopLevelDeclCtx {
429 switch (stack.pop()) {666 .decls = &container_decl.fields_and_decls,
430 State.Expression => |dest_ptr| {667 .visib_token = null,
431 // we're done668 .extern_token = null,
432 try dest_ptr.store(expression);669 .lib_name = null,
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 }670 }
448 }671 });
449 continue;672 continue;
450 },673 }
451 }674 }
452 },675 },
453676
454 State.ExprListItemOrEnd => |params| {677 State.ExpectToken => |token_id| {
455 var token = self.getNextToken();678 _ = (try self.eatToken(&stack, token_id)) ?? continue;
456 switch (token.id) {679 continue;
457 Token.Id.RParen => continue,680 },
458 else => {681
459 self.putBackToken(token);682 State.ExpectTokenSave => |expect_token_save| {
460 stack.append(State { .ExprListCommaOrEnd = params }) catch unreachable;683 *expect_token_save.ptr = (try self.eatToken(&stack, expect_token_save.id)) ?? continue;
461 try stack.append(State { .Expression = DestPtr{.List = params} });684 continue;
462 },685 },
686
687 State.IfToken => |token_id| {
688 const token = self.getNextToken();
689 if (@TagType(Token.Id)(token.id) != token_id) {
690 self.putBackToken(token);
691 _ = stack.pop();
692 continue;
463 }693 }
694 continue;
464 },695 },
465696
466 State.ExprListCommaOrEnd => |params| {697 State.IfTokenSave => |if_token_save| {
467 var token = self.getNextToken();698 const token = self.getNextToken();
468 switch (token.id) {699 if (@TagType(Token.Id)(token.id) != if_token_save.id) {
469 Token.Id.Comma => {700 self.putBackToken(token);
470 stack.append(State { .ExprListItemOrEnd = params }) catch unreachable;701 _ = stack.pop();
471 },702 continue;
472 Token.Id.RParen => continue,
473 else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)),
474 }703 }
704
705 *if_token_save.ptr = token;
706 continue;
475 },707 },
476708
477 State.AddrOfModifiers => |addr_of_info| {709 State.Optional => { },
478 var token = self.getNextToken();710
479 switch (token.id) {711 State.Expression => |dest_ptr| {
480 Token.Id.Keyword_align => {712 const token = self.getNextToken();
481 stack.append(state) catch unreachable;713 switch (token.id) {
482 if (addr_of_info.align_expr != null) return self.parseError(token, "multiple align qualifiers");714 Token.Id.Keyword_try => {
483 _ = try self.eatToken(Token.Id.LParen);715 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Try);
716 dest_ptr.store(&node.base);
717
718 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
719 continue;
720 },
721 Token.Id.Keyword_return => {
722 const node = try self.createControlFlowExpr(arena, token, ast.NodeControlFlowExpression.Kind.Return);
723 dest_ptr.store(&node.base);
724
725 stack.append(State {
726 .Optional = RevertState {
727 .parser = *self,
728 .tokenizer = *self.tokenizer,
729 .ptr = &node.rhs,
730 }
731 }) catch unreachable;
732 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
733 continue;
734 },
735 Token.Id.Keyword_break => {
736 const label = blk: {
737 const colon = self.getNextToken();
738 if (colon.id != Token.Id.Colon) {
739 self.putBackToken(colon);
740 break :blk null;
741 }
742
743 break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
744 };
745
746 const node = try self.createControlFlowExpr(arena, token,
747 ast.NodeControlFlowExpression.Kind {
748 .Break = label,
749 }
750 );
751 dest_ptr.store(&node.base);
752
753 stack.append(State {
754 .Optional = RevertState {
755 .parser = *self,
756 .tokenizer = *self.tokenizer,
757 .ptr = &node.rhs,
758 }
759 }) catch unreachable;
760 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
761 continue;
762 },
763 Token.Id.Keyword_continue => {
764 const label = blk: {
765 const colon = self.getNextToken();
766 if (colon.id != Token.Id.Colon) {
767 self.putBackToken(colon);
768 break :blk null;
769 }
770
771 break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
772 };
773
774 const node = try self.createControlFlowExpr(arena, token,
775 ast.NodeControlFlowExpression.Kind {
776 .Continue = label,
777 }
778 );
779 dest_ptr.store(&node.base);
780 continue;
781 },
782 Token.Id.Keyword_cancel => {
783 const cancel_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Cancel);
784 dest_ptr.store(&cancel_node.base);
785 stack.append(State { .Expression = DestPtr { .Field = &cancel_node.rhs } }) catch unreachable;
786 },
787 Token.Id.Keyword_resume => {
788 const resume_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Resume);
789 dest_ptr.store(&resume_node.base);
790 stack.append(State { .Expression = DestPtr { .Field = &resume_node.rhs } }) catch unreachable;
791 },
792 Token.Id.Keyword_suspend => {
793 const node = try arena.create(ast.NodeSuspend);
794 *node = ast.NodeSuspend {
795 .base = self.initNode(ast.Node.Id.Suspend),
796 .suspend_token = token,
797 .payload = null,
798 .body = null,
799 };
800 dest_ptr.store(&node.base);
801 stack.append(State { .SuspendBody = node }) catch unreachable;
802 try stack.append(State { .Payload = &node.payload });
803 continue;
804 },
805 Token.Id.Keyword_if => {
806 const node = try arena.create(ast.NodeIf);
807 *node = ast.NodeIf {
808 .base = self.initNode(ast.Node.Id.If),
809 .if_token = token,
810 .condition = undefined,
811 .payload = null,
812 .body = undefined,
813 .@"else" = null,
814 };
815 dest_ptr.store(&node.base);
816
817 stack.append(State { .Else = &node.@"else" }) catch unreachable;
818 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
819 try stack.append(State { .PointerPayload = &node.payload });
484 try stack.append(State { .ExpectToken = Token.Id.RParen });820 try stack.append(State { .ExpectToken = Token.Id.RParen });
485 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });821 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
822 try stack.append(State { .ExpectToken = Token.Id.LParen });
486 continue;823 continue;
487 },824 },
488 Token.Id.Keyword_const => {825 Token.Id.Keyword_while => {
489 stack.append(state) catch unreachable;826 stack.append(State {
490 if (addr_of_info.const_token != null) return self.parseError(token, "duplicate qualifier: const");827 .While = LoopCtx {
491 addr_of_info.const_token = token;828 .label = null,
829 .inline_token = null,
830 .loop_token = token,
831 .dest_ptr = dest_ptr,
832 }
833 }) catch unreachable;
492 continue;834 continue;
493 },835 },
494 Token.Id.Keyword_volatile => {836 Token.Id.Keyword_for => {
495 stack.append(state) catch unreachable;837 stack.append(State {
496 if (addr_of_info.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile");838 .For = LoopCtx {
497 addr_of_info.volatile_token = token;839 .label = null,
840 .inline_token = null,
841 .loop_token = token,
842 .dest_ptr = dest_ptr,
843 }
844 }) catch unreachable;
845 continue;
846 },
847 Token.Id.Keyword_switch => {
848 const node = try arena.create(ast.NodeSwitch);
849 *node = ast.NodeSwitch {
850 .base = self.initNode(ast.Node.Id.Switch),
851 .switch_token = token,
852 .expr = undefined,
853 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
854 .rbrace = undefined,
855 };
856 dest_ptr.store(&node.base);
857
858 stack.append(State {
859 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
860 .list = &node.cases,
861 .ptr = &node.rbrace,
862 },
863 }) catch unreachable;
864 try stack.append(State { .ExpectToken = Token.Id.LBrace });
865 try stack.append(State { .ExpectToken = Token.Id.RParen });
866 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
867 try stack.append(State { .ExpectToken = Token.Id.LParen });
868 },
869 Token.Id.Keyword_comptime => {
870 const node = try arena.create(ast.NodeComptime);
871 *node = ast.NodeComptime {
872 .base = self.initNode(ast.Node.Id.Comptime),
873 .comptime_token = token,
874 .expr = undefined,
875 };
876 dest_ptr.store(&node.base);
877 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
878 continue;
879 },
880 Token.Id.LBrace => {
881 const block = try self.createBlock(arena, (?Token)(null), token);
882 dest_ptr.store(&block.base);
883
884 stack.append(State { .Block = block }) catch unreachable;
498 continue;885 continue;
499 },886 },
500 else => {887 else => {
501 self.putBackToken(token);888 self.putBackToken(token);
889 stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
502 continue;890 continue;
503 },891 }
504 }892 }
505 },893 },
506894
507 State.TypeExpr => |dest_ptr| {895 State.RangeExpressionBegin => |dest_ptr| {
896 stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;
897 try stack.append(State { .Expression = dest_ptr });
898 continue;
899 },
900
901 State.RangeExpressionEnd => |dest_ptr| {
508 const token = self.getNextToken();902 const token = self.getNextToken();
509 if (token.id == Token.Id.Keyword_var) {903 if (token.id == Token.Id.Ellipsis3) {
510 @panic("TODO param with type var");904 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Range);
905 node.lhs = dest_ptr.get();
906 dest_ptr.store(&node.base);
907
908 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
909 continue;
910 } else {
911 self.putBackToken(token);
912 continue;
511 }913 }
512 self.putBackToken(token);914 },
513915
514 stack.append(State { .Expression = dest_ptr }) catch unreachable;916 State.AssignmentExpressionBegin => |dest_ptr| {
917 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
918 try stack.append(State { .Expression = dest_ptr });
515 continue;919 continue;
516 },920 },
517921
518 State.FnProto => |fn_proto| {922 State.AssignmentExpressionEnd => |dest_ptr| {
519 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;923 const token = self.getNextToken();
520 try stack.append(State { .ParamDecl = fn_proto });924 if (tokenIdToAssignment(token.id)) |ass_id| {
521 try stack.append(State { .ExpectToken = Token.Id.LParen });925 const node = try self.createInfixOp(arena, token, ass_id);
926 node.lhs = dest_ptr.get();
927 dest_ptr.store(&node.base);
522928
523 const next_token = self.getNextToken();929 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
524 if (next_token.id == Token.Id.Identifier) {930 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
525 fn_proto.name_token = next_token;931 continue;
932 } else {
933 self.putBackToken(token);
526 continue;934 continue;
527 }935 }
528 self.putBackToken(next_token);936 },
937
938 State.UnwrapExpressionBegin => |dest_ptr| {
939 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
940 try stack.append(State { .BoolOrExpressionBegin = dest_ptr });
529 continue;941 continue;
530 },942 },
531943
532 State.FnProtoAlign => |fn_proto| {944 State.UnwrapExpressionEnd => |dest_ptr| {
533 const token = self.getNextToken();945 const token = self.getNextToken();
534 if (token.id == Token.Id.Keyword_align) {946 switch (token.id) {
535 @panic("TODO fn proto align");947 Token.Id.Keyword_catch => {
948 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp { .Catch = null });
949 node.lhs = dest_ptr.get();
950 dest_ptr.store(&node.base);
951
952 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
953 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
954 try stack.append(State { .Payload = &node.op.Catch });
955 continue;
956 },
957 Token.Id.QuestionMarkQuestionMark => {
958 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.UnwrapMaybe);
959 node.lhs = dest_ptr.get();
960 dest_ptr.store(&node.base);
961
962 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
963 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
964 continue;
965 },
966 else => {
967 self.putBackToken(token);
968 continue;
969 },
536 }970 }
537 self.putBackToken(token);971 },
538 stack.append(State {972
539 .FnProtoReturnType = fn_proto,973 State.BoolOrExpressionBegin => |dest_ptr| {
540 }) catch unreachable;974 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
975 try stack.append(State { .BoolAndExpressionBegin = dest_ptr });
541 continue;976 continue;
542 },977 },
543978
544 State.FnProtoReturnType => |fn_proto| {979 State.BoolOrExpressionEnd => |dest_ptr| {
545 const token = self.getNextToken();980 const token = self.getNextToken();
546 switch (token.id) {981 switch (token.id) {
547 Token.Id.Keyword_var => {982 Token.Id.Keyword_or => {
548 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Infer = token };983 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolOr);
549 },984 node.lhs = dest_ptr.get();
550 Token.Id.Bang => {985 dest_ptr.store(&node.base);
551 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };986
552 stack.append(State {987 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
553 .TypeExpr = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},988 try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } });
554 }) catch unreachable;989 continue;
555 },990 },
556 else => {991 else => {
557 self.putBackToken(token);992 self.putBackToken(token);
558 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };993 continue;
559 stack.append(State {
560 .TypeExpr = DestPtr {.Field = &fn_proto.return_type.Explicit},
561 }) catch unreachable;
562 },994 },
563 }995 }
564 if (token.id == Token.Id.Keyword_align) {996 },
565 @panic("TODO fn proto align");997
566 }998 State.BoolAndExpressionBegin => |dest_ptr| {
999 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1000 try stack.append(State { .ComparisonExpressionBegin = dest_ptr });
567 continue;1001 continue;
568 },1002 },
5691003
570 State.ParamDecl => |fn_proto| {1004 State.BoolAndExpressionEnd => |dest_ptr| {
571 var token = self.getNextToken();1005 const token = self.getNextToken();
572 if (token.id == Token.Id.RParen) {1006 switch (token.id) {
573 continue;1007 Token.Id.Keyword_and => {
574 }1008 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolAnd);
575 const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params);1009 node.lhs = dest_ptr.get();
576 if (token.id == Token.Id.Keyword_comptime) {1010 dest_ptr.store(&node.base);
577 param_decl.comptime_token = token;1011
578 token = self.getNextToken();1012 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
579 } else if (token.id == Token.Id.Keyword_noalias) {1013 try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } });
580 param_decl.noalias_token = token;1014 continue;
581 token = self.getNextToken();1015 },
582 }1016 else => {
583 if (token.id == Token.Id.Identifier) {1017 self.putBackToken(token);
584 const next_token = self.getNextToken();1018 continue;
585 if (next_token.id == Token.Id.Colon) {1019 },
586 param_decl.name_token = token;
587 token = self.getNextToken();
588 } else {
589 self.putBackToken(next_token);
590 }
591 }1020 }
592 if (token.id == Token.Id.Ellipsis3) {1021 },
593 param_decl.var_args_token = token;1022
594 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;1023 State.ComparisonExpressionBegin => |dest_ptr| {
1024 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1025 try stack.append(State { .BinaryOrExpressionBegin = dest_ptr });
1026 continue;
1027 },
1028
1029 State.ComparisonExpressionEnd => |dest_ptr| {
1030 const token = self.getNextToken();
1031 if (tokenIdToComparison(token.id)) |comp_id| {
1032 const node = try self.createInfixOp(arena, token, comp_id);
1033 node.lhs = dest_ptr.get();
1034 dest_ptr.store(&node.base);
1035
1036 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1037 try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } });
595 continue;1038 continue;
596 } else {1039 } else {
597 self.putBackToken(token);1040 self.putBackToken(token);
1041 continue;
598 }1042 }
1043 },
5991044
600 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;1045 State.BinaryOrExpressionBegin => |dest_ptr| {
601 try stack.append(State.ParamDeclComma);1046 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
602 try stack.append(State {1047 try stack.append(State { .BinaryXorExpressionBegin = dest_ptr });
603 .TypeExpr = DestPtr {.Field = &param_decl.type_node}
604 });
605 continue;1048 continue;
606 },1049 },
6071050
608 State.ParamDeclComma => {1051 State.BinaryOrExpressionEnd => |dest_ptr| {
609 const token = self.getNextToken();1052 const token = self.getNextToken();
610 switch (token.id) {1053 switch (token.id) {
611 Token.Id.RParen => {1054 Token.Id.Pipe => {
612 _ = stack.pop(); // pop off the ParamDecl1055 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitOr);
1056 node.lhs = dest_ptr.get();
1057 dest_ptr.store(&node.base);
1058
1059 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1060 try stack.append(State { .BinaryXorExpressionBegin = DestPtr { .Field = &node.rhs } });
1061 continue;
1062 },
1063 else => {
1064 self.putBackToken(token);
613 continue;1065 continue;
614 },1066 },
615 Token.Id.Comma => continue,
616 else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)),
617 }1067 }
618 },1068 },
6191069
620 State.FnDef => |fn_proto| {1070 State.BinaryXorExpressionBegin => |dest_ptr| {
1071 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1072 try stack.append(State { .BinaryAndExpressionBegin = dest_ptr });
1073 continue;
1074 },
1075
1076 State.BinaryXorExpressionEnd => |dest_ptr| {
621 const token = self.getNextToken();1077 const token = self.getNextToken();
622 switch(token.id) {1078 switch (token.id) {
623 Token.Id.LBrace => {1079 Token.Id.Caret => {
624 const block = try self.createBlock(arena, token);1080 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitXor);
625 fn_proto.body_node = &block.base;1081 node.lhs = dest_ptr.get();
626 stack.append(State { .Block = block }) catch unreachable;1082 dest_ptr.store(&node.base);
1083
1084 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1085 try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } });
1086 continue;
1087 },
1088 else => {
1089 self.putBackToken(token);
627 continue;1090 continue;
628 },1091 },
629 Token.Id.Semicolon => continue,
630 else => return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id)),
631 }1092 }
632 },1093 },
6331094
634 State.Block => |block| {1095 State.BinaryAndExpressionBegin => |dest_ptr| {
1096 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1097 try stack.append(State { .BitShiftExpressionBegin = dest_ptr });
1098 continue;
1099 },
1100
1101 State.BinaryAndExpressionEnd => |dest_ptr| {
635 const token = self.getNextToken();1102 const token = self.getNextToken();
636 switch (token.id) {1103 switch (token.id) {
637 Token.Id.RBrace => {1104 Token.Id.Ampersand => {
638 block.end_token = token;1105 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitAnd);
1106 node.lhs = dest_ptr.get();
1107 dest_ptr.store(&node.base);
1108
1109 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1110 try stack.append(State { .BitShiftExpressionBegin = DestPtr { .Field = &node.rhs } });
639 continue;1111 continue;
640 },1112 },
641 else => {1113 else => {
642 self.putBackToken(token);1114 self.putBackToken(token);
643 stack.append(State { .Block = block }) catch unreachable;
644 try stack.append(State { .Statement = block });
645 continue;1115 continue;
646 },1116 },
647 }1117 }
648 },1118 },
6491119
650 State.Statement => |block| {1120 State.BitShiftExpressionBegin => |dest_ptr| {
651 {1121 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
652 // Look for comptime var, comptime const1122 try stack.append(State { .AdditionExpressionBegin = dest_ptr });
653 const comptime_token = self.getNextToken();1123 continue;
654 if (comptime_token.id == Token.Id.Keyword_comptime) {1124 },
655 const mut_token = self.getNextToken();1125
656 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {1126 State.BitShiftExpressionEnd => |dest_ptr| {
657 // TODO shouldn't need these casts1127 const token = self.getNextToken();
658 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),1128 if (tokenIdToBitShift(token.id)) |bitshift_id| {
659 mut_token, (?Token)(comptime_token), (?Token)(null));1129 const node = try self.createInfixOp(arena, token, bitshift_id);
660 try stack.append(State { .VarDecl = var_decl });1130 node.lhs = dest_ptr.get();
661 continue;1131 dest_ptr.store(&node.base);
662 }1132
663 self.putBackToken(mut_token);1133 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
664 }1134 try stack.append(State { .AdditionExpressionBegin = DestPtr { .Field = &node.rhs } });
665 self.putBackToken(comptime_token);1135 continue;
666 }1136 } else {
667 {1137 self.putBackToken(token);
668 // Look for const, var1138 continue;
669 const mut_token = self.getNextToken();
670 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
671 // TODO shouldn't need these casts
672 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
673 mut_token, (?Token)(null), (?Token)(null));
674 try stack.append(State { .VarDecl = var_decl });
675 continue;
676 }
677 self.putBackToken(mut_token);
678 }1139 }
1140 },
6791141
680 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;1142 State.AdditionExpressionBegin => |dest_ptr| {
681 try stack.append(State { .Expression = DestPtr{.List = &block.statements} });1143 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1144 try stack.append(State { .MultiplyExpressionBegin = dest_ptr });
682 continue;1145 continue;
683 },1146 },
6841147
685 // These are data, not control flow.1148 State.AdditionExpressionEnd => |dest_ptr| {
686 State.InfixOp => unreachable,1149 const token = self.getNextToken();
687 State.PrefixOp => unreachable,1150 if (tokenIdToAddition(token.id)) |add_id| {
688 State.Operand => unreachable,1151 const node = try self.createInfixOp(arena, token, add_id);
689 }1152 node.lhs = dest_ptr.get();
690 }1153 dest_ptr.store(&node.base);
691 }
692
693 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {
694 if (self.pending_line_comment_node) |comment_node| {
695 self.pending_line_comment_node = null;
696 return ast.Node {.id = id, .comment = comment_node};
697 }
698 return ast.Node {.id = id, .comment = null };
699 }
7001154
701 fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot {1155 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
702 const node = try arena.create(ast.NodeRoot);1156 try stack.append(State { .MultiplyExpressionBegin = DestPtr { .Field = &node.rhs } });
1157 continue;
1158 } else {
1159 self.putBackToken(token);
1160 continue;
1161 }
1162 },
1163
1164 State.MultiplyExpressionBegin => |dest_ptr| {
1165 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1166 try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr });
1167 continue;
1168 },
1169
1170 State.MultiplyExpressionEnd => |dest_ptr| {
1171 const token = self.getNextToken();
1172 if (tokenIdToMultiply(token.id)) |mult_id| {
1173 const node = try self.createInfixOp(arena, token, mult_id);
1174 node.lhs = dest_ptr.get();
1175 dest_ptr.store(&node.base);
1176
1177 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1178 try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } });
1179 continue;
1180 } else {
1181 self.putBackToken(token);
1182 continue;
1183 }
1184 },
1185
1186 State.CurlySuffixExpressionBegin => |dest_ptr| {
1187 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1188 try stack.append(State { .TypeExprBegin = dest_ptr });
1189 continue;
1190 },
1191
1192 State.CurlySuffixExpressionEnd => |dest_ptr| {
1193 const token = self.getNextToken();
1194 if (token.id != Token.Id.LBrace) {
1195 self.putBackToken(token);
1196 continue;
1197 }
1198
1199 const next = self.getNextToken();
1200 switch (next.id) {
1201 Token.Id.Period => {
1202 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {
1203 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
1204 });
1205 node.lhs = dest_ptr.get();
1206 dest_ptr.store(&node.base);
1207
1208 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1209 try stack.append(State {
1210 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
1211 .list = &node.op.StructInitializer,
1212 .ptr = &node.rtoken,
1213 }
1214 });
1215 self.putBackToken(next);
1216 continue;
1217 },
1218 else => {
1219 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {
1220 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
1221 });
1222 node.lhs = dest_ptr.get();
1223 dest_ptr.store(&node.base);
1224
1225 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1226 try stack.append(State {
1227 .ExprListItemOrEnd = ExprListCtx {
1228 .list = &node.op.ArrayInitializer,
1229 .end = Token.Id.RBrace,
1230 .ptr = &node.rtoken,
1231 }
1232 });
1233 self.putBackToken(next);
1234 continue;
1235 },
1236 }
1237 },
1238
1239 State.TypeExprBegin => |dest_ptr| {
1240 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1241 try stack.append(State { .PrefixOpExpression = dest_ptr });
1242 continue;
1243 },
1244
1245 State.TypeExprEnd => |dest_ptr| {
1246 const token = self.getNextToken();
1247 switch (token.id) {
1248 Token.Id.Bang => {
1249 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.ErrorUnion);
1250 node.lhs = dest_ptr.get();
1251 dest_ptr.store(&node.base);
1252
1253 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1254 try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } });
1255 continue;
1256 },
1257 else => {
1258 self.putBackToken(token);
1259 continue;
1260 },
1261 }
1262 },
1263
1264 State.PrefixOpExpression => |dest_ptr| {
1265 const token = self.getNextToken();
1266 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
1267 const node = try self.createPrefixOp(arena, token, prefix_id);
1268 dest_ptr.store(&node.base);
1269
1270 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1271 if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
1272 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
1273 }
1274 continue;
1275 } else {
1276 self.putBackToken(token);
1277 stack.append(State { .SuffixOpExpressionBegin = dest_ptr }) catch unreachable;
1278 continue;
1279 }
1280 },
1281
1282 State.SuffixOpExpressionBegin => |dest_ptr| {
1283 const token = self.getNextToken();
1284 switch (token.id) {
1285 Token.Id.Keyword_async => {
1286 const async_node = try arena.create(ast.NodeAsyncAttribute);
1287 *async_node = ast.NodeAsyncAttribute {
1288 .base = self.initNode(ast.Node.Id.AsyncAttribute),
1289 .async_token = token,
1290 .allocator_type = null,
1291 .rangle_bracket = null,
1292 };
1293
1294 stack.append(State {
1295 .AsyncEnd = AsyncEndCtx {
1296 .dest_ptr = dest_ptr,
1297 .attribute = async_node,
1298 }
1299 }) catch unreachable;
1300 try stack.append(State { .SuffixOpExpressionEnd = dest_ptr });
1301 try stack.append(State { .PrimaryExpression = dest_ptr });
1302
1303 const langle_bracket = self.getNextToken();
1304 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
1305 self.putBackToken(langle_bracket);
1306 continue;
1307 }
1308
1309 async_node.rangle_bracket = Token(undefined);
1310 try stack.append(State {
1311 .ExpectTokenSave = ExpectTokenSave {
1312 .id = Token.Id.AngleBracketRight,
1313 .ptr = &??async_node.rangle_bracket,
1314 }
1315 });
1316 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
1317 continue;
1318 },
1319 else => {
1320 self.putBackToken(token);
1321 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1322 try stack.append(State { .PrimaryExpression = dest_ptr });
1323 continue;
1324 }
1325 }
1326 },
1327
1328 State.SuffixOpExpressionEnd => |dest_ptr| {
1329 const token = self.getNextToken();
1330 switch (token.id) {
1331 Token.Id.LParen => {
1332 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {
1333 .Call = ast.NodeSuffixOp.CallInfo {
1334 .params = ArrayList(&ast.Node).init(arena),
1335 .async_attr = null,
1336 }
1337 });
1338 node.lhs = dest_ptr.get();
1339 dest_ptr.store(&node.base);
1340
1341 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1342 try stack.append(State {
1343 .ExprListItemOrEnd = ExprListCtx {
1344 .list = &node.op.Call.params,
1345 .end = Token.Id.RParen,
1346 .ptr = &node.rtoken,
1347 }
1348 });
1349 continue;
1350 },
1351 Token.Id.LBracket => {
1352 const node = try arena.create(ast.NodeSuffixOp);
1353 *node = ast.NodeSuffixOp {
1354 .base = self.initNode(ast.Node.Id.SuffixOp),
1355 .lhs = undefined,
1356 .op = ast.NodeSuffixOp.SuffixOp {
1357 .ArrayAccess = undefined,
1358 },
1359 .rtoken = undefined,
1360 };
1361 node.lhs = dest_ptr.get();
1362 dest_ptr.store(&node.base);
1363
1364 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1365 try stack.append(State { .SliceOrArrayAccess = node });
1366 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }});
1367 continue;
1368 },
1369 Token.Id.Period => {
1370 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period);
1371 node.lhs = dest_ptr.get();
1372 dest_ptr.store(&node.base);
1373
1374 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1375 try stack.append(State { .SuffixOpExpressionBegin = DestPtr { .Field = &node.rhs }});
1376 continue;
1377 },
1378 else => {
1379 self.putBackToken(token);
1380 continue;
1381 },
1382 }
1383 },
1384
1385 State.PrimaryExpression => |dest_ptr| {
1386 const token = self.getNextToken();
1387 switch (token.id) {
1388 Token.Id.IntegerLiteral => {
1389 dest_ptr.store(&(try self.createIntegerLiteral(arena, token)).base);
1390 continue;
1391 },
1392 Token.Id.FloatLiteral => {
1393 dest_ptr.store(&(try self.createFloatLiteral(arena, token)).base);
1394 continue;
1395 },
1396 Token.Id.StringLiteral => {
1397 dest_ptr.store(&(try self.createStringLiteral(arena, token)).base);
1398 continue;
1399 },
1400 Token.Id.CharLiteral => {
1401 const node = try arena.create(ast.NodeCharLiteral);
1402 *node = ast.NodeCharLiteral {
1403 .base = self.initNode(ast.Node.Id.CharLiteral),
1404 .token = token,
1405 };
1406 dest_ptr.store(&node.base);
1407 continue;
1408 },
1409 Token.Id.Keyword_undefined => {
1410 dest_ptr.store(&(try self.createUndefined(arena, token)).base);
1411 continue;
1412 },
1413 Token.Id.Keyword_true, Token.Id.Keyword_false => {
1414 const node = try arena.create(ast.NodeBoolLiteral);
1415 *node = ast.NodeBoolLiteral {
1416 .base = self.initNode(ast.Node.Id.BoolLiteral),
1417 .token = token,
1418 };
1419 dest_ptr.store(&node.base);
1420 continue;
1421 },
1422 Token.Id.Keyword_null => {
1423 const node = try arena.create(ast.NodeNullLiteral);
1424 *node = ast.NodeNullLiteral {
1425 .base = self.initNode(ast.Node.Id.NullLiteral),
1426 .token = token,
1427 };
1428 dest_ptr.store(&node.base);
1429 continue;
1430 },
1431 Token.Id.Keyword_this => {
1432 const node = try arena.create(ast.NodeThisLiteral);
1433 *node = ast.NodeThisLiteral {
1434 .base = self.initNode(ast.Node.Id.ThisLiteral),
1435 .token = token,
1436 };
1437 dest_ptr.store(&node.base);
1438 continue;
1439 },
1440 Token.Id.Keyword_var => {
1441 const node = try arena.create(ast.NodeVarType);
1442 *node = ast.NodeVarType {
1443 .base = self.initNode(ast.Node.Id.VarType),
1444 .token = token,
1445 };
1446 dest_ptr.store(&node.base);
1447 },
1448 Token.Id.Keyword_unreachable => {
1449 const node = try arena.create(ast.NodeUnreachable);
1450 *node = ast.NodeUnreachable {
1451 .base = self.initNode(ast.Node.Id.Unreachable),
1452 .token = token,
1453 };
1454 dest_ptr.store(&node.base);
1455 continue;
1456 },
1457 Token.Id.MultilineStringLiteralLine => {
1458 const node = try arena.create(ast.NodeMultilineStringLiteral);
1459 *node = ast.NodeMultilineStringLiteral {
1460 .base = self.initNode(ast.Node.Id.MultilineStringLiteral),
1461 .tokens = ArrayList(Token).init(arena),
1462 };
1463 dest_ptr.store(&node.base);
1464 try node.tokens.append(token);
1465
1466 while (true) {
1467 const multiline_str = self.getNextToken();
1468 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
1469 self.putBackToken(multiline_str);
1470 break;
1471 }
1472
1473 try node.tokens.append(multiline_str);
1474 }
1475 continue;
1476 },
1477 Token.Id.LParen => {
1478 const node = try arena.create(ast.NodeGroupedExpression);
1479 *node = ast.NodeGroupedExpression {
1480 .base = self.initNode(ast.Node.Id.GroupedExpression),
1481 .lparen = token,
1482 .expr = undefined,
1483 .rparen = undefined,
1484 };
1485 dest_ptr.store(&node.base);
1486 stack.append(State {
1487 .ExpectTokenSave = ExpectTokenSave {
1488 .id = Token.Id.RParen,
1489 .ptr = &node.rparen,
1490 }
1491 }) catch unreachable;
1492 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1493 continue;
1494 },
1495 Token.Id.Builtin => {
1496 const node = try arena.create(ast.NodeBuiltinCall);
1497 *node = ast.NodeBuiltinCall {
1498 .base = self.initNode(ast.Node.Id.BuiltinCall),
1499 .builtin_token = token,
1500 .params = ArrayList(&ast.Node).init(arena),
1501 .rparen_token = undefined,
1502 };
1503 dest_ptr.store(&node.base);
1504 stack.append(State {
1505 .ExprListItemOrEnd = ExprListCtx {
1506 .list = &node.params,
1507 .end = Token.Id.RParen,
1508 .ptr = &node.rparen_token,
1509 }
1510 }) catch unreachable;
1511 try stack.append(State { .ExpectToken = Token.Id.LParen, });
1512 continue;
1513 },
1514 Token.Id.LBracket => {
1515 const rbracket_token = self.getNextToken();
1516 if (rbracket_token.id == Token.Id.RBracket) {
1517 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
1518 .SliceType = ast.NodePrefixOp.AddrOfInfo {
1519 .align_expr = null,
1520 .bit_offset_start_token = null,
1521 .bit_offset_end_token = null,
1522 .const_token = null,
1523 .volatile_token = null,
1524 }
1525 });
1526 dest_ptr.store(&node.base);
1527 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1528 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1529 continue;
1530 }
1531
1532 self.putBackToken(rbracket_token);
1533
1534 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
1535 .ArrayType = undefined,
1536 });
1537 dest_ptr.store(&node.base);
1538 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1539 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1540 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayType } });
1541
1542 },
1543 Token.Id.Keyword_error => {
1544 const next = self.getNextToken();
1545
1546 if (next.id != Token.Id.LBrace) {
1547 self.putBackToken(next);
1548 const node = try arena.create(ast.NodeErrorType);
1549 *node = ast.NodeErrorType {
1550 .base = self.initNode(ast.Node.Id.ErrorType),
1551 .token = token,
1552 };
1553 dest_ptr.store(&node.base);
1554 continue;
1555 }
1556
1557 const node = try arena.create(ast.NodeErrorSetDecl);
1558 *node = ast.NodeErrorSetDecl {
1559 .base = self.initNode(ast.Node.Id.ErrorSetDecl),
1560 .error_token = token,
1561 .decls = ArrayList(&ast.NodeIdentifier).init(arena),
1562 .rbrace_token = undefined,
1563 };
1564 dest_ptr.store(&node.base);
1565
1566 while (true) {
1567 const t = self.getNextToken();
1568 switch (t.id) {
1569 Token.Id.RBrace => {
1570 node.rbrace_token = t;
1571 break;
1572 },
1573 Token.Id.Identifier => {
1574 try node.decls.append(
1575 try self.createIdentifier(arena, t)
1576 );
1577 },
1578 else => {
1579 try self.parseError(&stack, token, "expected {} or {}, found {}",
1580 @tagName(Token.Id.RBrace),
1581 @tagName(Token.Id.Identifier),
1582 @tagName(token.id));
1583 continue;
1584 }
1585 }
1586
1587 const t2 = self.getNextToken();
1588 switch (t2.id) {
1589 Token.Id.RBrace => {
1590 node.rbrace_token = t;
1591 break;
1592 },
1593 Token.Id.Comma => continue,
1594 else => {
1595 try self.parseError(&stack, token, "expected {} or {}, found {}",
1596 @tagName(Token.Id.RBrace),
1597 @tagName(Token.Id.Comma),
1598 @tagName(token.id));
1599 continue;
1600 }
1601 }
1602 }
1603 continue;
1604 },
1605 Token.Id.Keyword_packed => {
1606 stack.append(State {
1607 .ContainerExtern = ContainerExternCtx {
1608 .dest_ptr = dest_ptr,
1609 .ltoken = token,
1610 .layout = ast.NodeContainerDecl.Layout.Packed,
1611 },
1612 }) catch unreachable;
1613 },
1614 Token.Id.Keyword_extern => {
1615 const next = self.getNextToken();
1616 if (next.id == Token.Id.Keyword_fn) {
1617 // TODO shouldn't need this cast
1618 const fn_proto = try self.createFnProto(arena, next,
1619 (?Token)(token), (?&ast.Node)(null), (?Token)(null), (?Token)(null), (?Token)(null));
1620 dest_ptr.store(&fn_proto.base);
1621 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1622 continue;
1623 }
1624
1625 self.putBackToken(next);
1626 stack.append(State {
1627 .ContainerExtern = ContainerExternCtx {
1628 .dest_ptr = dest_ptr,
1629 .ltoken = token,
1630 .layout = ast.NodeContainerDecl.Layout.Extern,
1631 },
1632 }) catch unreachable;
1633 },
1634 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
1635 self.putBackToken(token);
1636 stack.append(State {
1637 .ContainerExtern = ContainerExternCtx {
1638 .dest_ptr = dest_ptr,
1639 .ltoken = token,
1640 .layout = ast.NodeContainerDecl.Layout.Auto,
1641 },
1642 }) catch unreachable;
1643 },
1644 Token.Id.Identifier => {
1645 const next = self.getNextToken();
1646 if (next.id != Token.Id.Colon) {
1647 self.putBackToken(next);
1648 dest_ptr.store(&(try self.createIdentifier(arena, token)).base);
1649 continue;
1650 }
1651
1652 stack.append(State {
1653 .LabeledExpression = LabelCtx {
1654 .label = token,
1655 .dest_ptr = dest_ptr
1656 }
1657 }) catch unreachable;
1658 continue;
1659 },
1660 Token.Id.Keyword_fn => {
1661 // TODO shouldn't need these casts
1662 const fn_proto = try self.createFnProto(arena, token,
1663 (?Token)(null), (?&ast.Node)(null), (?Token)(null), (?Token)(null), (?Token)(null));
1664 dest_ptr.store(&fn_proto.base);
1665 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1666 continue;
1667 },
1668 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
1669 const fn_token = (try self.eatToken(&stack, Token.Id.Keyword_fn)) ?? continue;
1670 // TODO shouldn't need this cast
1671 const fn_proto = try self.createFnProto(arena, fn_token,
1672 (?Token)(null), (?&ast.Node)(null), (?Token)(token), (?Token)(null), (?Token)(null));
1673 dest_ptr.store(&fn_proto.base);
1674 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1675 continue;
1676 },
1677 Token.Id.Keyword_asm => {
1678 const is_volatile = blk: {
1679 const volatile_token = self.getNextToken();
1680 if (volatile_token.id != Token.Id.Keyword_volatile) {
1681 self.putBackToken(volatile_token);
1682 break :blk false;
1683 }
1684 break :blk true;
1685 };
1686 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
1687 const template = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
1688 // TODO parse template
1689
1690 const node = try arena.create(ast.NodeAsm);
1691 *node = ast.NodeAsm {
1692 .base = self.initNode(ast.Node.Id.Asm),
1693 .asm_token = token,
1694 .is_volatile = is_volatile,
1695 .template = template,
1696 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
1697 .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
1698 .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
1699 .cloppers = ArrayList(&ast.NodeStringLiteral).init(arena),
1700 .rparen = undefined,
1701 };
1702 dest_ptr.store(&node.base);
1703
1704 stack.append(State {
1705 .ExpectTokenSave = ExpectTokenSave {
1706 .id = Token.Id.RParen,
1707 .ptr = &node.rparen,
1708 }
1709 }) catch unreachable;
1710 try stack.append(State { .AsmClopperItems = &node.cloppers });
1711 try stack.append(State { .IfToken = Token.Id.Colon });
1712 try stack.append(State { .AsmInputItems = &node.inputs });
1713 try stack.append(State { .IfToken = Token.Id.Colon });
1714 try stack.append(State { .AsmOutputItems = &node.outputs });
1715 try stack.append(State { .IfToken = Token.Id.Colon });
1716 },
1717 Token.Id.Keyword_inline => {
1718 stack.append(State {
1719 .Inline = InlineCtx {
1720 .label = null,
1721 .inline_token = token,
1722 .dest_ptr = dest_ptr,
1723 }
1724 }) catch unreachable;
1725 continue;
1726 },
1727 else => {
1728 try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
1729 continue;
1730 }
1731 }
1732 },
1733
1734 State.SliceOrArrayAccess => |node| {
1735 var token = self.getNextToken();
1736
1737 switch (token.id) {
1738 Token.Id.Ellipsis2 => {
1739 const start = node.op.ArrayAccess;
1740 node.op = ast.NodeSuffixOp.SuffixOp {
1741 .Slice = ast.NodeSuffixOp.SliceRange {
1742 .start = start,
1743 .end = undefined,
1744 }
1745 };
1746
1747 const rbracket_token = self.getNextToken();
1748 if (rbracket_token.id != Token.Id.RBracket) {
1749 self.putBackToken(rbracket_token);
1750 stack.append(State {
1751 .ExpectTokenSave = ExpectTokenSave {
1752 .id = Token.Id.RBracket,
1753 .ptr = &node.rtoken,
1754 }
1755 }) catch unreachable;
1756 try stack.append(State { .Expression = DestPtr { .NullableField = &node.op.Slice.end } });
1757 } else {
1758 node.rtoken = rbracket_token;
1759 }
1760 continue;
1761 },
1762 Token.Id.RBracket => {
1763 node.rtoken = token;
1764 continue;
1765 },
1766 else => {
1767 try self.parseError(&stack, token, "expected ']' or '..', found {}", @tagName(token.id));
1768 continue;
1769 }
1770 }
1771 },
1772
1773
1774 State.AsmOutputItems => |items| {
1775 const lbracket = self.getNextToken();
1776 if (lbracket.id != Token.Id.LBracket) {
1777 self.putBackToken(lbracket);
1778 continue;
1779 }
1780
1781 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1782 try stack.append(State { .IfToken = Token.Id.Comma });
1783
1784 const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
1785 _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;
1786 const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
1787
1788 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
1789 try stack.append(State { .ExpectToken = Token.Id.RParen });
1790
1791 const node = try arena.create(ast.NodeAsmOutput);
1792 *node = ast.NodeAsmOutput {
1793 .base = self.initNode(ast.Node.Id.AsmOutput),
1794 .symbolic_name = try self.createIdentifier(arena, symbolic_name),
1795 .constraint = try self.createStringLiteral(arena, constraint),
1796 .kind = undefined,
1797 };
1798 try items.append(node);
1799
1800 const symbol_or_arrow = self.getNextToken();
1801 switch (symbol_or_arrow.id) {
1802 Token.Id.Identifier => {
1803 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createIdentifier(arena, symbol_or_arrow) };
1804 },
1805 Token.Id.Arrow => {
1806 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1807 try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });
1808 },
1809 else => {
1810 try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
1811 @tagName(Token.Id.Identifier),
1812 @tagName(symbol_or_arrow.id));
1813 continue;
1814 },
1815 }
1816 },
1817
1818 State.AsmInputItems => |items| {
1819 const lbracket = self.getNextToken();
1820 if (lbracket.id != Token.Id.LBracket) {
1821 self.putBackToken(lbracket);
1822 continue;
1823 }
1824
1825 stack.append(State { .AsmInputItems = items }) catch unreachable;
1826 try stack.append(State { .IfToken = Token.Id.Comma });
1827
1828 const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
1829 _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;
1830 const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
1831
1832 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
1833 try stack.append(State { .ExpectToken = Token.Id.RParen });
1834
1835 const node = try arena.create(ast.NodeAsmInput);
1836 *node = ast.NodeAsmInput {
1837 .base = self.initNode(ast.Node.Id.AsmInput),
1838 .symbolic_name = try self.createIdentifier(arena, symbolic_name),
1839 .constraint = try self.createStringLiteral(arena, constraint),
1840 .expr = undefined,
1841 };
1842 try items.append(node);
1843 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1844 },
1845
1846 State.AsmClopperItems => |items| {
1847 const string = self.getNextToken();
1848 if (string.id != Token.Id.StringLiteral) {
1849 self.putBackToken(string);
1850 continue;
1851 }
1852
1853 try items.append(try self.createStringLiteral(arena, string));
1854 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1855 try stack.append(State { .IfToken = Token.Id.Comma });
1856 },
1857
1858 State.ExprListItemOrEnd => |list_state| {
1859 var token = self.getNextToken();
1860
1861 const IdTag = @TagType(Token.Id);
1862 if (IdTag(list_state.end) == token.id) {
1863 *list_state.ptr = token;
1864 continue;
1865 }
1866
1867 self.putBackToken(token);
1868 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1869 try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } });
1870 },
1871
1872 State.FieldInitListItemOrEnd => |list_state| {
1873 var token = self.getNextToken();
1874
1875 if (token.id == Token.Id.RBrace){
1876 *list_state.ptr = token;
1877 continue;
1878 }
1879
1880 self.putBackToken(token);
1881
1882 const node = try arena.create(ast.NodeFieldInitializer);
1883 *node = ast.NodeFieldInitializer {
1884 .base = self.initNode(ast.Node.Id.FieldInitializer),
1885 .period_token = undefined,
1886 .name_token = undefined,
1887 .expr = undefined,
1888 };
1889 try list_state.list.append(node);
1890
1891 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1892 try stack.append(State { .Expression = DestPtr{.Field = &node.expr} });
1893 try stack.append(State { .ExpectToken = Token.Id.Equal });
1894 try stack.append(State {
1895 .ExpectTokenSave = ExpectTokenSave {
1896 .id = Token.Id.Identifier,
1897 .ptr = &node.name_token,
1898 }
1899 });
1900 try stack.append(State {
1901 .ExpectTokenSave = ExpectTokenSave {
1902 .id = Token.Id.Period,
1903 .ptr = &node.period_token,
1904 }
1905 });
1906 },
1907
1908 State.SwitchCaseOrEnd => |list_state| {
1909 var token = self.getNextToken();
1910
1911 if (token.id == Token.Id.RBrace){
1912 *list_state.ptr = token;
1913 continue;
1914 }
1915
1916 self.putBackToken(token);
1917
1918 const node = try arena.create(ast.NodeSwitchCase);
1919 *node = ast.NodeSwitchCase {
1920 .base = self.initNode(ast.Node.Id.SwitchCase),
1921 .items = ArrayList(&ast.Node).init(arena),
1922 .payload = null,
1923 .expr = undefined,
1924 };
1925 try list_state.list.append(node);
1926 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
1927 try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } });
1928 try stack.append(State { .PointerPayload = &node.payload });
1929
1930 const maybe_else = self.getNextToken();
1931 if (maybe_else.id == Token.Id.Keyword_else) {
1932 const else_node = try arena.create(ast.NodeSwitchElse);
1933 *else_node = ast.NodeSwitchElse {
1934 .base = self.initNode(ast.Node.Id.SwitchElse),
1935 .token = maybe_else,
1936 };
1937 try node.items.append(&else_node.base);
1938 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1939 continue;
1940 } else {
1941 self.putBackToken(maybe_else);
1942 try stack.append(State { .SwitchCaseItem = &node.items });
1943 continue;
1944 }
1945 },
1946
1947 State.SwitchCaseItem => |case_items| {
1948 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1949 try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });
1950 },
1951
1952 State.ExprListCommaOrEnd => |list_state| {
1953 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
1954 continue;
1955 },
1956
1957 State.FieldInitListCommaOrEnd => |list_state| {
1958 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
1959 continue;
1960 },
1961
1962 State.FieldListCommaOrEnd => |container_decl| {
1963 try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,
1964 State { .ContainerDecl = container_decl });
1965 continue;
1966 },
1967
1968 State.SwitchCaseCommaOrEnd => |list_state| {
1969 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
1970 continue;
1971 },
1972
1973 State.SwitchCaseItemCommaOrEnd => |case_items| {
1974 try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
1975 continue;
1976 },
1977
1978 State.Else => |dest| {
1979 const else_token = self.getNextToken();
1980 if (else_token.id != Token.Id.Keyword_else) {
1981 self.putBackToken(else_token);
1982 continue;
1983 }
1984
1985 const node = try arena.create(ast.NodeElse);
1986 *node = ast.NodeElse {
1987 .base = self.initNode(ast.Node.Id.Else),
1988 .else_token = else_token,
1989 .payload = null,
1990 .body = undefined,
1991 };
1992 *dest = node;
1993
1994 stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable;
1995 try stack.append(State { .Payload = &node.payload });
1996 },
1997
1998 State.WhileContinueExpr => |dest| {
1999 const colon = self.getNextToken();
2000 if (colon.id != Token.Id.Colon) {
2001 self.putBackToken(colon);
2002 continue;
2003 }
2004
2005 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
2006 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
2007 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = dest } });
2008 },
2009
2010 State.SuspendBody => |suspend_node| {
2011 if (suspend_node.payload != null) {
2012 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } });
2013 }
2014 continue;
2015 },
2016
2017 State.AsyncEnd => |ctx| {
2018 const node = ctx.dest_ptr.get();
2019
2020 switch (node.id) {
2021 ast.Node.Id.FnProto => {
2022 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
2023 fn_proto.async_attr = ctx.attribute;
2024 },
2025 ast.Node.Id.SuffixOp => {
2026 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
2027 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
2028 suffix_op.op.Call.async_attr = ctx.attribute;
2029 continue;
2030 }
2031
2032 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2033 @tagName(suffix_op.op));
2034 continue;
2035 },
2036 else => {
2037 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2038 @tagName(node.id));
2039 continue;
2040 }
2041 }
2042 },
2043
2044 State.Payload => |dest| {
2045 const lpipe = self.getNextToken();
2046 if (lpipe.id != Token.Id.Pipe) {
2047 self.putBackToken(lpipe);
2048 continue;
2049 }
2050
2051 const error_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2052 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
2053 const node = try arena.create(ast.NodePayload);
2054 *node = ast.NodePayload {
2055 .base = self.initNode(ast.Node.Id.Payload),
2056 .lpipe = lpipe,
2057 .error_symbol = try self.createIdentifier(arena, error_symbol),
2058 .rpipe = rpipe
2059 };
2060 *dest = node;
2061 },
2062
2063 State.PointerPayload => |dest| {
2064 const lpipe = self.getNextToken();
2065 if (lpipe.id != Token.Id.Pipe) {
2066 self.putBackToken(lpipe);
2067 continue;
2068 }
2069
2070 const is_ptr = blk: {
2071 const asterik = self.getNextToken();
2072 if (asterik.id == Token.Id.Asterisk) {
2073 break :blk true;
2074 } else {
2075 self.putBackToken(asterik);
2076 break :blk false;
2077 }
2078 };
2079
2080 const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2081 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
2082 const node = try arena.create(ast.NodePointerPayload);
2083 *node = ast.NodePointerPayload {
2084 .base = self.initNode(ast.Node.Id.PointerPayload),
2085 .lpipe = lpipe,
2086 .is_ptr = is_ptr,
2087 .value_symbol = try self.createIdentifier(arena, value_symbol),
2088 .rpipe = rpipe
2089 };
2090 *dest = node;
2091 },
2092
2093 State.PointerIndexPayload => |dest| {
2094 const lpipe = self.getNextToken();
2095 if (lpipe.id != Token.Id.Pipe) {
2096 self.putBackToken(lpipe);
2097 continue;
2098 }
2099
2100 const is_ptr = blk: {
2101 const asterik = self.getNextToken();
2102 if (asterik.id == Token.Id.Asterisk) {
2103 break :blk true;
2104 } else {
2105 self.putBackToken(asterik);
2106 break :blk false;
2107 }
2108 };
2109
2110 const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2111 const index_symbol = blk: {
2112 const comma = self.getNextToken();
2113 if (comma.id != Token.Id.Comma) {
2114 self.putBackToken(comma);
2115 break :blk null;
2116 }
2117
2118 const symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2119 break :blk try self.createIdentifier(arena, symbol);
2120 };
2121
2122 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
2123 const node = try arena.create(ast.NodePointerIndexPayload);
2124 *node = ast.NodePointerIndexPayload {
2125 .base = self.initNode(ast.Node.Id.PointerIndexPayload),
2126 .lpipe = lpipe,
2127 .is_ptr = is_ptr,
2128 .value_symbol = try self.createIdentifier(arena, value_symbol),
2129 .index_symbol = index_symbol,
2130 .rpipe = rpipe
2131 };
2132 *dest = node;
2133 },
2134
2135 State.AddrOfModifiers => |addr_of_info| {
2136 var token = self.getNextToken();
2137 switch (token.id) {
2138 Token.Id.Keyword_align => {
2139 stack.append(state) catch unreachable;
2140 if (addr_of_info.align_expr != null) {
2141 try self.parseError(&stack, token, "multiple align qualifiers");
2142 continue;
2143 }
2144 try stack.append(State { .ExpectToken = Token.Id.RParen });
2145 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });
2146 try stack.append(State { .ExpectToken = Token.Id.LParen });
2147 continue;
2148 },
2149 Token.Id.Keyword_const => {
2150 stack.append(state) catch unreachable;
2151 if (addr_of_info.const_token != null) {
2152 try self.parseError(&stack, token, "duplicate qualifier: const");
2153 continue;
2154 }
2155 addr_of_info.const_token = token;
2156 continue;
2157 },
2158 Token.Id.Keyword_volatile => {
2159 stack.append(state) catch unreachable;
2160 if (addr_of_info.volatile_token != null) {
2161 try self.parseError(&stack, token, "duplicate qualifier: volatile");
2162 continue;
2163 }
2164 addr_of_info.volatile_token = token;
2165 continue;
2166 },
2167 else => {
2168 self.putBackToken(token);
2169 continue;
2170 },
2171 }
2172 },
2173
2174 State.FnProto => |fn_proto| {
2175 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
2176 try stack.append(State { .ParamDecl = fn_proto });
2177 try stack.append(State { .ExpectToken = Token.Id.LParen });
2178
2179 const next_token = self.getNextToken();
2180 if (next_token.id == Token.Id.Identifier) {
2181 fn_proto.name_token = next_token;
2182 continue;
2183 }
2184 self.putBackToken(next_token);
2185 continue;
2186 },
2187
2188 State.FnProtoAlign => |fn_proto| {
2189 const token = self.getNextToken();
2190 if (token.id == Token.Id.Keyword_align) {
2191 @panic("TODO fn proto align");
2192 }
2193 self.putBackToken(token);
2194 stack.append(State {
2195 .FnProtoReturnType = fn_proto,
2196 }) catch unreachable;
2197 continue;
2198 },
2199
2200 State.FnProtoReturnType => |fn_proto| {
2201 const token = self.getNextToken();
2202 switch (token.id) {
2203 Token.Id.Bang => {
2204 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
2205 stack.append(State {
2206 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},
2207 }) catch unreachable;
2208 },
2209 else => {
2210 self.putBackToken(token);
2211 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
2212 stack.append(State {
2213 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.Explicit},
2214 }) catch unreachable;
2215 },
2216 }
2217 if (token.id == Token.Id.Keyword_align) {
2218 @panic("TODO fn proto align");
2219 }
2220 continue;
2221 },
2222
2223 State.ParamDecl => |fn_proto| {
2224 var token = self.getNextToken();
2225 if (token.id == Token.Id.RParen) {
2226 continue;
2227 }
2228 const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params);
2229 if (token.id == Token.Id.Keyword_comptime) {
2230 param_decl.comptime_token = token;
2231 token = self.getNextToken();
2232 } else if (token.id == Token.Id.Keyword_noalias) {
2233 param_decl.noalias_token = token;
2234 token = self.getNextToken();
2235 }
2236 if (token.id == Token.Id.Identifier) {
2237 const next_token = self.getNextToken();
2238 if (next_token.id == Token.Id.Colon) {
2239 param_decl.name_token = token;
2240 token = self.getNextToken();
2241 } else {
2242 self.putBackToken(next_token);
2243 }
2244 }
2245 if (token.id == Token.Id.Ellipsis3) {
2246 param_decl.var_args_token = token;
2247 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
2248 continue;
2249 } else {
2250 self.putBackToken(token);
2251 }
2252
2253 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
2254 try stack.append(State.ParamDeclComma);
2255 try stack.append(State {
2256 .TypeExprBegin = DestPtr {.Field = &param_decl.type_node}
2257 });
2258 continue;
2259 },
2260
2261 State.ParamDeclComma => {
2262 const token = self.getNextToken();
2263 switch (token.id) {
2264 Token.Id.RParen => {
2265 _ = stack.pop(); // pop off the ParamDecl
2266 continue;
2267 },
2268 Token.Id.Comma => continue,
2269 else => {
2270 try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id));
2271 continue;
2272 },
2273 }
2274 },
2275
2276 State.FnDef => |fn_proto| {
2277 const token = self.getNextToken();
2278 switch(token.id) {
2279 Token.Id.LBrace => {
2280 const block = try self.createBlock(arena, (?Token)(null), token);
2281 fn_proto.body_node = &block.base;
2282 stack.append(State { .Block = block }) catch unreachable;
2283 continue;
2284 },
2285 Token.Id.Semicolon => continue,
2286 else => {
2287 try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id));
2288 continue;
2289 },
2290 }
2291 },
2292
2293 State.LabeledExpression => |ctx| {
2294 const token = self.getNextToken();
2295 switch (token.id) {
2296 Token.Id.LBrace => {
2297 const block = try self.createBlock(arena, (?Token)(ctx.label), token);
2298 ctx.dest_ptr.store(&block.base);
2299
2300 stack.append(State { .Block = block }) catch unreachable;
2301 continue;
2302 },
2303 Token.Id.Keyword_while => {
2304 stack.append(State {
2305 .While = LoopCtx {
2306 .label = ctx.label,
2307 .inline_token = null,
2308 .loop_token = token,
2309 .dest_ptr = ctx.dest_ptr,
2310 }
2311 }) catch unreachable;
2312 continue;
2313 },
2314 Token.Id.Keyword_for => {
2315 stack.append(State {
2316 .For = LoopCtx {
2317 .label = ctx.label,
2318 .inline_token = null,
2319 .loop_token = token,
2320 .dest_ptr = ctx.dest_ptr,
2321 }
2322 }) catch unreachable;
2323 continue;
2324 },
2325 Token.Id.Keyword_inline => {
2326 stack.append(State {
2327 .Inline = InlineCtx {
2328 .label = ctx.label,
2329 .inline_token = token,
2330 .dest_ptr = ctx.dest_ptr,
2331 }
2332 }) catch unreachable;
2333 continue;
2334 },
2335 else => {
2336 try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
2337 continue;
2338 },
2339 }
2340 },
2341
2342 State.Inline => |ctx| {
2343 const token = self.getNextToken();
2344 switch (token.id) {
2345 Token.Id.Keyword_while => {
2346 stack.append(State {
2347 .While = LoopCtx {
2348 .inline_token = ctx.inline_token,
2349 .label = ctx.label,
2350 .loop_token = token,
2351 .dest_ptr = ctx.dest_ptr,
2352 }
2353 }) catch unreachable;
2354 continue;
2355 },
2356 Token.Id.Keyword_for => {
2357 stack.append(State {
2358 .For = LoopCtx {
2359 .inline_token = ctx.inline_token,
2360 .label = ctx.label,
2361 .loop_token = token,
2362 .dest_ptr = ctx.dest_ptr,
2363 }
2364 }) catch unreachable;
2365 continue;
2366 },
2367 else => {
2368 try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id));
2369 continue;
2370 },
2371 }
2372 },
2373
2374 State.While => |ctx| {
2375 const node = try arena.create(ast.NodeWhile);
2376 *node = ast.NodeWhile {
2377 .base = self.initNode(ast.Node.Id.While),
2378 .label = ctx.label,
2379 .inline_token = ctx.inline_token,
2380 .while_token = ctx.loop_token,
2381 .condition = undefined,
2382 .payload = null,
2383 .continue_expr = null,
2384 .body = undefined,
2385 .@"else" = null,
2386 };
2387 ctx.dest_ptr.store(&node.base);
2388
2389 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2390 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2391 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
2392 try stack.append(State { .PointerPayload = &node.payload });
2393 try stack.append(State { .ExpectToken = Token.Id.RParen });
2394 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2395 try stack.append(State { .ExpectToken = Token.Id.LParen });
2396 },
2397
2398 State.For => |ctx| {
2399 const node = try arena.create(ast.NodeFor);
2400 *node = ast.NodeFor {
2401 .base = self.initNode(ast.Node.Id.For),
2402 .label = ctx.label,
2403 .inline_token = ctx.inline_token,
2404 .for_token = ctx.loop_token,
2405 .array_expr = undefined,
2406 .payload = null,
2407 .body = undefined,
2408 .@"else" = null,
2409 };
2410 ctx.dest_ptr.store(&node.base);
2411
2412 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2413 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2414 try stack.append(State { .PointerIndexPayload = &node.payload });
2415 try stack.append(State { .ExpectToken = Token.Id.RParen });
2416 try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });
2417 try stack.append(State { .ExpectToken = Token.Id.LParen });
2418 },
2419
2420 State.Block => |block| {
2421 const token = self.getNextToken();
2422 switch (token.id) {
2423 Token.Id.RBrace => {
2424 block.rbrace = token;
2425 continue;
2426 },
2427 else => {
2428 self.putBackToken(token);
2429 stack.append(State { .Block = block }) catch unreachable;
2430 try stack.append(State { .Statement = block });
2431 continue;
2432 },
2433 }
2434 },
2435
2436 State.Statement => |block| {
2437 const next = self.getNextToken();
2438 switch (next.id) {
2439 Token.Id.Keyword_comptime => {
2440 const mut_token = self.getNextToken();
2441 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
2442 // TODO shouldn't need these casts
2443 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
2444 mut_token, (?Token)(next), (?Token)(null), null);
2445 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2446 continue;
2447 } else {
2448 self.putBackToken(mut_token);
2449 self.putBackToken(next);
2450 const statememt = try block.statements.addOne();
2451 stack.append(State { .Semicolon = statememt }) catch unreachable;
2452 try stack.append(State { .Expression = DestPtr{.Field = statememt } });
2453 }
2454 },
2455 Token.Id.Keyword_var, Token.Id.Keyword_const => {
2456 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
2457 next, (?Token)(null), (?Token)(null), null);
2458 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2459 continue;
2460 },
2461 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
2462 const node = try arena.create(ast.NodeDefer);
2463 *node = ast.NodeDefer {
2464 .base = self.initNode(ast.Node.Id.Defer),
2465 .defer_token = next,
2466 .kind = switch (next.id) {
2467 Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
2468 Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
2469 else => unreachable,
2470 },
2471 .expr = undefined,
2472 };
2473 try block.statements.append(&node.base);
2474
2475 stack.append(State { .Semicolon = &node.base }) catch unreachable;
2476 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = &node.expr } });
2477 continue;
2478 },
2479 Token.Id.LBrace => {
2480 const inner_block = try self.createBlock(arena, (?Token)(null), next);
2481 try block.statements.append(&inner_block.base);
2482
2483 stack.append(State { .Block = inner_block }) catch unreachable;
2484 continue;
2485 },
2486 else => {
2487 self.putBackToken(next);
2488 const statememt = try block.statements.addOne();
2489 stack.append(State { .Semicolon = statememt }) catch unreachable;
2490 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } });
2491 continue;
2492 }
2493 }
2494
2495 },
2496
2497 State.Semicolon => |node_ptr| {
2498 const node = *node_ptr;
2499 if (requireSemiColon(node)) {
2500 _ = (try self.eatToken(&stack, Token.Id.Semicolon)) ?? continue;
2501 }
2502 }
2503 }
2504 }
2505 }
2506
2507 fn requireSemiColon(node: &const ast.Node) bool {
2508 var n = node;
2509 while (true) {
2510 switch (n.id) {
2511 ast.Node.Id.Root,
2512 ast.Node.Id.StructField,
2513 ast.Node.Id.UnionTag,
2514 ast.Node.Id.EnumTag,
2515 ast.Node.Id.ParamDecl,
2516 ast.Node.Id.Block,
2517 ast.Node.Id.Payload,
2518 ast.Node.Id.PointerPayload,
2519 ast.Node.Id.PointerIndexPayload,
2520 ast.Node.Id.Switch,
2521 ast.Node.Id.SwitchCase,
2522 ast.Node.Id.SwitchElse,
2523 ast.Node.Id.FieldInitializer,
2524 ast.Node.Id.LineComment,
2525 ast.Node.Id.TestDecl => return false,
2526 ast.Node.Id.While => {
2527 const while_node = @fieldParentPtr(ast.NodeWhile, "base", n);
2528 if (while_node.@"else") |@"else"| {
2529 n = @"else".base;
2530 continue;
2531 }
2532
2533 n = while_node.body;
2534 },
2535 ast.Node.Id.For => {
2536 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
2537 if (for_node.@"else") |@"else"| {
2538 n = @"else".base;
2539 continue;
2540 }
2541
2542 n = for_node.body;
2543 },
2544 ast.Node.Id.If => {
2545 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
2546 if (if_node.@"else") |@"else"| {
2547 n = @"else".base;
2548 continue;
2549 }
2550
2551 n = if_node.body;
2552 },
2553 ast.Node.Id.Else => {
2554 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
2555 n = else_node.body;
2556 },
2557 ast.Node.Id.Defer => {
2558 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
2559 n = defer_node.expr;
2560 },
2561 ast.Node.Id.Comptime => {
2562 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
2563 n = comptime_node.expr;
2564 },
2565 ast.Node.Id.Suspend => {
2566 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
2567 if (suspend_node.body) |body| {
2568 n = body;
2569 continue;
2570 }
2571
2572 return true;
2573 },
2574 else => return true,
2575 }
2576 }
2577 }
2578
2579 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {
2580 var token = self.getNextToken();
2581 switch (token.id) {
2582 Token.Id.Comma => {
2583 stack.append(state_after_comma) catch unreachable;
2584 },
2585 else => {
2586 const IdTag = @TagType(Token.Id);
2587 if (IdTag(*end) == token.id) {
2588 if (maybe_ptr) |ptr| {
2589 *ptr = token;
2590 }
2591 return;
2592 }
2593
2594 try self.parseError(stack, token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id));
2595 },
2596 }
2597 }
2598
2599 fn tokenIdToAssignment(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2600 // TODO: We have to cast all cases because of this:
2601 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2602 return switch (*id) {
2603 Token.Id.AmpersandEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitAnd),
2604 Token.Id.AngleBracketAngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftLeft),
2605 Token.Id.AngleBracketAngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftRight),
2606 Token.Id.AsteriskEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimes),
2607 Token.Id.AsteriskPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimesWarp),
2608 Token.Id.CaretEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitXor),
2609 Token.Id.Equal => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Assign),
2610 Token.Id.MinusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinus),
2611 Token.Id.MinusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinusWrap),
2612 Token.Id.PercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMod),
2613 Token.Id.PipeEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitOr),
2614 Token.Id.PlusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlus),
2615 Token.Id.PlusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlusWrap),
2616 Token.Id.SlashEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignDiv),
2617 else => null,
2618 };
2619 }
2620
2621 fn tokenIdToComparison(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2622 // TODO: We have to cast all cases because of this:
2623 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2624 return switch (*id) {
2625 Token.Id.BangEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BangEqual),
2626 Token.Id.EqualEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.EqualEqual),
2627 Token.Id.AngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.LessThan),
2628 Token.Id.AngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.LessOrEqual),
2629 Token.Id.AngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.GreaterThan),
2630 Token.Id.AngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.GreaterOrEqual),
2631 else => null,
2632 };
2633 }
2634
2635 fn tokenIdToBitShift(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2636 // TODO: We have to cast all cases because of this:
2637 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2638 return switch (*id) {
2639 Token.Id.AngleBracketAngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftLeft),
2640 Token.Id.AngleBracketAngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftRight),
2641 else => null,
2642 };
2643 }
2644
2645 fn tokenIdToAddition(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2646 // TODO: We have to cast all cases because of this:
2647 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2648 return switch (*id) {
2649 Token.Id.Minus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Sub),
2650 Token.Id.MinusPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.SubWrap),
2651 Token.Id.Plus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Add),
2652 Token.Id.PlusPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AddWrap),
2653 Token.Id.PlusPlus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayCat),
2654 else => null,
2655 };
2656 }
2657
2658 fn tokenIdToMultiply(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2659 // TODO: We have to cast all cases because of this:
2660 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2661 return switch (*id) {
2662 Token.Id.Slash => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Div),
2663 Token.Id.Asterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mult),
2664 Token.Id.AsteriskAsterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayMult),
2665 Token.Id.AsteriskPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.MultWrap),
2666 Token.Id.Percent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mod),
2667 Token.Id.PipePipe => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.MergeErrorSets),
2668 else => null,
2669 };
2670 }
2671
2672 fn tokenIdToPrefixOp(id: &const Token.Id) ?ast.NodePrefixOp.PrefixOp {
2673 // TODO: We have to cast all cases because of this:
2674 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2675 return switch (*id) {
2676 Token.Id.Bang => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BoolNot),
2677 Token.Id.Tilde => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BitNot),
2678 Token.Id.Minus => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Negation),
2679 Token.Id.MinusPercent => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.NegationWrap),
2680 Token.Id.Asterisk => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Deref),
2681 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
2682 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
2683 .align_expr = null,
2684 .bit_offset_start_token = null,
2685 .bit_offset_end_token = null,
2686 .const_token = null,
2687 .volatile_token = null,
2688 },
2689 },
2690 Token.Id.QuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.MaybeType),
2691 Token.Id.QuestionMarkQuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.UnwrapMaybe),
2692 Token.Id.Keyword_await => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Await),
2693 else => null,
2694 };
2695 }
2696
2697 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {
2698 if (self.pending_line_comment_node) |comment_node| {
2699 self.pending_line_comment_node = null;
2700 return ast.Node {.id = id, .comment = comment_node};
2701 }
2702 return ast.Node {.id = id, .comment = null };
2703 }
2704
2705 fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot {
2706 const node = try arena.create(ast.NodeRoot);
7032707
704 *node = ast.NodeRoot {2708 *node = ast.NodeRoot {
705 .base = self.initNode(ast.Node.Id.Root),2709 .base = self.initNode(ast.Node.Id.Root),
...@@ -711,7 +2715,7 @@ pub const Parser = struct {...@@ -711,7 +2715,7 @@ pub const Parser = struct {
711 }2715 }
7122716
713 fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token,2717 fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token,
714 comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl2718 comptime_token: &const ?Token, extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl
715 {2719 {
716 const node = try arena.create(ast.NodeVarDecl);2720 const node = try arena.create(ast.NodeVarDecl);
7172721
...@@ -724,7 +2728,7 @@ pub const Parser = struct {...@@ -724,7 +2728,7 @@ pub const Parser = struct {
724 .type_node = null,2728 .type_node = null,
725 .align_node = null,2729 .align_node = null,
726 .init_node = null,2730 .init_node = null,
727 .lib_name = null,2731 .lib_name = lib_name,
728 // initialized later2732 // initialized later
729 .name_token = undefined,2733 .name_token = undefined,
730 .eq_token = undefined,2734 .eq_token = undefined,
...@@ -733,8 +2737,33 @@ pub const Parser = struct {...@@ -733,8 +2737,33 @@ pub const Parser = struct {
733 return node;2737 return node;
734 }2738 }
7352739
2740 fn createStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeStringLiteral {
2741 const node = try arena.create(ast.NodeStringLiteral);
2742
2743 assert(token.id == Token.Id.StringLiteral);
2744 *node = ast.NodeStringLiteral {
2745 .base = self.initNode(ast.Node.Id.StringLiteral),
2746 .token = *token,
2747 };
2748 return node;
2749 }
2750
2751 fn createTestDecl(self: &Parser, arena: &mem.Allocator, test_token: &const Token, name: &ast.Node,
2752 block: &ast.NodeBlock) !&ast.NodeTestDecl
2753 {
2754 const node = try arena.create(ast.NodeTestDecl);
2755
2756 *node = ast.NodeTestDecl {
2757 .base = self.initNode(ast.Node.Id.TestDecl),
2758 .test_token = *test_token,
2759 .name = name,
2760 .body_node = &block.base,
2761 };
2762 return node;
2763 }
2764
736 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,2765 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,
737 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto2766 lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
738 {2767 {
739 const node = try arena.create(ast.NodeFnProto);2768 const node = try arena.create(ast.NodeFnProto);
7402769
...@@ -749,8 +2778,9 @@ pub const Parser = struct {...@@ -749,8 +2778,9 @@ pub const Parser = struct {
749 .extern_token = *extern_token,2778 .extern_token = *extern_token,
750 .inline_token = *inline_token,2779 .inline_token = *inline_token,
751 .cc_token = *cc_token,2780 .cc_token = *cc_token,
2781 .async_attr = null,
752 .body_node = null,2782 .body_node = null,
753 .lib_name = null,2783 .lib_name = lib_name,
754 .align_expr = null,2784 .align_expr = null,
755 };2785 };
756 return node;2786 return node;
...@@ -770,14 +2800,28 @@ pub const Parser = struct {...@@ -770,14 +2800,28 @@ pub const Parser = struct {
770 return node;2800 return node;
771 }2801 }
7722802
773 fn createBlock(self: &Parser, arena: &mem.Allocator, begin_token: &const Token) !&ast.NodeBlock {2803 fn createBlock(self: &Parser, arena: &mem.Allocator, label: &const ?Token, lbrace: &const Token) !&ast.NodeBlock {
774 const node = try arena.create(ast.NodeBlock);2804 const node = try arena.create(ast.NodeBlock);
7752805
776 *node = ast.NodeBlock {2806 *node = ast.NodeBlock {
777 .base = self.initNode(ast.Node.Id.Block),2807 .base = self.initNode(ast.Node.Id.Block),
778 .begin_token = *begin_token,2808 .label = *label,
779 .end_token = undefined,2809 .lbrace = *lbrace,
780 .statements = ArrayList(&ast.Node).init(arena),2810 .statements = ArrayList(&ast.Node).init(arena),
2811 .rbrace = undefined,
2812 };
2813 return node;
2814 }
2815
2816 fn createControlFlowExpr(self: &Parser, arena: &mem.Allocator, ltoken: &const Token,
2817 kind: &const ast.NodeControlFlowExpression.Kind) !&ast.NodeControlFlowExpression
2818 {
2819 const node = try arena.create(ast.NodeControlFlowExpression);
2820 *node = ast.NodeControlFlowExpression {
2821 .base = self.initNode(ast.Node.Id.ControlFlowExpression),
2822 .ltoken = *ltoken,
2823 .kind = *kind,
2824 .rhs = null,
781 };2825 };
782 return node;2826 return node;
783 }2827 }
...@@ -807,6 +2851,18 @@ pub const Parser = struct {...@@ -807,6 +2851,18 @@ pub const Parser = struct {
807 return node;2851 return node;
808 }2852 }
8092853
2854 fn createSuffixOp(self: &Parser, arena: &mem.Allocator, op: &const ast.NodeSuffixOp.SuffixOp) !&ast.NodeSuffixOp {
2855 const node = try arena.create(ast.NodeSuffixOp);
2856
2857 *node = ast.NodeSuffixOp {
2858 .base = self.initNode(ast.Node.Id.SuffixOp),
2859 .lhs = undefined,
2860 .op = *op,
2861 .rtoken = undefined,
2862 };
2863 return node;
2864 }
2865
810 fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier {2866 fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier {
811 const node = try arena.create(ast.NodeIdentifier);2867 const node = try arena.create(ast.NodeIdentifier);
8122868
...@@ -837,6 +2893,16 @@ pub const Parser = struct {...@@ -837,6 +2893,16 @@ pub const Parser = struct {
837 return node;2893 return node;
838 }2894 }
8392895
2896 fn createUndefined(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeUndefinedLiteral {
2897 const node = try arena.create(ast.NodeUndefinedLiteral);
2898
2899 *node = ast.NodeUndefinedLiteral {
2900 .base = self.initNode(ast.Node.Id.UndefinedLiteral),
2901 .token = *token,
2902 };
2903 return node;
2904 }
2905
840 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {2906 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
841 const node = try self.createIdentifier(arena, name_token);2907 const node = try self.createIdentifier(arena, name_token);
842 try dest_ptr.store(&node.base);2908 try dest_ptr.store(&node.base);
...@@ -850,54 +2916,78 @@ pub const Parser = struct {...@@ -850,54 +2916,78 @@ pub const Parser = struct {
850 }2916 }
8512917
852 fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token,2918 fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token,
853 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,2919 extern_token: &const ?Token, lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token,
854 inline_token: &const ?Token) !&ast.NodeFnProto2920 inline_token: &const ?Token) !&ast.NodeFnProto
855 {2921 {
856 const node = try self.createFnProto(arena, fn_token, extern_token, cc_token, visib_token, inline_token);2922 const node = try self.createFnProto(arena, fn_token, extern_token, lib_name, cc_token, visib_token, inline_token);
857 try list.append(&node.base);2923 try list.append(&node.base);
858 return node;2924 return node;
859 }2925 }
8602926
861 fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),2927 fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),
862 visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,2928 visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
863 extern_token: &const ?Token) !&ast.NodeVarDecl2929 extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl
864 {2930 {
865 const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token);2931 const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token, lib_name);
866 try list.append(&node.base);2932 try list.append(&node.base);
867 return node;2933 return node;
868 }2934 }
8692935
870 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {2936 fn createAttachTestDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),
871 const loc = self.tokenizer.getTokenLocation(token);2937 test_token: &const Token, name: &ast.Node, block: &ast.NodeBlock) !&ast.NodeTestDecl
872 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args);2938 {
873 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);2939 const node = try self.createTestDecl(arena, test_token, name, block);
874 {2940 try list.append(&node.base);
875 var i: usize = 0;2941 return node;
876 while (i < token.column) : (i += 1) {2942 }
877 warn(" ");2943
2944 fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void {
2945 // Before reporting an error. We pop the stack to see if our state was optional
2946 self.revertIfOptional(stack) catch {
2947 const loc = self.tokenizer.getTokenLocation(0, token);
2948 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
2949 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
2950 {
2951 var i: usize = 0;
2952 while (i < loc.column) : (i += 1) {
2953 warn(" ");
2954 }
878 }2955 }
879 }2956 {
880 {2957 const caret_count = token.end - token.start;
881 const caret_count = token.end - token.start;2958 var i: usize = 0;
882 var i: usize = 0;2959 while (i < caret_count) : (i += 1) {
883 while (i < caret_count) : (i += 1) {2960 warn("~");
884 warn("~");2961 }
885 }2962 }
886 }2963 warn("\n");
887 warn("\n");2964 return error.ParseError;
888 return error.ParseError;2965 };
889 }2966 }
8902967
891 fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) !void {2968 fn eatToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token {
2969 const token = self.getNextToken();
892 if (token.id != id) {2970 if (token.id != id) {
893 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));2971 try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
2972 return null;
894 }2973 }
2974 return token;
895 }2975 }
8962976
897 fn eatToken(self: &Parser, id: @TagType(Token.Id)) !Token {2977 fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void {
898 const token = self.getNextToken();2978 while (stack.popOrNull()) |state| {
899 try self.expectToken(token, id);2979 switch (state) {
900 return token;2980 State.Optional => |revert| {
2981 *self = revert.parser;
2982 *self.tokenizer = revert.tokenizer;
2983 *revert.ptr = null;
2984 return;
2985 },
2986 else => { }
2987 }
2988 }
2989
2990 return error.NoOptionalStateFound;
901 }2991 }
9022992
903 fn putBackToken(self: &Parser, token: &const Token) void {2993 fn putBackToken(self: &Parser, token: &const Token) void {
...@@ -956,6 +3046,7 @@ pub const Parser = struct {...@@ -956,6 +3046,7 @@ pub const Parser = struct {
956 Expression: &ast.Node,3046 Expression: &ast.Node,
957 VarDecl: &ast.NodeVarDecl,3047 VarDecl: &ast.NodeVarDecl,
958 Statement: &ast.Node,3048 Statement: &ast.Node,
3049 FieldInitializer: &ast.NodeFieldInitializer,
959 PrintIndent,3050 PrintIndent,
960 Indent: usize,3051 Indent: usize,
961 };3052 };
...@@ -976,9 +3067,8 @@ pub const Parser = struct {...@@ -976,9 +3067,8 @@ pub const Parser = struct {
976 try stack.append(RenderState {3067 try stack.append(RenderState {
977 .Text = blk: {3068 .Text = blk: {
978 const prev_node = root_node.decls.at(i - 1);3069 const prev_node = root_node.decls.at(i - 1);
979 const prev_line_index = prev_node.lastToken().line;3070 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken());
980 const this_line_index = decl.firstToken().line;3071 if (loc.line >= 2) {
981 if (this_line_index - prev_line_index >= 2) {
982 break :blk "\n\n";3072 break :blk "\n\n";
983 }3073 }
984 break :blk "\n";3074 break :blk "\n";
...@@ -996,64 +3086,76 @@ pub const Parser = struct {...@@ -996,64 +3086,76 @@ pub const Parser = struct {
996 switch (decl.id) {3086 switch (decl.id) {
997 ast.Node.Id.FnProto => {3087 ast.Node.Id.FnProto => {
998 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);3088 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);
999 if (fn_proto.visib_token) |visib_token| {
1000 switch (visib_token.id) {
1001 Token.Id.Keyword_pub => try stream.print("pub "),
1002 Token.Id.Keyword_export => try stream.print("export "),
1003 else => unreachable,
1004 }
1005 }
1006 if (fn_proto.extern_token) |extern_token| {
1007 try stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
1008 }
1009 try stream.print("fn");
1010
1011 if (fn_proto.name_token) |name_token| {
1012 try stream.print(" {}", self.tokenizer.getTokenSlice(name_token));
1013 }
10143089
1015 try stream.print("(");3090 if (fn_proto.body_node) |body_node| {
10163091 stack.append(RenderState { .Expression = body_node}) catch unreachable;
1017 if (fn_proto.body_node == null) {3092 try stack.append(RenderState { .Text = " "});
1018 try stack.append(RenderState { .Text = ";" });3093 } else {
3094 stack.append(RenderState { .Text = ";" }) catch unreachable;
1019 }3095 }
10203096
1021 try stack.append(RenderState { .FnProtoRParen = fn_proto});3097 try stack.append(RenderState { .Expression = decl });
1022 var i = fn_proto.params.len;3098 },
1023 while (i != 0) {3099 ast.Node.Id.Use => {
1024 i -= 1;3100 const use_decl = @fieldParentPtr(ast.NodeUse, "base", decl);
1025 const param_decl_node = fn_proto.params.items[i];3101 if (use_decl.visib_token) |visib_token| {
1026 try stack.append(RenderState { .ParamDecl = param_decl_node});3102 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
1027 if (i != 0) {
1028 try stack.append(RenderState { .Text = ", " });
1029 }
1030 }3103 }
3104 try stream.print("use ");
3105 try stack.append(RenderState { .Text = ";" });
3106 try stack.append(RenderState { .Expression = use_decl.expr });
1031 },3107 },
1032 ast.Node.Id.VarDecl => {3108 ast.Node.Id.VarDecl => {
1033 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);3109 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
1034 try stack.append(RenderState { .VarDecl = var_decl});3110 try stack.append(RenderState { .VarDecl = var_decl});
3111 },
3112 ast.Node.Id.TestDecl => {
3113 const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
3114 try stream.print("test ");
3115 try stack.append(RenderState { .Expression = test_decl.body_node });
3116 try stack.append(RenderState { .Text = " " });
3117 try stack.append(RenderState { .Expression = test_decl.name });
3118 },
3119 ast.Node.Id.StructField => {
3120 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
3121 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3122 try stack.append(RenderState { .Expression = field.type_expr});
3123 },
3124 ast.Node.Id.UnionTag => {
3125 const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl);
3126 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3127
3128 if (tag.type_expr) |type_expr| {
3129 try stream.print(": ");
3130 try stack.append(RenderState { .Expression = type_expr});
3131 }
3132 },
3133 ast.Node.Id.EnumTag => {
3134 const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl);
3135 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
10353136
3137 if (tag.value) |value| {
3138 try stream.print(" = ");
3139 try stack.append(RenderState { .Expression = value});
3140 }
3141 },
3142 ast.Node.Id.Comptime => {
3143 if (requireSemiColon(decl)) {
3144 try stack.append(RenderState { .Text = ";" });
3145 }
3146 try stack.append(RenderState { .Expression = decl });
1036 },3147 },
1037 else => unreachable,3148 else => unreachable,
1038 }3149 }
1039 },3150 },
10403151
1041 RenderState.VarDecl => |var_decl| {3152 RenderState.FieldInitializer => |field_init| {
1042 if (var_decl.visib_token) |visib_token| {3153 try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token));
1043 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));3154 try stream.print(" = ");
1044 }3155 try stack.append(RenderState { .Expression = field_init.expr });
1045 if (var_decl.extern_token) |extern_token| {3156 },
1046 try stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
1047 if (var_decl.lib_name != null) {
1048 @panic("TODO");
1049 }
1050 }
1051 if (var_decl.comptime_token) |comptime_token| {
1052 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
1053 }
1054 try stream.print("{} ", self.tokenizer.getTokenSlice(var_decl.mut_token));
1055 try stream.print("{}", self.tokenizer.getTokenSlice(var_decl.name_token));
10563157
3158 RenderState.VarDecl => |var_decl| {
1057 try stack.append(RenderState { .Text = ";" });3159 try stack.append(RenderState { .Text = ";" });
1058 if (var_decl.init_node) |init_node| {3160 if (var_decl.init_node) |init_node| {
1059 try stack.append(RenderState { .Expression = init_node });3161 try stack.append(RenderState { .Expression = init_node });
...@@ -1065,8 +3167,30 @@ pub const Parser = struct {...@@ -1065,8 +3167,30 @@ pub const Parser = struct {
1065 try stack.append(RenderState { .Text = " align(" });3167 try stack.append(RenderState { .Text = " align(" });
1066 }3168 }
1067 if (var_decl.type_node) |type_node| {3169 if (var_decl.type_node) |type_node| {
1068 try stream.print(": ");
1069 try stack.append(RenderState { .Expression = type_node });3170 try stack.append(RenderState { .Expression = type_node });
3171 try stack.append(RenderState { .Text = ": " });
3172 }
3173 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) });
3174 try stack.append(RenderState { .Text = " " });
3175 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) });
3176
3177 if (var_decl.comptime_token) |comptime_token| {
3178 try stack.append(RenderState { .Text = " " });
3179 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3180 }
3181
3182 if (var_decl.extern_token) |extern_token| {
3183 if (var_decl.lib_name != null) {
3184 try stack.append(RenderState { .Text = " " });
3185 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3186 }
3187 try stack.append(RenderState { .Text = " " });
3188 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) });
3189 }
3190
3191 if (var_decl.visib_token) |visib_token| {
3192 try stack.append(RenderState { .Text = " " });
3193 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
1070 }3194 }
1071 },3195 },
10723196
...@@ -1097,6 +3221,10 @@ pub const Parser = struct {...@@ -1097,6 +3221,10 @@ pub const Parser = struct {
1097 },3221 },
1098 ast.Node.Id.Block => {3222 ast.Node.Id.Block => {
1099 const block = @fieldParentPtr(ast.NodeBlock, "base", base);3223 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
3224 if (block.label) |label| {
3225 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3226 }
3227
1100 if (block.statements.len == 0) {3228 if (block.statements.len == 0) {
1101 try stream.write("{}");3229 try stream.write("{}");
1102 } else {3230 } else {
...@@ -1115,10 +3243,9 @@ pub const Parser = struct {...@@ -1115,10 +3243,9 @@ pub const Parser = struct {
1115 try stack.append(RenderState {3243 try stack.append(RenderState {
1116 .Text = blk: {3244 .Text = blk: {
1117 if (i != 0) {3245 if (i != 0) {
1118 const prev_statement_node = block.statements.items[i - 1];3246 const prev_node = block.statements.items[i - 1];
1119 const prev_line_index = prev_statement_node.lastToken().line;3247 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken());
1120 const this_line_index = statement_node.firstToken().line;3248 if (loc.line >= 2) {
1121 if (this_line_index - prev_line_index >= 2) {
1122 break :blk "\n\n";3249 break :blk "\n\n";
1123 }3250 }
1124 }3251 }
...@@ -1128,19 +3255,98 @@ pub const Parser = struct {...@@ -1128,19 +3255,98 @@ pub const Parser = struct {
1128 }3255 }
1129 }3256 }
1130 },3257 },
3258 ast.Node.Id.Defer => {
3259 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", base);
3260 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
3261 try stack.append(RenderState { .Expression = defer_node.expr });
3262 },
3263 ast.Node.Id.Comptime => {
3264 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", base);
3265 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
3266 try stack.append(RenderState { .Expression = comptime_node.expr });
3267 },
3268 ast.Node.Id.AsyncAttribute => {
3269 const async_attr = @fieldParentPtr(ast.NodeAsyncAttribute, "base", base);
3270 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
3271
3272 if (async_attr.allocator_type) |allocator_type| {
3273 try stack.append(RenderState { .Text = ">" });
3274 try stack.append(RenderState { .Expression = allocator_type });
3275 try stack.append(RenderState { .Text = "<" });
3276 }
3277 },
3278 ast.Node.Id.Suspend => {
3279 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", base);
3280 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
3281
3282 if (suspend_node.body) |body| {
3283 try stack.append(RenderState { .Expression = body });
3284 try stack.append(RenderState { .Text = " " });
3285 }
3286
3287 if (suspend_node.payload) |payload| {
3288 try stack.append(RenderState { .Expression = &payload.base });
3289 try stack.append(RenderState { .Text = " " });
3290 }
3291 },
1131 ast.Node.Id.InfixOp => {3292 ast.Node.Id.InfixOp => {
1132 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);3293 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
1133 try stack.append(RenderState { .Expression = prefix_op_node.rhs });3294 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
1134 switch (prefix_op_node.op) {3295
1135 ast.NodeInfixOp.InfixOp.EqualEqual => {3296 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
1136 try stack.append(RenderState { .Text = " == "});3297 if (prefix_op_node.op.Catch) |payload| {
1137 },3298 try stack.append(RenderState { .Text = " " });
1138 ast.NodeInfixOp.InfixOp.BangEqual => {3299 try stack.append(RenderState { .Expression = &payload.base });
1139 try stack.append(RenderState { .Text = " != "});3300 }
1140 },3301 try stack.append(RenderState { .Text = " catch " });
1141 ast.NodeInfixOp.InfixOp.Period => {3302 } else {
1142 try stack.append(RenderState { .Text = "."});3303 const text = switch (prefix_op_node.op) {
1143 },3304 ast.NodeInfixOp.InfixOp.Add => " + ",
3305 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
3306 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
3307 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
3308 ast.NodeInfixOp.InfixOp.Assign => " = ",
3309 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
3310 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
3311 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
3312 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
3313 ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
3314 ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
3315 ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
3316 ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
3317 ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
3318 ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
3319 ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
3320 ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
3321 ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
3322 ast.NodeInfixOp.InfixOp.BangEqual => " != ",
3323 ast.NodeInfixOp.InfixOp.BitAnd => " & ",
3324 ast.NodeInfixOp.InfixOp.BitOr => " | ",
3325 ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
3326 ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
3327 ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
3328 ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
3329 ast.NodeInfixOp.InfixOp.BoolOr => " or ",
3330 ast.NodeInfixOp.InfixOp.Div => " / ",
3331 ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
3332 ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
3333 ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
3334 ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
3335 ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
3336 ast.NodeInfixOp.InfixOp.LessThan => " < ",
3337 ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
3338 ast.NodeInfixOp.InfixOp.Mod => " % ",
3339 ast.NodeInfixOp.InfixOp.Mult => " * ",
3340 ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
3341 ast.NodeInfixOp.InfixOp.Period => ".",
3342 ast.NodeInfixOp.InfixOp.Sub => " - ",
3343 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
3344 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
3345 ast.NodeInfixOp.InfixOp.Range => " ... ",
3346 ast.NodeInfixOp.InfixOp.Catch => unreachable,
3347 };
3348
3349 try stack.append(RenderState { .Text = text });
1144 }3350 }
1145 try stack.append(RenderState { .Expression = prefix_op_node.lhs });3351 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
1146 },3352 },
...@@ -1148,12 +3354,6 @@ pub const Parser = struct {...@@ -1148,12 +3354,6 @@ pub const Parser = struct {
1148 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);3354 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
1149 try stack.append(RenderState { .Expression = prefix_op_node.rhs });3355 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
1150 switch (prefix_op_node.op) {3356 switch (prefix_op_node.op) {
1151 ast.NodePrefixOp.PrefixOp.Return => {
1152 try stream.write("return ");
1153 },
1154 ast.NodePrefixOp.PrefixOp.Try => {
1155 try stream.write("try ");
1156 },
1157 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {3357 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
1158 try stream.write("&");3358 try stream.write("&");
1159 if (addr_of_info.volatile_token != null) {3359 if (addr_of_info.volatile_token != null) {
...@@ -1168,7 +3368,179 @@ pub const Parser = struct {...@@ -1168,7 +3368,179 @@ pub const Parser = struct {
1168 try stack.append(RenderState { .Expression = align_expr});3368 try stack.append(RenderState { .Expression = align_expr});
1169 }3369 }
1170 },3370 },
3371 ast.NodePrefixOp.PrefixOp.SliceType => |addr_of_info| {
3372 try stream.write("[]");
3373 if (addr_of_info.volatile_token != null) {
3374 try stack.append(RenderState { .Text = "volatile "});
3375 }
3376 if (addr_of_info.const_token != null) {
3377 try stack.append(RenderState { .Text = "const "});
3378 }
3379 if (addr_of_info.align_expr) |align_expr| {
3380 try stream.print("align(");
3381 try stack.append(RenderState { .Text = ") "});
3382 try stack.append(RenderState { .Expression = align_expr});
3383 }
3384 },
3385 ast.NodePrefixOp.PrefixOp.ArrayType => |array_index| {
3386 try stack.append(RenderState { .Text = "]"});
3387 try stack.append(RenderState { .Expression = array_index});
3388 try stack.append(RenderState { .Text = "["});
3389 },
3390 ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"),
3391 ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"),
3392 ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"),
3393 ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"),
3394 ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"),
3395 ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "),
3396 ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"),
3397 ast.NodePrefixOp.PrefixOp.MaybeType => try stream.write("?"),
3398 ast.NodePrefixOp.PrefixOp.Await => try stream.write("await "),
3399 ast.NodePrefixOp.PrefixOp.Cancel => try stream.write("cancel "),
3400 ast.NodePrefixOp.PrefixOp.Resume => try stream.write("resume "),
3401 }
3402 },
3403 ast.Node.Id.SuffixOp => {
3404 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", base);
3405
3406 switch (suffix_op.op) {
3407 ast.NodeSuffixOp.SuffixOp.Call => |call_info| {
3408 try stack.append(RenderState { .Text = ")"});
3409 var i = call_info.params.len;
3410 while (i != 0) {
3411 i -= 1;
3412 const param_node = call_info.params.at(i);
3413 try stack.append(RenderState { .Expression = param_node});
3414 if (i != 0) {
3415 try stack.append(RenderState { .Text = ", " });
3416 }
3417 }
3418 try stack.append(RenderState { .Text = "("});
3419 try stack.append(RenderState { .Expression = suffix_op.lhs });
3420
3421 if (call_info.async_attr) |async_attr| {
3422 try stack.append(RenderState { .Text = " "});
3423 try stack.append(RenderState { .Expression = &async_attr.base });
3424 }
3425 },
3426 ast.NodeSuffixOp.SuffixOp.ArrayAccess => |index_expr| {
3427 try stack.append(RenderState { .Text = "]"});
3428 try stack.append(RenderState { .Expression = index_expr});
3429 try stack.append(RenderState { .Text = "["});
3430 try stack.append(RenderState { .Expression = suffix_op.lhs });
3431 },
3432 ast.NodeSuffixOp.SuffixOp.Slice => |range| {
3433 try stack.append(RenderState { .Text = "]"});
3434 if (range.end) |end| {
3435 try stack.append(RenderState { .Expression = end});
3436 }
3437 try stack.append(RenderState { .Text = ".."});
3438 try stack.append(RenderState { .Expression = range.start});
3439 try stack.append(RenderState { .Text = "["});
3440 try stack.append(RenderState { .Expression = suffix_op.lhs });
3441 },
3442 ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {
3443 try stack.append(RenderState { .Text = " }"});
3444 var i = field_inits.len;
3445 while (i != 0) {
3446 i -= 1;
3447 const field_init = field_inits.at(i);
3448 try stack.append(RenderState { .FieldInitializer = field_init });
3449 try stack.append(RenderState { .Text = " " });
3450 if (i != 0) {
3451 try stack.append(RenderState { .Text = "," });
3452 }
3453 }
3454 try stack.append(RenderState { .Text = "{"});
3455 try stack.append(RenderState { .Expression = suffix_op.lhs });
3456 },
3457 ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {
3458 try stack.append(RenderState { .Text = " }"});
3459 var i = exprs.len;
3460 while (i != 0) {
3461 i -= 1;
3462 const expr = exprs.at(i);
3463 try stack.append(RenderState { .Expression = expr });
3464 try stack.append(RenderState { .Text = " " });
3465 if (i != 0) {
3466 try stack.append(RenderState { .Text = "," });
3467 }
3468 }
3469 try stack.append(RenderState { .Text = "{"});
3470 try stack.append(RenderState { .Expression = suffix_op.lhs });
3471 },
3472 }
3473 },
3474 ast.Node.Id.ControlFlowExpression => {
3475 const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
3476 switch (flow_expr.kind) {
3477 ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| {
3478 try stream.print("break");
3479 if (maybe_blk_token) |blk_token| {
3480 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3481 }
3482 },
3483 ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| {
3484 try stream.print("continue");
3485 if (maybe_blk_token) |blk_token| {
3486 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3487 }
3488 },
3489 ast.NodeControlFlowExpression.Kind.Return => {
3490 try stream.print("return");
3491 },
3492
1171 }3493 }
3494
3495 if (flow_expr.rhs) |rhs| {
3496 try stream.print(" ");
3497 try stack.append(RenderState { .Expression = rhs });
3498 }
3499 },
3500 ast.Node.Id.Payload => {
3501 const payload = @fieldParentPtr(ast.NodePayload, "base", base);
3502 try stack.append(RenderState { .Text = "|"});
3503 try stack.append(RenderState { .Expression = &payload.error_symbol.base });
3504 try stack.append(RenderState { .Text = "|"});
3505 },
3506 ast.Node.Id.PointerPayload => {
3507 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
3508 try stack.append(RenderState { .Text = "|"});
3509 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3510
3511 if (payload.is_ptr) {
3512 try stack.append(RenderState { .Text = "*"});
3513 }
3514
3515 try stack.append(RenderState { .Text = "|"});
3516 },
3517 ast.Node.Id.PointerIndexPayload => {
3518 const payload = @fieldParentPtr(ast.NodePointerIndexPayload, "base", base);
3519 try stack.append(RenderState { .Text = "|"});
3520
3521 if (payload.index_symbol) |index_symbol| {
3522 try stack.append(RenderState { .Expression = &index_symbol.base });
3523 try stack.append(RenderState { .Text = ", "});
3524 }
3525
3526 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3527
3528 if (payload.is_ptr) {
3529 try stack.append(RenderState { .Text = "*"});
3530 }
3531
3532 try stack.append(RenderState { .Text = "|"});
3533 },
3534 ast.Node.Id.GroupedExpression => {
3535 const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base);
3536 try stack.append(RenderState { .Text = ")"});
3537 try stack.append(RenderState { .Expression = grouped_expr.expr });
3538 try stack.append(RenderState { .Text = "("});
3539 },
3540 ast.Node.Id.FieldInitializer => {
3541 const field_init = @fieldParentPtr(ast.NodeFieldInitializer, "base", base);
3542 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
3543 try stack.append(RenderState { .Expression = field_init.expr });
1172 },3544 },
1173 ast.Node.Id.IntegerLiteral => {3545 ast.Node.Id.IntegerLiteral => {
1174 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);3546 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);
...@@ -1182,6 +3554,151 @@ pub const Parser = struct {...@@ -1182,6 +3554,151 @@ pub const Parser = struct {
1182 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);3554 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
1183 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));3555 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
1184 },3556 },
3557 ast.Node.Id.CharLiteral => {
3558 const char_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3559 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
3560 },
3561 ast.Node.Id.BoolLiteral => {
3562 const bool_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3563 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
3564 },
3565 ast.Node.Id.NullLiteral => {
3566 const null_literal = @fieldParentPtr(ast.NodeNullLiteral, "base", base);
3567 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
3568 },
3569 ast.Node.Id.ThisLiteral => {
3570 const this_literal = @fieldParentPtr(ast.NodeThisLiteral, "base", base);
3571 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
3572 },
3573 ast.Node.Id.Unreachable => {
3574 const unreachable_node = @fieldParentPtr(ast.NodeUnreachable, "base", base);
3575 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
3576 },
3577 ast.Node.Id.ErrorType => {
3578 const error_type = @fieldParentPtr(ast.NodeErrorType, "base", base);
3579 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
3580 },
3581 ast.Node.Id.VarType => {
3582 const var_type = @fieldParentPtr(ast.NodeVarType, "base", base);
3583 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
3584 },
3585 ast.Node.Id.ContainerDecl => {
3586 const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base);
3587
3588 switch (container_decl.layout) {
3589 ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "),
3590 ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "),
3591 ast.NodeContainerDecl.Layout.Auto => { },
3592 }
3593
3594 switch (container_decl.kind) {
3595 ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"),
3596 ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"),
3597 ast.NodeContainerDecl.Kind.Union => try stream.print("union"),
3598 }
3599
3600 try stack.append(RenderState { .Text = "}"});
3601 try stack.append(RenderState.PrintIndent);
3602 try stack.append(RenderState { .Indent = indent });
3603 try stack.append(RenderState { .Text = "\n"});
3604
3605 const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
3606 var i = fields_and_decls.len;
3607 while (i != 0) {
3608 i -= 1;
3609 const node = fields_and_decls[i];
3610 try stack.append(RenderState { .TopLevelDecl = node});
3611 try stack.append(RenderState.PrintIndent);
3612 try stack.append(RenderState {
3613 .Text = blk: {
3614 if (i != 0) {
3615 const prev_node = fields_and_decls[i - 1];
3616 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3617 if (loc.line >= 2) {
3618 break :blk "\n\n";
3619 }
3620 }
3621 break :blk "\n";
3622 },
3623 });
3624
3625 if (i != 0) {
3626 const prev_node = fields_and_decls[i - 1];
3627 switch (prev_node.id) {
3628 ast.Node.Id.StructField,
3629 ast.Node.Id.UnionTag,
3630 ast.Node.Id.EnumTag => {
3631 try stack.append(RenderState { .Text = "," });
3632 },
3633 else => { }
3634 }
3635 }
3636 }
3637 try stack.append(RenderState { .Indent = indent + indent_delta});
3638 try stack.append(RenderState { .Text = "{"});
3639
3640 switch (container_decl.init_arg_expr) {
3641 ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
3642 ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
3643 ast.NodeContainerDecl.InitArg.Type => |type_expr| {
3644 try stack.append(RenderState { .Text = ") "});
3645 try stack.append(RenderState { .Expression = type_expr});
3646 try stack.append(RenderState { .Text = "("});
3647 },
3648 }
3649 },
3650 ast.Node.Id.ErrorSetDecl => {
3651 const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base);
3652 try stream.print("error ");
3653
3654 try stack.append(RenderState { .Text = "}"});
3655 try stack.append(RenderState.PrintIndent);
3656 try stack.append(RenderState { .Indent = indent });
3657 try stack.append(RenderState { .Text = "\n"});
3658
3659 const decls = err_set_decl.decls.toSliceConst();
3660 var i = decls.len;
3661 while (i != 0) {
3662 i -= 1;
3663 const node = decls[i];
3664 try stack.append(RenderState { .Expression = &node.base});
3665 try stack.append(RenderState.PrintIndent);
3666 try stack.append(RenderState {
3667 .Text = blk: {
3668 if (i != 0) {
3669 const prev_node = decls[i - 1];
3670 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3671 if (loc.line >= 2) {
3672 break :blk "\n\n";
3673 }
3674 }
3675 break :blk "\n";
3676 },
3677 });
3678
3679 if (i != 0) {
3680 try stack.append(RenderState { .Text = "," });
3681 }
3682 }
3683 try stack.append(RenderState { .Indent = indent + indent_delta});
3684 try stack.append(RenderState { .Text = "{"});
3685 },
3686 ast.Node.Id.MultilineStringLiteral => {
3687 const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
3688 try stream.print("\n");
3689
3690 var i : usize = 0;
3691 while (i < multiline_str_literal.tokens.len) : (i += 1) {
3692 const t = multiline_str_literal.tokens.at(i);
3693 try stream.writeByteNTimes(' ', indent + indent_delta);
3694 try stream.print("{}", self.tokenizer.getTokenSlice(t));
3695 }
3696 try stream.writeByteNTimes(' ', indent + indent_delta);
3697 },
3698 ast.Node.Id.UndefinedLiteral => {
3699 const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);
3700 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
3701 },
1185 ast.Node.Id.BuiltinCall => {3702 ast.Node.Id.BuiltinCall => {
1186 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);3703 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);
1187 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));3704 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
...@@ -1196,11 +3713,420 @@ pub const Parser = struct {...@@ -1196,11 +3713,420 @@ pub const Parser = struct {
1196 }3713 }
1197 }3714 }
1198 },3715 },
1199 ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),3716 ast.Node.Id.FnProto => {
1200 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),3717 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", base);
3718
3719 switch (fn_proto.return_type) {
3720 ast.NodeFnProto.ReturnType.Explicit => |node| {
3721 try stack.append(RenderState { .Expression = node});
3722 },
3723 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
3724 try stack.append(RenderState { .Expression = node});
3725 try stack.append(RenderState { .Text = "!"});
3726 },
3727 }
3728
3729 if (fn_proto.align_expr != null) {
3730 @panic("TODO");
3731 }
3732
3733 try stack.append(RenderState { .Text = ") " });
3734 var i = fn_proto.params.len;
3735 while (i != 0) {
3736 i -= 1;
3737 const param_decl_node = fn_proto.params.items[i];
3738 try stack.append(RenderState { .ParamDecl = param_decl_node});
3739 if (i != 0) {
3740 try stack.append(RenderState { .Text = ", " });
3741 }
3742 }
3743
3744 try stack.append(RenderState { .Text = "(" });
3745 if (fn_proto.name_token) |name_token| {
3746 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) });
3747 try stack.append(RenderState { .Text = " " });
3748 }
3749
3750 try stack.append(RenderState { .Text = "fn" });
3751
3752 if (fn_proto.async_attr) |async_attr| {
3753 try stack.append(RenderState { .Text = " " });
3754 try stack.append(RenderState { .Expression = &async_attr.base });
3755 }
3756
3757 if (fn_proto.cc_token) |cc_token| {
3758 try stack.append(RenderState { .Text = " " });
3759 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) });
3760 }
3761
3762 if (fn_proto.lib_name) |lib_name| {
3763 try stack.append(RenderState { .Text = " " });
3764 try stack.append(RenderState { .Expression = lib_name });
3765 }
3766 if (fn_proto.extern_token) |extern_token| {
3767 try stack.append(RenderState { .Text = " " });
3768 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) });
3769 }
3770
3771 if (fn_proto.visib_token) |visib_token| {
3772 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
3773 try stack.append(RenderState { .Text = " " });
3774 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3775 }
3776 },
3777 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
3778 ast.Node.Id.Switch => {
3779 const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base);
3780 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
3781
3782 try stack.append(RenderState { .Text = "}"});
3783 try stack.append(RenderState.PrintIndent);
3784 try stack.append(RenderState { .Indent = indent });
3785 try stack.append(RenderState { .Text = "\n"});
3786
3787 const cases = switch_node.cases.toSliceConst();
3788 var i = cases.len;
3789 while (i != 0) {
3790 i -= 1;
3791 const node = cases[i];
3792 try stack.append(RenderState { .Expression = &node.base});
3793 try stack.append(RenderState.PrintIndent);
3794 try stack.append(RenderState {
3795 .Text = blk: {
3796 if (i != 0) {
3797 const prev_node = cases[i - 1];
3798 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3799 if (loc.line >= 2) {
3800 break :blk "\n\n";
3801 }
3802 }
3803 break :blk "\n";
3804 },
3805 });
3806
3807 if (i != 0) {
3808 try stack.append(RenderState { .Text = "," });
3809 }
3810 }
3811 try stack.append(RenderState { .Indent = indent + indent_delta});
3812 try stack.append(RenderState { .Text = ") {"});
3813 try stack.append(RenderState { .Expression = switch_node.expr });
3814 },
3815 ast.Node.Id.SwitchCase => {
3816 const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
3817
3818 try stack.append(RenderState { .Expression = switch_case.expr });
3819 if (switch_case.payload) |payload| {
3820 try stack.append(RenderState { .Text = " " });
3821 try stack.append(RenderState { .Expression = &payload.base });
3822 }
3823 try stack.append(RenderState { .Text = " => "});
3824
3825 const items = switch_case.items.toSliceConst();
3826 var i = items.len;
3827 while (i != 0) {
3828 i -= 1;
3829 try stack.append(RenderState { .Expression = items[i] });
3830
3831 if (i != 0) {
3832 try stack.append(RenderState { .Text = ", " });
3833 }
3834 }
3835 },
3836 ast.Node.Id.SwitchElse => {
3837 const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
3838 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
3839 },
3840 ast.Node.Id.Else => {
3841 const else_node = @fieldParentPtr(ast.NodeElse, "base", base);
3842 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
3843
3844 switch (else_node.body.id) {
3845 ast.Node.Id.Block, ast.Node.Id.If,
3846 ast.Node.Id.For, ast.Node.Id.While,
3847 ast.Node.Id.Switch => {
3848 try stream.print(" ");
3849 try stack.append(RenderState { .Expression = else_node.body });
3850 },
3851 else => {
3852 try stack.append(RenderState { .Indent = indent });
3853 try stack.append(RenderState { .Expression = else_node.body });
3854 try stack.append(RenderState.PrintIndent);
3855 try stack.append(RenderState { .Indent = indent + indent_delta });
3856 try stack.append(RenderState { .Text = "\n" });
3857 }
3858 }
3859
3860 if (else_node.payload) |payload| {
3861 try stack.append(RenderState { .Text = " " });
3862 try stack.append(RenderState { .Expression = &payload.base });
3863 }
3864 },
3865 ast.Node.Id.While => {
3866 const while_node = @fieldParentPtr(ast.NodeWhile, "base", base);
3867 if (while_node.label) |label| {
3868 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3869 }
3870
3871 if (while_node.inline_token) |inline_token| {
3872 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
3873 }
3874
3875 try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token));
3876
3877 if (while_node.@"else") |@"else"| {
3878 try stack.append(RenderState { .Expression = &@"else".base });
3879
3880 if (while_node.body.id == ast.Node.Id.Block) {
3881 try stack.append(RenderState { .Text = " " });
3882 } else {
3883 try stack.append(RenderState.PrintIndent);
3884 try stack.append(RenderState { .Text = "\n" });
3885 }
3886 }
3887
3888 if (while_node.body.id == ast.Node.Id.Block) {
3889 try stack.append(RenderState { .Expression = while_node.body });
3890 try stack.append(RenderState { .Text = " " });
3891 } else {
3892 try stack.append(RenderState { .Indent = indent });
3893 try stack.append(RenderState { .Expression = while_node.body });
3894 try stack.append(RenderState.PrintIndent);
3895 try stack.append(RenderState { .Indent = indent + indent_delta });
3896 try stack.append(RenderState { .Text = "\n" });
3897 }
3898
3899 if (while_node.continue_expr) |continue_expr| {
3900 try stack.append(RenderState { .Text = ")" });
3901 try stack.append(RenderState { .Expression = continue_expr });
3902 try stack.append(RenderState { .Text = ": (" });
3903 try stack.append(RenderState { .Text = " " });
3904 }
3905
3906 if (while_node.payload) |payload| {
3907 try stack.append(RenderState { .Expression = &payload.base });
3908 try stack.append(RenderState { .Text = " " });
3909 }
3910
3911 try stack.append(RenderState { .Text = ")" });
3912 try stack.append(RenderState { .Expression = while_node.condition });
3913 try stack.append(RenderState { .Text = "(" });
3914 },
3915 ast.Node.Id.For => {
3916 const for_node = @fieldParentPtr(ast.NodeFor, "base", base);
3917 if (for_node.label) |label| {
3918 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3919 }
3920
3921 if (for_node.inline_token) |inline_token| {
3922 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
3923 }
3924
3925 try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
3926
3927 if (for_node.@"else") |@"else"| {
3928 try stack.append(RenderState { .Expression = &@"else".base });
3929
3930 if (for_node.body.id == ast.Node.Id.Block) {
3931 try stack.append(RenderState { .Text = " " });
3932 } else {
3933 try stack.append(RenderState.PrintIndent);
3934 try stack.append(RenderState { .Text = "\n" });
3935 }
3936 }
3937
3938 if (for_node.body.id == ast.Node.Id.Block) {
3939 try stack.append(RenderState { .Expression = for_node.body });
3940 try stack.append(RenderState { .Text = " " });
3941 } else {
3942 try stack.append(RenderState { .Indent = indent });
3943 try stack.append(RenderState { .Expression = for_node.body });
3944 try stack.append(RenderState.PrintIndent);
3945 try stack.append(RenderState { .Indent = indent + indent_delta });
3946 try stack.append(RenderState { .Text = "\n" });
3947 }
3948
3949 if (for_node.payload) |payload| {
3950 try stack.append(RenderState { .Expression = &payload.base });
3951 try stack.append(RenderState { .Text = " " });
3952 }
3953
3954 try stack.append(RenderState { .Text = ")" });
3955 try stack.append(RenderState { .Expression = for_node.array_expr });
3956 try stack.append(RenderState { .Text = "(" });
3957 },
3958 ast.Node.Id.If => {
3959 const if_node = @fieldParentPtr(ast.NodeIf, "base", base);
3960 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
3961
3962 switch (if_node.body.id) {
3963 ast.Node.Id.Block, ast.Node.Id.If,
3964 ast.Node.Id.For, ast.Node.Id.While,
3965 ast.Node.Id.Switch => {
3966 if (if_node.@"else") |@"else"| {
3967 try stack.append(RenderState { .Expression = &@"else".base });
3968
3969 if (if_node.body.id == ast.Node.Id.Block) {
3970 try stack.append(RenderState { .Text = " " });
3971 } else {
3972 try stack.append(RenderState.PrintIndent);
3973 try stack.append(RenderState { .Text = "\n" });
3974 }
3975 }
3976 },
3977 else => {
3978 if (if_node.@"else") |@"else"| {
3979 try stack.append(RenderState { .Expression = @"else".body });
3980
3981 if (@"else".payload) |payload| {
3982 try stack.append(RenderState { .Text = " " });
3983 try stack.append(RenderState { .Expression = &payload.base });
3984 }
3985
3986 try stack.append(RenderState { .Text = " " });
3987 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) });
3988 try stack.append(RenderState { .Text = " " });
3989 }
3990 }
3991 }
3992
3993 try stack.append(RenderState { .Expression = if_node.body });
3994 try stack.append(RenderState { .Text = " " });
3995
3996 if (if_node.payload) |payload| {
3997 try stack.append(RenderState { .Expression = &payload.base });
3998 try stack.append(RenderState { .Text = " " });
3999 }
4000
4001 try stack.append(RenderState { .Text = ")" });
4002 try stack.append(RenderState { .Expression = if_node.condition });
4003 try stack.append(RenderState { .Text = "(" });
4004 },
4005 ast.Node.Id.Asm => {
4006 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
4007 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
4008
4009 if (asm_node.is_volatile) {
4010 try stream.write("volatile ");
4011 }
4012
4013 try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template));
4014
4015 try stack.append(RenderState { .Indent = indent });
4016 try stack.append(RenderState { .Text = ")" });
4017 {
4018 const cloppers = asm_node.cloppers.toSliceConst();
4019 var i = cloppers.len;
4020 while (i != 0) {
4021 i -= 1;
4022 try stack.append(RenderState { .Expression = &cloppers[i].base });
4023
4024 if (i != 0) {
4025 try stack.append(RenderState { .Text = ", " });
4026 }
4027 }
4028 }
4029 try stack.append(RenderState { .Text = ": " });
4030 try stack.append(RenderState.PrintIndent);
4031 try stack.append(RenderState { .Indent = indent + indent_delta });
4032 try stack.append(RenderState { .Text = "\n" });
4033 {
4034 const inputs = asm_node.inputs.toSliceConst();
4035 var i = inputs.len;
4036 while (i != 0) {
4037 i -= 1;
4038 const node = inputs[i];
4039 try stack.append(RenderState { .Expression = &node.base});
4040
4041 if (i != 0) {
4042 try stack.append(RenderState.PrintIndent);
4043 try stack.append(RenderState {
4044 .Text = blk: {
4045 const prev_node = inputs[i - 1];
4046 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4047 if (loc.line >= 2) {
4048 break :blk "\n\n";
4049 }
4050 break :blk "\n";
4051 },
4052 });
4053 try stack.append(RenderState { .Text = "," });
4054 }
4055 }
4056 }
4057 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4058 try stack.append(RenderState { .Text = ": "});
4059 try stack.append(RenderState.PrintIndent);
4060 try stack.append(RenderState { .Indent = indent + indent_delta});
4061 try stack.append(RenderState { .Text = "\n" });
4062 {
4063 const outputs = asm_node.outputs.toSliceConst();
4064 var i = outputs.len;
4065 while (i != 0) {
4066 i -= 1;
4067 const node = outputs[i];
4068 try stack.append(RenderState { .Expression = &node.base});
4069
4070 if (i != 0) {
4071 try stack.append(RenderState.PrintIndent);
4072 try stack.append(RenderState {
4073 .Text = blk: {
4074 const prev_node = outputs[i - 1];
4075 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4076 if (loc.line >= 2) {
4077 break :blk "\n\n";
4078 }
4079 break :blk "\n";
4080 },
4081 });
4082 try stack.append(RenderState { .Text = "," });
4083 }
4084 }
4085 }
4086 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4087 try stack.append(RenderState { .Text = ": "});
4088 try stack.append(RenderState.PrintIndent);
4089 try stack.append(RenderState { .Indent = indent + indent_delta});
4090 try stack.append(RenderState { .Text = "\n" });
4091 },
4092 ast.Node.Id.AsmInput => {
4093 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
4094
4095 try stack.append(RenderState { .Text = ")"});
4096 try stack.append(RenderState { .Expression = asm_input.expr});
4097 try stack.append(RenderState { .Text = " ("});
4098 try stack.append(RenderState { .Expression = &asm_input.constraint.base});
4099 try stack.append(RenderState { .Text = "] "});
4100 try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base});
4101 try stack.append(RenderState { .Text = "["});
4102 },
4103 ast.Node.Id.AsmOutput => {
4104 const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base);
4105
4106 try stack.append(RenderState { .Text = ")"});
4107 switch (asm_output.kind) {
4108 ast.NodeAsmOutput.Kind.Variable => |variable_name| {
4109 try stack.append(RenderState { .Expression = &variable_name.base});
4110 },
4111 ast.NodeAsmOutput.Kind.Return => |return_type| {
4112 try stack.append(RenderState { .Expression = return_type});
4113 try stack.append(RenderState { .Text = "-> "});
4114 },
4115 }
4116 try stack.append(RenderState { .Text = " ("});
4117 try stack.append(RenderState { .Expression = &asm_output.constraint.base});
4118 try stack.append(RenderState { .Text = "] "});
4119 try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base});
4120 try stack.append(RenderState { .Text = "["});
4121 },
12014122
4123 ast.Node.Id.StructField,
4124 ast.Node.Id.UnionTag,
4125 ast.Node.Id.EnumTag,
1202 ast.Node.Id.Root,4126 ast.Node.Id.Root,
1203 ast.Node.Id.VarDecl,4127 ast.Node.Id.VarDecl,
4128 ast.Node.Id.Use,
4129 ast.Node.Id.TestDecl,
1204 ast.Node.Id.ParamDecl => unreachable,4130 ast.Node.Id.ParamDecl => unreachable,
1205 },4131 },
1206 RenderState.FnProtoRParen => |fn_proto| {4132 RenderState.FnProtoRParen => |fn_proto| {
...@@ -1217,9 +4143,6 @@ pub const Parser = struct {...@@ -1217,9 +4143,6 @@ pub const Parser = struct {
1217 ast.NodeFnProto.ReturnType.Explicit => |node| {4143 ast.NodeFnProto.ReturnType.Explicit => |node| {
1218 try stack.append(RenderState { .Expression = node});4144 try stack.append(RenderState { .Expression = node});
1219 },4145 },
1220 ast.NodeFnProto.ReturnType.Infer => {
1221 try stream.print("var");
1222 },
1223 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {4146 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
1224 try stream.print("!");4147 try stream.print("!");
1225 try stack.append(RenderState { .Expression = node});4148 try stack.append(RenderState { .Expression = node});
...@@ -1239,8 +4162,10 @@ pub const Parser = struct {...@@ -1239,8 +4162,10 @@ pub const Parser = struct {
1239 try stack.append(RenderState { .VarDecl = var_decl});4162 try stack.append(RenderState { .VarDecl = var_decl});
1240 },4163 },
1241 else => {4164 else => {
1242 try stack.append(RenderState { .Text = ";"});4165 if (requireSemiColon(base)) {
1243 try stack.append(RenderState { .Expression = base});4166 try stack.append(RenderState { .Text = ";" });
4167 }
4168 try stack.append(RenderState { .Expression = base });
1244 },4169 },
1245 }4170 }
1246 },4171 },
...@@ -1324,7 +4249,7 @@ fn testCanonical(source: []const u8) !void {...@@ -1324,7 +4249,7 @@ fn testCanonical(source: []const u8) !void {
1324 }4249 }
1325}4250}
13264251
1327test "zig fmt" {4252test "zig fmt: get stdout or fail" {
1328 try testCanonical(4253 try testCanonical(
1329 \\const std = @import("std");4254 \\const std = @import("std");
1330 \\4255 \\
...@@ -1335,7 +4260,9 @@ test "zig fmt" {...@@ -1335,7 +4260,9 @@ test "zig fmt" {
1335 \\}4260 \\}
1336 \\4261 \\
1337 );4262 );
4263}
13384264
4265test "zig fmt: preserve spacing" {
1339 try testCanonical(4266 try testCanonical(
1340 \\const std = @import("std");4267 \\const std = @import("std");
1341 \\4268 \\
...@@ -1348,25 +4275,26 @@ test "zig fmt" {...@@ -1348,25 +4275,26 @@ test "zig fmt" {
1348 \\}4275 \\}
1349 \\4276 \\
1350 );4277 );
4278}
13514279
4280test "zig fmt: return types" {
1352 try testCanonical(4281 try testCanonical(
1353 \\pub fn main() !void {}4282 \\pub fn main() !void {}
1354 \\pub fn main() var {}4283 \\pub fn main() var {}
1355 \\pub fn main() i32 {}4284 \\pub fn main() i32 {}
1356 \\4285 \\
1357 );4286 );
4287}
13584288
4289test "zig fmt: imports" {
1359 try testCanonical(4290 try testCanonical(
1360 \\const std = @import("std");4291 \\const std = @import("std");
1361 \\const std = @import();4292 \\const std = @import();
1362 \\4293 \\
1363 );4294 );
4295}
13644296
1365 try testCanonical(4297test "zig fmt: global declarations" {
1366 \\extern fn puts(s: &const u8) c_int;
1367 \\
1368 );
1369
1370 try testCanonical(4298 try testCanonical(
1371 \\const a = b;4299 \\const a = b;
1372 \\pub const a = b;4300 \\pub const a = b;
...@@ -1376,50 +4304,746 @@ test "zig fmt" {...@@ -1376,50 +4304,746 @@ test "zig fmt" {
1376 \\pub const a: i32 = b;4304 \\pub const a: i32 = b;
1377 \\var a: i32 = b;4305 \\var a: i32 = b;
1378 \\pub var a: i32 = b;4306 \\pub var a: i32 = b;
4307 \\extern const a: i32 = b;
4308 \\pub extern const a: i32 = b;
4309 \\extern var a: i32 = b;
4310 \\pub extern var a: i32 = b;
4311 \\extern "a" const a: i32 = b;
4312 \\pub extern "a" const a: i32 = b;
4313 \\extern "a" var a: i32 = b;
4314 \\pub extern "a" var a: i32 = b;
1379 \\4315 \\
1380 );4316 );
4317}
13814318
4319test "zig fmt: extern declaration" {
1382 try testCanonical(4320 try testCanonical(
1383 \\extern var foo: c_int;4321 \\extern var foo: c_int;
1384 \\4322 \\
1385 );4323 );
4324}
13864325
1387 try testCanonical(4326test "zig fmt: alignment" {
4327 try testCanonical(
1388 \\var foo: c_int align(1);4328 \\var foo: c_int align(1);
1389 \\4329 \\
1390 );4330 );
4331}
13914332
4333test "zig fmt: C main" {
1392 try testCanonical(4334 try testCanonical(
1393 \\fn main(argc: c_int, argv: &&u8) c_int {4335 \\fn main(argc: c_int, argv: &&u8) c_int {
1394 \\ const a = b;4336 \\ const a = b;
1395 \\}4337 \\}
1396 \\4338 \\
1397 );4339 );
4340}
13984341
4342test "zig fmt: return" {
1399 try testCanonical(4343 try testCanonical(
1400 \\fn foo(argc: c_int, argv: &&u8) c_int {4344 \\fn foo(argc: c_int, argv: &&u8) c_int {
1401 \\ return 0;4345 \\ return 0;
1402 \\}4346 \\}
1403 \\4347 \\
4348 \\fn bar() void {
4349 \\ return;
4350 \\}
4351 \\
4352 );
4353}
4354
4355test "zig fmt: pointer attributes" {
4356 try testCanonical(
4357 \\extern fn f1(s: &align(&u8) u8) c_int;
4358 \\extern fn f2(s: &&align(1) &const &volatile u8) c_int;
4359 \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int;
4360 \\extern fn f4(s: &align(1) const volatile u8) c_int;
4361 \\
1404 );4362 );
4363}
14054364
4365test "zig fmt: slice attributes" {
1406 try testCanonical(4366 try testCanonical(
1407 \\extern fn f1(s: &align(&u8) u8) c_int;4367 \\extern fn f1(s: &align(&u8) u8) c_int;
4368 \\extern fn f2(s: &&align(1) &const &volatile u8) c_int;
4369 \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int;
4370 \\extern fn f4(s: &align(1) const volatile u8) c_int;
4371 \\
4372 );
4373}
4374
4375test "zig fmt: test declaration" {
4376 try testCanonical(
4377 \\test "test name" {
4378 \\ const a = 1;
4379 \\ var b = 1;
4380 \\}
4381 \\
4382 );
4383}
4384
4385test "zig fmt: infix operators" {
4386 try testCanonical(
4387 \\test "infix operators" {
4388 \\ var i = undefined;
4389 \\ i = 2;
4390 \\ i *= 2;
4391 \\ i |= 2;
4392 \\ i ^= 2;
4393 \\ i <<= 2;
4394 \\ i >>= 2;
4395 \\ i &= 2;
4396 \\ i *= 2;
4397 \\ i *%= 2;
4398 \\ i -= 2;
4399 \\ i -%= 2;
4400 \\ i += 2;
4401 \\ i +%= 2;
4402 \\ i /= 2;
4403 \\ i %= 2;
4404 \\ _ = i == i;
4405 \\ _ = i != i;
4406 \\ _ = i != i;
4407 \\ _ = i.i;
4408 \\ _ = i || i;
4409 \\ _ = i!i;
4410 \\ _ = i ** i;
4411 \\ _ = i ++ i;
4412 \\ _ = i ?? i;
4413 \\ _ = i % i;
4414 \\ _ = i / i;
4415 \\ _ = i *% i;
4416 \\ _ = i * i;
4417 \\ _ = i -% i;
4418 \\ _ = i - i;
4419 \\ _ = i +% i;
4420 \\ _ = i + i;
4421 \\ _ = i << i;
4422 \\ _ = i >> i;
4423 \\ _ = i & i;
4424 \\ _ = i ^ i;
4425 \\ _ = i | i;
4426 \\ _ = i >= i;
4427 \\ _ = i <= i;
4428 \\ _ = i > i;
4429 \\ _ = i < i;
4430 \\ _ = i and i;
4431 \\ _ = i or i;
4432 \\}
4433 \\
4434 );
4435}
4436
4437test "zig fmt: precedence" {
4438 try testCanonical(
4439 \\test "precedence" {
4440 \\ a!b();
4441 \\ (a!b)();
4442 \\ !a!b;
4443 \\ !(a!b);
4444 \\ !a{ };
4445 \\ !(a{ });
4446 \\ a + b{ };
4447 \\ (a + b){ };
4448 \\ a << b + c;
4449 \\ (a << b) + c;
4450 \\ a & b << c;
4451 \\ (a & b) << c;
4452 \\ a ^ b & c;
4453 \\ (a ^ b) & c;
4454 \\ a | b ^ c;
4455 \\ (a | b) ^ c;
4456 \\ a == b | c;
4457 \\ (a == b) | c;
4458 \\ a and b == c;
4459 \\ (a and b) == c;
4460 \\ a or b and c;
4461 \\ (a or b) and c;
4462 \\ (a or b) and c;
4463 \\}
4464 \\
4465 );
4466}
4467
4468test "zig fmt: prefix operators" {
4469 try testCanonical(
4470 \\test "prefix operators" {
4471 \\ try return --%~??!*&0;
4472 \\}
4473 \\
4474 );
4475}
4476
4477test "zig fmt: call expression" {
4478 try testCanonical(
4479 \\test "test calls" {
4480 \\ a();
4481 \\ a(1);
4482 \\ a(1, 2);
4483 \\ a(1, 2) + a(1, 2);
4484 \\}
4485 \\
4486 );
4487}
4488
4489test "zig fmt: var args" {
4490 try testCanonical(
4491 \\fn print(args: ...) void {}
4492 \\
4493 );
4494}
4495
4496test "zig fmt: var type" {
4497 try testCanonical(
4498 \\fn print(args: var) var {}
4499 \\const Var = var;
4500 \\const i: var = 0;
4501 \\
4502 );
4503}
4504
4505test "zig fmt: extern function" {
4506 try testCanonical(
4507 \\extern fn puts(s: &const u8) c_int;
4508 \\extern "c" fn puts(s: &const u8) c_int;
4509 \\
4510 );
4511}
4512
4513test "zig fmt: multiline string" {
4514 try testCanonical(
4515 \\const s =
4516 \\ \\ something
4517 \\ \\ something else
4518 \\ ;
4519 \\
4520 );
4521}
4522
4523test "zig fmt: values" {
4524 try testCanonical(
4525 \\test "values" {
4526 \\ 1;
4527 \\ 1.0;
4528 \\ "string";
4529 \\ c"cstring";
4530 \\ 'c';
4531 \\ true;
4532 \\ false;
4533 \\ null;
4534 \\ undefined;
4535 \\ error;
4536 \\ this;
4537 \\ unreachable;
4538 \\}
4539 \\
4540 );
4541}
4542
4543test "zig fmt: indexing" {
4544 try testCanonical(
4545 \\test "test index" {
4546 \\ a[0];
4547 \\ a[0 + 5];
4548 \\ a[0..];
4549 \\ a[0..5];
4550 \\ a[a[0]];
4551 \\ a[a[0..]];
4552 \\ a[a[0..5]];
4553 \\ a[a[0]..];
4554 \\ a[a[0..5]..];
4555 \\ a[a[0]..a[0]];
4556 \\ a[a[0..5]..a[0]];
4557 \\ a[a[0..5]..a[0..5]];
4558 \\}
4559 \\
4560 );
4561}
4562
4563test "zig fmt: struct declaration" {
4564 try testCanonical(
4565 \\const S = struct {
4566 \\ const Self = this;
4567 \\ f1: u8,
4568 \\
4569 \\ fn method(self: &Self) Self {
4570 \\ return *self;
4571 \\ }
4572 \\
4573 \\ f2: u8
4574 \\};
4575 \\
4576 \\const Ps = packed struct {
4577 \\ a: u8,
4578 \\ b: u8,
4579 \\
4580 \\ c: u8
4581 \\};
4582 \\
4583 \\const Es = extern struct {
4584 \\ a: u8,
4585 \\ b: u8,
4586 \\
4587 \\ c: u8
4588 \\};
4589 \\
4590 );
4591}
4592
4593test "zig fmt: enum declaration" {
4594 try testCanonical(
4595 \\const E = enum {
4596 \\ Ok,
4597 \\ SomethingElse = 0
4598 \\};
4599 \\
4600 \\const E2 = enum(u8) {
4601 \\ Ok,
4602 \\ SomethingElse = 255,
4603 \\ SomethingThird
4604 \\};
4605 \\
4606 \\const Ee = extern enum {
4607 \\ Ok,
4608 \\ SomethingElse,
4609 \\ SomethingThird
4610 \\};
4611 \\
4612 \\const Ep = packed enum {
4613 \\ Ok,
4614 \\ SomethingElse,
4615 \\ SomethingThird
4616 \\};
4617 \\
4618 );
4619}
4620
4621test "zig fmt: union declaration" {
4622 try testCanonical(
4623 \\const U = union {
4624 \\ Int: u8,
4625 \\ Float: f32,
4626 \\ None,
4627 \\ Bool: bool
4628 \\};
4629 \\
4630 \\const Ue = union(enum) {
4631 \\ Int: u8,
4632 \\ Float: f32,
4633 \\ None,
4634 \\ Bool: bool
4635 \\};
4636 \\
4637 \\const E = enum {
4638 \\ Int,
4639 \\ Float,
4640 \\ None,
4641 \\ Bool
4642 \\};
4643 \\
4644 \\const Ue2 = union(E) {
4645 \\ Int: u8,
4646 \\ Float: f32,
4647 \\ None,
4648 \\ Bool: bool
4649 \\};
4650 \\
4651 \\const Eu = extern union {
4652 \\ Int: u8,
4653 \\ Float: f32,
4654 \\ None,
4655 \\ Bool: bool
4656 \\};
4657 \\
4658 );
4659}
4660
4661test "zig fmt: error set declaration" {
4662 try testCanonical(
4663 \\const E = error {
4664 \\ A,
4665 \\ B,
4666 \\
4667 \\ C
4668 \\};
4669 \\
4670 );
4671}
4672
4673test "zig fmt: arrays" {
4674 try testCanonical(
4675 \\test "test array" {
4676 \\ const a: [2]u8 = [2]u8{ 1, 2 };
4677 \\ const a: [2]u8 = []u8{ 1, 2 };
4678 \\ const a: [0]u8 = []u8{ };
4679 \\}
4680 \\
4681 );
4682}
4683
4684test "zig fmt: container initializers" {
4685 try testCanonical(
4686 \\const a1 = []u8{ };
4687 \\const a2 = []u8{ 1, 2, 3, 4 };
4688 \\const s1 = S{ };
4689 \\const s2 = S{ .a = 1, .b = 2 };
4690 \\
4691 );
4692}
4693
4694test "zig fmt: catch" {
4695 try testCanonical(
4696 \\test "catch" {
4697 \\ const a: error!u8 = 0;
4698 \\ _ = a catch return;
4699 \\ _ = a catch |err| return;
4700 \\}
4701 \\
4702 );
4703}
4704
4705test "zig fmt: blocks" {
4706 try testCanonical(
4707 \\test "blocks" {
4708 \\ {
4709 \\ const a = 0;
4710 \\ const b = 0;
4711 \\ }
4712 \\
4713 \\ blk: {
4714 \\ const a = 0;
4715 \\ const b = 0;
4716 \\ }
4717 \\
4718 \\ const r = blk: {
4719 \\ const a = 0;
4720 \\ const b = 0;
4721 \\ };
4722 \\}
4723 \\
4724 );
4725}
4726
4727test "zig fmt: switch" {
4728 try testCanonical(
4729 \\test "switch" {
4730 \\ switch (0) {
4731 \\ 0 => {},
4732 \\ 1 => unreachable,
4733 \\ 2, 3 => {},
4734 \\ 4 ... 7 => {},
4735 \\ 1 + 4 * 3 + 22 => {},
4736 \\ else => {
4737 \\ const a = 1;
4738 \\ const b = a;
4739 \\ }
4740 \\ }
4741 \\
4742 \\ const res = switch (0) {
4743 \\ 0 => 0,
4744 \\ 1 => 2,
4745 \\ else => 4
4746 \\ };
4747 \\
4748 \\ const Union = union(enum) {
4749 \\ Int: i64,
4750 \\ Float: f64
4751 \\ };
4752 \\
4753 \\ const u = Union{ .Int = 0 };
4754 \\ switch (u) {
4755 \\ Union.Int => |int| {},
4756 \\ Union.Float => |*float| unreachable
4757 \\ }
4758 \\}
4759 \\
4760 );
4761}
4762
4763test "zig fmt: while" {
4764 try testCanonical(
4765 \\test "while" {
4766 \\ while (10 < 1) {
4767 \\ unreachable;
4768 \\ }
4769 \\
4770 \\ while (10 < 1)
4771 \\ unreachable;
4772 \\
4773 \\ var i: usize = 0;
4774 \\ while (i < 10) : (i += 1) {
4775 \\ continue;
4776 \\ }
4777 \\
4778 \\ i = 0;
4779 \\ while (i < 10) : (i += 1)
4780 \\ continue;
4781 \\
4782 \\ i = 0;
4783 \\ var j: usize = 0;
4784 \\ while (i < 10) : ({
4785 \\ i += 1;
4786 \\ j += 1;
4787 \\ }) {
4788 \\ continue;
4789 \\ }
4790 \\
4791 \\ var a: ?u8 = 2;
4792 \\ while (a) |v| : (a = null) {
4793 \\ continue;
4794 \\ }
4795 \\
4796 \\ while (a) |v| : (a = null)
4797 \\ unreachable;
4798 \\
4799 \\ label: while (10 < 0) {
4800 \\ unreachable;
4801 \\ }
4802 \\
4803 \\ const res = while (0 < 10) {
4804 \\ break 7;
4805 \\ } else {
4806 \\ unreachable;
4807 \\ };
4808 \\
4809 \\ const res = while (0 < 10)
4810 \\ break 7
4811 \\ else
4812 \\ unreachable;
4813 \\
4814 \\ var a: error!u8 = 0;
4815 \\ while (a) |v| {
4816 \\ a = error.Err;
4817 \\ } else |err| {
4818 \\ i = 1;
4819 \\ }
4820 \\
4821 \\ comptime var k: usize = 0;
4822 \\ inline while (i < 10) : (i += 1)
4823 \\ j += 2;
4824 \\}
4825 \\
4826 );
4827}
4828
4829test "zig fmt: for" {
4830 try testCanonical(
4831 \\test "for" {
4832 \\ const a = []u8{ 1, 2, 3 };
4833 \\ for (a) |v| {
4834 \\ continue;
4835 \\ }
4836 \\
4837 \\ for (a) |v|
4838 \\ continue;
4839 \\
4840 \\ for (a) |*v|
4841 \\ continue;
4842 \\
4843 \\ for (a) |v, i| {
4844 \\ continue;
4845 \\ }
4846 \\
4847 \\ for (a) |v, i|
4848 \\ continue;
4849 \\
4850 \\ const res = for (a) |v, i| {
4851 \\ break v;
4852 \\ } else {
4853 \\ unreachable;
4854 \\ };
4855 \\
4856 \\ var num: usize = 0;
4857 \\ inline for (a) |v, i| {
4858 \\ num += v;
4859 \\ num += i;
4860 \\ }
4861 \\}
4862 \\
4863 );
4864}
4865
4866test "zig fmt: if" {
4867 try testCanonical(
4868 \\test "if" {
4869 \\ if (10 < 0) {
4870 \\ unreachable;
4871 \\ }
4872 \\
4873 \\ if (10 < 0) unreachable;
4874 \\
4875 \\ if (10 < 0) {
4876 \\ unreachable;
4877 \\ } else {
4878 \\ const a = 20;
4879 \\ }
4880 \\
4881 \\ if (10 < 0) {
4882 \\ unreachable;
4883 \\ } else if (5 < 0) {
4884 \\ unreachable;
4885 \\ } else {
4886 \\ const a = 20;
4887 \\ }
4888 \\
4889 \\ const is_world_broken = if (10 < 0) true else false;
4890 \\
4891 \\ const a: ?u8 = 10;
4892 \\ const b: ?u8 = null;
4893 \\ if (a) |v| {
4894 \\ const some = v;
4895 \\ } else if (b) |*v| {
4896 \\ unreachable;
4897 \\ } else {
4898 \\ const some = 10;
4899 \\ }
4900 \\
4901 \\ const non_null_a = if (a) |v| v else 0;
4902 \\
4903 \\ const a_err: error!u8 = 0;
4904 \\ if (a_err) |v| {
4905 \\ const p = v;
4906 \\ } else |err| {
4907 \\ unreachable;
4908 \\ }
4909 \\}
4910 \\
4911 );
4912}
4913
4914test "zig fmt: defer" {
4915 try testCanonical(
4916 \\test "defer" {
4917 \\ var i: usize = 0;
4918 \\ defer i = 1;
4919 \\ defer {
4920 \\ i += 2;
4921 \\ i *= i;
4922 \\ }
4923 \\
4924 \\ errdefer i += 3;
4925 \\ errdefer {
4926 \\ i += 2;
4927 \\ i /= i;
4928 \\ }
4929 \\}
4930 \\
4931 );
4932}
4933
4934test "zig fmt: comptime" {
4935 try testCanonical(
4936 \\fn a() u8 {
4937 \\ return 5;
4938 \\}
4939 \\
4940 \\fn b(comptime i: u8) u8 {
4941 \\ return i;
4942 \\}
4943 \\
4944 \\const av = comptime a();
4945 \\const av2 = comptime blk: {
4946 \\ var res = a();
4947 \\ res *= b(2);
4948 \\ break :blk res;
4949 \\};
4950 \\
4951 \\comptime {
4952 \\ _ = a();
4953 \\}
4954 \\
4955 \\test "comptime" {
4956 \\ const av3 = comptime a();
4957 \\ const av4 = comptime blk: {
4958 \\ var res = a();
4959 \\ res *= a();
4960 \\ break :blk res;
4961 \\ };
4962 \\
4963 \\ comptime var i = 0;
4964 \\ comptime {
4965 \\ i = a();
4966 \\ i += b(i);
4967 \\ }
4968 \\}
4969 \\
4970 );
4971}
4972
4973test "zig fmt: fn type" {
4974 try testCanonical(
4975 \\fn a(i: u8) u8 {
4976 \\ return i + 1;
4977 \\}
4978 \\
4979 \\const a: fn(u8) u8 = undefined;
4980 \\const b: extern fn(u8) u8 = undefined;
4981 \\const c: nakedcc fn(u8) u8 = undefined;
4982 \\const ap: fn(u8) u8 = a;
4983 \\
4984 );
4985}
4986
4987test "zig fmt: inline asm" {
4988 try testCanonical(
4989 \\pub fn syscall1(number: usize, arg1: usize) usize {
4990 \\ return asm volatile ("syscall"
4991 \\ : [ret] "={rax}" (-> usize)
4992 \\ : [number] "{rax}" (number),
4993 \\ [arg1] "{rdi}" (arg1)
4994 \\ : "rcx", "r11");
4995 \\}
1408 \\4996 \\
1409 );4997 );
4998}
14104999
5000test "zig fmt: coroutines" {
1411 try testCanonical(5001 try testCanonical(
1412 \\extern fn f1(s: &&align(1) &const &volatile u8) c_int;5002 \\async fn simpleAsyncFn() void {
1413 \\extern fn f2(s: &align(1) const &align(1) volatile &const volatile u8) c_int;5003 \\ x += 1;
1414 \\extern fn f3(s: &align(1) const volatile u8) c_int;5004 \\ suspend;
5005 \\ x += 1;
5006 \\ suspend |p| {}
5007 \\ const p = async simpleAsyncFn() catch unreachable;
5008 \\ await p;
5009 \\}
5010 \\
5011 \\test "coroutine suspend, resume, cancel" {
5012 \\ const p = try async<std.debug.global_allocator> testAsyncSeq();
5013 \\ resume p;
5014 \\ cancel p;
5015 \\}
1415 \\5016 \\
1416 );5017 );
5018}
14175019
5020test "zig fmt: Block after if" {
1418 try testCanonical(5021 try testCanonical(
1419 \\fn f1(a: bool, b: bool) bool {5022 \\test "Block after if" {
1420 \\ a != b;5023 \\ if (true) {
1421 \\ return a == b;5024 \\ const a = 0;
5025 \\ }
5026 \\
5027 \\ {
5028 \\ const a = 0;
5029 \\ }
1422 \\}5030 \\}
1423 \\5031 \\
1424 );5032 );
1425}5033}
5034
5035test "zig fmt: use" {
5036 try testCanonical(
5037 \\use @import("std");
5038 \\pub use @import("std");
5039 \\
5040 );
5041}
5042
5043test "zig fmt: string identifier" {
5044 try testCanonical(
5045 \\const @"a b" = @"c d".@"e f";
5046 \\fn @"g h"() void {}
5047 \\
5048 );
5049}
std/zig/tokenizer.zig+434-38
...@@ -5,8 +5,6 @@ pub const Token = struct {...@@ -5,8 +5,6 @@ pub const Token = struct {
5 id: Id,5 id: Id,
6 start: usize,6 start: usize,
7 end: usize,7 end: usize,
8 line: usize,
9 column: usize,
108
11 const KeywordId = struct {9 const KeywordId = struct {
12 bytes: []const u8,10 bytes: []const u8,
...@@ -17,14 +15,18 @@ pub const Token = struct {...@@ -17,14 +15,18 @@ pub const Token = struct {
17 KeywordId{.bytes="align", .id = Id.Keyword_align},15 KeywordId{.bytes="align", .id = Id.Keyword_align},
18 KeywordId{.bytes="and", .id = Id.Keyword_and},16 KeywordId{.bytes="and", .id = Id.Keyword_and},
19 KeywordId{.bytes="asm", .id = Id.Keyword_asm},17 KeywordId{.bytes="asm", .id = Id.Keyword_asm},
18 KeywordId{.bytes="async", .id = Id.Keyword_async},
19 KeywordId{.bytes="await", .id = Id.Keyword_await},
20 KeywordId{.bytes="break", .id = Id.Keyword_break},20 KeywordId{.bytes="break", .id = Id.Keyword_break},
21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},
22 KeywordId{.bytes="cancel", .id = Id.Keyword_cancel},
22 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},23 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},
23 KeywordId{.bytes="const", .id = Id.Keyword_const},24 KeywordId{.bytes="const", .id = Id.Keyword_const},
24 KeywordId{.bytes="continue", .id = Id.Keyword_continue},25 KeywordId{.bytes="continue", .id = Id.Keyword_continue},
25 KeywordId{.bytes="defer", .id = Id.Keyword_defer},26 KeywordId{.bytes="defer", .id = Id.Keyword_defer},
26 KeywordId{.bytes="else", .id = Id.Keyword_else},27 KeywordId{.bytes="else", .id = Id.Keyword_else},
27 KeywordId{.bytes="enum", .id = Id.Keyword_enum},28 KeywordId{.bytes="enum", .id = Id.Keyword_enum},
29 KeywordId{.bytes="errdefer", .id = Id.Keyword_errdefer},
28 KeywordId{.bytes="error", .id = Id.Keyword_error},30 KeywordId{.bytes="error", .id = Id.Keyword_error},
29 KeywordId{.bytes="export", .id = Id.Keyword_export},31 KeywordId{.bytes="export", .id = Id.Keyword_export},
30 KeywordId{.bytes="extern", .id = Id.Keyword_extern},32 KeywordId{.bytes="extern", .id = Id.Keyword_extern},
...@@ -39,10 +41,12 @@ pub const Token = struct {...@@ -39,10 +41,12 @@ pub const Token = struct {
39 KeywordId{.bytes="or", .id = Id.Keyword_or},41 KeywordId{.bytes="or", .id = Id.Keyword_or},
40 KeywordId{.bytes="packed", .id = Id.Keyword_packed},42 KeywordId{.bytes="packed", .id = Id.Keyword_packed},
41 KeywordId{.bytes="pub", .id = Id.Keyword_pub},43 KeywordId{.bytes="pub", .id = Id.Keyword_pub},
44 KeywordId{.bytes="resume", .id = Id.Keyword_resume},
42 KeywordId{.bytes="return", .id = Id.Keyword_return},45 KeywordId{.bytes="return", .id = Id.Keyword_return},
43 KeywordId{.bytes="section", .id = Id.Keyword_section},46 KeywordId{.bytes="section", .id = Id.Keyword_section},
44 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},47 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},
45 KeywordId{.bytes="struct", .id = Id.Keyword_struct},48 KeywordId{.bytes="struct", .id = Id.Keyword_struct},
49 KeywordId{.bytes="suspend", .id = Id.Keyword_suspend},
46 KeywordId{.bytes="switch", .id = Id.Keyword_switch},50 KeywordId{.bytes="switch", .id = Id.Keyword_switch},
47 KeywordId{.bytes="test", .id = Id.Keyword_test},51 KeywordId{.bytes="test", .id = Id.Keyword_test},
48 KeywordId{.bytes="this", .id = Id.Keyword_this},52 KeywordId{.bytes="this", .id = Id.Keyword_this},
...@@ -72,38 +76,74 @@ pub const Token = struct {...@@ -72,38 +76,74 @@ pub const Token = struct {
72 Invalid,76 Invalid,
73 Identifier,77 Identifier,
74 StringLiteral: StrLitKind,78 StringLiteral: StrLitKind,
75 StringIdentifier,79 MultilineStringLiteralLine: StrLitKind,
80 CharLiteral,
76 Eof,81 Eof,
77 Builtin,82 Builtin,
78 Bang,83 Bang,
79 Pipe,84 Pipe,
85 PipePipe,
80 PipeEqual,86 PipeEqual,
81 Equal,87 Equal,
82 EqualEqual,88 EqualEqual,
89 EqualAngleBracketRight,
83 BangEqual,90 BangEqual,
84 LParen,91 LParen,
85 RParen,92 RParen,
86 Semicolon,93 Semicolon,
87 Percent,94 Percent,
95 PercentEqual,
88 LBrace,96 LBrace,
89 RBrace,97 RBrace,
98 LBracket,
99 RBracket,
90 Period,100 Period,
91 Ellipsis2,101 Ellipsis2,
92 Ellipsis3,102 Ellipsis3,
103 Caret,
104 CaretEqual,
105 Plus,
106 PlusPlus,
107 PlusEqual,
108 PlusPercent,
109 PlusPercentEqual,
93 Minus,110 Minus,
111 MinusEqual,
112 MinusPercent,
113 MinusPercentEqual,
114 Asterisk,
115 AsteriskEqual,
116 AsteriskAsterisk,
117 AsteriskPercent,
118 AsteriskPercentEqual,
94 Arrow,119 Arrow,
95 Colon,120 Colon,
96 Slash,121 Slash,
122 SlashEqual,
97 Comma,123 Comma,
98 Ampersand,124 Ampersand,
99 AmpersandEqual,125 AmpersandEqual,
126 QuestionMark,
127 QuestionMarkQuestionMark,
128 AngleBracketLeft,
129 AngleBracketLeftEqual,
130 AngleBracketAngleBracketLeft,
131 AngleBracketAngleBracketLeftEqual,
132 AngleBracketRight,
133 AngleBracketRightEqual,
134 AngleBracketAngleBracketRight,
135 AngleBracketAngleBracketRightEqual,
136 Tilde,
100 IntegerLiteral,137 IntegerLiteral,
101 FloatLiteral,138 FloatLiteral,
102 LineComment,139 LineComment,
103 Keyword_align,140 Keyword_align,
104 Keyword_and,141 Keyword_and,
105 Keyword_asm,142 Keyword_asm,
143 Keyword_async,
144 Keyword_await,
106 Keyword_break,145 Keyword_break,
146 Keyword_cancel,
107 Keyword_catch,147 Keyword_catch,
108 Keyword_comptime,148 Keyword_comptime,
109 Keyword_const,149 Keyword_const,
...@@ -111,6 +151,7 @@ pub const Token = struct {...@@ -111,6 +151,7 @@ pub const Token = struct {
111 Keyword_defer,151 Keyword_defer,
112 Keyword_else,152 Keyword_else,
113 Keyword_enum,153 Keyword_enum,
154 Keyword_errdefer,
114 Keyword_error,155 Keyword_error,
115 Keyword_export,156 Keyword_export,
116 Keyword_extern,157 Keyword_extern,
...@@ -125,10 +166,12 @@ pub const Token = struct {...@@ -125,10 +166,12 @@ pub const Token = struct {
125 Keyword_or,166 Keyword_or,
126 Keyword_packed,167 Keyword_packed,
127 Keyword_pub,168 Keyword_pub,
169 Keyword_resume,
128 Keyword_return,170 Keyword_return,
129 Keyword_section,171 Keyword_section,
130 Keyword_stdcallcc,172 Keyword_stdcallcc,
131 Keyword_struct,173 Keyword_struct,
174 Keyword_suspend,
132 Keyword_switch,175 Keyword_switch,
133 Keyword_test,176 Keyword_test,
134 Keyword_this,177 Keyword_this,
...@@ -147,28 +190,34 @@ pub const Token = struct {...@@ -147,28 +190,34 @@ pub const Token = struct {
147pub const Tokenizer = struct {190pub const Tokenizer = struct {
148 buffer: []const u8,191 buffer: []const u8,
149 index: usize,192 index: usize,
150 line: usize,
151 column: usize,
152 pending_invalid_token: ?Token,193 pending_invalid_token: ?Token,
153194
154 pub const LineLocation = struct {195 pub const Location = struct {
196 line: usize,
197 column: usize,
155 line_start: usize,198 line_start: usize,
156 line_end: usize,199 line_end: usize,
157 };200 };
158201
159 pub fn getTokenLocation(self: &Tokenizer, token: &const Token) LineLocation {202 pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location {
160 var loc = LineLocation {203 var loc = Location {
161 .line_start = 0,204 .line = 0,
205 .column = 0,
206 .line_start = start_index,
162 .line_end = self.buffer.len,207 .line_end = self.buffer.len,
163 };208 };
164 for (self.buffer) |c, i| {209 for (self.buffer[start_index..]) |c, i| {
165 if (i == token.start) {210 if (i + start_index == token.start) {
166 loc.line_end = i;211 loc.line_end = i + start_index;
167 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}212 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
168 return loc;213 return loc;
169 }214 }
170 if (c == '\n') {215 if (c == '\n') {
216 loc.line += 1;
217 loc.column = 0;
171 loc.line_start = i + 1;218 loc.line_start = i + 1;
219 } else {
220 loc.column += 1;
172 }221 }
173 }222 }
174 return loc;223 return loc;
...@@ -183,8 +232,6 @@ pub const Tokenizer = struct {...@@ -183,8 +232,6 @@ pub const Tokenizer = struct {
183 return Tokenizer {232 return Tokenizer {
184 .buffer = buffer,233 .buffer = buffer,
185 .index = 0,234 .index = 0,
186 .line = 0,
187 .column = 0,
188 .pending_invalid_token = null,235 .pending_invalid_token = null,
189 };236 };
190 }237 }
...@@ -196,10 +243,19 @@ pub const Tokenizer = struct {...@@ -196,10 +243,19 @@ pub const Tokenizer = struct {
196 C,243 C,
197 StringLiteral,244 StringLiteral,
198 StringLiteralBackslash,245 StringLiteralBackslash,
246 MultilineStringLiteralLine,
247 MultilineStringLiteralLineBackslash,
248 CharLiteral,
249 CharLiteralBackslash,
250 CharLiteralEnd,
251 Backslash,
199 Equal,252 Equal,
200 Bang,253 Bang,
201 Pipe,254 Pipe,
202 Minus,255 Minus,
256 MinusPercent,
257 Asterisk,
258 AsteriskPercent,
203 Slash,259 Slash,
204 LineComment,260 LineComment,
205 Zero,261 Zero,
...@@ -210,6 +266,15 @@ pub const Tokenizer = struct {...@@ -210,6 +266,15 @@ pub const Tokenizer = struct {
210 FloatExponentUnsigned,266 FloatExponentUnsigned,
211 FloatExponentNumber,267 FloatExponentNumber,
212 Ampersand,268 Ampersand,
269 Caret,
270 Percent,
271 QuestionMark,
272 Plus,
273 PlusPercent,
274 AngleBracketLeft,
275 AngleBracketAngleBracketLeft,
276 AngleBracketRight,
277 AngleBracketAngleBracketRight,
213 Period,278 Period,
214 Period2,279 Period2,
215 SawAtSign,280 SawAtSign,
...@@ -220,26 +285,22 @@ pub const Tokenizer = struct {...@@ -220,26 +285,22 @@ pub const Tokenizer = struct {
220 self.pending_invalid_token = null;285 self.pending_invalid_token = null;
221 return token;286 return token;
222 }287 }
288 const start_index = self.index;
223 var state = State.Start;289 var state = State.Start;
224 var result = Token {290 var result = Token {
225 .id = Token.Id.Eof,291 .id = Token.Id.Eof,
226 .start = self.index,292 .start = self.index,
227 .end = undefined,293 .end = undefined,
228 .line = self.line,
229 .column = self.column,
230 };294 };
231 while (self.index < self.buffer.len) {295 while (self.index < self.buffer.len) : (self.index += 1) {
232 const c = self.buffer[self.index];296 const c = self.buffer[self.index];
233 switch (state) {297 switch (state) {
234 State.Start => switch (c) {298 State.Start => switch (c) {
235 ' ' => {299 ' ' => {
236 result.start = self.index + 1;300 result.start = self.index + 1;
237 result.column += 1;
238 },301 },
239 '\n' => {302 '\n' => {
240 result.start = self.index + 1;303 result.start = self.index + 1;
241 result.line += 1;
242 result.column = 0;
243 },304 },
244 'c' => {305 'c' => {
245 state = State.C;306 state = State.C;
...@@ -249,6 +310,9 @@ pub const Tokenizer = struct {...@@ -249,6 +310,9 @@ pub const Tokenizer = struct {
249 state = State.StringLiteral;310 state = State.StringLiteral;
250 result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal };311 result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal };
251 },312 },
313 '\'' => {
314 state = State.CharLiteral;
315 },
252 'a'...'b', 'd'...'z', 'A'...'Z', '_' => {316 'a'...'b', 'd'...'z', 'A'...'Z', '_' => {
253 state = State.Identifier;317 state = State.Identifier;
254 result.id = Token.Id.Identifier;318 result.id = Token.Id.Identifier;
...@@ -275,6 +339,16 @@ pub const Tokenizer = struct {...@@ -275,6 +339,16 @@ pub const Tokenizer = struct {
275 self.index += 1;339 self.index += 1;
276 break;340 break;
277 },341 },
342 '[' => {
343 result.id = Token.Id.LBracket;
344 self.index += 1;
345 break;
346 },
347 ']' => {
348 result.id = Token.Id.RBracket;
349 self.index += 1;
350 break;
351 },
278 ';' => {352 ';' => {
279 result.id = Token.Id.Semicolon;353 result.id = Token.Id.Semicolon;
280 self.index += 1;354 self.index += 1;
...@@ -291,9 +365,29 @@ pub const Tokenizer = struct {...@@ -291,9 +365,29 @@ pub const Tokenizer = struct {
291 break;365 break;
292 },366 },
293 '%' => {367 '%' => {
294 result.id = Token.Id.Percent;368 state = State.Percent;
295 self.index += 1;369 },
296 break;370 '*' => {
371 state = State.Asterisk;
372 },
373 '+' => {
374 state = State.Plus;
375 },
376 '?' => {
377 state = State.QuestionMark;
378 },
379 '<' => {
380 state = State.AngleBracketLeft;
381 },
382 '>' => {
383 state = State.AngleBracketRight;
384 },
385 '^' => {
386 state = State.Caret;
387 },
388 '\\' => {
389 state = State.Backslash;
390 result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.Normal };
297 },391 },
298 '{' => {392 '{' => {
299 result.id = Token.Id.LBrace;393 result.id = Token.Id.LBrace;
...@@ -305,6 +399,11 @@ pub const Tokenizer = struct {...@@ -305,6 +399,11 @@ pub const Tokenizer = struct {
305 self.index += 1;399 self.index += 1;
306 break;400 break;
307 },401 },
402 '~' => {
403 result.id = Token.Id.Tilde;
404 self.index += 1;
405 break;
406 },
308 '.' => {407 '.' => {
309 state = State.Period;408 state = State.Period;
310 },409 },
...@@ -334,7 +433,7 @@ pub const Tokenizer = struct {...@@ -334,7 +433,7 @@ pub const Tokenizer = struct {
334433
335 State.SawAtSign => switch (c) {434 State.SawAtSign => switch (c) {
336 '"' => {435 '"' => {
337 result.id = Token.Id.StringIdentifier;436 result.id = Token.Id.Identifier;
338 state = State.StringLiteral;437 state = State.StringLiteral;
339 },438 },
340 else => {439 else => {
...@@ -356,6 +455,107 @@ pub const Tokenizer = struct {...@@ -356,6 +455,107 @@ pub const Tokenizer = struct {
356 break;455 break;
357 },456 },
358 },457 },
458
459 State.Asterisk => switch (c) {
460 '=' => {
461 result.id = Token.Id.AsteriskEqual;
462 self.index += 1;
463 break;
464 },
465 '*' => {
466 result.id = Token.Id.AsteriskAsterisk;
467 self.index += 1;
468 break;
469 },
470 '%' => {
471 state = State.AsteriskPercent;
472 },
473 else => {
474 result.id = Token.Id.Asterisk;
475 break;
476 }
477 },
478
479 State.AsteriskPercent => switch (c) {
480 '=' => {
481 result.id = Token.Id.AsteriskPercentEqual;
482 self.index += 1;
483 break;
484 },
485 else => {
486 result.id = Token.Id.AsteriskPercent;
487 break;
488 }
489 },
490
491 State.QuestionMark => switch (c) {
492 '?' => {
493 result.id = Token.Id.QuestionMarkQuestionMark;
494 self.index += 1;
495 break;
496 },
497 else => {
498 result.id = Token.Id.QuestionMark;
499 break;
500 },
501 },
502
503 State.Percent => switch (c) {
504 '=' => {
505 result.id = Token.Id.PercentEqual;
506 self.index += 1;
507 break;
508 },
509 else => {
510 result.id = Token.Id.Percent;
511 break;
512 },
513 },
514
515 State.Plus => switch (c) {
516 '=' => {
517 result.id = Token.Id.PlusEqual;
518 self.index += 1;
519 break;
520 },
521 '+' => {
522 result.id = Token.Id.PlusPlus;
523 self.index += 1;
524 break;
525 },
526 '%' => {
527 state = State.PlusPercent;
528 },
529 else => {
530 result.id = Token.Id.Plus;
531 break;
532 },
533 },
534
535 State.PlusPercent => switch (c) {
536 '=' => {
537 result.id = Token.Id.PlusPercentEqual;
538 self.index += 1;
539 break;
540 },
541 else => {
542 result.id = Token.Id.PlusPercent;
543 break;
544 },
545 },
546
547 State.Caret => switch (c) {
548 '=' => {
549 result.id = Token.Id.CaretEqual;
550 self.index += 1;
551 break;
552 },
553 else => {
554 result.id = Token.Id.Caret;
555 break;
556 }
557 },
558
359 State.Identifier => switch (c) {559 State.Identifier => switch (c) {
360 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},560 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
361 else => {561 else => {
...@@ -369,8 +569,17 @@ pub const Tokenizer = struct {...@@ -369,8 +569,17 @@ pub const Tokenizer = struct {
369 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},569 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
370 else => break,570 else => break,
371 },571 },
572 State.Backslash => switch (c) {
573 '\\' => {
574 state = State.MultilineStringLiteralLine;
575 },
576 else => break,
577 },
372 State.C => switch (c) {578 State.C => switch (c) {
373 '\\' => @panic("TODO"),579 '\\' => {
580 state = State.Backslash;
581 result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.C };
582 },
374 '"' => {583 '"' => {
375 state = State.StringLiteral;584 state = State.StringLiteral;
376 result.id = Token.Id { .StringLiteral = Token.StrLitKind.C };585 result.id = Token.Id { .StringLiteral = Token.StrLitKind.C };
...@@ -399,6 +608,64 @@ pub const Tokenizer = struct {...@@ -399,6 +608,64 @@ pub const Tokenizer = struct {
399 },608 },
400 },609 },
401610
611 State.CharLiteral => switch (c) {
612 '\\' => {
613 state = State.CharLiteralBackslash;
614 },
615 '\'' => {
616 result.id = Token.Id.Invalid;
617 break;
618 },
619 else => {
620 if (c < 0x20 or c == 0x7f) {
621 result.id = Token.Id.Invalid;
622 break;
623 }
624
625 state = State.CharLiteralEnd;
626 }
627 },
628
629 State.CharLiteralBackslash => switch (c) {
630 '\n' => {
631 result.id = Token.Id.Invalid;
632 break;
633 },
634 else => {
635 state = State.CharLiteralEnd;
636 },
637 },
638
639 State.CharLiteralEnd => switch (c) {
640 '\'' => {
641 result.id = Token.Id.CharLiteral;
642 self.index += 1;
643 break;
644 },
645 else => {
646 result.id = Token.Id.Invalid;
647 break;
648 },
649 },
650
651 State.MultilineStringLiteralLine => switch (c) {
652 '\\' => {
653 state = State.MultilineStringLiteralLineBackslash;
654 },
655 '\n' => {
656 self.index += 1;
657 break;
658 },
659 else => self.checkLiteralCharacter(),
660 },
661
662 State.MultilineStringLiteralLineBackslash => switch (c) {
663 '\n' => break, // Look for this error later.
664 else => {
665 state = State.MultilineStringLiteralLine;
666 },
667 },
668
402 State.Bang => switch (c) {669 State.Bang => switch (c) {
403 '=' => {670 '=' => {
404 result.id = Token.Id.BangEqual;671 result.id = Token.Id.BangEqual;
...@@ -417,6 +684,11 @@ pub const Tokenizer = struct {...@@ -417,6 +684,11 @@ pub const Tokenizer = struct {
417 self.index += 1;684 self.index += 1;
418 break;685 break;
419 },686 },
687 '|' => {
688 result.id = Token.Id.PipePipe;
689 self.index += 1;
690 break;
691 },
420 else => {692 else => {
421 result.id = Token.Id.Pipe;693 result.id = Token.Id.Pipe;
422 break;694 break;
...@@ -429,6 +701,11 @@ pub const Tokenizer = struct {...@@ -429,6 +701,11 @@ pub const Tokenizer = struct {
429 self.index += 1;701 self.index += 1;
430 break;702 break;
431 },703 },
704 '>' => {
705 result.id = Token.Id.EqualAngleBracketRight;
706 self.index += 1;
707 break;
708 },
432 else => {709 else => {
433 result.id = Token.Id.Equal;710 result.id = Token.Id.Equal;
434 break;711 break;
...@@ -441,12 +718,86 @@ pub const Tokenizer = struct {...@@ -441,12 +718,86 @@ pub const Tokenizer = struct {
441 self.index += 1;718 self.index += 1;
442 break;719 break;
443 },720 },
721 '=' => {
722 result.id = Token.Id.MinusEqual;
723 self.index += 1;
724 break;
725 },
726 '%' => {
727 state = State.MinusPercent;
728 },
444 else => {729 else => {
445 result.id = Token.Id.Minus;730 result.id = Token.Id.Minus;
446 break;731 break;
447 },732 },
448 },733 },
449734
735 State.MinusPercent => switch (c) {
736 '=' => {
737 result.id = Token.Id.MinusPercentEqual;
738 self.index += 1;
739 break;
740 },
741 else => {
742 result.id = Token.Id.MinusPercent;
743 break;
744 }
745 },
746
747 State.AngleBracketLeft => switch (c) {
748 '<' => {
749 state = State.AngleBracketAngleBracketLeft;
750 },
751 '=' => {
752 result.id = Token.Id.AngleBracketLeftEqual;
753 self.index += 1;
754 break;
755 },
756 else => {
757 result.id = Token.Id.AngleBracketLeft;
758 break;
759 },
760 },
761
762 State.AngleBracketAngleBracketLeft => switch (c) {
763 '=' => {
764 result.id = Token.Id.AngleBracketAngleBracketLeftEqual;
765 self.index += 1;
766 break;
767 },
768 else => {
769 result.id = Token.Id.AngleBracketAngleBracketLeft;
770 break;
771 },
772 },
773
774 State.AngleBracketRight => switch (c) {
775 '>' => {
776 state = State.AngleBracketAngleBracketRight;
777 },
778 '=' => {
779 result.id = Token.Id.AngleBracketRightEqual;
780 self.index += 1;
781 break;
782 },
783 else => {
784 result.id = Token.Id.AngleBracketRight;
785 break;
786 },
787 },
788
789 State.AngleBracketAngleBracketRight => switch (c) {
790 '=' => {
791 result.id = Token.Id.AngleBracketAngleBracketRightEqual;
792 self.index += 1;
793 break;
794 },
795 else => {
796 result.id = Token.Id.AngleBracketAngleBracketRight;
797 break;
798 },
799 },
800
450 State.Period => switch (c) {801 State.Period => switch (c) {
451 '.' => {802 '.' => {
452 state = State.Period2;803 state = State.Period2;
...@@ -474,6 +825,11 @@ pub const Tokenizer = struct {...@@ -474,6 +825,11 @@ pub const Tokenizer = struct {
474 result.id = Token.Id.LineComment;825 result.id = Token.Id.LineComment;
475 state = State.LineComment;826 state = State.LineComment;
476 },827 },
828 '=' => {
829 result.id = Token.Id.SlashEqual;
830 self.index += 1;
831 break;
832 },
477 else => {833 else => {
478 result.id = Token.Id.Slash;834 result.id = Token.Id.Slash;
479 break;835 break;
...@@ -547,14 +903,6 @@ pub const Tokenizer = struct {...@@ -547,14 +903,6 @@ pub const Tokenizer = struct {
547 else => break,903 else => break,
548 },904 },
549 }905 }
550
551 self.index += 1;
552 if (c == '\n') {
553 self.line += 1;
554 self.column = 0;
555 } else {
556 self.column += 1;
557 }
558 } else if (self.index == self.buffer.len) {906 } else if (self.index == self.buffer.len) {
559 switch (state) {907 switch (state) {
560 State.Start,908 State.Start,
...@@ -564,6 +912,7 @@ pub const Tokenizer = struct {...@@ -564,6 +912,7 @@ pub const Tokenizer = struct {
564 State.FloatFraction,912 State.FloatFraction,
565 State.FloatExponentNumber,913 State.FloatExponentNumber,
566 State.StringLiteral, // find this error later914 State.StringLiteral, // find this error later
915 State.MultilineStringLiteralLine,
567 State.Builtin => {},916 State.Builtin => {},
568917
569 State.Identifier => {918 State.Identifier => {
...@@ -578,6 +927,11 @@ pub const Tokenizer = struct {...@@ -578,6 +927,11 @@ pub const Tokenizer = struct {
578 State.NumberDot,927 State.NumberDot,
579 State.FloatExponentUnsigned,928 State.FloatExponentUnsigned,
580 State.SawAtSign,929 State.SawAtSign,
930 State.Backslash,
931 State.MultilineStringLiteralLineBackslash,
932 State.CharLiteral,
933 State.CharLiteralBackslash,
934 State.CharLiteralEnd,
581 State.StringLiteralBackslash => {935 State.StringLiteralBackslash => {
582 result.id = Token.Id.Invalid;936 result.id = Token.Id.Invalid;
583 },937 },
...@@ -609,8 +963,45 @@ pub const Tokenizer = struct {...@@ -609,8 +963,45 @@ pub const Tokenizer = struct {
609 State.Pipe => {963 State.Pipe => {
610 result.id = Token.Id.Pipe;964 result.id = Token.Id.Pipe;
611 },965 },
966 State.AngleBracketAngleBracketRight => {
967 result.id = Token.Id.AngleBracketAngleBracketRight;
968 },
969 State.AngleBracketRight => {
970 result.id = Token.Id.AngleBracketRight;
971 },
972 State.AngleBracketAngleBracketLeft => {
973 result.id = Token.Id.AngleBracketAngleBracketLeft;
974 },
975 State.AngleBracketLeft => {
976 result.id = Token.Id.AngleBracketLeft;
977 },
978 State.PlusPercent => {
979 result.id = Token.Id.PlusPercent;
980 },
981 State.Plus => {
982 result.id = Token.Id.Plus;
983 },
984 State.QuestionMark => {
985 result.id = Token.Id.QuestionMark;
986 },
987 State.Percent => {
988 result.id = Token.Id.Percent;
989 },
990 State.Caret => {
991 result.id = Token.Id.Caret;
992 },
993 State.AsteriskPercent => {
994 result.id = Token.Id.AsteriskPercent;
995 },
996 State.Asterisk => {
997 result.id = Token.Id.Asterisk;
998 },
999 State.MinusPercent => {
1000 result.id = Token.Id.MinusPercent;
1001 },
612 }1002 }
613 }1003 }
1004
614 if (result.id == Token.Id.Eof) {1005 if (result.id == Token.Id.Eof) {
615 if (self.pending_invalid_token) |token| {1006 if (self.pending_invalid_token) |token| {
616 self.pending_invalid_token = null;1007 self.pending_invalid_token = null;
...@@ -634,8 +1025,6 @@ pub const Tokenizer = struct {...@@ -634,8 +1025,6 @@ pub const Tokenizer = struct {
634 .id = Token.Id.Invalid,1025 .id = Token.Id.Invalid,
635 .start = self.index,1026 .start = self.index,
636 .end = self.index + invalid_length,1027 .end = self.index + invalid_length,
637 .line = self.line,
638 .column = self.column,
639 };1028 };
640 }1029 }
6411030
...@@ -685,9 +1074,16 @@ test "tokenizer" {...@@ -685,9 +1074,16 @@ test "tokenizer" {
685 });1074 });
686}1075}
6871076
1077test "tokenizer - chars" {
1078 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});
1079}
1080
688test "tokenizer - invalid token characters" {1081test "tokenizer - invalid token characters" {
689 testTokenize("#", []Token.Id{Token.Id.Invalid});1082 testTokenize("#", []Token.Id{Token.Id.Invalid});
690 testTokenize("`", []Token.Id{Token.Id.Invalid});1083 testTokenize("`", []Token.Id{Token.Id.Invalid});
1084 testTokenize("'c", []Token.Id {Token.Id.Invalid});
1085 testTokenize("'", []Token.Id {Token.Id.Invalid});
1086 testTokenize("''", []Token.Id {Token.Id.Invalid, Token.Id.Invalid});
691}1087}
6921088
693test "tokenizer - invalid literal/comment characters" {1089test "tokenizer - invalid literal/comment characters" {
...@@ -739,7 +1135,7 @@ test "tokenizer - string identifier and builtin fns" {...@@ -739,7 +1135,7 @@ test "tokenizer - string identifier and builtin fns" {
739 ,1135 ,
740 []Token.Id{1136 []Token.Id{
741 Token.Id.Keyword_const,1137 Token.Id.Keyword_const,
742 Token.Id.StringIdentifier,1138 Token.Id.Identifier,
743 Token.Id.Equal,1139 Token.Id.Equal,
744 Token.Id.Builtin,1140 Token.Id.Builtin,
745 Token.Id.LParen,1141 Token.Id.LParen,
...@@ -752,8 +1148,8 @@ test "tokenizer - string identifier and builtin fns" {...@@ -752,8 +1148,8 @@ test "tokenizer - string identifier and builtin fns" {
7521148
753test "tokenizer - pipe and then invalid" {1149test "tokenizer - pipe and then invalid" {
754 testTokenize("||=", []Token.Id{1150 testTokenize("||=", []Token.Id{
755 Token.Id.Pipe,1151 Token.Id.PipePipe,
756 Token.Id.PipeEqual,1152 Token.Id.Equal,
757 });1153 });
758}1154}
7591155
test/build_examples.zig+1
...@@ -14,6 +14,7 @@ pub fn addCases(cases: &tests.BuildExamplesContext) void {...@@ -14,6 +14,7 @@ pub fn addCases(cases: &tests.BuildExamplesContext) void {
14 cases.addBuildFile("example/mix_o_files/build.zig");14 cases.addBuildFile("example/mix_o_files/build.zig");
15 }15 }
16 cases.addBuildFile("test/standalone/issue_339/build.zig");16 cases.addBuildFile("test/standalone/issue_339/build.zig");
17 cases.addBuildFile("test/standalone/issue_794/build.zig");
17 cases.addBuildFile("test/standalone/pkg_import/build.zig");18 cases.addBuildFile("test/standalone/pkg_import/build.zig");
18 cases.addBuildFile("test/standalone/use_alias/build.zig");19 cases.addBuildFile("test/standalone/use_alias/build.zig");
19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");20 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
test/cases/coroutines.zig+87-6
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
34
4var x: i32 = 1;5var x: i32 = 1;
56
6test "create a coroutine and cancel it" {7test "create a coroutine and cancel it" {
7 const p = try async(std.debug.global_allocator) simpleAsyncFn();8 const p = try async<std.debug.global_allocator> simpleAsyncFn();
9 comptime assert(@typeOf(p) == promise->void);
8 cancel p;10 cancel p;
9 assert(x == 2);11 assert(x == 2);
10}12}
...@@ -17,7 +19,7 @@ async fn simpleAsyncFn() void {...@@ -17,7 +19,7 @@ async fn simpleAsyncFn() void {
1719
18test "coroutine suspend, resume, cancel" {20test "coroutine suspend, resume, cancel" {
19 seq('a');21 seq('a');
20 const p = try async(std.debug.global_allocator) testAsyncSeq();22 const p = try async<std.debug.global_allocator> testAsyncSeq();
21 seq('c');23 seq('c');
22 resume p;24 resume p;
23 seq('f');25 seq('f');
...@@ -43,7 +45,7 @@ fn seq(c: u8) void {...@@ -43,7 +45,7 @@ fn seq(c: u8) void {
43}45}
4446
45test "coroutine suspend with block" {47test "coroutine suspend with block" {
46 const p = try async(std.debug.global_allocator) testSuspendBlock();48 const p = try async<std.debug.global_allocator> testSuspendBlock();
47 std.debug.assert(!result);49 std.debug.assert(!result);
48 resume a_promise;50 resume a_promise;
49 std.debug.assert(result);51 std.debug.assert(result);
...@@ -55,6 +57,7 @@ var result = false;...@@ -55,6 +57,7 @@ var result = false;
5557
56async fn testSuspendBlock() void {58async fn testSuspendBlock() void {
57 suspend |p| {59 suspend |p| {
60 comptime assert(@typeOf(p) == promise->void);
58 a_promise = p;61 a_promise = p;
59 }62 }
60 result = true;63 result = true;
...@@ -65,7 +68,7 @@ var await_final_result: i32 = 0;...@@ -65,7 +68,7 @@ var await_final_result: i32 = 0;
6568
66test "coroutine await" {69test "coroutine await" {
67 await_seq('a');70 await_seq('a');
68 const p = async(std.debug.global_allocator) await_amain() catch unreachable;71 const p = async<std.debug.global_allocator> await_amain() catch unreachable;
69 await_seq('f');72 await_seq('f');
70 resume await_a_promise;73 resume await_a_promise;
71 await_seq('i');74 await_seq('i');
...@@ -104,7 +107,7 @@ var early_final_result: i32 = 0;...@@ -104,7 +107,7 @@ var early_final_result: i32 = 0;
104107
105test "coroutine await early return" {108test "coroutine await early return" {
106 early_seq('a');109 early_seq('a');
107 const p = async(std.debug.global_allocator) early_amain() catch unreachable;110 const p = async<std.debug.global_allocator> early_amain() catch unreachable;
108 early_seq('f');111 early_seq('f');
109 assert(early_final_result == 1234);112 assert(early_final_result == 1234);
110 assert(std.mem.eql(u8, early_points, "abcdef"));113 assert(std.mem.eql(u8, early_points, "abcdef"));
...@@ -133,7 +136,7 @@ fn early_seq(c: u8) void {...@@ -133,7 +136,7 @@ fn early_seq(c: u8) void {
133136
134test "coro allocation failure" {137test "coro allocation failure" {
135 var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);138 var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
136 if (async(&failing_allocator.allocator) asyncFuncThatNeverGetsRun()) {139 if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
137 @panic("expected allocation failure");140 @panic("expected allocation failure");
138 } else |err| switch (err) {141 } else |err| switch (err) {
139 error.OutOfMemory => {},142 error.OutOfMemory => {},
...@@ -143,3 +146,81 @@ test "coro allocation failure" {...@@ -143,3 +146,81 @@ test "coro allocation failure" {
143async fn asyncFuncThatNeverGetsRun() void {146async fn asyncFuncThatNeverGetsRun() void {
144 @panic("coro frame allocation should fail");147 @panic("coro frame allocation should fail");
145}148}
149
150test "async function with dot syntax" {
151 const S = struct {
152 var y: i32 = 1;
153 async fn foo() void {
154 y += 1;
155 suspend;
156 }
157 };
158 const p = try async<std.debug.global_allocator> S.foo();
159 cancel p;
160 assert(S.y == 2);
161}
162
163test "async fn pointer in a struct field" {
164 var data: i32 = 1;
165 const Foo = struct {
166 bar: async<&std.mem.Allocator> fn(&i32) void,
167 };
168 var foo = Foo {
169 .bar = simpleAsyncFn2,
170 };
171 const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable;
172 assert(data == 2);
173 cancel p;
174 assert(data == 4);
175}
176
177async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
178 defer *y += 2;
179 *y += 1;
180 suspend;
181}
182
183test "async fn with inferred error set" {
184 const p = (async<std.debug.global_allocator> failing()) catch unreachable;
185 resume p;
186 cancel p;
187}
188
189async fn failing() !void {
190 suspend;
191 return error.Fail;
192}
193
194test "error return trace across suspend points - early return" {
195 const p = nonFailing();
196 resume p;
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
198 cancel p2;
199}
200
201test "error return trace across suspend points - async return" {
202 const p = nonFailing();
203 const p2 = try async<std.debug.global_allocator> printTrace(p);
204 resume p;
205 cancel p2;
206}
207
208fn nonFailing() promise->error!void {
209 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
210}
211
212async fn suspendThenFail() error!void {
213 suspend;
214 return error.Fail;
215}
216
217async fn printTrace(p: promise->error!void) void {
218 (await p) catch |e| {
219 std.debug.assert(e == error.Fail);
220 if (@errorReturnTrace()) |trace| {
221 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {
223 @panic("expected return trace");
224 }
225 };
226}
test/cases/eval.zig+11-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;1const std = @import("std");
2const assert = std.debug.assert;
2const builtin = @import("builtin");3const builtin = @import("builtin");
34
4test "compile time recursion" {5test "compile time recursion" {
...@@ -503,3 +504,12 @@ test "const ptr to comptime mutable data is not memoized" {...@@ -503,3 +504,12 @@ test "const ptr to comptime mutable data is not memoized" {
503 assert(foo.read_x() == 2);504 assert(foo.read_x() == 2);
504 }505 }
505}506}
507
508test "array concat of slices gives slice" {
509 comptime {
510 var a: []const u8 = "aoeu";
511 var b: []const u8 = "asdf";
512 const c = a ++ b;
513 assert(std.mem.eql(u8, c, "aoeuasdf"));
514 }
515}
test/compile_errors.zig+10-1
...@@ -1,6 +1,15 @@...@@ -1,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) void {3pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("wrong type passed to @panic",
5 \\export fn entry() void {
6 \\ var e = error.Foo;
7 \\ @panic(e);
8 \\}
9 ,
10 ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'");
11
12
4 cases.add("@tagName used on union with no associated enum tag",13 cases.add("@tagName used on union with no associated enum tag",
5 \\const FloatInt = extern union {14 \\const FloatInt = extern union {
6 \\ Float: f32,15 \\ Float: f32,
...@@ -17,7 +26,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -17,7 +26,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17 cases.add("returning error from void async function",26 cases.add("returning error from void async function",
18 \\const std = @import("std");27 \\const std = @import("std");
19 \\export fn entry() void {28 \\export fn entry() void {
20 \\ const p = async(std.debug.global_allocator) amain() catch unreachable;29 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;
21 \\}30 \\}
22 \\async fn amain() void {31 \\async fn amain() void {
23 \\ return error.ShouldBeCompileError;32 \\ return error.ShouldBeCompileError;
test/gen_h.zig+11
...@@ -51,6 +51,16 @@ pub fn addCases(cases: &tests.GenHContext) void {...@@ -51,6 +51,16 @@ pub fn addCases(cases: &tests.GenHContext) void {
51 \\51 \\
52 );52 );
5353
54 cases.add("declare opaque type",
55 \\export const Foo = @OpaqueType();
56 \\
57 \\export fn entry(foo: ?&Foo) void { }
58 ,
59 \\struct Foo;
60 \\
61 \\TEST_EXPORT void entry(struct Foo * foo);
62 );
63
54 cases.add("array field-type",64 cases.add("array field-type",
55 \\const Foo = extern struct {65 \\const Foo = extern struct {
56 \\ A: [2]i32,66 \\ A: [2]i32,
...@@ -66,4 +76,5 @@ pub fn addCases(cases: &tests.GenHContext) void {...@@ -66,4 +76,5 @@ pub fn addCases(cases: &tests.GenHContext) void {
66 \\TEST_EXPORT void entry(struct Foo foo, uint8_t bar[]);76 \\TEST_EXPORT void entry(struct Foo foo, uint8_t bar[]);
67 \\77 \\
68 );78 );
79
69}80}
test/runtime_safety.zig+30
...@@ -281,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -281,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
281 \\ f.float = 12.34;281 \\ f.float = 12.34;
282 \\}282 \\}
283 );283 );
284
285 // This case makes sure that the code compiles and runs. There is not actually a special
286 // runtime safety check having to do specifically with error return traces across suspend points.
287 cases.addRuntimeSafety("error return trace across suspend points",
288 \\const std = @import("std");
289 \\
290 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
291 \\ std.os.exit(126);
292 \\}
293 \\
294 \\pub fn main() void {
295 \\ const p = nonFailing();
296 \\ resume p;
297 \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable;
298 \\ cancel p2;
299 \\}
300 \\
301 \\fn nonFailing() promise->error!void {
302 \\ return async<std.debug.global_allocator> failing() catch unreachable;
303 \\}
304 \\
305 \\async fn failing() error!void {
306 \\ suspend;
307 \\ return error.Fail;
308 \\}
309 \\
310 \\async fn printTrace(p: promise->error!void) void {
311 \\ (await p) catch unreachable;
312 \\}
313 );
284}314}
test/standalone/issue_794/a_directory/foo.h created+1
...@@ -0,0 +1 @@
1#define NUMBER 1234
test/standalone/issue_794/build.zig created+11
...@@ -0,0 +1,11 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: &Builder) void {
4 const test_artifact = b.addTest("main.zig");
5 test_artifact.addIncludeDir("a_directory");
6
7 b.default_step.dependOn(&test_artifact.step);
8
9 const test_step = b.step("test", "Test the program");
10 test_step.dependOn(&test_artifact.step);
11}
test/standalone/issue_794/main.zig created+7
...@@ -0,0 +1,7 @@
1const c = @cImport(@cInclude("foo.h"));
2const std = @import("std");
3const assert = std.debug.assert;
4
5test "c import" {
6 comptime assert(c.NUMBER == 1234);
7}