authorgravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2018-08-06 01:43:19-04:00
committergravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2018-08-06 01:43:19-04:00
logd2f5e57b68da0b16e5789ca19045ccbcb4ecfa8d
treee9fa3caec533a0d1e2b434868b2fde1f9240e5c8
parent06614b3fa09954464c2e2f32756cacedc178a282
parent63a23e848a62d5f167f8d5478de9766cb24aa6eb

Merge branch 'master' into zen_stdlib


369 files changed, 60719 insertions(+), 20923 deletions(-)

.gitattributes+1
......@@ -1 +1,2 @@
11*.zig text eol=lf
2langref.html.in text eol=lf
.gitignore+12
......@@ -1,3 +1,15 @@
1# This file is for zig-specific build artifacts.
2# If you have OS-specific or editor-specific files to ignore,
3# such as *.swp or .DS_Store, put those in your global
4# ~/.gitignore and put this in your ~/.gitconfig:
5#
6# [core]
7# excludesfile = ~/.gitignore
8#
9# Cheers!
10# -andrewrk
11
112zig-cache/
213build/
314build-*/
15docgen_tmp/
.travis.yml+13-9
......@@ -1,18 +1,22 @@
11sudo: required
22services:
3 - docker
3- docker
44os:
5 - linux
6 - osx
5- linux
6- osx
77dist: trusty
88osx_image: xcode8.3
99language: cpp
1010before_install:
11 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
12 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_before_install; fi
11- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
12- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_before_install; fi
1313install:
14 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_install; fi
15 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_install; fi
14- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_install; fi
15- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_install; fi
1616script:
17 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_script; fi
18 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_script; fi
17- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_script; fi
18- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_script; fi
19env:
20 global:
21 - secure: QmJ+eLOxj3Irl5SHxt6lQvrj7++1AIz8bYri6RScAQGHQPIztkmbpBjAkpFgYaWPkZ04ROtamFXdS7oHtJHSECesgPoqM/CHIychQkgpDq30+TsFyYbBpDGHY+N6r2WnQTvg+9EuAp6P365us6qFS0D5zQ3P40c56uMbazFu3J4W1HZP+pLWlLjEXaN88ePhHWqNZyvwGMkLpYl3ghcrE9H4vGZQ7jenRW4UmskLEkuhUPJbQiow3Td8arJiRmLVISzWqneqNraLUpGyUVr4F3Rbjzacfoo3r9ZZynhY0mFsEye82x6TMGgH2xsNGkd91zpQuckWUT+pQv/G6FXpnEnjIJSO2Z5WAxXrx6xB1k2HZ17/4NWLF3fJVhdQJm3mS6odeGzUjgGrl1A42evxU+7VbcofEJq1aMiLgU1jUT2pt+pefCwmKJYLpEsSzuyrVxgvskQz0QpC053TAYSNf2Jj6Qhg9YDWyOeemYmDgffTqErF7AYhc6NKH0s0XKkIiNFSxorkEsfG/Ck1o+15slHNmWZXlmXToxDqFkLDoPvfGKg7koU5YTGvci/F9ZKb1juhGLxZbwap/18zN40BqA+Ip2yDBJAKxsIiwSjSIguy6g/Z1I50s0xNGOr36urfRRQX5H+rqr/xCZ63B6WSe6qBcZboWAQMDn8HLS9Xiwc=
22 - secure: dnb7r5guUeMOX9e7XlPUSZzmga8VW3G9Q1aa7LxEKiTjSnWhu5KpPDe8o1X3Rj6nc5iXDqmBH/C/7eNXPDyXJJWPvpE2YRpGymyUkRaakul0QBKJEaMvwy2SuAfS69CWC+TSzfGRvtSYkdpBhhLvs0h5S819S5jYbCNSCmOKfFucaP5NsHNIZ/I19oIeTPTa0/UnVm7DLFZXZjvbS+czkdyH1DhbT85sLj+XqNTzLePImE68efrjaHnlSy/CzBVJzj55UgD5i9fxNCQWzGWim/SD5xZ0zKtLycSOf6wQN2lCo0lkjw9rDlYz69mM5L9ikfYL9oHDPZnh84oXKglQ5miOHCgqs/qs4439I05lIu8i/EfbFA55YG4NyO3rL9YVOOt5gwiwvJYhDcnkVVzSl0o5bsoZgQfYvPWaIQKNkl3C53zfDQjgqS54CeDzlZpFrQTDQ1RrH8oeVC1gfYAeMabMDadox5rfZmLIN5JTf/F8iD/QdxGcoUvkEENcQgfP9PnubExtexgHGsEmqbm6ORSZ1MkEh2m3fo0f8KE6TbN1UigmcQ8nTkWBHsSmfHnB8HwJQp8mwQmDamXA+Hl3e3w4LOdYkJVlNW1/TTyJJOOvjMQCjF8SJmPHuh+QpqKbSaT9XM/vBhxbIZEufH8kawJKCBBcCNspGMNjhXfNjM0=
CMakeLists.txt+89-10
......@@ -22,7 +22,7 @@ set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}"
2222find_program(GIT_EXE NAMES git)
2323if(GIT_EXE)
2424 execute_process(
25 COMMAND ${GIT_EXE} name-rev HEAD --tags --name-only --no-undefined --always
25 COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
2626 OUTPUT_VARIABLE ZIG_GIT_REV
2727 OUTPUT_STRIP_TRAILING_WHITESPACE)
2828 if(ZIG_GIT_REV MATCHES "\\^0$")
......@@ -30,7 +30,7 @@ if(GIT_EXE)
3030 message("WARNING: Tag does not match configured Zig version")
3131 endif()
3232 else()
33 set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}.${ZIG_GIT_REV}")
33 set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}")
3434 endif()
3535endif()
3636message("Configuring zig version ${ZIG_VERSION}")
......@@ -196,7 +196,7 @@ else()
196196 if(MSVC)
197197 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")
198198 else()
199 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment")
199 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment -Wno-class-memaccess -Wno-unknown-warning-option")
200200 endif()
201201 set_target_properties(embedded_lld_lib PROPERTIES
202202 COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS}
......@@ -261,12 +261,15 @@ endif()
261261set(EMBEDDED_SOFTFLOAT_SOURCES
262262 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c"
263263 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c"
264 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c"
264265 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c"
265266 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c"
266267 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c"
268 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c"
267269 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c"
268270 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c"
269271 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c"
272 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c"
270273 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c"
271274 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c"
272275 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c"
......@@ -293,8 +296,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
293296 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c"
294297 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c"
295298 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c"
299 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c"
300 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c"
301 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c"
302 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c"
303 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c"
304 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c"
305 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c"
306 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c"
307 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c"
308 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c"
309 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c"
296310 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c"
297311 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c"
312 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c"
298313 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c"
299314 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c"
300315 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c"
......@@ -411,10 +426,15 @@ set(ZIG_SOURCES
411426)
412427set(ZIG_CPP_SOURCES
413428 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
429 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
414430)
415431
416432set(ZIG_STD_FILES
417433 "array_list.zig"
434 "atomic/index.zig"
435 "atomic/int.zig"
436 "atomic/queue.zig"
437 "atomic/stack.zig"
418438 "base64.zig"
419439 "buf_map.zig"
420440 "buf_set.zig"
......@@ -424,33 +444,43 @@ set(ZIG_STD_FILES
424444 "c/index.zig"
425445 "c/linux.zig"
426446 "c/windows.zig"
447 "crypto/blake2.zig"
448 "crypto/hmac.zig"
427449 "crypto/index.zig"
428450 "crypto/md5.zig"
429451 "crypto/sha1.zig"
430452 "crypto/sha2.zig"
431453 "crypto/sha3.zig"
432 "crypto/blake2.zig"
433 "crypto/hmac.zig"
434454 "cstr.zig"
435455 "debug/failing_allocator.zig"
436456 "debug/index.zig"
437457 "dwarf.zig"
458 "dynamic_library.zig"
438459 "elf.zig"
439460 "empty.zig"
440461 "event.zig"
462 "event/channel.zig"
463 "event/future.zig"
464 "event/group.zig"
465 "event/lock.zig"
466 "event/locked.zig"
467 "event/loop.zig"
468 "event/tcp.zig"
441469 "fmt/errol/enum3.zig"
442470 "fmt/errol/index.zig"
443471 "fmt/errol/lookup.zig"
444472 "fmt/index.zig"
445 "hash_map.zig"
446 "hash/index.zig"
447473 "hash/adler.zig"
448474 "hash/crc.zig"
449475 "hash/fnv.zig"
476 "hash/index.zig"
450477 "hash/siphash.zig"
478 "hash_map.zig"
451479 "heap.zig"
452480 "index.zig"
453481 "io.zig"
482 "json.zig"
483 "lazy_init.zig"
454484 "linked_list.zig"
455485 "macho.zig"
456486 "math/acos.zig"
......@@ -460,8 +490,32 @@ set(ZIG_STD_FILES
460490 "math/atan.zig"
461491 "math/atan2.zig"
462492 "math/atanh.zig"
493 "math/big/index.zig"
494 "math/big/int.zig"
463495 "math/cbrt.zig"
464496 "math/ceil.zig"
497 "math/complex/abs.zig"
498 "math/complex/acos.zig"
499 "math/complex/acosh.zig"
500 "math/complex/arg.zig"
501 "math/complex/asin.zig"
502 "math/complex/asinh.zig"
503 "math/complex/atan.zig"
504 "math/complex/atanh.zig"
505 "math/complex/conj.zig"
506 "math/complex/cos.zig"
507 "math/complex/cosh.zig"
508 "math/complex/exp.zig"
509 "math/complex/index.zig"
510 "math/complex/ldexp.zig"
511 "math/complex/log.zig"
512 "math/complex/pow.zig"
513 "math/complex/proj.zig"
514 "math/complex/sin.zig"
515 "math/complex/sinh.zig"
516 "math/complex/sqrt.zig"
517 "math/complex/tan.zig"
518 "math/complex/tanh.zig"
465519 "math/copysign.zig"
466520 "math/cos.zig"
467521 "math/cosh.zig"
......@@ -498,24 +552,35 @@ set(ZIG_STD_FILES
498552 "math/tan.zig"
499553 "math/tanh.zig"
500554 "math/trunc.zig"
501 "math/x86_64/sqrt.zig"
502555 "mem.zig"
503556 "net.zig"
504557 "os/child_process.zig"
505558 "os/darwin.zig"
506 "os/darwin_errno.zig"
559 "os/darwin/errno.zig"
560 "os/epoch.zig"
507561 "os/file.zig"
562 "os/get_app_data_dir.zig"
508563 "os/get_user_id.zig"
509564 "os/index.zig"
510565 "os/linux/errno.zig"
511566 "os/linux/index.zig"
567 "os/linux/vdso.zig"
512568 "os/linux/x86_64.zig"
513569 "os/path.zig"
570 "os/time.zig"
571 "os/windows/advapi32.zig"
514572 "os/windows/error.zig"
515573 "os/windows/index.zig"
574 "os/windows/kernel32.zig"
575 "os/windows/ole32.zig"
576 "os/windows/shell32.zig"
577 "os/windows/shlwapi.zig"
578 "os/windows/user32.zig"
516579 "os/windows/util.zig"
517580 "os/zen.zig"
518581 "rand/index.zig"
582 "rand/ziggurat.zig"
583 "segmented_list.zig"
519584 "sort.zig"
520585 "special/bootstrap.zig"
521586 "special/bootstrap_lib.zig"
......@@ -525,6 +590,8 @@ set(ZIG_STD_FILES
525590 "special/compiler_rt/aulldiv.zig"
526591 "special/compiler_rt/aullrem.zig"
527592 "special/compiler_rt/comparetf2.zig"
593 "special/compiler_rt/divti3.zig"
594 "special/compiler_rt/extendXfYf2.zig"
528595 "special/compiler_rt/fixuint.zig"
529596 "special/compiler_rt/fixunsdfdi.zig"
530597 "special/compiler_rt/fixunsdfsi.zig"
......@@ -535,7 +602,17 @@ set(ZIG_STD_FILES
535602 "special/compiler_rt/fixunstfdi.zig"
536603 "special/compiler_rt/fixunstfsi.zig"
537604 "special/compiler_rt/fixunstfti.zig"
605 "special/compiler_rt/floatunditf.zig"
606 "special/compiler_rt/floatunsitf.zig"
607 "special/compiler_rt/floatuntidf.zig"
608 "special/compiler_rt/floatuntisf.zig"
609 "special/compiler_rt/floatuntitf.zig"
610 "special/compiler_rt/floattidf.zig"
611 "special/compiler_rt/floattisf.zig"
612 "special/compiler_rt/floattitf.zig"
613 "special/compiler_rt/muloti4.zig"
538614 "special/compiler_rt/index.zig"
615 "special/compiler_rt/truncXfYf2.zig"
539616 "special/compiler_rt/udivmod.zig"
540617 "special/compiler_rt/udivmoddi4.zig"
541618 "special/compiler_rt/udivmodti4.zig"
......@@ -546,7 +623,9 @@ set(ZIG_STD_FILES
546623 "unicode.zig"
547624 "zig/ast.zig"
548625 "zig/index.zig"
549 "zig/parser.zig"
626 "zig/parse.zig"
627 "zig/parse_string_literal.zig"
628 "zig/render.zig"
550629 "zig/tokenizer.zig"
551630)
552631
README.md+24-59
......@@ -1,9 +1,9 @@
1![ZIG](http://ziglang.org/zig-logo.svg)
1![ZIG](https://ziglang.org/zig-logo.svg)
22
33A programming language designed for robustness, optimality, and
44clarity.
55
6[ziglang.org](http://ziglang.org)
6[ziglang.org](https://ziglang.org)
77
88## Feature Highlights
99
......@@ -21,19 +21,19 @@ clarity.
2121 * Compatible with C libraries with no wrapper necessary. Directly include
2222 C .h files and get access to the functions and symbols therein.
2323 * Provides standard library which competes with the C standard library and is
24 always compiled against statically in source form. Compile units do not
24 always compiled against statically in source form. Zig binaries do not
2525 depend on libc unless explicitly linked.
26 * Nullable type instead of null pointers.
26 * Optional type instead of null pointers.
2727 * Safe unions, tagged unions, and C ABI compatible unions.
2828 * Generics so that one can write efficient data structures that work for any
2929 data type.
3030 * No header files required. Top level declarations are entirely
3131 order-independent.
3232 * Compile-time code execution. Compile-time reflection.
33 * Partial compile-time function evaluation with eliminates the need for
33 * Partial compile-time function evaluation which eliminates the need for
3434 a preprocessor or macros.
3535 * The binaries produced by Zig have complete debugging information so you can,
36 for example, use GDB or MSVC to debug your software.
36 for example, use GDB, MSVC, or LLDB to debug your software.
3737 * Built-in unit tests with `zig test`.
3838 * Friendly toward package maintainers. Reproducible build, bootstrapping
3939 process carefully documented. Issues filed by package maintainers are
......@@ -55,66 +55,28 @@ that counts as "freestanding" for the purposes of this table.
5555|i386 | OK | planned | OK | planned | planned |
5656|x86_64 | OK | OK | OK | OK | planned |
5757|arm | OK | planned | planned | N/A | planned |
58|aarch64 | OK | planned | planned | planned | planned |
59|bpf | OK | planned | planned | N/A | planned |
60|hexagon | OK | planned | planned | N/A | planned |
61|mips | OK | planned | planned | N/A | planned |
62|powerpc | OK | planned | planned | N/A | planned |
63|r600 | OK | planned | planned | N/A | planned |
64|amdgcn | OK | planned | planned | N/A | planned |
65|sparc | OK | planned | planned | N/A | planned |
66|s390x | OK | planned | planned | N/A | planned |
67|thumb | OK | planned | planned | N/A | planned |
68|spir | OK | planned | planned | N/A | planned |
69|lanai | OK | planned | planned | N/A | planned |
58|aarch64 | OK | planned | N/A | planned | planned |
59|bpf | OK | planned | N/A | N/A | planned |
60|hexagon | OK | planned | N/A | N/A | planned |
61|mips | OK | planned | N/A | N/A | planned |
62|powerpc | OK | planned | N/A | N/A | planned |
63|r600 | OK | planned | N/A | N/A | planned |
64|amdgcn | OK | planned | N/A | N/A | planned |
65|sparc | OK | planned | N/A | N/A | planned |
66|s390x | OK | planned | N/A | N/A | planned |
67|thumb | OK | planned | N/A | N/A | planned |
68|spir | OK | planned | N/A | N/A | planned |
69|lanai | OK | planned | N/A | N/A | planned |
7070
7171## Community
7272
73 * IRC: `#zig` on Freenode.
73 * IRC: `#zig` on Freenode ([Channel Logs](https://irclog.whitequark.org/zig/)).
7474 * Reddit: [/r/zig](https://www.reddit.com/r/zig)
7575 * Email list: [ziglang@googlegroups.com](https://groups.google.com/forum/#!forum/ziglang)
7676
77### Wanted: Windows Developers
78
79Flesh out the standard library for Windows, streamline Zig installation and
80distribution for Windows. Work with LLVM and LLD teams to improve
81PDB/CodeView/MSVC debugging. Implement stack traces for Windows in the MinGW
82environment and the MSVC environment.
83
84### Wanted: MacOS and iOS Developers
85
86Flesh out the standard library for MacOS. Improve the MACH-O linker. Implement
87stack traces for MacOS. Streamline the process of using Zig to build for
88iOS.
89
90### Wanted: Android Developers
91
92Flesh out the standard library for Android. Streamline the process of using
93Zig to build for Android and for depending on Zig code on Android.
94
95### Wanted: Web Developers
96
97Figure out what are the use cases for compiling Zig to WebAssembly. Create demo
98projects with it and streamline experience for users trying to output
99WebAssembly. Work on the documentation generator outputting useful searchable html
100documentation. Create Zig modules for common web tasks such as WebSockets and gzip.
101
102### Wanted: Embedded Developers
103
104Flesh out the standard library for uncommon CPU architectures and OS targets.
105Drive issue discussion for cross compiling and using Zig in constrained
106or unusual environments.
107
108### Wanted: Game Developers
109
110Create cross platform Zig modules to compete with SDL and GLFW. Create an
111OpenGL library that does not depend on libc. Drive the usability of Zig
112for video games. Create a general purpose allocator that does not depend on
113libc. Create demo games using Zig.
114
11577## Building
11678
117[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)
79[![Build Status](https://travis-ci.org/ziglang/zig.svg?branch=master)](https://travis-ci.org/ziglang/zig)
11880[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)
11981
12082### Stage 1: Build Zig from C++ Source Code
......@@ -161,7 +123,7 @@ bin/zig build --build-file ../build.zig test
161123
162124##### Windows
163125
164See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows
126See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
165127
166128### Stage 2: Build Self-Hosted Zig from Zig Source Code
167129
......@@ -182,6 +144,9 @@ binary.
182144
183145This is the actual compiler binary that we will install to the system.
184146
147*Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is
148not yet supported.*
149
185150#### Debug / Development Build
186151
187152```
build.zig+144-97
......@@ -10,13 +10,13 @@ const ArrayList = std.ArrayList;
1010const Buffer = std.Buffer;
1111const io = std.io;
1212
13pub fn build(b: &Builder) !void {
13pub fn build(b: *Builder) !void {
1414 const mode = b.standardReleaseOptions();
1515
1616 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
1717
1818 const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
19 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8 {
19 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
2020 docgen_exe.getOutputPath(),
2121 rel_zig_exe,
2222 "doc/langref.html.in",
......@@ -30,109 +30,79 @@ pub fn build(b: &Builder) !void {
3030 const test_step = b.step("test", "Run all the tests");
3131
3232 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
33 const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
33 const build_info = try b.exec([][]const u8{
34 b.zig_exe,
35 "BUILD_INFO",
36 });
3437 var index: usize = 0;
35 const cmake_binary_dir = nextValue(&index, build_info);
36 const cxx_compiler = nextValue(&index, build_info);
37 const llvm_config_exe = nextValue(&index, build_info);
38 const lld_include_dir = nextValue(&index, build_info);
39 const lld_libraries = nextValue(&index, build_info);
40 const std_files = nextValue(&index, build_info);
41 const c_header_files = nextValue(&index, build_info);
42 const dia_guids_lib = nextValue(&index, build_info);
38 var ctx = Context{
39 .cmake_binary_dir = nextValue(&index, build_info),
40 .cxx_compiler = nextValue(&index, build_info),
41 .llvm_config_exe = nextValue(&index, build_info),
42 .lld_include_dir = nextValue(&index, build_info),
43 .lld_libraries = nextValue(&index, build_info),
44 .std_files = nextValue(&index, build_info),
45 .c_header_files = nextValue(&index, build_info),
46 .dia_guids_lib = nextValue(&index, build_info),
47 .llvm = undefined,
48 .no_rosegment = b.option(bool, "no-rosegment", "Workaround to enable valgrind builds") orelse false,
49 };
50 ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
4351
44 const llvm = findLLVM(b, llvm_config_exe) catch unreachable;
52 var test_stage2 = b.addTest("src-self-hosted/test.zig");
53 test_stage2.setBuildMode(builtin.Mode.Debug);
4554
4655 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
4756 exe.setBuildMode(mode);
4857
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
53 exe.addIncludeDir("src");
54 exe.addIncludeDir(cmake_binary_dir);
55 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");
56 if (lld_include_dir.len != 0) {
57 exe.addIncludeDir(lld_include_dir);
58 var it = mem.split(lld_libraries, ";");
59 while (it.next()) |lib| {
60 exe.addObjectFile(lib);
61 }
62 } else {
63 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_elf");
64 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_coff");
65 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_lib");
66 }
67 dependOnLib(exe, llvm);
68
69 if (exe.target.getOs() == builtin.Os.linux) {
70 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
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 }
80 exe.addObjectFile(libstdcxx_path);
81
82 exe.linkSystemLibrary("pthread");
83 } else if (exe.target.isDarwin()) {
84 exe.linkSystemLibrary("c++");
85 }
86
87 if (dia_guids_lib.len != 0) {
88 exe.addObjectFile(dia_guids_lib);
89 }
90
91 if (exe.target.getOs() != builtin.Os.windows) {
92 exe.linkSystemLibrary("xml2");
93 }
94 exe.linkSystemLibrary("c");
58 try configureStage2(b, test_stage2, ctx);
59 try configureStage2(b, exe, ctx);
9560
9661 b.default_step.dependOn(&exe.step);
9762
98 const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") ?? false;
63 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
64 const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
9965 if (!skip_self_hosted) {
10066 test_step.dependOn(&exe.step);
10167 }
102 const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") ?? false;
68 const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") orelse false;
10369 exe.setVerboseLink(verbose_link_exe);
10470
10571 b.installArtifact(exe);
106 installStdLib(b, std_files);
107 installCHeaders(b, c_header_files);
72 installStdLib(b, ctx.std_files);
73 installCHeaders(b, ctx.c_header_files);
10874
10975 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
110 const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") ?? false;
11176
112 test_step.dependOn(docs_step);
77 const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
78 test_stage2_step.dependOn(&test_stage2.step);
79 test_step.dependOn(test_stage2_step);
80
81 const all_modes = []builtin.Mode{
82 builtin.Mode.Debug,
83 builtin.Mode.ReleaseSafe,
84 builtin.Mode.ReleaseFast,
85 builtin.Mode.ReleaseSmall,
86 };
87 const modes = if (skip_release) []builtin.Mode{builtin.Mode.Debug} else all_modes;
11388
114 test_step.dependOn(tests.addPkgTests(b, test_filter,
115 "test/behavior.zig", "behavior", "Run the behavior tests",
116 with_lldb));
89 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes));
11790
118 test_step.dependOn(tests.addPkgTests(b, test_filter,
119 "std/index.zig", "std", "Run the standard library tests",
120 with_lldb));
91 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
12192
122 test_step.dependOn(tests.addPkgTests(b, test_filter,
123 "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests",
124 with_lldb));
93 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", modes));
12594
126 test_step.dependOn(tests.addCompareOutputTests(b, test_filter));
127 test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
128 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));
129 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
130 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter));
95 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
96 test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes));
97 test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
98 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
99 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
131100 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
132101 test_step.dependOn(tests.addGenHTests(b, test_filter));
102 test_step.dependOn(docs_step);
133103}
134104
135fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) void {
105fn dependOnLib(lib_exe_obj: var, dep: *const LibraryDep) void {
136106 for (dep.libdirs.toSliceConst()) |lib_dir| {
137107 lib_exe_obj.addLibPath(lib_dir);
138108 }
......@@ -147,10 +117,9 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) vo
147117 }
148118}
149119
150fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) void {
120fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
151121 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
152 lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp",
153 b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
122 lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
154123}
155124
156125const LibraryDep = struct {
......@@ -160,12 +129,22 @@ const LibraryDep = struct {
160129 includes: ArrayList([]const u8),
161130};
162131
163fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
164 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
165 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
166 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
132fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
133 const libs_output = try b.exec([][]const u8{
134 llvm_config_exe,
135 "--libs",
136 "--system-libs",
137 });
138 const includes_output = try b.exec([][]const u8{
139 llvm_config_exe,
140 "--includedir",
141 });
142 const libdir_output = try b.exec([][]const u8{
143 llvm_config_exe,
144 "--libdir",
145 });
167146
168 var result = LibraryDep {
147 var result = LibraryDep{
169148 .libs = ArrayList([]const u8).init(b.allocator),
170149 .system_libs = ArrayList([]const u8).init(b.allocator),
171150 .includes = ArrayList([]const u8).init(b.allocator),
......@@ -208,7 +187,7 @@ fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
208187 return result;
209188}
210189
211pub fn installStdLib(b: &Builder, stdlib_files: []const u8) void {
190pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
212191 var it = mem.split(stdlib_files, ";");
213192 while (it.next()) |stdlib_file| {
214193 const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;
......@@ -217,7 +196,7 @@ pub fn installStdLib(b: &Builder, stdlib_files: []const u8) void {
217196 }
218197}
219198
220pub fn installCHeaders(b: &Builder, c_header_files: []const u8) void {
199pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
221200 var it = mem.split(c_header_files, ";");
222201 while (it.next()) |c_header_file| {
223202 const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;
......@@ -226,21 +205,89 @@ pub fn installCHeaders(b: &Builder, c_header_files: []const u8) void {
226205 }
227206}
228207
229fn nextValue(index: &usize, build_info: []const u8) []const u8 {
230 const start = *index;
231 while (true) : (*index += 1) {
232 switch (build_info[*index]) {
208fn nextValue(index: *usize, build_info: []const u8) []const u8 {
209 const start = index.*;
210 while (true) : (index.* += 1) {
211 switch (build_info[index.*]) {
233212 '\n' => {
234 const result = build_info[start..*index];
235 *index += 1;
213 const result = build_info[start..index.*];
214 index.* += 1;
236215 return result;
237216 },
238217 '\r' => {
239 const result = build_info[start..*index];
240 *index += 2;
218 const result = build_info[start..index.*];
219 index.* += 2;
241220 return result;
242221 },
243222 else => continue,
244223 }
245224 }
246225}
226
227fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
228 // This is for finding /lib/libz.a on alpine linux.
229 // TODO turn this into -Dextra-lib-path=/lib option
230 exe.addLibPath("/lib");
231
232 exe.setNoRoSegment(ctx.no_rosegment);
233
234 exe.addIncludeDir("src");
235 exe.addIncludeDir(ctx.cmake_binary_dir);
236 addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
237 if (ctx.lld_include_dir.len != 0) {
238 exe.addIncludeDir(ctx.lld_include_dir);
239 var it = mem.split(ctx.lld_libraries, ";");
240 while (it.next()) |lib| {
241 exe.addObjectFile(lib);
242 }
243 } else {
244 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_wasm");
245 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_elf");
246 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff");
247 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib");
248 }
249 dependOnLib(exe, ctx.llvm);
250
251 if (exe.target.getOs() == builtin.Os.linux) {
252 const libstdcxx_path_padded = try b.exec([][]const u8{
253 ctx.cxx_compiler,
254 "-print-file-name=libstdc++.a",
255 });
256 const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?;
257 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
258 warn(
259 \\Unable to determine path to libstdc++.a
260 \\On Fedora, install libstdc++-static and try again.
261 \\
262 );
263 return error.RequiredLibraryNotFound;
264 }
265 exe.addObjectFile(libstdcxx_path);
266
267 exe.linkSystemLibrary("pthread");
268 } else if (exe.target.isDarwin()) {
269 exe.linkSystemLibrary("c++");
270 }
271
272 if (ctx.dia_guids_lib.len != 0) {
273 exe.addObjectFile(ctx.dia_guids_lib);
274 }
275
276 if (exe.target.getOs() != builtin.Os.windows) {
277 exe.linkSystemLibrary("xml2");
278 }
279 exe.linkSystemLibrary("c");
280}
281
282const Context = struct {
283 cmake_binary_dir: []const u8,
284 cxx_compiler: []const u8,
285 llvm_config_exe: []const u8,
286 lld_include_dir: []const u8,
287 lld_libraries: []const u8,
288 std_files: []const u8,
289 c_header_files: []const u8,
290 dia_guids_lib: []const u8,
291 llvm: LibraryDep,
292 no_rosegment: bool,
293};
ci/appveyor/appveyor.yml-1
......@@ -6,5 +6,4 @@ build_script:
66after_build:
77 - '%APPVEYOR_BUILD_FOLDER%\ci\appveyor\after_build.bat'
88cache:
9 - 'llvm+clang-5.0.1-win64-msvc-release.tar.xz'
109 - 'llvm+clang-6.0.0-win64-msvc-release.tar.xz'
deps/lld/COFF/Driver.cpp+3
......@@ -72,6 +72,9 @@ bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
7272 exitLld(errorCount() ? 1 : 0);
7373
7474 freeArena();
75 ObjFile::Instances.clear();
76 ImportFile::Instances.clear();
77 BitcodeFile::Instances.clear();
7578 return !errorCount();
7679}
7780
doc/codegen.md+4-4
......@@ -6,7 +6,7 @@ Every type has a "handle". If a type is a simple primitive type such as i32 or
66f64, the handle is "by value", meaning that we pass around the value itself when
77we refer to a value of that type.
88
9If a type is a container, error union, maybe type, slice, or array, then its
9If a type is a container, error union, optional type, slice, or array, then its
1010handle is a pointer, and everywhere we refer to a value of this type we refer to
1111a pointer.
1212
......@@ -19,7 +19,7 @@ Error union types are represented as:
1919 payload: T,
2020 }
2121
22Maybe types are represented as:
22Optional types are represented as:
2323
2424 struct {
2525 payload: T,
......@@ -28,6 +28,6 @@ Maybe types are represented as:
2828
2929## Data Optimizations
3030
31Maybe pointer types are special: the 0x0 pointer value is used to represent a
32null pointer. Thus, instead of the struct above, maybe pointer types are
31Optional pointer types are special: the 0x0 pointer value is used to represent a
32null pointer. Thus, instead of the struct above, optional pointer types are
3333represented as a `usize` in codegen and the handle is by value.
doc/docgen.zig+183-92
......@@ -25,13 +25,13 @@ pub fn main() !void {
2525
2626 if (!args_it.skip()) @panic("expected self arg");
2727
28 const zig_exe = try (args_it.next(allocator) ?? @panic("expected zig exe arg"));
28 const zig_exe = try (args_it.next(allocator) orelse @panic("expected zig exe arg"));
2929 defer allocator.free(zig_exe);
3030
31 const in_file_name = try (args_it.next(allocator) ?? @panic("expected input arg"));
31 const in_file_name = try (args_it.next(allocator) orelse @panic("expected input arg"));
3232 defer allocator.free(in_file_name);
3333
34 const out_file_name = try (args_it.next(allocator) ?? @panic("expected output arg"));
34 const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));
3535 defer allocator.free(out_file_name);
3636
3737 var in_file = try os.File.openRead(allocator, in_file_name);
......@@ -51,14 +51,8 @@ pub fn main() !void {
5151 var toc = try genToc(allocator, &tokenizer);
5252
5353 try os.makePath(allocator, tmp_dir_name);
54 defer {
55 // TODO issue #709
56 // disabled to pass CI tests, but obviously we want to implement this
57 // and then remove this workaround
58 if (builtin.os != builtin.Os.windows) {
59 os.deleteTree(allocator, tmp_dir_name) catch {};
60 }
61 }
54 defer os.deleteTree(allocator, tmp_dir_name) catch {};
55
6256 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
6357 try buffered_out_stream.flush();
6458}
......@@ -95,7 +89,7 @@ const Tokenizer = struct {
9589 };
9690
9791 fn init(source_file_name: []const u8, buffer: []const u8) Tokenizer {
98 return Tokenizer {
92 return Tokenizer{
9993 .buffer = buffer,
10094 .index = 0,
10195 .state = State.Start,
......@@ -104,8 +98,8 @@ const Tokenizer = struct {
10498 };
10599 }
106100
107 fn next(self: &Tokenizer) Token {
108 var result = Token {
101 fn next(self: *Tokenizer) Token {
102 var result = Token{
109103 .id = Token.Id.Eof,
110104 .start = self.index,
111105 .end = undefined,
......@@ -196,8 +190,8 @@ const Tokenizer = struct {
196190 line_end: usize,
197191 };
198192
199 fn getTokenLocation(self: &Tokenizer, token: &const Token) Location {
200 var loc = Location {
193 fn getTokenLocation(self: *Tokenizer, token: *const Token) Location {
194 var loc = Location{
201195 .line = 0,
202196 .column = 0,
203197 .line_start = 0,
......@@ -221,7 +215,7 @@ const Tokenizer = struct {
221215 }
222216};
223217
224fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) error {
218fn parseError(tokenizer: *Tokenizer, token: *const Token, comptime fmt: []const u8, args: ...) error {
225219 const loc = tokenizer.getTokenLocation(token);
226220 warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args);
227221 if (loc.line_start <= loc.line_end) {
......@@ -244,13 +238,13 @@ fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const
244238 return error.ParseError;
245239}
246240
247fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) !void {
241fn assertToken(tokenizer: *Tokenizer, token: *const Token, id: Token.Id) !void {
248242 if (token.id != id) {
249243 return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
250244 }
251245}
252246
253fn eatToken(tokenizer: &Tokenizer, id: Token.Id) !Token {
247fn eatToken(tokenizer: *Tokenizer, id: Token.Id) !Token {
254248 const token = tokenizer.next();
255249 try assertToken(tokenizer, token, id);
256250 return token;
......@@ -300,6 +294,7 @@ const Link = struct {
300294const Node = union(enum) {
301295 Content: []const u8,
302296 Nav,
297 Builtin,
303298 HeaderOpen: HeaderOpen,
304299 SeeAlso: []const SeeAlsoItem,
305300 Code: Code,
......@@ -317,7 +312,7 @@ const Action = enum {
317312 Close,
318313};
319314
320fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
315fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
321316 var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator);
322317 errdefer urls.deinit();
323318
......@@ -346,7 +341,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
346341 break;
347342 },
348343 Token.Id.Content => {
349 try nodes.append(Node {.Content = tokenizer.buffer[token.start..token.end] });
344 try nodes.append(Node{ .Content = tokenizer.buffer[token.start..token.end] });
350345 },
351346 Token.Id.BracketOpen => {
352347 const tag_token = try eatToken(tokenizer, Token.Id.TagContent);
......@@ -356,6 +351,9 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
356351 _ = try eatToken(tokenizer, Token.Id.BracketClose);
357352
358353 try nodes.append(Node.Nav);
354 } else if (mem.eql(u8, tag_name, "builtin")) {
355 _ = try eatToken(tokenizer, Token.Id.BracketClose);
356 try nodes.append(Node.Builtin);
359357 } else if (mem.eql(u8, tag_name, "header_open")) {
360358 _ = try eatToken(tokenizer, Token.Id.Separator);
361359 const content_token = try eatToken(tokenizer, Token.Id.TagContent);
......@@ -365,11 +363,13 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
365363 header_stack_size += 1;
366364
367365 const urlized = try urlize(allocator, content);
368 try nodes.append(Node{.HeaderOpen = HeaderOpen {
369 .name = content,
370 .url = urlized,
371 .n = header_stack_size,
372 }});
366 try nodes.append(Node{
367 .HeaderOpen = HeaderOpen{
368 .name = content,
369 .url = urlized,
370 .n = header_stack_size,
371 },
372 });
373373 if (try urls.put(urlized, tag_token)) |other_tag_token| {
374374 parseError(tokenizer, tag_token, "duplicate header url: #{}", urlized) catch {};
375375 parseError(tokenizer, other_tag_token, "other tag here") catch {};
......@@ -407,14 +407,14 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
407407 switch (see_also_tok.id) {
408408 Token.Id.TagContent => {
409409 const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end];
410 try list.append(SeeAlsoItem {
410 try list.append(SeeAlsoItem{
411411 .name = content,
412412 .token = see_also_tok,
413413 });
414414 },
415415 Token.Id.Separator => {},
416416 Token.Id.BracketClose => {
417 try nodes.append(Node {.SeeAlso = list.toOwnedSlice() } );
417 try nodes.append(Node{ .SeeAlso = list.toOwnedSlice() });
418418 break;
419419 },
420420 else => return parseError(tokenizer, see_also_tok, "invalid see_also token"),
......@@ -438,8 +438,8 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
438438 }
439439 };
440440
441 try nodes.append(Node {
442 .Link = Link {
441 try nodes.append(Node{
442 .Link = Link{
443443 .url = try urlize(allocator, url_name),
444444 .name = name,
445445 .token = name_tok,
......@@ -463,24 +463,24 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
463463 var code_kind_id: Code.Id = undefined;
464464 var is_inline = false;
465465 if (mem.eql(u8, code_kind_str, "exe")) {
466 code_kind_id = Code.Id { .Exe = ExpectedOutcome.Succeed };
466 code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Succeed };
467467 } else if (mem.eql(u8, code_kind_str, "exe_err")) {
468 code_kind_id = Code.Id { .Exe = ExpectedOutcome.Fail };
468 code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Fail };
469469 } else if (mem.eql(u8, code_kind_str, "test")) {
470470 code_kind_id = Code.Id.Test;
471471 } else if (mem.eql(u8, code_kind_str, "test_err")) {
472 code_kind_id = Code.Id { .TestError = name};
472 code_kind_id = Code.Id{ .TestError = name };
473473 name = "test";
474474 } else if (mem.eql(u8, code_kind_str, "test_safety")) {
475 code_kind_id = Code.Id { .TestSafety = name};
475 code_kind_id = Code.Id{ .TestSafety = name };
476476 name = "test";
477477 } else if (mem.eql(u8, code_kind_str, "obj")) {
478 code_kind_id = Code.Id { .Obj = null };
478 code_kind_id = Code.Id{ .Obj = null };
479479 } else if (mem.eql(u8, code_kind_str, "obj_err")) {
480 code_kind_id = Code.Id { .Obj = name };
480 code_kind_id = Code.Id{ .Obj = name };
481481 name = "test";
482482 } else if (mem.eql(u8, code_kind_str, "syntax")) {
483 code_kind_id = Code.Id { .Obj = null };
483 code_kind_id = Code.Id{ .Obj = null };
484484 is_inline = true;
485485 } else {
486486 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str);
......@@ -514,17 +514,20 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
514514 return parseError(tokenizer, end_code_tag, "invalid token inside code_begin: {}", end_tag_name);
515515 }
516516 _ = try eatToken(tokenizer, Token.Id.BracketClose);
517 } else unreachable; // TODO issue #707
518 try nodes.append(Node {.Code = Code {
519 .id = code_kind_id,
520 .name = name,
521 .source_token = source_token,
522 .is_inline = is_inline,
523 .mode = mode,
524 .link_objects = link_objects.toOwnedSlice(),
525 .target_windows = target_windows,
526 .link_libc = link_libc,
527 }});
517 } else
518 unreachable; // TODO issue #707
519 try nodes.append(Node{
520 .Code = Code{
521 .id = code_kind_id,
522 .name = name,
523 .source_token = source_token,
524 .is_inline = is_inline,
525 .mode = mode,
526 .link_objects = link_objects.toOwnedSlice(),
527 .target_windows = target_windows,
528 .link_libc = link_libc,
529 },
530 });
528531 tokenizer.code_node_count += 1;
529532 } else {
530533 return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);
......@@ -534,14 +537,14 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
534537 }
535538 }
536539
537 return Toc {
540 return Toc{
538541 .nodes = nodes.toOwnedSlice(),
539542 .toc = toc_buf.toOwnedSlice(),
540543 .urls = urls,
541544 };
542545}
543546
544fn urlize(allocator: &mem.Allocator, input: []const u8) ![]u8 {
547fn urlize(allocator: *mem.Allocator, input: []const u8) ![]u8 {
545548 var buf = try std.Buffer.initSize(allocator, 0);
546549 defer buf.deinit();
547550
......@@ -561,7 +564,7 @@ fn urlize(allocator: &mem.Allocator, input: []const u8) ![]u8 {
561564 return buf.toOwnedSlice();
562565}
563566
564fn escapeHtml(allocator: &mem.Allocator, input: []const u8) ![]u8 {
567fn escapeHtml(allocator: *mem.Allocator, input: []const u8) ![]u8 {
565568 var buf = try std.Buffer.initSize(allocator, 0);
566569 defer buf.deinit();
567570
......@@ -603,7 +606,7 @@ test "term color" {
603606 assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B"));
604607}
605608
606fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {
609fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
607610 var buf = try std.Buffer.initSize(allocator, 0);
608611 defer buf.deinit();
609612
......@@ -683,8 +686,14 @@ fn termColor(allocator: &mem.Allocator, input: []const u8) ![]u8 {
683686 return buf.toOwnedSlice();
684687}
685688
686fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var, zig_exe: []const u8) !void {
689fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
687690 var code_progress_index: usize = 0;
691
692 var env_map = try os.getEnvMap(allocator);
693 try env_map.set("ZIG_DEBUG_COLOR", "1");
694
695 const builtin_code = try escapeHtml(allocator, try getBuiltinCode(allocator, &env_map, zig_exe));
696
688697 for (toc.nodes) |node| {
689698 switch (node) {
690699 Node.Content => |data| {
......@@ -699,6 +708,9 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
699708 Node.Nav => {
700709 try out.write(toc.toc);
701710 },
711 Node.Builtin => {
712 try out.print("<pre><code class=\"zig\">{}</code></pre>", builtin_code);
713 },
702714 Node.HeaderOpen => |info| {
703715 try out.print("<h{} id=\"{}\">{}</h{}>\n", info.n, info.url, info.name, info.n);
704716 },
......@@ -727,16 +739,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
727739 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
728740 const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
729741 try io.writeFile(allocator, tmp_source_file_name, trimmed_raw_source);
730
742
731743 switch (code.id) {
732744 Code.Id.Exe => |expected_outcome| {
733745 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
734746 const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
735747 var build_args = std.ArrayList([]const u8).init(allocator);
736748 defer build_args.deinit();
737 try build_args.appendSlice([][]const u8 {zig_exe,
738 "build-exe", tmp_source_file_name,
739 "--output", tmp_bin_file_name,
749 try build_args.appendSlice([][]const u8{
750 zig_exe,
751 "build-exe",
752 tmp_source_file_name,
753 "--output",
754 tmp_bin_file_name,
740755 });
741756 try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", code.name);
742757 switch (code.mode) {
......@@ -749,6 +764,10 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
749764 try build_args.append("--release-fast");
750765 try out.print(" --release-fast");
751766 },
767 builtin.Mode.ReleaseSmall => {
768 try build_args.append("--release-small");
769 try out.print(" --release-small");
770 },
752771 }
753772 for (code.link_objects) |link_object| {
754773 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
......@@ -762,18 +781,20 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
762781 try build_args.append("c");
763782 try out.print(" --library c");
764783 }
765 _ = exec(allocator, build_args.toSliceConst()) catch return parseError(
766 tokenizer, code.source_token, "example failed to compile");
784 _ = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
767785
768 const run_args = [][]const u8 {tmp_bin_file_name};
786 const run_args = [][]const u8{tmp_bin_file_name};
769787
770788 const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {
771 const result = try os.ChildProcess.exec(allocator, run_args, null, null, max_doc_file_size);
789 const result = try os.ChildProcess.exec(allocator, run_args, null, &env_map, max_doc_file_size);
772790 switch (result.term) {
773791 os.ChildProcess.Term.Exited => |exit_code| {
774792 if (exit_code == 0) {
775793 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
776 for (run_args) |arg| warn("{} ", arg) else warn("\n");
794 for (run_args) |arg|
795 warn("{} ", arg)
796 else
797 warn("\n");
777798 return parseError(tokenizer, code.source_token, "example incorrectly compiled");
778799 }
779800 },
......@@ -781,11 +802,9 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
781802 }
782803 break :blk result;
783804 } else blk: {
784 break :blk exec(allocator, run_args) catch return parseError(
785 tokenizer, code.source_token, "example crashed");
805 break :blk exec(allocator, &env_map, run_args) catch return parseError(tokenizer, code.source_token, "example crashed");
786806 };
787807
788
789808 const escaped_stderr = try escapeHtml(allocator, result.stderr);
790809 const escaped_stdout = try escapeHtml(allocator, result.stdout);
791810
......@@ -798,7 +817,11 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
798817 var test_args = std.ArrayList([]const u8).init(allocator);
799818 defer test_args.deinit();
800819
801 try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
820 try test_args.appendSlice([][]const u8{
821 zig_exe,
822 "test",
823 tmp_source_file_name,
824 });
802825 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
803826 switch (code.mode) {
804827 builtin.Mode.Debug => {},
......@@ -810,16 +833,22 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
810833 try test_args.append("--release-fast");
811834 try out.print(" --release-fast");
812835 },
836 builtin.Mode.ReleaseSmall => {
837 try test_args.append("--release-small");
838 try out.print(" --release-small");
839 },
813840 }
814841 if (code.target_windows) {
815842 try test_args.appendSlice([][]const u8{
816 "--target-os", "windows",
817 "--target-arch", "x86_64",
818 "--target-environ", "msvc",
843 "--target-os",
844 "windows",
845 "--target-arch",
846 "x86_64",
847 "--target-environ",
848 "msvc",
819849 });
820850 }
821 const result = exec(allocator, test_args.toSliceConst()) catch return parseError(
822 tokenizer, code.source_token, "test failed");
851 const result = exec(allocator, &env_map, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");
823852 const escaped_stderr = try escapeHtml(allocator, result.stderr);
824853 const escaped_stdout = try escapeHtml(allocator, result.stdout);
825854 try out.print("\n{}{}</code></pre>\n", escaped_stderr, escaped_stdout);
......@@ -828,7 +857,13 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
828857 var test_args = std.ArrayList([]const u8).init(allocator);
829858 defer test_args.deinit();
830859
831 try test_args.appendSlice([][]const u8 {zig_exe, "test", "--color", "on", tmp_source_file_name});
860 try test_args.appendSlice([][]const u8{
861 zig_exe,
862 "test",
863 "--color",
864 "on",
865 tmp_source_file_name,
866 });
832867 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
833868 switch (code.mode) {
834869 builtin.Mode.Debug => {},
......@@ -840,19 +875,29 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
840875 try test_args.append("--release-fast");
841876 try out.print(" --release-fast");
842877 },
878 builtin.Mode.ReleaseSmall => {
879 try test_args.append("--release-small");
880 try out.print(" --release-small");
881 },
843882 }
844 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
883 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);
845884 switch (result.term) {
846885 os.ChildProcess.Term.Exited => |exit_code| {
847886 if (exit_code == 0) {
848887 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
849 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
888 for (test_args.toSliceConst()) |arg|
889 warn("{} ", arg)
890 else
891 warn("\n");
850892 return parseError(tokenizer, code.source_token, "example incorrectly compiled");
851893 }
852894 },
853895 else => {
854896 warn("{}\nThe following command crashed:\n", result.stderr);
855 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
897 for (test_args.toSliceConst()) |arg|
898 warn("{} ", arg)
899 else
900 warn("\n");
856901 return parseError(tokenizer, code.source_token, "example compile crashed");
857902 },
858903 }
......@@ -869,25 +914,36 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
869914 var test_args = std.ArrayList([]const u8).init(allocator);
870915 defer test_args.deinit();
871916
872 try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
917 try test_args.appendSlice([][]const u8{
918 zig_exe,
919 "test",
920 tmp_source_file_name,
921 });
873922 switch (code.mode) {
874923 builtin.Mode.Debug => {},
875924 builtin.Mode.ReleaseSafe => try test_args.append("--release-safe"),
876925 builtin.Mode.ReleaseFast => try test_args.append("--release-fast"),
926 builtin.Mode.ReleaseSmall => try test_args.append("--release-small"),
877927 }
878928
879 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
929 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);
880930 switch (result.term) {
881931 os.ChildProcess.Term.Exited => |exit_code| {
882932 if (exit_code == 0) {
883933 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
884 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
934 for (test_args.toSliceConst()) |arg|
935 warn("{} ", arg)
936 else
937 warn("\n");
885938 return parseError(tokenizer, code.source_token, "example test incorrectly succeeded");
886939 }
887940 },
888941 else => {
889942 warn("{}\nThe following command crashed:\n", result.stderr);
890 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
943 for (test_args.toSliceConst()) |arg|
944 warn("{} ", arg)
945 else
946 warn("\n");
891947 return parseError(tokenizer, code.source_token, "example compile crashed");
892948 },
893949 }
......@@ -905,9 +961,20 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
905961 var build_args = std.ArrayList([]const u8).init(allocator);
906962 defer build_args.deinit();
907963
908 try build_args.appendSlice([][]const u8 {zig_exe, "build-obj", tmp_source_file_name,
909 "--color", "on",
910 "--output", tmp_obj_file_name});
964 const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
965 const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext);
966
967 try build_args.appendSlice([][]const u8{
968 zig_exe,
969 "build-obj",
970 tmp_source_file_name,
971 "--color",
972 "on",
973 "--output",
974 tmp_obj_file_name,
975 "--output-h",
976 output_h_file_name,
977 });
911978
912979 if (!code.is_inline) {
913980 try out.print("<pre><code class=\"shell\">$ zig build-obj {}.zig", code.name);
......@@ -927,21 +994,33 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
927994 try out.print(" --release-fast");
928995 }
929996 },
997 builtin.Mode.ReleaseSmall => {
998 try build_args.append("--release-small");
999 if (!code.is_inline) {
1000 try out.print(" --release-small");
1001 }
1002 },
9301003 }
9311004
9321005 if (maybe_error_match) |error_match| {
933 const result = try os.ChildProcess.exec(allocator, build_args.toSliceConst(), null, null, max_doc_file_size);
1006 const result = try os.ChildProcess.exec(allocator, build_args.toSliceConst(), null, &env_map, max_doc_file_size);
9341007 switch (result.term) {
9351008 os.ChildProcess.Term.Exited => |exit_code| {
9361009 if (exit_code == 0) {
9371010 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
938 for (build_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
1011 for (build_args.toSliceConst()) |arg|
1012 warn("{} ", arg)
1013 else
1014 warn("\n");
9391015 return parseError(tokenizer, code.source_token, "example build incorrectly succeeded");
9401016 }
9411017 },
9421018 else => {
9431019 warn("{}\nThe following command crashed:\n", result.stderr);
944 for (build_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
1020 for (build_args.toSliceConst()) |arg|
1021 warn("{} ", arg)
1022 else
1023 warn("\n");
9451024 return parseError(tokenizer, code.source_token, "example compile crashed");
9461025 },
9471026 }
......@@ -956,8 +1035,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
9561035 try out.print("</code></pre>\n");
9571036 }
9581037 } else {
959 _ = exec(allocator, build_args.toSliceConst()) catch return parseError(
960 tokenizer, code.source_token, "example failed to compile");
1038 _ = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
9611039 }
9621040 if (!code.is_inline) {
9631041 try out.print("</code></pre>\n");
......@@ -968,24 +1046,37 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
9681046 },
9691047 }
9701048 }
971
9721049}
9731050
974fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
975 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
1051fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !os.ChildProcess.ExecResult {
1052 const result = try os.ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size);
9761053 switch (result.term) {
9771054 os.ChildProcess.Term.Exited => |exit_code| {
9781055 if (exit_code != 0) {
9791056 warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);
980 for (args) |arg| warn("{} ", arg) else warn("\n");
1057 for (args) |arg|
1058 warn("{} ", arg)
1059 else
1060 warn("\n");
9811061 return error.ChildExitError;
9821062 }
9831063 },
9841064 else => {
9851065 warn("{}\nThe following command crashed:\n", result.stderr);
986 for (args) |arg| warn("{} ", arg) else warn("\n");
1066 for (args) |arg|
1067 warn("{} ", arg)
1068 else
1069 warn("\n");
9871070 return error.ChildCrashed;
9881071 },
9891072 }
9901073 return result;
9911074}
1075
1076fn getBuiltinCode(allocator: *mem.Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 {
1077 const result = try exec(allocator, env_map, []const []const u8{
1078 zig_exe,
1079 "builtin",
1080 });
1081 return result.stdout;
1082}
doc/langref.html.in+2242-689
......@@ -96,7 +96,7 @@
9696 </p>
9797 <p>
9898 If you search for something specific in this documentation and do not find it,
99 please <a href="https://github.com/zig-lang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
99 please <a href="https://github.com/ziglang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
100100 </p>
101101 <p>
102102 The code samples in this document are compiled and tested as part of the main test suite of Zig.
......@@ -134,6 +134,58 @@ pub fn main() void {
134134 </p>
135135 {#see_also|Values|@import|Errors|Root Source File#}
136136 {#header_close#}
137 {#header_open|Comments#}
138 {#code_begin|test|comments#}
139const assert = @import("std").debug.assert;
140
141test "comments" {
142 // Comments in Zig start with "//" and end at the next LF byte (end of line).
143 // The below line is a comment, and won't be executed.
144
145 //assert(false);
146
147 const x = true; // another comment
148 assert(x);
149}
150 {#code_end#}
151 <p>
152 There are no multiline comments in Zig (e.g. like <code>/* */</code>
153 comments in C). This helps allow Zig to have the property that each line
154 of code can be tokenized out of context.
155 </p>
156 {#header_open|Doc comments#}
157 <p>
158 A doc comment is one that begins with exactly three slashes (i.e.
159 <code class="zig">///</code> but not <code class="zig">////</code>);
160 multiple doc comments in a row are merged together to form a multiline
161 doc comment. The doc comment documents whatever immediately follows it.
162 </p>
163 {#code_begin|syntax|doc_comments#}
164/// A structure for storing a timestamp, with nanosecond precision (this is a
165/// multiline doc comment).
166const Timestamp = struct {
167 /// The number of seconds since the epoch (this is also a doc comment).
168 seconds: i64, // signed so we can represent pre-1970 (not a doc comment)
169 /// The number of nanoseconds past the second (doc comment again).
170 nanos: u32,
171
172 /// Returns a `Timestamp` struct representing the Unix epoch; that is, the
173 /// moment of 1970 Jan 1 00:00:00 UTC (this is a doc comment too).
174 pub fn unixEpoch() Timestamp {
175 return Timestamp{
176 .seconds = 0,
177 .nanos = 0,
178 };
179 }
180};
181 {#code_end#}
182 <p>
183 Doc comments are only allowed in certain places; eventually, it will
184 become a compile error have a doc comment in an unexpected place, such as
185 in the middle of an expression, or just before a non-doc comment.
186 </p>
187 {#header_close#}
188 {#header_close#}
137189 {#header_open|Values#}
138190 {#code_begin|exe|values#}
139191const std = @import("std");
......@@ -156,18 +208,18 @@ pub fn main() void {
156208 true or false,
157209 !true);
158210
159 // nullable
160 var nullable_value: ?[]const u8 = null;
161 assert(nullable_value == null);
211 // optional
212 var optional_value: ?[]const u8 = null;
213 assert(optional_value == null);
162214
163 warn("\nnullable 1\ntype: {}\nvalue: {}\n",
164 @typeName(@typeOf(nullable_value)), nullable_value);
215 warn("\noptional 1\ntype: {}\nvalue: {}\n",
216 @typeName(@typeOf(optional_value)), optional_value);
165217
166 nullable_value = "hi";
167 assert(nullable_value != null);
218 optional_value = "hi";
219 assert(optional_value != null);
168220
169 warn("\nnullable 2\ntype: {}\nvalue: {}\n",
170 @typeName(@typeOf(nullable_value)), nullable_value);
221 warn("\noptional 2\ntype: {}\nvalue: {}\n",
222 @typeName(@typeOf(optional_value)), optional_value);
171223
172224 // error union
173225 var number_or_error: error!i32 = error.ArgNotFound;
......@@ -367,20 +419,25 @@ pub fn main() void {
367419 <td>for ABI compatibility with C</td>
368420 </tr>
369421
422 <tr>
423 <td><code>f16</code></td>
424 <td><code>float</code></td>
425 <td>16-bit floating point (10-bit mantissa) IEEE-754-2008 binary16</td>
426 </tr>
370427 <tr>
371428 <td><code>f32</code></td>
372429 <td><code>float</code></td>
373 <td>32-bit floating point (23-bit mantissa)</td>
430 <td>32-bit floating point (23-bit mantissa) IEEE-754-2008 binary32</td>
374431 </tr>
375432 <tr>
376433 <td><code>f64</code></td>
377434 <td><code>double</code></td>
378 <td>64-bit floating point (52-bit mantissa)</td>
435 <td>64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64</td>
379436 </tr>
380437 <tr>
381438 <td><code>f128</code></td>
382439 <td>(none)</td>
383 <td>128-bit floating point (112-bit mantissa)</td>
440 <td>128-bit floating point (112-bit mantissa) IEEE-754-2008 binary128</td>
384441 </tr>
385442 <tr>
386443 <td><code>bool</code></td>
......@@ -407,6 +464,16 @@ pub fn main() void {
407464 <td>(none)</td>
408465 <td>an error code</td>
409466 </tr>
467 <tr>
468 <td><code>comptime_int</code></td>
469 <td>(none)</td>
470 <td>Only allowed for {#link|comptime#}-known values. The type of integer literals.</td>
471 </tr>
472 <tr>
473 <td><code>comptime_float</code></td>
474 <td>(none)</td>
475 <td>Only allowed for {#link|comptime#}-known values. The type of float literals.</td>
476 </tr>
410477 </table>
411478 </div>
412479 {#see_also|Integers|Floats|void|Errors#}
......@@ -428,7 +495,7 @@ pub fn main() void {
428495 </tr>
429496 <tr>
430497 <td><code>null</code></td>
431 <td>used to set a nullable type to <code>null</code></td>
498 <td>used to set an optional type to <code>null</code></td>
432499 </tr>
433500 <tr>
434501 <td><code>undefined</code></td>
......@@ -440,7 +507,7 @@ pub fn main() void {
440507 </tr>
441508 </table>
442509 </div>
443 {#see_also|Nullables|this#}
510 {#see_also|Optionals|this#}
444511 {#header_close#}
445512 {#header_open|String Literals#}
446513 {#code_begin|test#}
......@@ -458,7 +525,7 @@ test "string literals" {
458525
459526 // A C string literal is a null terminated pointer.
460527 const null_terminated_bytes = c"hello";
461 assert(@typeOf(null_terminated_bytes) == &const u8);
528 assert(@typeOf(null_terminated_bytes) == [*]const u8);
462529 assert(null_terminated_bytes[5] == 0);
463530}
464531 {#code_end#}
......@@ -547,7 +614,7 @@ const c_string_literal =
547614;
548615 {#code_end#}
549616 <p>
550 In this example the variable <code>c_string_literal</code> has type <code>&amp;const char</code> and
617 In this example the variable <code>c_string_literal</code> has type <code>[*]const char</code> and
551618 has a terminating null byte.
552619 </p>
553620 {#see_also|@embedFile#}
......@@ -590,6 +657,7 @@ test "initialization" {
590657 x = 1;
591658}
592659 {#code_end#}
660 {#header_open|undefined#}
593661 <p>Use <code>undefined</code> to leave variables uninitialized:</p>
594662 {#code_begin|test#}
595663const assert = @import("std").debug.assert;
......@@ -600,6 +668,18 @@ test "init with undefined" {
600668 assert(x == 1);
601669}
602670 {#code_end#}
671 <p>
672 <code>undefined</code> can be {#link|implicitly cast|Implicit Casts#} to any type.
673 Once this happens, it is no longer possible to detect that the value is <code>undefined</code>.
674 <code>undefined</code> means the value could be anything, even something that is nonsense
675 according to the type. Translated into English, <code>undefined</code> means "Not a meaningful
676 value. Using this value would be a bug. The value will be unused, or overwritten before being used."
677 </p>
678 <p>
679 In {#link|Debug#} mode, Zig writes <code>0xaa</code> bytes to undefined memory. This is to catch
680 bugs early, and to help detect use of undefined memory in a debugger.
681 </p>
682 {#header_close#}
603683 {#header_close#}
604684 {#header_close#}
605685 {#header_open|Integers#}
......@@ -640,7 +720,19 @@ fn divide(a: i32, b: i32) i32 {
640720 {#header_close#}
641721 {#header_close#}
642722 {#header_open|Floats#}
723 <p>Zig has the following floating point types:</p>
724 <ul>
725 <li><code>f16</code> - IEEE-754-2008 binary16</li>
726 <li><code>f32</code> - IEEE-754-2008 binary32</li>
727 <li><code>f64</code> - IEEE-754-2008 binary64</li>
728 <li><code>f128</code> - IEEE-754-2008 binary128</li>
729 <li><code>c_longdouble</code> - matches <code>long double</code> for the target C ABI</li>
730 </ul>
643731 {#header_open|Float Literals#}
732 <p>
733 Float literals have type <code>comptime_float</code> which is guaranteed to hold at least all possible values
734 that the largest other floating point type can hold. Float literals {#link|implicitly cast|Implicit Casts#} to any other type.
735 </p>
644736 {#code_begin|syntax#}
645737const floating_point = 123.0E+77;
646738const another_float = 123.0;
......@@ -985,10 +1077,10 @@ a ^= b</code></pre></td>
9851077 </td>
9861078 </tr>
9871079 <tr>
988 <td><pre><code class="zig">a ?? b</code></pre></td>
1080 <td><pre><code class="zig">a orelse b</code></pre></td>
9891081 <td>
9901082 <ul>
991 <li>{#link|Nullables#}</li>
1083 <li>{#link|Optionals#}</li>
9921084 </ul>
9931085 </td>
9941086 <td>If <code>a</code> is <code>null</code>,
......@@ -998,24 +1090,24 @@ a ^= b</code></pre></td>
9981090 </td>
9991091 <td>
10001092 <pre><code class="zig">const value: ?u32 = null;
1001const unwrapped = value ?? 1234;
1093const unwrapped = value orelse 1234;
10021094unwrapped == 1234</code></pre>
10031095 </td>
10041096 </tr>
10051097 <tr>
1006 <td><pre><code class="zig">??a</code></pre></td>
1098 <td><pre><code class="zig">a.?</code></pre></td>
10071099 <td>
10081100 <ul>
1009 <li>{#link|Nullables#}</li>
1101 <li>{#link|Optionals#}</li>
10101102 </ul>
10111103 </td>
10121104 <td>
10131105 Equivalent to:
1014 <pre><code class="zig">a ?? unreachable</code></pre>
1106 <pre><code class="zig">a orelse unreachable</code></pre>
10151107 </td>
10161108 <td>
10171109 <pre><code class="zig">const value: ?u32 = 5678;
1018??value == 5678</code></pre>
1110value.? == 5678</code></pre>
10191111 </td>
10201112 </tr>
10211113 <tr>
......@@ -1047,7 +1139,7 @@ unwrapped == 1234</code></pre>
10471139 </td>
10481140 <td>
10491141 If <code>a</code> is <code>false</code>, returns <code>false</code>
1050 without evaluating <code>b</code>. Otherwise, retuns <code>b</code>.
1142 without evaluating <code>b</code>. Otherwise, returns <code>b</code>.
10511143 </td>
10521144 <td>
10531145 <pre><code class="zig">false and true == false</code></pre>
......@@ -1062,7 +1154,7 @@ unwrapped == 1234</code></pre>
10621154 </td>
10631155 <td>
10641156 If <code>a</code> is <code>true</code>, returns <code>true</code>
1065 without evaluating <code>b</code>. Otherwise, retuns <code>b</code>.
1157 without evaluating <code>b</code>. Otherwise, returns <code>b</code>.
10661158 </td>
10671159 <td>
10681160 <pre><code class="zig">false or true == true</code></pre>
......@@ -1103,7 +1195,7 @@ unwrapped == 1234</code></pre>
11031195 <td><pre><code class="zig">a == null<code></pre></td>
11041196 <td>
11051197 <ul>
1106 <li>{#link|Nullables#}</li>
1198 <li>{#link|Optionals#}</li>
11071199 </ul>
11081200 </td>
11091201 <td>
......@@ -1232,7 +1324,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
12321324 </td>
12331325 </tr>
12341326 <tr>
1235 <td><pre><code class="zig">*a<code></pre></td>
1327 <td><pre><code class="zig">a.*<code></pre></td>
12361328 <td>
12371329 <ul>
12381330 <li>{#link|Pointers#}</li>
......@@ -1244,7 +1336,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
12441336 <td>
12451337 <pre><code class="zig">const x: u32 = 1234;
12461338const ptr = &amp;x;
1247*x == 1234</code></pre>
1339x.* == 1234</code></pre>
12481340 </td>
12491341 </tr>
12501342 <tr>
......@@ -1258,7 +1350,23 @@ const ptr = &amp;x;
12581350 <td>
12591351 <pre><code class="zig">const x: u32 = 1234;
12601352const ptr = &amp;x;
1261*x == 1234</code></pre>
1353x.* == 1234</code></pre>
1354 </td>
1355 </tr>
1356 <tr>
1357 <td><pre><code class="zig">a || b<code></pre></td>
1358 <td>
1359 <ul>
1360 <li>{#link|Error Set Type#}</li>
1361 </ul>
1362 </td>
1363 <td>
1364 {#link|Merging Error Sets#}
1365 </td>
1366 <td>
1367 <pre><code class="zig">const A = error{One};
1368const B = error{Two};
1369(A || B) == error{One, Two}</code></pre>
12621370 </td>
12631371 </tr>
12641372 </table>
......@@ -1267,9 +1375,9 @@ const ptr = &amp;x;
12671375 {#header_open|Precedence#}
12681376 <pre><code>x() x[] x.y
12691377a!b
1270!x -x -%x ~x *x &amp;x ?x ??x
1271x{}
1272! * / % ** *%
1378!x -x -%x ~x &amp;x ?x
1379x{} x.* x.?
1380! * / % ** *% ||
12731381+ - ++ +% -%
12741382&lt;&lt; &gt;&gt;
12751383&amp;
......@@ -1278,7 +1386,7 @@ x{}
12781386== != &lt; &gt; &lt;= &gt;=
12791387and
12801388or
1281?? catch
1389orelse catch
12821390= *= /= %= += -= &lt;&lt;= &gt;&gt;= &amp;= ^= |=</code></pre>
12831391 {#header_close#}
12841392 {#header_close#}
......@@ -1288,7 +1396,7 @@ const assert = @import("std").debug.assert;
12881396const mem = @import("std").mem;
12891397
12901398// array literal
1291const message = []u8{'h', 'e', 'l', 'l', 'o'};
1399const message = []u8{ 'h', 'e', 'l', 'l', 'o' };
12921400
12931401// get the size of an array
12941402comptime {
......@@ -1316,7 +1424,7 @@ var some_integers: [100]i32 = undefined;
13161424
13171425test "modify an array" {
13181426 for (some_integers) |*item, i| {
1319 *item = i32(i);
1427 item.* = @intCast(i32, i);
13201428 }
13211429 assert(some_integers[10] == 10);
13221430 assert(some_integers[99] == 99);
......@@ -1324,11 +1432,11 @@ test "modify an array" {
13241432
13251433// array concatenation works if the values are known
13261434// at compile time
1327const part_one = []i32{1, 2, 3, 4};
1328const part_two = []i32{5, 6, 7, 8};
1435const part_one = []i32{ 1, 2, 3, 4 };
1436const part_two = []i32{ 5, 6, 7, 8 };
13291437const all_of_it = part_one ++ part_two;
13301438comptime {
1331 assert(mem.eql(i32, all_of_it, []i32{1,2,3,4,5,6,7,8}));
1439 assert(mem.eql(i32, all_of_it, []i32{ 1, 2, 3, 4, 5, 6, 7, 8 }));
13321440}
13331441
13341442// remember that string literals are arrays
......@@ -1357,9 +1465,9 @@ comptime {
13571465var fancy_array = init: {
13581466 var initial_value: [10]Point = undefined;
13591467 for (initial_value) |*pt, i| {
1360 *pt = Point {
1361 .x = i32(i),
1362 .y = i32(i) * 2,
1468 pt.* = Point{
1469 .x = @intCast(i32, i),
1470 .y = @intCast(i32, i) * 2,
13631471 };
13641472 }
13651473 break :init initial_value;
......@@ -1377,7 +1485,7 @@ test "compile-time array initalization" {
13771485// call a function to initialize an array
13781486var more_points = []Point{makePoint(3)} ** 10;
13791487fn makePoint(x: i32) Point {
1380 return Point {
1488 return Point{
13811489 .x = x,
13821490 .y = x * 2,
13831491 };
......@@ -1400,39 +1508,37 @@ test "address of syntax" {
14001508 const x_ptr = &x;
14011509
14021510 // Deference a pointer:
1403 assert(*x_ptr == 1234);
1511 assert(x_ptr.* == 1234);
14041512
14051513 // When you get the address of a const variable, you get a const pointer.
1406 assert(@typeOf(x_ptr) == &const i32);
1514 assert(@typeOf(x_ptr) == *const i32);
14071515
14081516 // If you want to mutate the value, you'd need an address of a mutable variable:
14091517 var y: i32 = 5678;
14101518 const y_ptr = &y;
1411 assert(@typeOf(y_ptr) == &i32);
1412 *y_ptr += 1;
1413 assert(*y_ptr == 5679);
1519 assert(@typeOf(y_ptr) == *i32);
1520 y_ptr.* += 1;
1521 assert(y_ptr.* == 5679);
14141522}
14151523
14161524test "pointer array access" {
1417 // Pointers do not support pointer arithmetic. If you
1418 // need such a thing, use array index syntax:
1419
1420 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1421 const ptr = &array[1];
1525 // Taking an address of an individual element gives a
1526 // pointer to a single item. This kind of pointer
1527 // does not support pointer arithmetic.
1528 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
1529 const ptr = &array[2];
1530 assert(@typeOf(ptr) == *u8);
14221531
14231532 assert(array[2] == 3);
1424 ptr[1] += 1;
1533 ptr.* += 1;
14251534 assert(array[2] == 4);
14261535}
14271536
14281537test "pointer slicing" {
1429 // In Zig, we prefer using slices over null-terminated pointers.
1430 // You can turn a pointer into a slice using slice syntax:
1431 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1432 const ptr = &array[1];
1433 const slice = ptr[1..3];
1434
1435 assert(slice.ptr == &ptr[1]);
1538 // In Zig, we prefer slices over pointers to null-terminated arrays.
1539 // You can turn an array into a slice using slice syntax:
1540 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
1541 const slice = array[2..4];
14361542 assert(slice.len == 2);
14371543
14381544 // Slices have bounds checking and are therefore protected
......@@ -1448,14 +1554,14 @@ comptime {
14481554 // @ptrCast.
14491555 var x: i32 = 1;
14501556 const ptr = &x;
1451 *ptr += 1;
1557 ptr.* += 1;
14521558 x += 1;
1453 assert(*ptr == 3);
1559 assert(ptr.* == 3);
14541560}
14551561
14561562test "@ptrToInt and @intToPtr" {
14571563 // To convert an integer address into a pointer, use @intToPtr:
1458 const ptr = @intToPtr(&i32, 0xdeadbeef);
1564 const ptr = @intToPtr(*i32, 0xdeadbeef);
14591565
14601566 // To convert a pointer to an integer, use @ptrToInt:
14611567 const addr = @ptrToInt(ptr);
......@@ -1467,7 +1573,7 @@ test "@ptrToInt and @intToPtr" {
14671573comptime {
14681574 // Zig is able to do this at compile-time, as long as
14691575 // ptr is never dereferenced.
1470 const ptr = @intToPtr(&i32, 0xdeadbeef);
1576 const ptr = @intToPtr(*i32, 0xdeadbeef);
14711577 const addr = @ptrToInt(ptr);
14721578 assert(@typeOf(addr) == usize);
14731579 assert(addr == 0xdeadbeef);
......@@ -1477,39 +1583,39 @@ test "volatile" {
14771583 // In Zig, loads and stores are assumed to not have side effects.
14781584 // If a given load or store should have side effects, such as
14791585 // Memory Mapped Input/Output (MMIO), use `volatile`:
1480 const mmio_ptr = @intToPtr(&volatile u8, 0x12345678);
1586 const mmio_ptr = @intToPtr(*volatile u8, 0x12345678);
14811587
14821588 // Now loads and stores with mmio_ptr are guaranteed to all happen
14831589 // and in the same order as in source code.
1484 assert(@typeOf(mmio_ptr) == &volatile u8);
1590 assert(@typeOf(mmio_ptr) == *volatile u8);
14851591}
14861592
1487test "nullable pointers" {
1488 // Pointers cannot be null. If you want a null pointer, use the nullable
1489 // prefix `?` to make the pointer type nullable.
1490 var ptr: ?&i32 = null;
1593test "optional pointers" {
1594 // Pointers cannot be null. If you want a null pointer, use the optional
1595 // prefix `?` to make the pointer type optional.
1596 var ptr: ?*i32 = null;
14911597
14921598 var x: i32 = 1;
14931599 ptr = &x;
14941600
1495 assert(*??ptr == 1);
1601 assert(ptr.?.* == 1);
14961602
1497 // Nullable pointers are the same size as normal pointers, because pointer
1603 // Optional pointers are the same size as normal pointers, because pointer
14981604 // value 0 is used as the null value.
1499 assert(@sizeOf(?&i32) == @sizeOf(&i32));
1605 assert(@sizeOf(?*i32) == @sizeOf(*i32));
15001606}
15011607
15021608test "pointer casting" {
15031609 // To convert one pointer type to another, use @ptrCast. This is an unsafe
15041610 // operation that Zig cannot protect you against. Use @ptrCast only when other
15051611 // conversions are not possible.
1506 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
1507 const u32_ptr = @ptrCast(&const u32, &bytes[0]);
1508 assert(*u32_ptr == 0x12121212);
1612 const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
1613 const u32_ptr = @ptrCast(*const u32, &bytes[0]);
1614 assert(u32_ptr.* == 0x12121212);
15091615
15101616 // Even this example is contrived - there are better ways to do the above than
15111617 // pointer casting. For example, using a slice narrowing cast:
1512 const u32_value = ([]const u32)(bytes[0..])[0];
1618 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
15131619 assert(u32_value == 0x12121212);
15141620
15151621 // And even another way, the most straightforward way to do it:
......@@ -1518,7 +1624,7 @@ test "pointer casting" {
15181624
15191625test "pointer child type" {
15201626 // pointer types have a `child` field which tells you the type they point to.
1521 assert((&u32).Child == u32);
1627 assert((*u32).Child == u32);
15221628}
15231629 {#code_end#}
15241630 {#header_open|Alignment#}
......@@ -1543,15 +1649,15 @@ const builtin = @import("builtin");
15431649test "variable alignment" {
15441650 var x: i32 = 1234;
15451651 const align_of_i32 = @alignOf(@typeOf(x));
1546 assert(@typeOf(&x) == &i32);
1547 assert(&i32 == &align(align_of_i32) i32);
1652 assert(@typeOf(&x) == *i32);
1653 assert(*i32 == *align(align_of_i32) i32);
15481654 if (builtin.arch == builtin.Arch.x86_64) {
1549 assert((&i32).alignment == 4);
1655 assert((*i32).alignment == 4);
15501656 }
15511657}
15521658 {#code_end#}
1553 <p>In the same way that a <code>&amp;i32</code> can be implicitly cast to a
1554 <code>&amp;const i32</code>, a pointer with a larger alignment can be implicitly
1659 <p>In the same way that a <code>*i32</code> can be {#link|implicitly cast|Implicit Casts#} to a
1660 <code>*const i32</code>, a pointer with a larger alignment can be implicitly
15551661 cast to a pointer with a smaller alignment, but not vice versa.
15561662 </p>
15571663 <p>
......@@ -1565,8 +1671,8 @@ var foo: u8 align(4) = 100;
15651671
15661672test "global variable alignment" {
15671673 assert(@typeOf(&foo).alignment == 4);
1568 assert(@typeOf(&foo) == &align(4) u8);
1569 const slice = (&foo)[0..1];
1674 assert(@typeOf(&foo) == *align(4) u8);
1675 const slice = (*[1]u8)(&foo)[0..];
15701676 assert(@typeOf(slice) == []align(4) u8);
15711677}
15721678
......@@ -1592,13 +1698,13 @@ test "function alignment" {
15921698const assert = @import("std").debug.assert;
15931699
15941700test "pointer alignment safety" {
1595 var array align(4) = []u32{0x11111111, 0x11111111};
1596 const bytes = ([]u8)(array[0..]);
1701 var array align(4) = []u32{ 0x11111111, 0x11111111 };
1702 const bytes = @sliceToBytes(array[0..]);
15971703 assert(foo(bytes) == 0x11111111);
15981704}
15991705fn foo(bytes: []u8) u32 {
16001706 const slice4 = bytes[1..5];
1601 const int_slice = ([]u32)(@alignCast(4, slice4));
1707 const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
16021708 return int_slice[0];
16031709}
16041710 {#code_end#}
......@@ -1610,10 +1716,10 @@ fn foo(bytes: []u8) u32 {
16101716 <code>u8</code> can alias any memory.
16111717 </p>
16121718 <p>As an example, this code produces undefined behavior:</p>
1613 <pre><code class="zig">*@ptrCast(&amp;u32, f32(12.34))</code></pre>
1719 <pre><code class="zig">@ptrCast(*u32, f32(12.34)).*</code></pre>
16141720 <p>Instead, use {#link|@bitCast#}:
16151721 <pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>
1616 <p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p>
1722 <p>As an added benefit, the <code>@bitCast</code> version works at compile-time.</p>
16171723 {#see_also|Slices|Memory#}
16181724 {#header_close#}
16191725 {#header_close#}
......@@ -1622,18 +1728,27 @@ fn foo(bytes: []u8) u32 {
16221728const assert = @import("std").debug.assert;
16231729
16241730test "basic slices" {
1625 var array = []i32{1, 2, 3, 4};
1731 var array = []i32{ 1, 2, 3, 4 };
16261732 // A slice is a pointer and a length. The difference between an array and
16271733 // a slice is that the array's length is part of the type and known at
16281734 // compile-time, whereas the slice's length is known at runtime.
16291735 // Both can be accessed with the `len` field.
16301736 const slice = array[0..array.len];
1631 assert(slice.ptr == &array[0]);
1737 assert(&slice[0] == &array[0]);
16321738 assert(slice.len == array.len);
16331739
1740 // Using the address-of operator on a slice gives a pointer to a single
1741 // item, while using the `ptr` field gives an unknown length pointer.
1742 assert(@typeOf(slice.ptr) == [*]i32);
1743 assert(@typeOf(&slice[0]) == *i32);
1744 assert(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0]));
1745
16341746 // Slices have array bounds checking. If you try to access something out
16351747 // of bounds, you'll get a safety check failure:
16361748 slice[10] += 1;
1749
1750 // Note that `slice.ptr` does not invoke safety checking, while `&slice[0]`
1751 // asserts that the slice has len >= 1.
16371752}
16381753 {#code_end#}
16391754 <p>This is one reason we prefer slices to pointers.</p>
......@@ -1663,7 +1778,7 @@ test "using slices for strings" {
16631778
16641779test "slice pointer" {
16651780 var array: [10]u8 = undefined;
1666 const ptr = &array[0];
1781 const ptr = &array;
16671782
16681783 // You can use slicing syntax to convert a pointer into a slice:
16691784 const slice = ptr[0..5];
......@@ -1681,8 +1796,8 @@ test "slice pointer" {
16811796test "slice widening" {
16821797 // Zig supports slice widening and slice narrowing. Cast a slice of u8
16831798 // to a slice of anything else, and Zig will perform the length conversion.
1684 const array align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
1685 const slice = ([]const u32)(array[0..]);
1799 const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
1800 const slice = @bytesToSlice(u32, array[0..]);
16861801 assert(slice.len == 2);
16871802 assert(slice[0] == 0x12121212);
16881803 assert(slice[1] == 0x13131313);
......@@ -1736,7 +1851,7 @@ const Vec3 = struct {
17361851 };
17371852 }
17381853
1739 pub fn dot(self: &const Vec3, other: &const Vec3) f32 {
1854 pub fn dot(self: *const Vec3, other: *const Vec3) f32 {
17401855 return self.x * other.x + self.y * other.y + self.z * other.z;
17411856 }
17421857};
......@@ -1768,7 +1883,7 @@ test "struct namespaced variable" {
17681883
17691884// struct field order is determined by the compiler for optimal performance.
17701885// however, you can still calculate a struct base pointer given a field pointer:
1771fn setYBasedOnX(x: &f32, y: f32) void {
1886fn setYBasedOnX(x: *f32, y: f32) void {
17721887 const point = @fieldParentPtr(Point, "x", x);
17731888 point.y = y;
17741889}
......@@ -1786,13 +1901,13 @@ test "field parent pointer" {
17861901fn LinkedList(comptime T: type) type {
17871902 return struct {
17881903 pub const Node = struct {
1789 prev: ?&Node,
1790 next: ?&Node,
1904 prev: ?*Node,
1905 next: ?*Node,
17911906 data: T,
17921907 };
17931908
1794 first: ?&Node,
1795 last: ?&Node,
1909 first: ?*Node,
1910 last: ?*Node,
17961911 len: usize,
17971912 };
17981913}
......@@ -1824,7 +1939,7 @@ test "linked list" {
18241939 .last = &node,
18251940 .len = 1,
18261941 };
1827 assert((??list2.first).data == 1234);
1942 assert(list2.first.?.data == 1234);
18281943}
18291944 {#code_end#}
18301945 {#see_also|comptime|@fieldParentPtr#}
......@@ -1854,9 +1969,9 @@ const Value = enum(u2) {
18541969// Now you can cast between u2 and Value.
18551970// The ordinal value starts from 0, counting up for each member.
18561971test "enum ordinal value" {
1857 assert(u2(Value.Zero) == 0);
1858 assert(u2(Value.One) == 1);
1859 assert(u2(Value.Two) == 2);
1972 assert(@enumToInt(Value.Zero) == 0);
1973 assert(@enumToInt(Value.One) == 1);
1974 assert(@enumToInt(Value.Two) == 2);
18601975}
18611976
18621977// You can override the ordinal value for an enum.
......@@ -1866,9 +1981,9 @@ const Value2 = enum(u32) {
18661981 Million = 1000000,
18671982};
18681983test "set enum ordinal value" {
1869 assert(u32(Value2.Hundred) == 100);
1870 assert(u32(Value2.Thousand) == 1000);
1871 assert(u32(Value2.Million) == 1000000);
1984 assert(@enumToInt(Value2.Hundred) == 100);
1985 assert(@enumToInt(Value2.Thousand) == 1000);
1986 assert(@enumToInt(Value2.Million) == 1000000);
18721987}
18731988
18741989// Enums can have methods, the same as structs and unions.
......@@ -2039,8 +2154,8 @@ const Variant = union(enum) {
20392154 Int: i32,
20402155 Bool: bool,
20412156
2042 fn truthy(self: &const Variant) bool {
2043 return switch (*self) {
2157 fn truthy(self: *const Variant) bool {
2158 return switch (self.*) {
20442159 Variant.Int => |x_int| x_int != 0,
20452160 Variant.Bool => |x_bool| x_bool,
20462161 };
......@@ -2151,7 +2266,7 @@ test "switch enum" {
21512266
21522267 // A reference to the matched value can be obtained using `*` syntax.
21532268 Item.C => |*item| blk: {
2154 (*item).x += 1;
2269 item.*.x += 1;
21552270 break :blk 6;
21562271 },
21572272
......@@ -2176,7 +2291,7 @@ test "switch inside function" {
21762291 // On an OS other than fuchsia, block is not even analyzed,
21772292 // so this compile error is not triggered.
21782293 // On fuchsia this compile error would be triggered.
2179 @compileError("windows not supported");
2294 @compileError("fuchsia not supported");
21802295 },
21812296 else => {},
21822297 }
......@@ -2185,21 +2300,28 @@ test "switch inside function" {
21852300 {#see_also|comptime|enum|@compileError|Compile Variables#}
21862301 {#header_close#}
21872302 {#header_open|while#}
2303 <p>
2304 A while loop is used to repeatedly execute an expression until
2305 some condition is no longer true.
2306 </p>
21882307 {#code_begin|test|while#}
21892308const assert = @import("std").debug.assert;
21902309
21912310test "while basic" {
2192 // A while loop is used to repeatedly execute an expression until
2193 // some condition is no longer true.
21942311 var i: usize = 0;
21952312 while (i < 10) {
21962313 i += 1;
21972314 }
21982315 assert(i == 10);
21992316}
2317 {#code_end#}
2318 <p>
2319 Use <code>break</code> to exit a while loop early.
2320 </p>
2321 {#code_begin|test|while#}
2322const assert = @import("std").debug.assert;
22002323
22012324test "while break" {
2202 // You can use break to exit a while loop early.
22032325 var i: usize = 0;
22042326 while (true) {
22052327 if (i == 10)
......@@ -2208,9 +2330,14 @@ test "while break" {
22082330 }
22092331 assert(i == 10);
22102332}
2333 {#code_end#}
2334 <p>
2335 Use <code>continue</code> to jump back to the beginning of the loop.
2336 </p>
2337 {#code_begin|test|while#}
2338const assert = @import("std").debug.assert;
22112339
22122340test "while continue" {
2213 // You can use continue to jump back to the beginning of the loop.
22142341 var i: usize = 0;
22152342 while (true) {
22162343 i += 1;
......@@ -2220,25 +2347,42 @@ test "while continue" {
22202347 }
22212348 assert(i == 10);
22222349}
2350 {#code_end#}
2351 <p>
2352 While loops support a continue expression which is executed when the loop
2353 is continued. The <code>continue</code> keyword respects this expression.
2354 </p>
2355 {#code_begin|test|while#}
2356const assert = @import("std").debug.assert;
22232357
2224test "while loop continuation expression" {
2225 // You can give an expression to the while loop to execute when
2226 // the loop is continued. This is respected by the continue control flow.
2358test "while loop continue expression" {
22272359 var i: usize = 0;
22282360 while (i < 10) : (i += 1) {}
22292361 assert(i == 10);
22302362}
22312363
2232test "while loop continuation expression, more complicated" {
2233 // More complex blocks can be used as an expression in the loop continue
2234 // expression.
2235 var i1: usize = 1;
2236 var j1: usize = 1;
2237 while (i1 * j1 < 2000) : ({ i1 *= 2; j1 *= 3; }) {
2238 const my_ij1 = i1 * j1;
2239 assert(my_ij1 < 2000);
2364test "while loop continue expression, more complicated" {
2365 var i: usize = 1;
2366 var j: usize = 1;
2367 while (i * j < 2000) : ({ i *= 2; j *= 3; }) {
2368 const my_ij = i * j;
2369 assert(my_ij < 2000);
22402370 }
22412371}
2372 {#code_end#}
2373 <p>
2374 While loops are expressions. The result of the expression is the
2375 result of the <code>else</code> clause of a while loop, which is executed when
2376 the condition of the while loop is tested as false.
2377 </p>
2378 <p>
2379 <code>break</code>, like <code>return</code>, accepts a value
2380 parameter. This is the result of the <code>while</code> expression.
2381 When you <code>break</code> from a while loop, the <code>else</code> branch is not
2382 evaluated.
2383 </p>
2384 {#code_begin|test|while#}
2385const assert = @import("std").debug.assert;
22422386
22432387test "while else" {
22442388 assert(rangeHasNumber(0, 10, 5));
......@@ -2247,24 +2391,31 @@ test "while else" {
22472391
22482392fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
22492393 var i = begin;
2250 // While loops are expressions. The result of the expression is the
2251 // result of the else clause of a while loop, which is executed when
2252 // the condition of the while loop is tested as false.
22532394 return while (i < end) : (i += 1) {
22542395 if (i == number) {
2255 // break expressions, like return expressions, accept a value
2256 // parameter. This is the result of the while expression.
2257 // When you break from a while loop, the else branch is not
2258 // evaluated.
22592396 break true;
22602397 }
22612398 } else false;
22622399}
2400 {#code_end#}
2401 {#header_open|while with Optionals#}
2402 <p>
2403 Just like {#link|if#} expressions, while loops can take an optional as the
2404 condition and capture the payload. When {#link|null#} is encountered the loop
2405 exits.
2406 </p>
2407 <p>
2408 When the <code>|x|</code> syntax is present on a <code>while</code> expression,
2409 the while condition must have an {#link|Optional Type#}.
2410 </p>
2411 <p>
2412 The <code>else</code> branch is allowed on optional iteration. In this case, it will
2413 be executed on the first null value encountered.
2414 </p>
2415 {#code_begin|test|while#}
2416const assert = @import("std").debug.assert;
22632417
22642418test "while null capture" {
2265 // Just like if expressions, while loops can take a nullable as the
2266 // condition and capture the payload. When null is encountered the loop
2267 // exits.
22682419 var sum1: u32 = 0;
22692420 numbers_left = 3;
22702421 while (eventuallyNullSequence()) |value| {
......@@ -2272,8 +2423,6 @@ test "while null capture" {
22722423 }
22732424 assert(sum1 == 3);
22742425
2275 // The else branch is allowed on nullable iteration. In this case, it will
2276 // be executed on the first null value encountered.
22772426 var sum2: u32 = 0;
22782427 numbers_left = 3;
22792428 while (eventuallyNullSequence()) |value| {
......@@ -2281,18 +2430,6 @@ test "while null capture" {
22812430 } else {
22822431 assert(sum1 == 3);
22832432 }
2284
2285 // Just like if expressions, while loops can also take an error union as
2286 // the condition and capture the payload or the error code. When the
2287 // condition results in an error code the else branch is evaluated and
2288 // the loop is finished.
2289 var sum3: u32 = 0;
2290 numbers_left = 3;
2291 while (eventuallyErrorSequence()) |value| {
2292 sum3 += value;
2293 } else |err| {
2294 assert(err == error.ReachedZero);
2295 }
22962433}
22972434
22982435var numbers_left: u32 = undefined;
......@@ -2303,17 +2440,54 @@ fn eventuallyNullSequence() ?u32 {
23032440 };
23042441}
23052442
2443 {#code_end#}
2444 {#header_close#}
2445
2446 {#header_open|while with Error Unions#}
2447 <p>
2448 Just like {#link|if#} expressions, while loops can take an error union as
2449 the condition and capture the payload or the error code. When the
2450 condition results in an error code the else branch is evaluated and
2451 the loop is finished.
2452 </p>
2453 <p>
2454 When the <code>else |x|</code> syntax is present on a <code>while</code> expression,
2455 the while condition must have an {#link|Error Union Type#}.
2456 </p>
2457 {#code_begin|test|while#}
2458const assert = @import("std").debug.assert;
2459
2460test "while error union capture" {
2461 var sum1: u32 = 0;
2462 numbers_left = 3;
2463 while (eventuallyErrorSequence()) |value| {
2464 sum1 += value;
2465 } else |err| {
2466 assert(err == error.ReachedZero);
2467 }
2468}
2469
2470var numbers_left: u32 = undefined;
2471
23062472fn eventuallyErrorSequence() error!u32 {
23072473 return if (numbers_left == 0) error.ReachedZero else blk: {
23082474 numbers_left -= 1;
23092475 break :blk numbers_left;
23102476 };
23112477}
2478 {#code_end#}
2479 {#header_close#}
2480
2481 {#header_open|inline while#}
2482 <p>
2483 While loops can be inlined. This causes the loop to be unrolled, which
2484 allows the code to do some things which only work at compile time,
2485 such as use types as first class values.
2486 </p>
2487 {#code_begin|test#}
2488const assert = @import("std").debug.assert;
23122489
23132490test "inline while loop" {
2314 // While loops can be inlined. This causes the loop to be unrolled, which
2315 // allows the code to do some things which only work at compile time,
2316 // such as use types as first class values.
23172491 comptime var i = 0;
23182492 var sum: usize = 0;
23192493 inline while (i < 3) : (i += 1) {
......@@ -2332,7 +2506,17 @@ fn typeNameLength(comptime T: type) usize {
23322506 return @typeName(T).len;
23332507}
23342508 {#code_end#}
2335 {#see_also|if|Nullables|Errors|comptime|unreachable#}
2509 <p>
2510 It is recommended to use <code>inline</code> loops only for one of these reasons:
2511 </p>
2512 <ul>
2513 <li>You need the loop to execute at {#link|comptime#} for the semantics to work.</li>
2514 <li>
2515 You have a benchmark to prove that forcibly unrolling the loop in this way is measurably faster.
2516 </li>
2517 </ul>
2518 {#header_close#}
2519 {#see_also|if|Optionals|Errors|comptime|unreachable#}
23362520 {#header_close#}
23372521 {#header_open|for#}
23382522 {#code_begin|test|for#}
......@@ -2363,7 +2547,7 @@ test "for basics" {
23632547 var sum2: i32 = 0;
23642548 for (items) |value, i| {
23652549 assert(@typeOf(i) == usize);
2366 sum2 += i32(i);
2550 sum2 += @intCast(i32, i);
23672551 }
23682552 assert(sum2 == 10);
23692553}
......@@ -2374,7 +2558,7 @@ test "for reference" {
23742558 // Iterate over the slice by reference by
23752559 // specifying that the capture value is a pointer.
23762560 for (items) |*value| {
2377 *value += 1;
2561 value.* += 1;
23782562 }
23792563
23802564 assert(items[0] == 4);
......@@ -2392,22 +2576,27 @@ test "for else" {
23922576 if (value == null) {
23932577 break 9;
23942578 } else {
2395 sum += ??value;
2579 sum += value.?;
23962580 }
23972581 } else blk: {
23982582 assert(sum == 7);
23992583 break :blk sum;
24002584 };
24012585}
2402
2586 {#code_end#}
2587 {#header_open|inline for#}
2588 <p>
2589 For loops can be inlined. This causes the loop to be unrolled, which
2590 allows the code to do some things which only work at compile time,
2591 such as use types as first class values.
2592 The capture value and iterator value of inlined for loops are
2593 compile-time known.
2594 </p>
2595 {#code_begin|test#}
2596const assert = @import("std").debug.assert;
24032597
24042598test "inline for loop" {
24052599 const nums = []i32{2, 4, 6};
2406 // For loops can be inlined. This causes the loop to be unrolled, which
2407 // allows the code to do some things which only work at compile time,
2408 // such as use types as first class values.
2409 // The capture value and iterator value of inlined for loops are
2410 // compile-time known.
24112600 var sum: usize = 0;
24122601 inline for (nums) |i| {
24132602 const T = switch (i) {
......@@ -2425,6 +2614,16 @@ fn typeNameLength(comptime T: type) usize {
24252614 return @typeName(T).len;
24262615}
24272616 {#code_end#}
2617 <p>
2618 It is recommended to use <code>inline</code> loops only for one of these reasons:
2619 </p>
2620 <ul>
2621 <li>You need the loop to execute at {#link|comptime#} for the semantics to work.</li>
2622 <li>
2623 You have a benchmark to prove that forcibly unrolling the loop in this way is measurably faster.
2624 </li>
2625 </ul>
2626 {#header_close#}
24282627 {#see_also|while|comptime|Arrays|Slices#}
24292628 {#header_close#}
24302629 {#header_open|if#}
......@@ -2453,7 +2652,7 @@ test "if boolean" {
24532652 assert(result == 47);
24542653}
24552654
2456test "if nullable" {
2655test "if optional" {
24572656 // If expressions test for null.
24582657
24592658 const a: ?u32 = 0;
......@@ -2483,7 +2682,7 @@ test "if nullable" {
24832682 // Access the value by reference using a pointer capture.
24842683 var c: ?u32 = 3;
24852684 if (c) |*value| {
2486 *value = 2;
2685 value.* = 2;
24872686 }
24882687
24892688 if (c) |value| {
......@@ -2524,7 +2723,7 @@ test "if error union" {
25242723 // Access the value by reference using a pointer capture.
25252724 var c: error!u32 = 3;
25262725 if (c) |*value| {
2527 *value = 9;
2726 value.* = 9;
25282727 } else |err| {
25292728 unreachable;
25302729 }
......@@ -2536,7 +2735,7 @@ test "if error union" {
25362735 }
25372736}
25382737 {#code_end#}
2539 {#see_also|Nullables|Errors#}
2738 {#see_also|Optionals|Errors#}
25402739 {#header_close#}
25412740 {#header_open|defer#}
25422741 {#code_begin|test|defer#}
......@@ -2771,39 +2970,30 @@ fn foo() void { }
27712970 {#code_end#}
27722971 {#header_open|Pass-by-value Parameters#}
27732972 <p>
2774 In Zig, structs, unions, and enums with payloads cannot be passed by value
2775 to a function.
2973 In Zig, structs, unions, and enums with payloads can be passed directly to a function:
27762974 </p>
2777 {#code_begin|test_err|not copyable; cannot pass by value#}
2778const Foo = struct {
2975 {#code_begin|test#}
2976const Point = struct {
27792977 x: i32,
2978 y: i32,
27802979};
27812980
2782fn bar(foo: Foo) void {}
2783
2784test "pass aggregate type by value to function" {
2785 bar(Foo {.x = 12,});
2981fn foo(point: Point) i32 {
2982 return point.x + point.y;
27862983}
2787 {#code_end#}
2788 <p>
2789 Instead, one must use <code>&amp;const</code>. Zig allows implicitly casting something
2790 to a const pointer to it:
2791 </p>
2792 {#code_begin|test#}
2793const Foo = struct {
2794 x: i32,
2795};
27962984
2797fn bar(foo: &const Foo) void {}
2985const assert = @import("std").debug.assert;
27982986
2799test "implicitly cast to const pointer" {
2800 bar(Foo {.x = 12,});
2987test "pass aggregate type by non-copy value to function" {
2988 assert(foo(Point{ .x = 1, .y = 2 }) == 3);
28012989}
28022990 {#code_end#}
28032991 <p>
2804 However,
2805 the C ABI does allow passing structs and unions by value. So functions which
2806 use the C calling convention may pass structs and unions by value.
2992 In this case, the value may be passed by reference, or by value, whichever way
2993 Zig decides will be faster.
2994 </p>
2995 <p>
2996 For extern functions, Zig follows the C ABI for passing structs and unions by value.
28072997 </p>
28082998 {#header_close#}
28092999 {#header_open|Function Reflection#}
......@@ -2827,10 +3017,10 @@ test "fn reflection" {
28273017 </p>
28283018 <p>
28293019 The number of unique error values across the entire compilation should determine the size of the error set type.
2830 However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/zig-lang/zig/issues/786">#768</a>.
3020 However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/ziglang/zig/issues/786">#768</a>.
28313021 </p>
28323022 <p>
2833 You can implicitly cast an error from a subset to its superset:
3023 You can {#link|implicitly cast|Implicit Casts#} an error from a subset to its superset:
28343024 </p>
28353025 {#code_begin|test#}
28363026const std = @import("std");
......@@ -2963,7 +3153,7 @@ test "parse u64" {
29633153 <p>
29643154 Within the function definition, you can see some return statements that return
29653155 an error, and at the bottom a return statement that returns a <code>u64</code>.
2966 Both types implicitly cast to <code>error!u64</code>.
3156 Both types {#link|implicitly cast|Implicit Casts#} to <code>error!u64</code>.
29673157 </p>
29683158 <p>
29693159 What it looks like to use this function varies depending on what you're
......@@ -2975,6 +3165,7 @@ test "parse u64" {
29753165 <li>You know with complete certainty it will not return an error, so want to unconditionally unwrap it.</li>
29763166 <li>You want to take a different action for each possible error.</li>
29773167 </ul>
3168 {#header_open|catch#}
29783169 <p>If you want to provide a default value, you can use the <code>catch</code> binary operator:</p>
29793170 {#code_begin|syntax#}
29803171fn doAThing(str: []u8) void {
......@@ -2987,6 +3178,8 @@ fn doAThing(str: []u8) void {
29873178 a default value of 13. The type of the right hand side of the binary <code>catch</code> operator must
29883179 match the unwrapped error union type, or be of type <code>noreturn</code>.
29893180 </p>
3181 {#header_close#}
3182 {#header_open|try#}
29903183 <p>Let's say you wanted to return the error if you got one, otherwise continue with the
29913184 function logic:</p>
29923185 {#code_begin|syntax#}
......@@ -3009,6 +3202,7 @@ fn doAThing(str: []u8) !void {
30093202 from the current function with the same error. Otherwise, the expression results in
30103203 the unwrapped value.
30113204 </p>
3205 {#header_close#}
30123206 <p>
30133207 Maybe you know with complete certainty that an expression will never be an error.
30143208 In this case you can do this:
......@@ -3023,7 +3217,7 @@ fn doAThing(str: []u8) !void {
30233217 </p>
30243218 <p>
30253219 Finally, you may want to take a different action for every situation. For that, we combine
3026 the <code>if</code> and <code>switch</code> expression:
3220 the {#link|if#} and {#link|switch#} expression:
30273221 </p>
30283222 {#code_begin|syntax#}
30293223fn doAThing(str: []u8) void {
......@@ -3038,9 +3232,10 @@ fn doAThing(str: []u8) void {
30383232 }
30393233}
30403234 {#code_end#}
3235 {#header_open|errdefer#}
30413236 <p>
30423237 The other component to error handling is defer statements.
3043 In addition to an unconditional <code>defer</code>, Zig has <code>errdefer</code>,
3238 In addition to an unconditional {#link|defer#}, Zig has <code>errdefer</code>,
30443239 which evaluates the deferred expression on block exit path if and only if
30453240 the function returned with an error from the block.
30463241 </p>
......@@ -3054,7 +3249,7 @@ fn createFoo(param: i32) !Foo {
30543249 // but we want to return it if the function succeeds.
30553250 errdefer deallocateFoo(foo);
30563251
3057 const tmp_buf = allocateTmpBuffer() ?? return error.OutOfMemory;
3252 const tmp_buf = allocateTmpBuffer() orelse return error.OutOfMemory;
30583253 // tmp_buf is truly a temporary resource, and we for sure want to clean it up
30593254 // before this block leaves scope
30603255 defer deallocateTmpBuffer(tmp_buf);
......@@ -3071,6 +3266,7 @@ fn createFoo(param: i32) !Foo {
30713266 the verbosity and cognitive overhead of trying to make sure every exit path
30723267 is covered. The deallocation code is always directly following the allocation code.
30733268 </p>
3269 {#header_close#}
30743270 <p>
30753271 A couple of other tidbits about error handling:
30763272 </p>
......@@ -3109,106 +3305,357 @@ test "error union" {
31093305 comptime assert(@typeOf(foo).ErrorSet == error);
31103306}
31113307 {#code_end#}
3112 <p>TODO the <code>||</code> operator for error sets</p>
3113 {#header_open|Inferred Error Sets#}
3114 <p>TODO</p>
3115 {#header_close#}
3116 {#header_close#}
3117 {#header_open|Error Return Traces#}
3118 <p>TODO</p>
3119 {#header_close#}
3120 {#header_close#}
3121 {#header_open|Nullables#}
3308 {#header_open|Merging Error Sets#}
31223309 <p>
3123 One area that Zig provides safety without compromising efficiency or
3124 readability is with the nullable type.
3310 Use the <code>||</code> operator to merge two error sets together. The resulting
3311 error set contains the errors of both error sets. Doc comments from the left-hand
3312 side override doc comments from the right-hand side. In this example, the doc
3313 comments for <code>C.PathNotFound</code> is <code>A doc comment</code>.
31253314 </p>
31263315 <p>
3127 The question mark symbolizes the nullable type. You can convert a type to a nullable
3128 type by putting a question mark in front of it, like this:
3316 This is especially useful for functions which return different error sets depending
3317 on {#link|comptime#} branches. For example, the Zig standard library uses
3318 <code>LinuxFileOpenError || WindowsFileOpenError</code> for the error set of opening
3319 files.
31293320 </p>
3130 {#code_begin|syntax#}
3131// normal integer
3132const normal_int: i32 = 1234;
3321 {#code_begin|test#}
3322const A = error{
3323 NotDir,
3324
3325 /// A doc comment
3326 PathNotFound,
3327};
3328const B = error{
3329 OutOfMemory,
3330
3331 /// B doc comment
3332 PathNotFound,
3333};
3334
3335const C = A || B;
3336
3337fn foo() C!void {
3338 return error.NotDir;
3339}
31333340
3134// nullable integer
3135const nullable_int: ?i32 = 5678;
3341test "merge error sets" {
3342 if (foo()) {
3343 @panic("unexpected");
3344 } else |err| switch (err) {
3345 error.OutOfMemory => @panic("unexpected"),
3346 error.PathNotFound => @panic("unexpected"),
3347 error.NotDir => {},
3348 }
3349}
31363350 {#code_end#}
3351 {#header_close#}
3352 {#header_open|Inferred Error Sets#}
31373353 <p>
3138 Now the variable <code>nullable_int</code> could be an <code>i32</code>, or <code>null</code>.
3354 Because many functions in Zig return a possible error, Zig supports inferring the error set.
3355 To infer the error set for a function, use this syntax:
31393356 </p>
3357{#code_begin|test#}
3358// With an inferred error set
3359pub fn add_inferred(comptime T: type, a: T, b: T) !T {
3360 var answer: T = undefined;
3361 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
3362}
3363
3364// With an explicit error set
3365pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
3366 var answer: T = undefined;
3367 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
3368}
3369
3370const Error = error {
3371 Overflow,
3372};
3373
3374const std = @import("std");
3375
3376test "inferred error set" {
3377 if (add_inferred(u8, 255, 1)) |_| unreachable else |err| switch (err) {
3378 error.Overflow => {}, // ok
3379 }
3380}
3381{#code_end#}
31403382 <p>
3141 Instead of integers, let's talk about pointers. Null references are the source of many runtime
3142 exceptions, and even stand accused of being
3143 <a href="https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/">the worst mistake of computer science</a>.
3383 When a function has an inferred error set, that function becomes generic and thus it becomes
3384 trickier to do certain things with it, such as obtain a function pointer, or have an error
3385 set that is consistent across different build targets. Additionally, inferred error sets
3386 are incompatible with recursion.
31443387 </p>
3145 <p>Zig does not have them.</p>
31463388 <p>
3147 Instead, you can use a nullable pointer. This secretly compiles down to a normal pointer,
3148 since we know we can use 0 as the null value for the nullable type. But the compiler
3149 can check your work and make sure you don't assign null to something that can't be null.
3389 In these situations, it is recommended to use an explicit error set. You can generally start
3390 with an empty error set and let compile errors guide you toward completing the set.
31503391 </p>
31513392 <p>
3152 Typically the downside of not having null is that it makes the code more verbose to
3153 write. But, let's compare some equivalent C code and Zig code.
3393 These limitations may be overcome in a future version of Zig.
31543394 </p>
3395 {#header_close#}
3396 {#header_close#}
3397 {#header_open|Error Return Traces#}
31553398 <p>
3156 Task: call malloc, if the result is null, return null.
3399 Error Return Traces show all the points in the code that an error was returned to the calling function. This makes it practical to use {#link|try#} everywhere and then still be able to know what happened if an error ends up bubbling all the way out of your application.
31573400 </p>
3158 <p>C code</p>
3159 <pre><code class="cpp">// malloc prototype included for reference
3160void *malloc(size_t size);
3401 {#code_begin|exe_err#}
3402pub fn main() !void {
3403 try foo(12);
3404}
31613405
3162struct Foo *do_a_thing(void) {
3163 char *ptr = malloc(1234);
3164 if (!ptr) return NULL;
3165 // ...
3166}</code></pre>
3167 <p>Zig code</p>
3168 {#code_begin|syntax#}
3169// malloc prototype included for reference
3170extern fn malloc(size: size_t) ?&u8;
3406fn foo(x: i32) !void {
3407 if (x >= 5) {
3408 try bar();
3409 } else {
3410 try bang2();
3411 }
3412}
31713413
3172fn doAThing() ?&Foo {
3173 const ptr = malloc(1234) ?? return null;
3174 // ...
3414fn bar() !void {
3415 if (baz()) {
3416 try quux();
3417 } else |err| switch (err) {
3418 error.FileNotFound => try hello(),
3419 else => try another(),
3420 }
3421}
3422
3423fn baz() !void {
3424 try bang1();
3425}
3426
3427fn quux() !void {
3428 try bang2();
3429}
3430
3431fn hello() !void {
3432 try bang2();
3433}
3434
3435fn another() !void {
3436 try bang1();
3437}
3438
3439fn bang1() !void {
3440 return error.FileNotFound;
3441}
3442
3443fn bang2() !void {
3444 return error.PermissionDenied;
31753445}
31763446 {#code_end#}
31773447 <p>
3178 Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"
3179 is <code>&u8</code> <em>not</em> <code>?&u8</code>. The <code>??</code> operator
3180 unwrapped the nullable type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
3181 it is used in the function.
3448 Look closely at this example. This is no stack trace.
31823449 </p>
31833450 <p>
3184 The other form of checking against NULL you might see looks like this:
3451 You can see that the final error bubbled up was <code>PermissionDenied</code>,
3452 but the original error that started this whole thing was <code>FileNotFound</code>. In the <code>bar</code> function, the code handles the original error code,
3453 and then returns another one, from the switch statement. Error Return Traces make this clear, whereas a stack trace would look like this:
31853454 </p>
3186 <pre><code class="cpp">void do_a_thing(struct Foo *foo) {
3187 // do some stuff
3455 {#code_begin|exe_err#}
3456pub fn main() void {
3457 foo(12);
3458}
31883459
3189 if (foo) {
3190 do_something_with_foo(foo);
3460fn foo(x: i32) void {
3461 if (x >= 5) {
3462 bar();
3463 } else {
3464 bang2();
31913465 }
3466}
31923467
3193 // do some stuff
3194}</code></pre>
3195 <p>
3196 In Zig you can accomplish the same thing:
3197 </p>
3198 {#code_begin|syntax#}
3199fn doAThing(nullable_foo: ?&Foo) void {
3200 // do some stuff
3201
3202 if (nullable_foo) |foo| {
3203 doSomethingWithFoo(foo);
3468fn bar() void {
3469 if (baz()) {
3470 quux();
3471 } else {
3472 hello();
32043473 }
3474}
32053475
3206 // do some stuff
3476fn baz() bool {
3477 return bang1();
32073478}
3208 {#code_end#}
3209 <p>
3479
3480fn quux() void {
3481 bang2();
3482}
3483
3484fn hello() void {
3485 bang2();
3486}
3487
3488fn bang1() bool {
3489 return false;
3490}
3491
3492fn bang2() void {
3493 @panic("PermissionDenied");
3494}
3495 {#code_end#}
3496 <p>
3497 Here, the stack trace does not explain how the control
3498 flow in <code>bar</code> got to the <code>hello()</code> call.
3499 One would have to open a debugger or further instrument the application
3500 in order to find out. The error return trace, on the other hand,
3501 shows exactly how the error bubbled up.
3502 </p>
3503 <p>
3504 This debugging feature makes it easier to iterate quickly on code that
3505 robustly handles all error conditions. This means that Zig developers
3506 will naturally find themselves writing correct, robust code in order
3507 to increase their development pace.
3508 </p>
3509 <p>
3510 Error Return Traces are enabled by default in {#link|Debug#} and {#link|ReleaseSafe#} builds and disabled by default in {#link|ReleaseFast#} and {#link|ReleaseSmall#} builds.
3511 </p>
3512 <p>
3513 There are a few ways to activate this error return tracing feature:
3514 </p>
3515 <ul>
3516 <li>Return an error from main</li>
3517 <li>An error makes its way to <code>catch unreachable</code> and you have not overridden the default panic handler</li>
3518 <li>Use {#link|errorReturnTrace#} to access the current return trace. You can use <code>std.debug.dumpStackTrace</code> to print it. This function returns comptime-known {#link|null#} when building without error return tracing support.</li>
3519 </ul>
3520 {#header_open|Implementation Details#}
3521 <p>
3522 To analyze performance cost, there are two cases:
3523 </p>
3524 <ul>
3525 <li>when no errors are returned</li>
3526 <li>when returning errors</li>
3527 </ul>
3528 <p>
3529 For the case when no errors are returned, the cost is a single memory write operation, only in the first non-failable function in the call graph that calls a failable function, i.e. when a function returning <code>void</code> calls a function returning <code>error</code>.
3530 This is to initialize this struct in the stack memory:
3531 </p>
3532 {#code_begin|syntax#}
3533pub const StackTrace = struct {
3534 index: usize,
3535 instruction_addresses: [N]usize,
3536};
3537 {#code_end#}
3538 <p>
3539 Here, N is the maximum function call depth as determined by call graph analysis. Recursion is ignored and counts for 2.
3540 </p>
3541 <p>
3542 A pointer to <code>StackTrace</code> is passed as a secret parameter to every function that can return an error, but it's always the first parameter, so it can likely sit in a register and stay there.
3543 </p>
3544 <p>
3545 That's it for the path when no errors occur. It's practically free in terms of performance.
3546 </p>
3547 <p>
3548 When generating the code for a function that returns an error, just before the <code>return</code> statement (only for the <code>return</code> statements that return errors), Zig generates a call to this function:
3549 </p>
3550 {#code_begin|syntax#}
3551// marked as "no-inline" in LLVM IR
3552fn __zig_return_error(stack_trace: *StackTrace) void {
3553 stack_trace.instruction_addresses[stack_trace.index] = @returnAddress();
3554 stack_trace.index = (stack_trace.index + 1) % N;
3555}
3556 {#code_end#}
3557 <p>
3558 The cost is 2 math operations plus some memory reads and writes. The memory accessed is constrained and should remain cached for the duration of the error return bubbling.
3559 </p>
3560 <p>
3561 As for code size cost, 1 function call before a return statement is no big deal. Even so,
3562 I have <a href="https://github.com/ziglang/zig/issues/690">a plan</a> to make the call to
3563 <code>__zig_return_error</code> a tail call, which brings the code size cost down to actually zero. What is a return statement in code without error return tracing can become a jump instruction in code with error return tracing.
3564 </p>
3565 {#header_close#}
3566 {#header_close#}
3567 {#header_close#}
3568 {#header_open|Optionals#}
3569 <p>
3570 One area that Zig provides safety without compromising efficiency or
3571 readability is with the optional type.
3572 </p>
3573 <p>
3574 The question mark symbolizes the optional type. You can convert a type to an optional
3575 type by putting a question mark in front of it, like this:
3576 </p>
3577 {#code_begin|syntax#}
3578// normal integer
3579const normal_int: i32 = 1234;
3580
3581// optional integer
3582const optional_int: ?i32 = 5678;
3583 {#code_end#}
3584 <p>
3585 Now the variable <code>optional_int</code> could be an <code>i32</code>, or <code>null</code>.
3586 </p>
3587 <p>
3588 Instead of integers, let's talk about pointers. Null references are the source of many runtime
3589 exceptions, and even stand accused of being
3590 <a href="https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/">the worst mistake of computer science</a>.
3591 </p>
3592 <p>Zig does not have them.</p>
3593 <p>
3594 Instead, you can use an optional pointer. This secretly compiles down to a normal pointer,
3595 since we know we can use 0 as the null value for the optional type. But the compiler
3596 can check your work and make sure you don't assign null to something that can't be null.
3597 </p>
3598 <p>
3599 Typically the downside of not having null is that it makes the code more verbose to
3600 write. But, let's compare some equivalent C code and Zig code.
3601 </p>
3602 <p>
3603 Task: call malloc, if the result is null, return null.
3604 </p>
3605 <p>C code</p>
3606 <pre><code class="cpp">// malloc prototype included for reference
3607void *malloc(size_t size);
3608
3609struct Foo *do_a_thing(void) {
3610 char *ptr = malloc(1234);
3611 if (!ptr) return NULL;
3612 // ...
3613}</code></pre>
3614 <p>Zig code</p>
3615 {#code_begin|syntax#}
3616// malloc prototype included for reference
3617extern fn malloc(size: size_t) ?*u8;
3618
3619fn doAThing() ?*Foo {
3620 const ptr = malloc(1234) orelse return null;
3621 // ...
3622}
3623 {#code_end#}
3624 <p>
3625 Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"
3626 is <code>*u8</code> <em>not</em> <code>?*u8</code>. The <code>orelse</code> keyword
3627 unwrapped the optional type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
3628 it is used in the function.
3629 </p>
3630 <p>
3631 The other form of checking against NULL you might see looks like this:
3632 </p>
3633 <pre><code class="cpp">void do_a_thing(struct Foo *foo) {
3634 // do some stuff
3635
3636 if (foo) {
3637 do_something_with_foo(foo);
3638 }
3639
3640 // do some stuff
3641}</code></pre>
3642 <p>
3643 In Zig you can accomplish the same thing:
3644 </p>
3645 {#code_begin|syntax#}
3646fn doAThing(optional_foo: ?*Foo) void {
3647 // do some stuff
3648
3649 if (optional_foo) |foo| {
3650 doSomethingWithFoo(foo);
3651 }
3652
3653 // do some stuff
3654}
3655 {#code_end#}
3656 <p>
32103657 Once again, the notable thing here is that inside the if block,
3211 <code>foo</code> is no longer a nullable pointer, it is a pointer, which
3658 <code>foo</code> is no longer an optional pointer, it is a pointer, which
32123659 cannot be null.
32133660 </p>
32143661 <p>
......@@ -3218,42 +3665,306 @@ fn doAThing(nullable_foo: ?&Foo) void {
32183665 The optimizer can sometimes make better decisions knowing that pointer arguments
32193666 cannot be null.
32203667 </p>
3221 {#header_open|Nullable Type#}
3222 <p>A nullable is created by putting <code>?</code> in front of a type. You can use compile-time
3223 reflection to access the child type of a nullable:</p>
3668 {#header_open|Optional Type#}
3669 <p>An optional is created by putting <code>?</code> in front of a type. You can use compile-time
3670 reflection to access the child type of an optional:</p>
32243671 {#code_begin|test#}
32253672const assert = @import("std").debug.assert;
32263673
3227test "nullable type" {
3228 // Declare a nullable and implicitly cast from null:
3674test "optional type" {
3675 // Declare an optional and implicitly cast from null:
32293676 var foo: ?i32 = null;
32303677
3231 // Implicitly cast from child type of a nullable
3678 // Implicitly cast from child type of an optional
32323679 foo = 1234;
32333680
3234 // Use compile-time reflection to access the child type of the nullable:
3681 // Use compile-time reflection to access the child type of the optional:
32353682 comptime assert(@typeOf(foo).Child == i32);
32363683}
3684 {#code_end#}
3685 {#header_close#}
3686 {#header_open|null#}
3687 <p>
3688 Just like {#link|undefined#}, <code>null</code> has its own type, and the only way to use it is to
3689 cast it to a different type:
3690 </p>
3691 {#code_begin|syntax#}
3692const optional_value: ?i32 = null;
32373693 {#code_end#}
32383694 {#header_close#}
32393695 {#header_close#}
32403696 {#header_open|Casting#}
3241 <p>TODO: explain implicit vs explicit casting</p>
3242 <p>TODO: resolve peer types builtin</p>
3243 <p>TODO: truncate builtin</p>
3244 <p>TODO: bitcast builtin</p>
3245 <p>TODO: int to ptr builtin</p>
3246 <p>TODO: ptr to int builtin</p>
3247 <p>TODO: ptrcast builtin</p>
3248 <p>TODO: explain number literals vs concrete types</p>
3697 <p>
3698 A <strong>type cast</strong> converts a value of one type to another.
3699 Zig has {#link|Implicit Casts#} for conversions that are known to be completely safe and unambiguous,
3700 and {#link|Explicit Casts#} for conversions that one would not want to happen on accident.
3701 There is also a third kind of type conversion called {#link|Peer Type Resolution#} for
3702 the case when a result type must be decided given multiple operand types.
3703 </p>
3704 {#header_open|Implicit Casts#}
3705 <p>
3706 An implicit cast occurs when one type is expected, but different type is provided:
3707 </p>
3708 {#code_begin|test#}
3709test "implicit cast - variable declaration" {
3710 var a: u8 = 1;
3711 var b: u16 = a;
3712}
3713
3714test "implicit cast - function call" {
3715 var a: u8 = 1;
3716 foo(a);
3717}
3718
3719fn foo(b: u16) void {}
3720
3721test "implicit cast - invoke a type as a function" {
3722 var a: u8 = 1;
3723 var b = u16(a);
3724}
3725 {#code_end#}
3726 <p>
3727 Implicit casts are only allowed when it is completely unambiguous how to get from one type to another,
3728 and the transformation is guaranteed to be safe.
3729 </p>
3730 {#header_open|Implicit Cast: Stricter Qualification#}
3731 <p>
3732 Values which have the same representation at runtime can be cast to increase the strictness
3733 of the qualifiers, no matter how nested the qualifiers are:
3734 </p>
3735 <ul>
3736 <li><code>const</code> - non-const to const is allowed</li>
3737 <li><code>volatile</code> - non-volatile to volatile is allowed</li>
3738 <li><code>align</code> - bigger to smaller alignment is allowed </li>
3739 <li>{#link|error sets|Error Set Type#} to supersets is allowed</li>
3740 </ul>
3741 <p>
3742 These casts are no-ops at runtime since the value representation does not change.
3743 </p>
3744 {#code_begin|test#}
3745test "implicit cast - const qualification" {
3746 var a: i32 = 1;
3747 var b: *i32 = &a;
3748 foo(b);
3749}
3750
3751fn foo(a: *const i32) void {}
3752 {#code_end#}
3753 <p>
3754 In addition, pointers implicitly cast to const optional pointers:
3755 </p>
3756 {#code_begin|test#}
3757const std = @import("std");
3758const assert = std.debug.assert;
3759const mem = std.mem;
3760
3761test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
3762 const window_name = [1][*]const u8{c"window name"};
3763 const x: [*]const ?[*]const u8 = &window_name;
3764 assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
3765}
3766 {#code_end#}
3767 {#header_close#}
3768 {#header_open|Implicit Cast: Integer and Float Widening#}
3769 <p>
3770 {#link|Integers#} implicitly cast to integer types which can represent every value of the old type, and likewise
3771 {#link|Floats#} implicitly cast to float types which can represent every value of the old type.
3772 </p>
3773 {#code_begin|test#}
3774const std = @import("std");
3775const assert = std.debug.assert;
3776const mem = std.mem;
3777
3778test "integer widening" {
3779 var a: u8 = 250;
3780 var b: u16 = a;
3781 var c: u32 = b;
3782 var d: u64 = c;
3783 var e: u64 = d;
3784 var f: u128 = e;
3785 assert(f == a);
3786}
3787
3788test "implicit unsigned integer to signed integer" {
3789 var a: u8 = 250;
3790 var b: i16 = a;
3791 assert(b == 250);
3792}
3793
3794test "float widening" {
3795 var a: f16 = 12.34;
3796 var b: f32 = a;
3797 var c: f64 = b;
3798 var d: f128 = c;
3799 assert(d == a);
3800}
3801 {#code_end#}
3802 {#header_close#}
3803 {#header_open|Implicit Cast: Arrays#}
3804 <p>TODO: [N]T to []const T</p>
3805 <p>TODO: *const [N]T to []const T</p>
3806 <p>TODO: [N]T to *const []const T</p>
3807 <p>TODO: [N]T to ?[]const T</p>
3808 <p>TODO: *[N]T to []T</p>
3809 <p>TODO: *[N]T to [*]T</p>
3810 <p>TODO: *T to *[1]T</p>
3811 <p>TODO: [N]T to E![]const T</p>
3812 {#header_close#}
3813 {#header_open|Implicit Cast: Optionals#}
3814 <p>TODO: T to ?T</p>
3815 <p>TODO: T to E!?T</p>
3816 <p>TODO: null to ?T</p>
3817 {#header_close#}
3818 {#header_open|Implicit Cast: T to E!T#}
3819 <p>TODO</p>
3820 {#header_close#}
3821 {#header_open|Implicit Cast: E to E!T#}
3822 <p>TODO</p>
32493823 {#header_close#}
3824 {#header_open|Implicit Cast: comptime_int to *const integer#}
3825 <p>TODO</p>
3826 {#header_close#}
3827 {#header_open|Implicit Cast: comptime_float to *const float#}
3828 <p>TODO</p>
3829 {#header_close#}
3830 {#header_open|Implicit Cast: compile-time known numbers#}
3831 <p>TODO</p>
3832 {#header_close#}
3833 {#header_open|Implicit Cast: union to enum#}
3834 <p>TODO</p>
3835 {#header_close#}
3836 {#header_open|Implicit Cast: enum to union#}
3837 <p>TODO</p>
3838 {#header_close#}
3839 {#header_open|Implicit Cast: T to *T when @sizeOf(T) == 0#}
3840 <p>TODO</p>
3841 {#header_close#}
3842 {#header_open|Implicit Cast: undefined#}
3843 <p>TODO</p>
3844 {#header_close#}
3845 {#header_open|Implicit Cast: T to *const T#}
3846 <p>TODO</p>
3847 {#header_close#}
3848 {#header_close#}
3849
3850 {#header_open|Explicit Casts#}
3851 <p>
3852 Explicit casts are performed via {#link|Builtin Functions#}.
3853 Some explicit casts are safe; some are not.
3854 Some explicit casts perform language-level assertions; some do not.
3855 Some explicit casts are no-ops at runtime; some are not.
3856 </p>
3857 <ul>
3858 <li>{#link|@bitCast#} - change type but maintain bit representation</li>
3859 <li>{#link|@alignCast#} - make a pointer have more alignment</li>
3860 <li>{#link|@boolToInt#} - convert true to 1 and false to 0</li>
3861 <li>{#link|@bytesToSlice#} - convert a slice of bytes to a slice of another type</li>
3862 <li>{#link|@enumToInt#} - obtain the integer tag value of an enum or tagged union</li>
3863 <li>{#link|@errSetCast#} - convert to a smaller error set</li>
3864 <li>{#link|@errorToInt#} - obtain the integer value of an error code</li>
3865 <li>{#link|@floatCast#} - convert a larger float to a smaller float</li>
3866 <li>{#link|@floatToInt#} - obtain the integer part of a float value</li>
3867 <li>{#link|@intCast#} - convert between integer types</li>
3868 <li>{#link|@intToEnum#} - obtain an enum value based on its integer tag value</li>
3869 <li>{#link|@intToError#} - obtain an error code based on its integer value</li>
3870 <li>{#link|@intToFloat#} - convert an integer to a float value</li>
3871 <li>{#link|@intToPtr#} - convert an address to a pointer</li>
3872 <li>{#link|@ptrCast#} - convert between pointer types</li>
3873 <li>{#link|@ptrToInt#} - obtain the address of a pointer</li>
3874 <li>{#link|@sliceToBytes#} - convert a slice of anything to a slice of bytes</li>
3875 <li>{#link|@truncate#} - convert between integer types, chopping off bits</li>
3876 </ul>
3877 {#header_close#}
3878
3879 {#header_open|Peer Type Resolution#}
3880 <p>TODO</p>
3881 {#header_close#}
3882 {#header_close#}
3883
32503884 {#header_open|void#}
3251 <p>TODO: assigning void has no codegen</p>
3252 <p>TODO: hashmap with void becomes a set</p>
3253 <p>TODO: difference between c_void and void</p>
3254 <p>TODO: void is the default return value of functions</p>
3255 <p>TODO: functions require assigning the return value</p>
3885 <p>
3886 <code>void</code> represents a type that has no value. Code that makes use of void values is
3887 not included in the final generated code:
3888 </p>
3889 {#code_begin|syntax#}
3890export fn entry() void {
3891 var x: void = {};
3892 var y: void = {};
3893 x = y;
3894}
3895 {#code_end#}
3896 <p>When this turns into LLVM IR, there is no code generated in the body of <code>entry</code>,
3897 even in debug mode. For example, on x86_64:</p>
3898 <pre><code>0000000000000010 &lt;entry&gt;:
3899 10: 55 push %rbp
3900 11: 48 89 e5 mov %rsp,%rbp
3901 14: 5d pop %rbp
3902 15: c3 retq </code></pre>
3903 <p>These assembly instructions do not have any code associated with the void values -
3904 they only perform the function call prologue and epilog.</p>
3905 <p>
3906 <code>void</code> can be useful for instantiating generic types. For example, given a
3907 <code>Map(Key, Value)</code>, one can pass <code>void</code> for the <code>Value</code>
3908 type to make it into a <code>Set</code>:
3909 </p>
3910 {#code_begin|test#}
3911const std = @import("std");
3912const assert = std.debug.assert;
3913
3914test "turn HashMap into a set with void" {
3915 var map = std.HashMap(i32, void, hash_i32, eql_i32).init(std.debug.global_allocator);
3916 defer map.deinit();
3917
3918 _ = try map.put(1, {});
3919 _ = try map.put(2, {});
3920
3921 assert(map.contains(2));
3922 assert(!map.contains(3));
3923
3924 _ = map.remove(2);
3925 assert(!map.contains(2));
3926}
3927
3928fn hash_i32(x: i32) u32 {
3929 return @bitCast(u32, x);
3930}
3931
3932fn eql_i32(a: i32, b: i32) bool {
3933 return a == b;
3934}
3935 {#code_end#}
3936 <p>Note that this is different than using a dummy value for the hash map value.
3937 By using <code>void</code> as the type of the value, the hash map entry type has no value field, and
3938 thus the hash map takes up less space. Further, all the code that deals with storing and loading the
3939 value is deleted, as seen above.
3940 </p>
3941 <p>
3942 <code>void</code> is distinct from <code>c_void</code>, which is defined like this:
3943 <code>pub const c_void = @OpaqueType();</code>.
3944 <code>void</code> has a known size of 0 bytes, and <code>c_void</code> has an unknown, but non-zero, size.
3945 </p>
3946 <p>
3947 Expressions of type <code>void</code> are the only ones whose value can be ignored. For example:
3948 </p>
3949 {#code_begin|test_err|expression value is ignored#}
3950test "ignoring expression value" {
3951 foo();
3952}
3953
3954fn foo() i32 {
3955 return 1234;
3956}
3957 {#code_end#}
3958 <p>However, if the expression has type <code>void</code>:</p>
3959 {#code_begin|test#}
3960test "ignoring expression value" {
3961 foo();
3962}
3963
3964fn foo() void {}
3965 {#code_end#}
32563966 {#header_close#}
3967
32573968 {#header_open|this#}
32583969 <p>TODO: example of this referring to Self struct</p>
32593970 <p>TODO: example of this referring to recursion function</p>
......@@ -3672,7 +4383,7 @@ fn List(comptime T: type) type {
36724383 </p>
36734384 {#code_begin|syntax#}
36744385const Node = struct {
3675 next: &Node,
4386 next: *Node,
36764387 name: []u8,
36774388};
36784389 {#code_end#}
......@@ -3704,7 +4415,7 @@ pub fn main() void {
37044415
37054416 {#code_begin|syntax#}
37064417/// Calls print and then flushes the buffer.
3707pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) error!void {
4418pub fn printf(self: *OutStream, comptime format: []const u8, args: ...) error!void {
37084419 const State = enum {
37094420 Start,
37104421 OpenBrace,
......@@ -3776,7 +4487,7 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) error!vo
37764487 and emits a function that actually looks like this:
37774488 </p>
37784489 {#code_begin|syntax#}
3779pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) !void {
4490pub fn printf(self: *OutStream, arg0: i32, arg1: []const u8) !void {
37804491 try self.write("here is a string: '");
37814492 try self.printValue(arg0);
37824493 try self.write("' here is a number: ");
......@@ -3790,15 +4501,12 @@ pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) !void {
37904501 on the type:
37914502 </p>
37924503 {#code_begin|syntax#}
3793pub fn printValue(self: &OutStream, value: var) !void {
4504pub fn printValue(self: *OutStream, value: var) !void {
37944505 const T = @typeOf(value);
37954506 if (@isInteger(T)) {
37964507 return self.printInt(T, value);
37974508 } else if (@isFloat(T)) {
37984509 return self.printFloat(T, value);
3799 } else if (@canImplicitCast([]const u8, value)) {
3800 const casted_value = ([]const u8)(value);
3801 return self.write(casted_value);
38024510 } else {
38034511 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");
38044512 }
......@@ -3837,31 +4545,297 @@ pub fn main() void {
38374545}
38384546 {#code_end#}
38394547 <p>
3840 This works fine.
4548 This works fine.
4549 </p>
4550 <p>
4551 Zig does not special case string formatting in the compiler and instead exposes enough power to accomplish this
4552 task in userland. It does so without introducing another language on top of Zig, such as
4553 a macro language or a preprocessor language. It's Zig all the way down.
4554 </p>
4555 {#header_close#}
4556 {#see_also|inline while|inline for#}
4557 {#header_close#}
4558 {#header_open|Assembly#}
4559 <p>TODO: example of inline assembly</p>
4560 <p>TODO: example of module level assembly</p>
4561 <p>TODO: example of using inline assembly return value</p>
4562 <p>TODO: example of using inline assembly assigning values to variables</p>
4563 {#header_close#}
4564 {#header_open|Atomics#}
4565 <p>TODO: @fence()</p>
4566 <p>TODO: @atomic rmw</p>
4567 <p>TODO: builtin atomic memory ordering enum</p>
4568 {#header_close#}
4569 {#header_open|Coroutines#}
4570 <p>
4571 A coroutine is a generalization of a function.
4572 </p>
4573 <p>
4574 When you call a function, it creates a stack frame,
4575 and then the function runs until it reaches a return
4576 statement, and then the stack frame is destroyed.
4577 At the callsite, the next line of code does not run
4578 until the function returns.
4579 </p>
4580 <p>
4581 A coroutine is like a function, but it can be suspended
4582 and resumed any number of times, and then it must be
4583 explicitly destroyed. When a coroutine suspends, it
4584 returns to the resumer.
4585 </p>
4586 {#header_open|Minimal Coroutine Example#}
4587 <p>
4588 Declare a coroutine with the <code>async</code> keyword.
4589 The expression in angle brackets must evaluate to a struct
4590 which has these fields:
4591 </p>
4592 <ul>
4593 <li><code>allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8</code> - where <code>Error</code> can be any error set.</li>
4594 <li><code>freeFn: fn (self: *Allocator, old_mem: []u8) void</code></li>
4595 </ul>
4596 <p>
4597 You may notice that this corresponds to the <code>std.mem.Allocator</code> interface.
4598 This makes it convenient to integrate with existing allocators. Note, however,
4599 that the language feature does not depend on the standard library, and any struct which
4600 has these fields is allowed.
4601 </p>
4602 <p>
4603 Omitting the angle bracket expression when defining an async function makes
4604 the function generic. Zig will infer the allocator type when the async function is called.
4605 </p>
4606 <p>
4607 Call a coroutine with the <code>async</code> keyword. Here, the expression in angle brackets
4608 is a pointer to the allocator struct that the coroutine expects.
4609 </p>
4610 <p>
4611 The result of an async function call is a <code>promise->T</code> type, where <code>T</code>
4612 is the return type of the async function. Once a promise has been created, it must be
4613 consumed, either with <code>cancel</code> or <code>await</code>:
4614 </p>
4615 <p>
4616 Async functions start executing when created, so in the following example, the entire
4617 async function completes before it is canceled:
4618 </p>
4619 {#code_begin|test#}
4620const std = @import("std");
4621const assert = std.debug.assert;
4622
4623var x: i32 = 1;
4624
4625test "create a coroutine and cancel it" {
4626 const p = try async<std.debug.global_allocator> simpleAsyncFn();
4627 comptime assert(@typeOf(p) == promise->void);
4628 cancel p;
4629 assert(x == 2);
4630}
4631async<*std.mem.Allocator> fn simpleAsyncFn() void {
4632 x += 1;
4633}
4634 {#code_end#}
4635 {#header_close#}
4636 {#header_open|Suspend and Resume#}
4637 <p>
4638 At any point, an async function may suspend itself. This causes control flow to
4639 return to the caller or resumer. The following code demonstrates where control flow
4640 goes:
4641 </p>
4642 {#code_begin|test#}
4643const std = @import("std");
4644const assert = std.debug.assert;
4645
4646test "coroutine suspend, resume, cancel" {
4647 seq('a');
4648 const p = try async<std.debug.global_allocator> testAsyncSeq();
4649 seq('c');
4650 resume p;
4651 seq('f');
4652 cancel p;
4653 seq('g');
4654
4655 assert(std.mem.eql(u8, points, "abcdefg"));
4656}
4657async fn testAsyncSeq() void {
4658 defer seq('e');
4659
4660 seq('b');
4661 suspend;
4662 seq('d');
4663}
4664var points = []u8{0} ** "abcdefg".len;
4665var index: usize = 0;
4666
4667fn seq(c: u8) void {
4668 points[index] = c;
4669 index += 1;
4670}
4671 {#code_end#}
4672 <p>
4673 When an async function suspends itself, it must be sure that it will be
4674 resumed or canceled somehow, for example by registering its promise handle
4675 in an event loop. Use a suspend capture block to gain access to the
4676 promise:
4677 </p>
4678 {#code_begin|test#}
4679const std = @import("std");
4680const assert = std.debug.assert;
4681
4682test "coroutine suspend with block" {
4683 const p = try async<std.debug.global_allocator> testSuspendBlock();
4684 std.debug.assert(!result);
4685 resume a_promise;
4686 std.debug.assert(result);
4687 cancel p;
4688}
4689
4690var a_promise: promise = undefined;
4691var result = false;
4692async fn testSuspendBlock() void {
4693 suspend {
4694 comptime assert(@typeOf(@handle()) == promise->void);
4695 a_promise = @handle();
4696 }
4697 result = true;
4698}
4699 {#code_end#}
4700 <p>
4701 Every suspend point in an async function represents a point at which the coroutine
4702 could be destroyed. If that happens, <code>defer</code> expressions that are in
4703 scope are run, as well as <code>errdefer</code> expressions.
4704 </p>
4705 <p>
4706 {#link|Await#} counts as a suspend point.
4707 </p>
4708 {#header_open|Breaking from Suspend Blocks#}
4709 <p>
4710 Suspend blocks support labeled break, just like {#link|while#} and {#link|for#}.
4711 </p>
4712 <p>
4713 Upon entering a <code>suspend</code> block, the coroutine is already considered
4714 suspended, and can be resumed. For example, if you started another kernel thread,
4715 and had that thread call <code>resume</code> on the promise handle provided by the
4716 <code>suspend</code> block, the new thread would begin executing after the suspend
4717 block, while the old thread continued executing the suspend block.
4718 </p>
4719 <p>
4720 However, the coroutine can be directly resumed from the suspend block, in which case it
4721 never returns to its resumer and continues executing.
4722 </p>
4723 {#code_begin|test#}
4724const std = @import("std");
4725const assert = std.debug.assert;
4726
4727test "resume from suspend" {
4728 var buf: [500]u8 = undefined;
4729 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
4730 var my_result: i32 = 1;
4731 const p = try async<a> testResumeFromSuspend(&my_result);
4732 cancel p;
4733 std.debug.assert(my_result == 2);
4734}
4735async fn testResumeFromSuspend(my_result: *i32) void {
4736 suspend {
4737 resume @handle();
4738 }
4739 my_result.* += 1;
4740 suspend;
4741 my_result.* += 1;
4742}
4743 {#code_end#}
4744 {#header_close#}
4745 {#header_close#}
4746 {#header_open|Await#}
4747 <p>
4748 The <code>await</code> keyword is used to coordinate with an async function's
4749 <code>return</code> statement.
4750 </p>
4751 <p>
4752 <code>await</code> is valid only in an <code>async</code> function, and it takes
4753 as an operand a promise handle.
4754 If the async function associated with the promise handle has already returned,
4755 then <code>await</code> destroys the target async function, and gives the return value.
4756 Otherwise, <code>await</code> suspends the current async function, registering its
4757 promise handle with the target coroutine. It becomes the target coroutine's responsibility
4758 to have ensured that it will be resumed or destroyed. When the target coroutine reaches
4759 its return statement, it gives the return value to the awaiter, destroys itself, and then
4760 resumes the awaiter.
4761 </p>
4762 <p>
4763 A promise handle must be consumed exactly once after it is created, either by <code>cancel</code> or <code>await</code>.
4764 </p>
4765 <p>
4766 <code>await</code> counts as a suspend point, and therefore at every <code>await</code>,
4767 a coroutine can be potentially destroyed, which would run <code>defer</code> and <code>errdefer</code> expressions.
4768 </p>
4769 {#code_begin|test#}
4770const std = @import("std");
4771const assert = std.debug.assert;
4772
4773var a_promise: promise = undefined;
4774var final_result: i32 = 0;
4775
4776test "coroutine await" {
4777 seq('a');
4778 const p = async<std.debug.global_allocator> amain() catch unreachable;
4779 seq('f');
4780 resume a_promise;
4781 seq('i');
4782 assert(final_result == 1234);
4783 assert(std.mem.eql(u8, seq_points, "abcdefghi"));
4784}
4785async fn amain() void {
4786 seq('b');
4787 const p = async another() catch unreachable;
4788 seq('e');
4789 final_result = await p;
4790 seq('h');
4791}
4792async fn another() i32 {
4793 seq('c');
4794 suspend {
4795 seq('d');
4796 a_promise = @handle();
4797 }
4798 seq('g');
4799 return 1234;
4800}
4801
4802var seq_points = []u8{0} ** "abcdefghi".len;
4803var seq_index: usize = 0;
4804
4805fn seq(c: u8) void {
4806 seq_points[seq_index] = c;
4807 seq_index += 1;
4808}
4809 {#code_end#}
4810 <p>
4811 In general, <code>suspend</code> is lower level than <code>await</code>. Most application
4812 code will use only <code>async</code> and <code>await</code>, but event loop
4813 implementations will make use of <code>suspend</code> internally.
38414814 </p>
4815 {#header_close#}
4816 {#header_open|Open Issues#}
38424817 <p>
3843 Zig does not special case string formatting in the compiler and instead exposes enough power to accomplish this
3844 task in userland. It does so without introducing another language on top of Zig, such as
3845 a macro language or a preprocessor language. It's Zig all the way down.
4818 There are a few issues with coroutines that are considered unresolved. Best be aware of them,
4819 as the situation is likely to change before 1.0.0:
38464820 </p>
3847 <p>TODO: suggestion to not use inline unless necessary</p>
3848 {#header_close#}
3849 {#header_close#}
3850 {#header_open|inline#}
3851 <p>TODO: inline while</p>
3852 <p>TODO: inline for</p>
3853 <p>TODO: suggestion to not use inline unless necessary</p>
3854 {#header_close#}
3855 {#header_open|Assembly#}
3856 <p>TODO: example of inline assembly</p>
3857 <p>TODO: example of module level assembly</p>
3858 <p>TODO: example of using inline assembly return value</p>
3859 <p>TODO: example of using inline assembly assigning values to variables</p>
4821 <ul>
4822 <li>Async functions have optimizations disabled - even in release modes - due to an
4823 <a href="https://github.com/ziglang/zig/issues/802">LLVM bug</a>.
4824 </li>
4825 <li>
4826 There are some situations where we can know statically that there will not be
4827 memory allocation failure, but Zig still forces us to handle it.
4828 TODO file an issue for this and link it here.
4829 </li>
4830 <li>
4831 Zig does not take advantage of LLVM's allocation elision optimization for
4832 coroutines. It crashed LLVM when I tried to do it the first time. This is
4833 related to the other 2 bullet points here. See
4834 <a href="https://github.com/ziglang/zig/issues/802">#802</a>.
4835 </li>
4836 </ul>
38604837 {#header_close#}
3861 {#header_open|Atomics#}
3862 <p>TODO: @fence()</p>
3863 <p>TODO: @atomic rmw</p>
3864 <p>TODO: builtin atomic memory ordering enum</p>
4838
38654839 {#header_close#}
38664840 {#header_open|Builtin Functions#}
38674841 <p>
......@@ -3870,18 +4844,46 @@ pub fn main() void {
38704844 at compile time.
38714845 </p>
38724846 {#header_open|@addWithOverflow#}
3873 <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
4847 <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool</code></pre>
38744848 <p>
3875 Performs <code>*result = a + b</code>. If overflow or underflow occurs,
4849 Performs <code>result.* = a + b</code>. If overflow or underflow occurs,
38764850 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
38774851 If no overflow or underflow occurs, returns <code>false</code>.
38784852 </p>
38794853 {#header_close#}
38804854 {#header_open|@ArgType#}
3881 <p>TODO</p>
4855 <pre><code class="zig">@ArgType(comptime T: type, comptime n: usize) type</code></pre>
4856 <p>
4857 This builtin function takes a function type and returns the type of the parameter at index <code>n</code>.
4858 </p>
4859 <p>
4860 <code>T</code> must be a function type.
4861 </p>
4862 <p>
4863 Note: This function is deprecated. Use {#link|@typeInfo#} instead.
4864 </p>
4865 {#header_close#}
4866 {#header_open|@atomicLoad#}
4867 <pre><code class="zig">@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T</code></pre>
4868 <p>
4869 This builtin function atomically dereferences a pointer and returns the value.
4870 </p>
4871 <p>
4872 <code>T</code> must be a pointer type, a <code>bool</code>,
4873 or an integer whose bit count meets these requirements:
4874 </p>
4875 <ul>
4876 <li>At least 8</li>
4877 <li>At most the same as usize</li>
4878 <li>Power of 2</li>
4879 </ul>
4880 <p>
4881 TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
4882 we can remove this restriction
4883 </p>
38824884 {#header_close#}
38834885 {#header_open|@atomicRmw#}
3884 <pre><code class="zig">@atomicRmw(comptime T: type, ptr: &amp;T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>
4886 <pre><code class="zig">@atomicRmw(comptime T: type, ptr: *T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T</code></pre>
38854887 <p>
38864888 This builtin function atomically modifies memory and then returns the previous value.
38874889 </p>
......@@ -3900,7 +4902,7 @@ pub fn main() void {
39004902 </p>
39014903 {#header_close#}
39024904 {#header_open|@bitCast#}
3903 <pre><code class="zig">@bitCast(comptime DestType: type, value: var) -&gt; DestType</code></pre>
4905 <pre><code class="zig">@bitCast(comptime DestType: type, value: var) DestType</code></pre>
39044906 <p>
39054907 Converts a value of one type to another type.
39064908 </p>
......@@ -3933,9 +4935,9 @@ pub fn main() void {
39334935
39344936 {#header_close#}
39354937 {#header_open|@alignCast#}
3936 <pre><code class="zig">@alignCast(comptime alignment: u29, ptr: var) -&gt; var</code></pre>
4938 <pre><code class="zig">@alignCast(comptime alignment: u29, ptr: var) var</code></pre>
39374939 <p>
3938 <code>ptr</code> can be <code>&amp;T</code>, <code>fn()</code>, <code>?&amp;T</code>,
4940 <code>ptr</code> can be <code>*T</code>, <code>fn()</code>, <code>?*T</code>,
39394941 <code>?fn()</code>, or <code>[]T</code>. It returns the same type as <code>ptr</code>
39404942 except with the alignment adjusted to the new value.
39414943 </p>
......@@ -3944,7 +4946,7 @@ pub fn main() void {
39444946
39454947 {#header_close#}
39464948 {#header_open|@alignOf#}
3947 <pre><code class="zig">@alignOf(comptime T: type) -&gt; (number literal)</code></pre>
4949 <pre><code class="zig">@alignOf(comptime T: type) (number literal)</code></pre>
39484950 <p>
39494951 This function returns the number of bytes that this type should be aligned to
39504952 for the current target to match the C ABI. When the child type of a pointer has
......@@ -3952,7 +4954,7 @@ pub fn main() void {
39524954 </p>
39534955 <pre><code class="zig">const assert = @import("std").debug.assert;
39544956comptime {
3955 assert(&u32 == &align(@alignOf(u32)) u32);
4957 assert(*u32 == *align(@alignOf(u32)) u32);
39564958}</code></pre>
39574959 <p>
39584960 The result is a target-specific compile time constant. It is guaranteed to be
......@@ -3960,6 +4962,31 @@ comptime {
39604962 </p>
39614963 {#see_also|Alignment#}
39624964 {#header_close#}
4965
4966 {#header_open|@boolToInt#}
4967 <pre><code class="zig">@boolToInt(value: bool) u1</code></pre>
4968 <p>
4969 Converts <code>true</code> to <code>u1(1)</code> and <code>false</code> to
4970 <code>u1(0)</code>.
4971 </p>
4972 <p>
4973 If the value is known at compile-time, the return type is <code>comptime_int</code>
4974 instead of <code>u1</code>.
4975 </p>
4976 {#header_close#}
4977
4978 {#header_open|@bytesToSlice#}
4979 <pre><code class="zig">@bytesToSlice(comptime Element: type, bytes: []u8) []Element</code></pre>
4980 <p>
4981 Converts a slice of bytes or array of bytes into a slice of <code>Element</code>.
4982 The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter.
4983 </p>
4984 <p>
4985 Attempting to convert a number of bytes with a length that does not evenly divide into a slice of
4986 elements results in safety-protected {#link|Undefined Behavior#}.
4987 </p>
4988 {#header_close#}
4989
39634990 {#header_open|@cDefine#}
39644991 <pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>
39654992 <p>
......@@ -3980,7 +5007,7 @@ comptime {
39805007 {#see_also|Import from C Header File|@cInclude|@cImport|@cUndef|void#}
39815008 {#header_close#}
39825009 {#header_open|@cImport#}
3983 <pre><code class="zig">@cImport(expression) -&gt; (namespace)</code></pre>
5010 <pre><code class="zig">@cImport(expression) (namespace)</code></pre>
39845011 <p>
39855012 This function parses C code and imports the functions, types, variables, and
39865013 compatible macro definitions into the result namespace.
......@@ -4025,14 +5052,8 @@ comptime {
40255052 </p>
40265053 {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
40275054 {#header_close#}
4028 {#header_open|@canImplicitCast#}
4029 <pre><code class="zig">@canImplicitCast(comptime T: type, value) -&gt; bool</code></pre>
4030 <p>
4031 Returns whether a value can be implicitly casted to a given type.
4032 </p>
4033 {#header_close#}
40345055 {#header_open|@clz#}
4035 <pre><code class="zig">@clz(x: T) -&gt; U</code></pre>
5056 <pre><code class="zig">@clz(x: T) U</code></pre>
40365057 <p>
40375058 This function counts the number of leading zeroes in <code>x</code> which is an integer
40385059 type <code>T</code>.
......@@ -4044,18 +5065,62 @@ comptime {
40445065 <p>
40455066 If <code>x</code> is zero, <code>@clz</code> returns <code>T.bit_count</code>.
40465067 </p>
4047
5068 {#see_also|@ctz|@popCount#}
5069 {#header_close#}
5070 {#header_open|@cmpxchgStrong#}
5071 <pre><code class="zig">@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T</code></pre>
5072 <p>
5073 This function performs a strong atomic compare exchange operation. It's the equivalent of this code,
5074 except atomic:
5075 </p>
5076 {#code_begin|syntax#}
5077fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_value: T) ?T {
5078 const old_value = ptr.*;
5079 if (old_value == expected_value) {
5080 ptr.* = new_value;
5081 return null;
5082 } else {
5083 return old_value;
5084 }
5085}
5086 {#code_end#}
5087 <p>
5088 If you are using cmpxchg in a loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented
5089 more efficiently in machine instructions.
5090 </p>
5091 <p>
5092 <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>.
5093 </p>
5094 <p><code>@typeOf(ptr).alignment</code> must be <code>&gt;= @sizeOf(T).</code></p>
5095 {#see_also|Compile Variables|cmpxchgWeak#}
40485096 {#header_close#}
4049 {#header_open|@cmpxchg#}
4050 <pre><code class="zig">@cmpxchg(ptr: &T, cmp: T, new: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; bool</code></pre>
5097 {#header_open|@cmpxchgWeak#}
5098 <pre><code class="zig">@cmpxchgWeak(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T</code></pre>
5099 <p>
5100 This function performs a weak atomic compare exchange operation. It's the equivalent of this code,
5101 except atomic:
5102 </p>
5103 {#code_begin|syntax#}
5104fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_value: T) ?T {
5105 const old_value = ptr.*;
5106 if (old_value == expected_value and usuallyTrueButSometimesFalse()) {
5107 ptr.* = new_value;
5108 return null;
5109 } else {
5110 return old_value;
5111 }
5112}
5113 {#code_end#}
40515114 <p>
4052 This function performs an atomic compare exchange operation.
5115 If you are using cmpxchg in a loop, the sporadic failure will be no problem, and <code>cmpxchgWeak</code>
5116 is the better choice, because it can be implemented more efficiently in machine instructions.
5117 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
40535118 </p>
40545119 <p>
40555120 <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>.
40565121 </p>
40575122 <p><code>@typeOf(ptr).alignment</code> must be <code>&gt;= @sizeOf(T).</code></p>
4058 {#see_also|Compile Variables#}
5123 {#see_also|Compile Variables|cmpxchgStrong#}
40595124 {#header_close#}
40605125 {#header_open|@compileError#}
40615126 <pre><code class="zig">@compileError(comptime msg: []u8)</code></pre>
......@@ -4124,7 +5189,7 @@ test "main" {
41245189 {#code_end#}
41255190 {#header_close#}
41265191 {#header_open|@ctz#}
4127 <pre><code class="zig">@ctz(x: T) -&gt; U</code></pre>
5192 <pre><code class="zig">@ctz(x: T) U</code></pre>
41285193 <p>
41295194 This function counts the number of trailing zeroes in <code>x</code> which is an integer
41305195 type <code>T</code>.
......@@ -4136,9 +5201,10 @@ test "main" {
41365201 <p>
41375202 If <code>x</code> is zero, <code>@ctz</code> returns <code>T.bit_count</code>.
41385203 </p>
5204 {#see_also|@clz|@popCount#}
41395205 {#header_close#}
41405206 {#header_open|@divExact#}
4141 <pre><code class="zig">@divExact(numerator: T, denominator: T) -&gt; T</code></pre>
5207 <pre><code class="zig">@divExact(numerator: T, denominator: T) T</code></pre>
41425208 <p>
41435209 Exact division. Caller guarantees <code>denominator != 0</code> and
41445210 <code>@divTrunc(numerator, denominator) * denominator == numerator</code>.
......@@ -4151,7 +5217,7 @@ test "main" {
41515217 {#see_also|@divTrunc|@divFloor#}
41525218 {#header_close#}
41535219 {#header_open|@divFloor#}
4154 <pre><code class="zig">@divFloor(numerator: T, denominator: T) -&gt; T</code></pre>
5220 <pre><code class="zig">@divFloor(numerator: T, denominator: T) T</code></pre>
41555221 <p>
41565222 Floored division. Rounds toward negative infinity. For unsigned integers it is
41575223 the same as <code>numerator / denominator</code>. Caller guarantees <code>denominator != 0</code> and
......@@ -4165,7 +5231,7 @@ test "main" {
41655231 {#see_also|@divTrunc|@divExact#}
41665232 {#header_close#}
41675233 {#header_open|@divTrunc#}
4168 <pre><code class="zig">@divTrunc(numerator: T, denominator: T) -&gt; T</code></pre>
5234 <pre><code class="zig">@divTrunc(numerator: T, denominator: T) T</code></pre>
41695235 <p>
41705236 Truncated division. Rounds toward zero. For unsigned integers it is
41715237 the same as <code>numerator / denominator</code>. Caller guarantees <code>denominator != 0</code> and
......@@ -4179,7 +5245,7 @@ test "main" {
41795245 {#see_also|@divFloor|@divExact#}
41805246 {#header_close#}
41815247 {#header_open|@embedFile#}
4182 <pre><code class="zig">@embedFile(comptime path: []const u8) -&gt; [X]u8</code></pre>
5248 <pre><code class="zig">@embedFile(comptime path: []const u8) [X]u8</code></pre>
41835249 <p>
41845250 This function returns a compile time constant fixed-size array with length
41855251 equal to the byte count of the file given by <code>path</code>. The contents of the array
......@@ -4190,29 +5256,25 @@ test "main" {
41905256 </p>
41915257 {#see_also|@import#}
41925258 {#header_close#}
4193 {#header_open|@export#}
4194 <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) -&gt; []const u8</code></pre>
4195 <p>
4196 Creates a symbol in the output object file.
4197 </p>
4198 {#header_close#}
4199 {#header_open|@tagName#}
4200 <pre><code class="zig">@tagName(value: var) -&gt; []const u8</code></pre>
5259
5260 {#header_open|@enumToInt#}
5261 <pre><code class="zig">@enumToInt(enum_value: var) var</code></pre>
42015262 <p>
4202 Converts an enum value or union value to a slice of bytes representing the name.
5263 Converts an enumeration value into its integer tag type.
42035264 </p>
5265 {#see_also|@intToEnum#}
42045266 {#header_close#}
4205 {#header_open|@TagType#}
4206 <pre><code class="zig">@TagType(T: type) -&gt; type</code></pre>
4207 <p>
4208 For an enum, returns the integer type that is used to store the enumeration value.
4209 </p>
5267
5268 {#header_open|@errSetCast#}
5269 <pre><code class="zig">@errSetCast(comptime T: DestType, value: var) DestType</code></pre>
42105270 <p>
4211 For a union, returns the enum type that is used to store the tag value.
5271 Converts an error value from one error set to another error set. Attempting to convert an error
5272 which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
42125273 </p>
42135274 {#header_close#}
5275
42145276 {#header_open|@errorName#}
4215 <pre><code class="zig">@errorName(err: error) -&gt; []u8</code></pre>
5277 <pre><code class="zig">@errorName(err: error) []u8</code></pre>
42165278 <p>
42175279 This function returns the string representation of an error. If an error
42185280 declaration is:
......@@ -4227,14 +5289,42 @@ test "main" {
42275289 error name table will be generated.
42285290 </p>
42295291 {#header_close#}
5292
42305293 {#header_open|@errorReturnTrace#}
4231 <pre><code class="zig">@errorReturnTrace() -&gt; ?&builtin.StackTrace</code></pre>
5294 <pre><code class="zig">@errorReturnTrace() ?*builtin.StackTrace</code></pre>
42325295 <p>
42335296 If the binary is built with error return tracing, and this function is invoked in a
42345297 function that calls a function with an error or error union return type, returns a
42355298 stack trace object. Otherwise returns `null`.
42365299 </p>
42375300 {#header_close#}
5301
5302 {#header_open|@errorToInt#}
5303 <pre><code class="zig">@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8)</code></pre>
5304 <p>
5305 Supports the following types:
5306 </p>
5307 <ul>
5308 <li>error unions</li>
5309 <li><code>E!void</code></li>
5310 </ul>
5311 <p>
5312 Converts an error to the integer representation of an error.
5313 </p>
5314 <p>
5315 It is generally recommended to avoid this
5316 cast, as the integer representation of an error is not stable across source code changes.
5317 </p>
5318 {#see_also|@intToError#}
5319 {#header_close#}
5320
5321 {#header_open|@export#}
5322 <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>
5323 <p>
5324 Creates a symbol in the output object file.
5325 </p>
5326 {#header_close#}
5327
42385328 {#header_open|@fence#}
42395329 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
42405330 <p>
......@@ -4245,13 +5335,40 @@ test "main" {
42455335 </p>
42465336 {#see_also|Compile Variables#}
42475337 {#header_close#}
5338
5339 {#header_open|@field#}
5340 <pre><code class="zig">@field(lhs: var, comptime field_name: []const u8) (field)</code></pre>
5341 <p>Preforms field access equivalent to <code>lhs.-&gtfield_name-&lt</code>.</p>
5342 {#header_close#}
5343
42485344 {#header_open|@fieldParentPtr#}
42495345 <pre><code class="zig">@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8,
4250 field_ptr: &T) -&gt; &ParentType</code></pre>
5346 field_ptr: *T) *ParentType</code></pre>
42515347 <p>
42525348 Given a pointer to a field, returns the base pointer of a struct.
42535349 </p>
42545350 {#header_close#}
5351
5352 {#header_open|@floatCast#}
5353 <pre><code class="zig">@floatCast(comptime DestType: type, value: var) DestType</code></pre>
5354 <p>
5355 Convert from one float type to another. This cast is safe, but may cause the
5356 numeric value to lose precision.
5357 </p>
5358 {#header_close#}
5359
5360 {#header_open|@floatToInt#}
5361 <pre><code class="zig">@floatToInt(comptime DestType: type, float: var) DestType</code></pre>
5362 <p>
5363 Converts the integer part of a floating point number to the destination type.
5364 </p>
5365 <p>
5366 If the integer part of the floating point number cannot fit in the destination type,
5367 it invokes safety-checked {#link|Undefined Behavior#}.
5368 </p>
5369 {#see_also|@intToFloat#}
5370 {#header_close#}
5371
42555372 {#header_open|@frameAddress#}
42565373 <pre><code class="zig">@frameAddress()</code></pre>
42575374 <p>
......@@ -4266,8 +5383,18 @@ test "main" {
42665383 This function is only valid within function scope.
42675384 </p>
42685385 {#header_close#}
5386 {#header_open|@handle#}
5387 <pre><code class="zig">@handle()</code></pre>
5388 <p>
5389 This function returns a <code>promise->T</code> type, where <code>T</code>
5390 is the return type of the async function in scope.
5391 </p>
5392 <p>
5393 This function is only valid within an async function scope.
5394 </p>
5395 {#header_close#}
42695396 {#header_open|@import#}
4270 <pre><code class="zig">@import(comptime path: []u8) -&gt; (namespace)</code></pre>
5397 <pre><code class="zig">@import(comptime path: []u8) (namespace)</code></pre>
42715398 <p>
42725399 This function finds a zig file corresponding to <code>path</code> and imports all the
42735400 public top level declarations into the resulting namespace.
......@@ -4287,7 +5414,7 @@ test "main" {
42875414 {#see_also|Compile Variables|@embedFile#}
42885415 {#header_close#}
42895416 {#header_open|@inlineCall#}
4290 <pre><code class="zig">@inlineCall(function: X, args: ...) -&gt; Y</code></pre>
5417 <pre><code class="zig">@inlineCall(function: X, args: ...) Y</code></pre>
42915418 <p>
42925419 This calls a function, in the same way that invoking an expression with parentheses does:
42935420 </p>
......@@ -4306,20 +5433,66 @@ fn add(a: i32, b: i32) i32 { return a + b; }
43065433 </p>
43075434 {#see_also|@noInlineCall#}
43085435 {#header_close#}
5436
5437 {#header_open|@intCast#}
5438 <pre><code class="zig">@intCast(comptime DestType: type, int: var) DestType</code></pre>
5439 <p>
5440 Converts an integer to another integer while keeping the same numerical value.
5441 Attempting to convert a number which is out of range of the destination type results in
5442 safety-protected {#link|Undefined Behavior#}.
5443 </p>
5444 {#header_close#}
5445
5446 {#header_open|@intToEnum#}
5447 <pre><code class="zig">@intToEnum(comptime DestType: type, int_value: @TagType(DestType)) DestType</code></pre>
5448 <p>
5449 Converts an integer into an {#link|enum#} value.
5450 </p>
5451 <p>
5452 Attempting to convert an integer which represents no value in the chosen enum type invokes
5453 safety-checked {#link|Undefined Behavior#}.
5454 </p>
5455 {#see_also|@enumToInt#}
5456 {#header_close#}
5457
5458 {#header_open|@intToError#}
5459 <pre><code class="zig">@intToError(value: @IntType(false, @sizeOf(error) * 8)) error</code></pre>
5460 <p>
5461 Converts from the integer representation of an error into the global error set type.
5462 </p>
5463 <p>
5464 It is generally recommended to avoid this
5465 cast, as the integer representation of an error is not stable across source code changes.
5466 </p>
5467 <p>
5468 Attempting to convert an integer that does not correspond to any error results in
5469 safety-protected {#link|Undefined Behavior#}.
5470 </p>
5471 {#see_also|@errorToInt#}
5472 {#header_close#}
5473
5474 {#header_open|@intToFloat#}
5475 <pre><code class="zig">@intToFloat(comptime DestType: type, int: var) DestType</code></pre>
5476 <p>
5477 Converts an integer to the closest floating point representation. To convert the other way, use {#link|@floatToInt#}. This cast is always safe.
5478 </p>
5479 {#header_close#}
5480
43095481 {#header_open|@intToPtr#}
4310 <pre><code class="zig">@intToPtr(comptime DestType: type, int: usize) -&gt; DestType</code></pre>
5482 <pre><code class="zig">@intToPtr(comptime DestType: type, int: usize) DestType</code></pre>
43115483 <p>
43125484 Converts an integer to a pointer. To convert the other way, use {#link|@ptrToInt#}.
43135485 </p>
43145486 {#header_close#}
5487
43155488 {#header_open|@IntType#}
4316 <pre><code class="zig">@IntType(comptime is_signed: bool, comptime bit_count: u8) -&gt; type</code></pre>
5489 <pre><code class="zig">@IntType(comptime is_signed: bool, comptime bit_count: u32) type</code></pre>
43175490 <p>
43185491 This function returns an integer type with the given signness and bit count.
43195492 </p>
43205493 {#header_close#}
43215494 {#header_open|@maxValue#}
4322 <pre><code class="zig">@maxValue(comptime T: type) -&gt; (number literal)</code></pre>
5495 <pre><code class="zig">@maxValue(comptime T: type) (number literal)</code></pre>
43235496 <p>
43245497 This function returns the maximum value of the integer type <code>T</code>.
43255498 </p>
......@@ -4328,7 +5501,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
43285501 </p>
43295502 {#header_close#}
43305503 {#header_open|@memberCount#}
4331 <pre><code class="zig">@memberCount(comptime T: type) -&gt; (number literal)</code></pre>
5504 <pre><code class="zig">@memberCount(comptime T: type) (number literal)</code></pre>
43325505 <p>
43335506 This function returns the number of members in a struct, enum, or union type.
43345507 </p>
......@@ -4340,7 +5513,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
43405513 </p>
43415514 {#header_close#}
43425515 {#header_open|@memberName#}
4343 <pre><code class="zig">@memberName(comptime T: type, comptime index: usize) -&gt; [N]u8</code></pre>
5516 <pre><code class="zig">@memberName(comptime T: type, comptime index: usize) [N]u8</code></pre>
43445517 <p>Returns the field name of a struct, union, or enum.</p>
43455518 <p>
43465519 The result is a compile time constant.
......@@ -4350,11 +5523,11 @@ fn add(a: i32, b: i32) i32 { return a + b; }
43505523 </p>
43515524 {#header_close#}
43525525 {#header_open|@memberType#}
4353 <pre><code class="zig">@memberType(comptime T: type, comptime index: usize) -&gt; type</code></pre>
5526 <pre><code class="zig">@memberType(comptime T: type, comptime index: usize) type</code></pre>
43545527 <p>Returns the field type of a struct or union.</p>
43555528 {#header_close#}
43565529 {#header_open|@memcpy#}
4357 <pre><code class="zig">@memcpy(noalias dest: &u8, noalias source: &const u8, byte_count: usize)</code></pre>
5530 <pre><code class="zig">@memcpy(noalias dest: *u8, noalias source: *const u8, byte_count: usize)</code></pre>
43585531 <p>
43595532 This function copies bytes from one region of memory to another. <code>dest</code> and
43605533 <code>source</code> are both pointers and must not overlap.
......@@ -4372,7 +5545,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
43725545mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
43735546 {#header_close#}
43745547 {#header_open|@memset#}
4375 <pre><code class="zig">@memset(dest: &u8, c: u8, byte_count: usize)</code></pre>
5548 <pre><code class="zig">@memset(dest: *u8, c: u8, byte_count: usize)</code></pre>
43765549 <p>
43775550 This function sets a region of memory to <code>c</code>. <code>dest</code> is a pointer.
43785551 </p>
......@@ -4380,7 +5553,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
43805553 This function is a low level intrinsic with no safety mechanisms. Most
43815554 code should not use this function, instead using something like this:
43825555 </p>
4383 <pre><code class="zig">for (dest[0...byte_count]) |*b| *b = c;</code></pre>
5556 <pre><code class="zig">for (dest[0...byte_count]) |*b| b.* = c;</code></pre>
43845557 <p>
43855558 The optimizer is intelligent enough to turn the above snippet into a memset.
43865559 </p>
......@@ -4389,7 +5562,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
43895562mem.set(u8, dest, c);</code></pre>
43905563 {#header_close#}
43915564 {#header_open|@minValue#}
4392 <pre><code class="zig">@minValue(comptime T: type) -&gt; (number literal)</code></pre>
5565 <pre><code class="zig">@minValue(comptime T: type) (number literal)</code></pre>
43935566 <p>
43945567 This function returns the minimum value of the integer type T.
43955568 </p>
......@@ -4398,7 +5571,7 @@ mem.set(u8, dest, c);</code></pre>
43985571 </p>
43995572 {#header_close#}
44005573 {#header_open|@mod#}
4401 <pre><code class="zig">@mod(numerator: T, denominator: T) -&gt; T</code></pre>
5574 <pre><code class="zig">@mod(numerator: T, denominator: T) T</code></pre>
44025575 <p>
44035576 Modulus division. For unsigned integers this is the same as
44045577 <code>numerator % denominator</code>. Caller guarantees <code>denominator &gt; 0</code>.
......@@ -4411,24 +5584,65 @@ mem.set(u8, dest, c);</code></pre>
44115584 {#see_also|@rem#}
44125585 {#header_close#}
44135586 {#header_open|@mulWithOverflow#}
4414 <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
5587 <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool</code></pre>
44155588 <p>
4416 Performs <code>*result = a * b</code>. If overflow or underflow occurs,
5589 Performs <code>result.* = a * b</code>. If overflow or underflow occurs,
44175590 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
44185591 If no overflow or underflow occurs, returns <code>false</code>.
44195592 </p>
44205593 {#header_close#}
5594 {#header_open|@newStackCall#}
5595 <pre><code class="zig">@newStackCall(new_stack: []u8, function: var, args: ...) var</code></pre>
5596 <p>
5597 This calls a function, in the same way that invoking an expression with parentheses does. However,
5598 instead of using the same stack as the caller, the function uses the stack provided in the <code>new_stack</code>
5599 parameter.
5600 </p>
5601 {#code_begin|test#}
5602const std = @import("std");
5603const assert = std.debug.assert;
5604
5605var new_stack_bytes: [1024]u8 = undefined;
5606
5607test "calling a function with a new stack" {
5608 const arg = 1234;
5609
5610 const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
5611 const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
5612 _ = targetFunction(arg);
5613
5614 assert(arg == 1234);
5615 assert(a < b);
5616}
5617
5618fn targetFunction(x: i32) usize {
5619 assert(x == 1234);
5620
5621 var local_variable: i32 = 42;
5622 const ptr = &local_variable;
5623 ptr.* += 1;
5624
5625 assert(local_variable == 43);
5626 return @ptrToInt(ptr);
5627}
5628 {#code_end#}
5629 {#header_close#}
44215630 {#header_open|@noInlineCall#}
4422 <pre><code class="zig">@noInlineCall(function: var, args: ...) -&gt; var</code></pre>
5631 <pre><code class="zig">@noInlineCall(function: var, args: ...) var</code></pre>
44235632 <p>
44245633 This calls a function, in the same way that invoking an expression with parentheses does:
44255634 </p>
4426 <pre><code class="zig">const assert = @import("std").debug.assert;
5635 {#code_begin|test#}
5636const assert = @import("std").debug.assert;
5637
44275638test "noinline function call" {
44285639 assert(@noInlineCall(add, 3, 9) == 12);
44295640}
44305641
4431fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
5642fn add(a: i32, b: i32) i32 {
5643 return a + b;
5644}
5645 {#code_end#}
44325646 <p>
44335647 Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call
44345648 will not be inlined. If the call must be inlined, a compile error is emitted.
......@@ -4436,13 +5650,13 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
44365650 {#see_also|@inlineCall#}
44375651 {#header_close#}
44385652 {#header_open|@offsetOf#}
4439 <pre><code class="zig">@offsetOf(comptime T: type, comptime field_name: [] const u8) -&gt; (number literal)</code></pre>
5653 <pre><code class="zig">@offsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre>
44405654 <p>
44415655 This function returns the byte offset of a field relative to its containing struct.
44425656 </p>
44435657 {#header_close#}
44445658 {#header_open|@OpaqueType#}
4445 <pre><code class="zig">@OpaqueType() -&gt; type</code></pre>
5659 <pre><code class="zig">@OpaqueType() type</code></pre>
44465660 <p>
44475661 Creates a new type with an unknown size and alignment.
44485662 </p>
......@@ -4450,12 +5664,12 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
44505664 This is typically used for type safety when interacting with C code that does not expose struct details.
44515665 Example:
44525666 </p>
4453 {#code_begin|test_err|expected type '&Derp', found '&Wat'#}
5667 {#code_begin|test_err|expected type '*Derp', found '*Wat'#}
44545668const Derp = @OpaqueType();
44555669const Wat = @OpaqueType();
44565670
4457extern fn bar(d: &Derp) void;
4458export fn foo(w: &Wat) void {
5671extern fn bar(d: *Derp) void;
5672export fn foo(w: *Wat) void {
44595673 bar(w);
44605674}
44615675
......@@ -4465,7 +5679,7 @@ test "call foo" {
44655679 {#code_end#}
44665680 {#header_close#}
44675681 {#header_open|@panic#}
4468 <pre><code class="zig">@panic(message: []const u8) -&gt; noreturn</code></pre>
5682 <pre><code class="zig">@panic(message: []const u8) noreturn</code></pre>
44695683 <p>
44705684 Invokes the panic handler function. By default the panic handler function
44715685 calls the public <code>panic</code> function exposed in the root source file, or
......@@ -4480,20 +5694,30 @@ test "call foo" {
44805694 </ul>
44815695 {#see_also|Root Source File#}
44825696 {#header_close#}
5697 {#header_open|@popCount#}
5698 <pre><code class="zig">@popCount(integer: var) var</code></pre>
5699 <p>Counts the number of bits set in an integer.</p>
5700 <p>
5701 If <code>integer</code> is known at {#link|comptime#}, the return type is <code>comptime_int</code>.
5702 Otherwise, the return type is an unsigned integer with the minimum number
5703 of bits that can represent the bit count of the integer type.
5704 </p>
5705 {#see_also|@ctz|@clz#}
5706 {#header_close#}
44835707 {#header_open|@ptrCast#}
4484 <pre><code class="zig">@ptrCast(comptime DestType: type, value: var) -&gt; DestType</code></pre>
5708 <pre><code class="zig">@ptrCast(comptime DestType: type, value: var) DestType</code></pre>
44855709 <p>
44865710 Converts a pointer of one type to a pointer of another type.
44875711 </p>
44885712 {#header_close#}
44895713 {#header_open|@ptrToInt#}
4490 <pre><code class="zig">@ptrToInt(value: var) -&gt; usize</code></pre>
5714 <pre><code class="zig">@ptrToInt(value: var) usize</code></pre>
44915715 <p>
44925716 Converts <code>value</code> to a <code>usize</code> which is the address of the pointer. <code>value</code> can be one of these types:
44935717 </p>
44945718 <ul>
4495 <li><code>&amp;T</code></li>
4496 <li><code>?&amp;T</code></li>
5719 <li><code>*T</code></li>
5720 <li><code>?*T</code></li>
44975721 <li><code>fn()</code></li>
44985722 <li><code>?fn()</code></li>
44995723 </ul>
......@@ -4501,7 +5725,7 @@ test "call foo" {
45015725
45025726 {#header_close#}
45035727 {#header_open|@rem#}
4504 <pre><code class="zig">@rem(numerator: T, denominator: T) -&gt; T</code></pre>
5728 <pre><code class="zig">@rem(numerator: T, denominator: T) T</code></pre>
45055729 <p>
45065730 Remainder division. For unsigned integers this is the same as
45075731 <code>numerator % denominator</code>. Caller guarantees <code>denominator &gt; 0</code>.
......@@ -4617,14 +5841,8 @@ pub const FloatMode = enum {
46175841 </p>
46185842 {#see_also|Compile Variables#}
46195843 {#header_close#}
4620 {#header_open|@setGlobalSection#}
4621 <pre><code class="zig">@setGlobalSection(global_variable_name, comptime section_name: []const u8) -&gt; bool</code></pre>
4622 <p>
4623 Puts the global variable in the specified section.
4624 </p>
4625 {#header_close#}
46265844 {#header_open|@shlExact#}
4627 <pre><code class="zig">@shlExact(value: T, shift_amt: Log2T) -&gt; T</code></pre>
5845 <pre><code class="zig">@shlExact(value: T, shift_amt: Log2T) T</code></pre>
46285846 <p>
46295847 Performs the left shift operation (<code>&lt;&lt;</code>). Caller guarantees
46305848 that the shift will not shift any 1 bits out.
......@@ -4636,9 +5854,9 @@ pub const FloatMode = enum {
46365854 {#see_also|@shrExact|@shlWithOverflow#}
46375855 {#header_close#}
46385856 {#header_open|@shlWithOverflow#}
4639 <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -&gt; bool</code></pre>
5857 <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool</code></pre>
46405858 <p>
4641 Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,
5859 Performs <code>result.* = a &lt;&lt; b</code>. If overflow or underflow occurs,
46425860 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
46435861 If no overflow or underflow occurs, returns <code>false</code>.
46445862 </p>
......@@ -4649,7 +5867,7 @@ pub const FloatMode = enum {
46495867 {#see_also|@shlExact|@shrExact#}
46505868 {#header_close#}
46515869 {#header_open|@shrExact#}
4652 <pre><code class="zig">@shrExact(value: T, shift_amt: Log2T) -&gt; T</code></pre>
5870 <pre><code class="zig">@shrExact(value: T, shift_amt: Log2T) T</code></pre>
46535871 <p>
46545872 Performs the right shift operation (<code>&gt;&gt;</code>). Caller guarantees
46555873 that the shift will not shift any 1 bits out.
......@@ -4660,8 +5878,9 @@ pub const FloatMode = enum {
46605878 </p>
46615879 {#see_also|@shlExact|@shlWithOverflow#}
46625880 {#header_close#}
5881
46635882 {#header_open|@sizeOf#}
4664 <pre><code class="zig">@sizeOf(comptime T: type) -&gt; (number literal)</code></pre>
5883 <pre><code class="zig">@sizeOf(comptime T: type) comptime_int</code></pre>
46655884 <p>
46665885 This function returns the number of bytes it takes to store <code>T</code> in memory.
46675886 </p>
......@@ -4669,16 +5888,50 @@ pub const FloatMode = enum {
46695888 The result is a target-specific compile time constant.
46705889 </p>
46715890 {#header_close#}
5891
5892 {#header_open|@sliceToBytes#}
5893 <pre><code class="zig">@sliceToBytes(value: var) []u8</code></pre>
5894 <p>
5895 Converts a slice or array to a slice of <code>u8</code>. The resulting slice has the same
5896 {#link|pointer|Pointers#} properties as the parameter.
5897 </p>
5898 {#header_close#}
5899
5900 {#header_open|@sqrt#}
5901 <pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>
5902 <p>
5903 Performs the square root of a floating point number. Uses a dedicated hardware instruction
5904 when available. Currently only supports f32 and f64 at runtime. f128 at runtime is TODO.
5905 </p>
5906 <p>
5907 This is a low-level intrinsic. Most code can use <code>std.math.sqrt</code> instead.
5908 </p>
5909 {#header_close#}
46725910 {#header_open|@subWithOverflow#}
4673 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
5911 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool</code></pre>
46745912 <p>
4675 Performs <code>*result = a - b</code>. If overflow or underflow occurs,
5913 Performs <code>result.* = a - b</code>. If overflow or underflow occurs,
46765914 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
46775915 If no overflow or underflow occurs, returns <code>false</code>.
46785916 </p>
46795917 {#header_close#}
5918 {#header_open|@tagName#}
5919 <pre><code class="zig">@tagName(value: var) []const u8</code></pre>
5920 <p>
5921 Converts an enum value or union value to a slice of bytes representing the name.
5922 </p>
5923 {#header_close#}
5924 {#header_open|@TagType#}
5925 <pre><code class="zig">@TagType(T: type) type</code></pre>
5926 <p>
5927 For an enum, returns the integer type that is used to store the enumeration value.
5928 </p>
5929 <p>
5930 For a union, returns the enum type that is used to store the tag value.
5931 </p>
5932 {#header_close#}
46805933 {#header_open|@truncate#}
4681 <pre><code class="zig">@truncate(comptime T: type, integer) -&gt; T</code></pre>
5934 <pre><code class="zig">@truncate(comptime T: type, integer) T</code></pre>
46825935 <p>
46835936 This function truncates bits from an integer type, resulting in a smaller
46845937 integer type.
......@@ -4702,7 +5955,7 @@ const b: u8 = @truncate(u8, a);
47025955
47035956 {#header_close#}
47045957 {#header_open|@typeId#}
4705 <pre><code class="zig">@typeId(comptime T: type) -&gt; @import("builtin").TypeId</code></pre>
5958 <pre><code class="zig">@typeId(comptime T: type) @import("builtin").TypeId</code></pre>
47065959 <p>
47075960 Returns which kind of type something is. Possible values:
47085961 </p>
......@@ -4717,11 +5970,11 @@ pub const TypeId = enum {
47175970 Pointer,
47185971 Array,
47195972 Struct,
4720 FloatLiteral,
4721 IntLiteral,
4722 UndefinedLiteral,
4723 NullLiteral,
4724 Nullable,
5973 ComptimeFloat,
5974 ComptimeInt,
5975 Undefined,
5976 Null,
5977 Optional,
47255978 ErrorUnion,
47265979 Error,
47275980 Enum,
......@@ -4732,18 +5985,201 @@ pub const TypeId = enum {
47325985 BoundFn,
47335986 ArgTuple,
47345987 Opaque,
5988};
5989 {#code_end#}
5990 {#header_close#}
5991 {#header_open|@typeInfo#}
5992 <pre><code class="zig">@typeInfo(comptime T: type) @import("builtin").TypeInfo</code></pre>
5993 <p>
5994 Returns information on the type. Returns a value of the following union:
5995 </p>
5996 {#code_begin|syntax#}
5997pub const TypeInfo = union(TypeId) {
5998 Type: void,
5999 Void: void,
6000 Bool: void,
6001 NoReturn: void,
6002 Int: Int,
6003 Float: Float,
6004 Pointer: Pointer,
6005 Array: Array,
6006 Struct: Struct,
6007 ComptimeFloat: void,
6008 ComptimeInt: void,
6009 Undefined: void,
6010 Null: void,
6011 Optional: Optional,
6012 ErrorUnion: ErrorUnion,
6013 ErrorSet: ErrorSet,
6014 Enum: Enum,
6015 Union: Union,
6016 Fn: Fn,
6017 Namespace: void,
6018 Block: void,
6019 BoundFn: Fn,
6020 ArgTuple: void,
6021 Opaque: void,
6022 Promise: Promise,
6023
6024
6025 pub const Int = struct {
6026 is_signed: bool,
6027 bits: u8,
6028 };
6029
6030 pub const Float = struct {
6031 bits: u8,
6032 };
6033
6034 pub const Pointer = struct {
6035 size: Size,
6036 is_const: bool,
6037 is_volatile: bool,
6038 alignment: u32,
6039 child: type,
6040
6041 pub const Size = enum {
6042 One,
6043 Many,
6044 Slice,
6045 };
6046 };
6047
6048 pub const Array = struct {
6049 len: usize,
6050 child: type,
6051 };
6052
6053 pub const ContainerLayout = enum {
6054 Auto,
6055 Extern,
6056 Packed,
6057 };
6058
6059 pub const StructField = struct {
6060 name: []const u8,
6061 offset: ?usize,
6062 field_type: type,
6063 };
6064
6065 pub const Struct = struct {
6066 layout: ContainerLayout,
6067 fields: []StructField,
6068 defs: []Definition,
6069 };
6070
6071 pub const Optional = struct {
6072 child: type,
6073 };
6074
6075 pub const ErrorUnion = struct {
6076 error_set: type,
6077 payload: type,
6078 };
6079
6080 pub const Error = struct {
6081 name: []const u8,
6082 value: usize,
6083 };
6084
6085 pub const ErrorSet = struct {
6086 errors: []Error,
6087 };
6088
6089 pub const EnumField = struct {
6090 name: []const u8,
6091 value: usize,
6092 };
6093
6094 pub const Enum = struct {
6095 layout: ContainerLayout,
6096 tag_type: type,
6097 fields: []EnumField,
6098 defs: []Definition,
6099 };
6100
6101 pub const UnionField = struct {
6102 name: []const u8,
6103 enum_field: ?EnumField,
6104 field_type: type,
6105 };
6106
6107 pub const Union = struct {
6108 layout: ContainerLayout,
6109 tag_type: ?type,
6110 fields: []UnionField,
6111 defs: []Definition,
6112 };
6113
6114 pub const CallingConvention = enum {
6115 Unspecified,
6116 C,
6117 Cold,
6118 Naked,
6119 Stdcall,
6120 Async,
6121 };
6122
6123 pub const FnArg = struct {
6124 is_generic: bool,
6125 is_noalias: bool,
6126 arg_type: ?type,
6127 };
6128
6129 pub const Fn = struct {
6130 calling_convention: CallingConvention,
6131 is_generic: bool,
6132 is_var_args: bool,
6133 return_type: ?type,
6134 async_allocator_type: ?type,
6135 args: []FnArg,
6136 };
6137
6138 pub const Promise = struct {
6139 child: ?type,
6140 };
6141
6142 pub const Definition = struct {
6143 name: []const u8,
6144 is_pub: bool,
6145 data: Data,
6146
6147 pub const Data = union(enum) {
6148 Type: type,
6149 Var: type,
6150 Fn: FnDef,
6151
6152 pub const FnDef = struct {
6153 fn_type: type,
6154 inline_type: Inline,
6155 calling_convention: CallingConvention,
6156 is_var_args: bool,
6157 is_extern: bool,
6158 is_export: bool,
6159 lib_name: ?[]const u8,
6160 return_type: type,
6161 arg_names: [][] const u8,
6162
6163 pub const Inline = enum {
6164 Auto,
6165 Always,
6166 Never,
6167 };
6168 };
6169 };
6170 };
47356171};
47366172 {#code_end#}
47376173 {#header_close#}
47386174 {#header_open|@typeName#}
4739 <pre><code class="zig">@typeName(T: type) -&gt; []u8</code></pre>
6175 <pre><code class="zig">@typeName(T: type) []u8</code></pre>
47406176 <p>
47416177 This function returns the string representation of a type.
47426178 </p>
47436179
47446180 {#header_close#}
47456181 {#header_open|@typeOf#}
4746 <pre><code class="zig">@typeOf(expression) -&gt; type</code></pre>
6182 <pre><code class="zig">@typeOf(expression) type</code></pre>
47476183 <p>
47486184 This function returns a compile-time constant, which is the type of the
47496185 expression passed as an argument. The expression is evaluated.
......@@ -4753,12 +6189,13 @@ pub const TypeId = enum {
47536189 {#header_close#}
47546190 {#header_open|Build Mode#}
47556191 <p>
4756 Zig has three build modes:
6192 Zig has four build modes:
47576193 </p>
47586194 <ul>
47596195 <li>{#link|Debug#} (default)</li>
47606196 <li>{#link|ReleaseFast#}</li>
47616197 <li>{#link|ReleaseSafe#}</li>
6198 <li>{#link|ReleaseSmall#}</li>
47626199 </ul>
47636200 <p>
47646201 To add standard build options to a <code>build.zig</code> file:
......@@ -4766,7 +6203,7 @@ pub const TypeId = enum {
47666203 {#code_begin|syntax#}
47676204const Builder = @import("std").build.Builder;
47686205
4769pub fn build(b: &Builder) void {
6206pub fn build(b: *Builder) void {
47706207 const exe = b.addExecutable("example", "example.zig");
47716208 exe.setBuildMode(b.standardReleaseOptions());
47726209 b.default_step.dependOn(&exe.step);
......@@ -4775,14 +6212,16 @@ pub fn build(b: &Builder) void {
47756212 <p>
47766213 This causes these options to be available:
47776214 </p>
4778 <pre><code class="shell"> -Drelease-safe=(bool) optimizations on and safety on
4779 -Drelease-fast=(bool) optimizations on and safety off</code></pre>
6215 <pre><code class="shell"> -Drelease-safe=[bool] optimizations on and safety on
6216 -Drelease-fast=[bool] optimizations on and safety off
6217 -Drelease-small=[bool] size optimizations on and safety off</code></pre>
47806218 {#header_open|Debug#}
47816219 <pre><code class="shell">$ zig build-exe example.zig</code></pre>
47826220 <ul>
47836221 <li>Fast compilation speed</li>
47846222 <li>Safety checks enabled</li>
47856223 <li>Slow runtime performance</li>
6224 <li>Large binary size</li>
47866225 </ul>
47876226 {#header_close#}
47886227 {#header_open|ReleaseFast#}
......@@ -4791,6 +6230,7 @@ pub fn build(b: &Builder) void {
47916230 <li>Fast runtime performance</li>
47926231 <li>Safety checks disabled</li>
47936232 <li>Slow compilation speed</li>
6233 <li>Large binary size</li>
47946234 </ul>
47956235 {#header_close#}
47966236 {#header_open|ReleaseSafe#}
......@@ -4799,17 +6239,27 @@ pub fn build(b: &Builder) void {
47996239 <li>Medium runtime performance</li>
48006240 <li>Safety checks enabled</li>
48016241 <li>Slow compilation speed</li>
6242 <li>Large binary size</li>
6243 </ul>
6244 {#header_close#}
6245 {#header_open|ReleaseSmall#}
6246 <pre><code class="shell">$ zig build-exe example.zig --release-small</code></pre>
6247 <ul>
6248 <li>Medium runtime performance</li>
6249 <li>Safety checks disabled</li>
6250 <li>Slow compilation speed</li>
6251 <li>Small binary size</li>
48026252 </ul>
4803 {#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
48046253 {#header_close#}
6254 {#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
48056255 {#header_close#}
48066256 {#header_open|Undefined Behavior#}
48076257 <p>
48086258 Zig has many instances of undefined behavior. If undefined behavior is
4809 detected at compile-time, Zig emits an error. Most undefined behavior that
4810 cannot be detected at compile-time can be detected at runtime. In these cases,
4811 Zig has safety checks. Safety checks can be disabled on a per-block basis
4812 with <code>@setRuntimeSafety</code>. The {#link|ReleaseFast#}
6259 detected at compile-time, Zig emits a compile error and refuses to continue.
6260 Most undefined behavior that cannot be detected at compile-time can be detected
6261 at runtime. In these cases, Zig has safety checks. Safety checks can be disabled
6262 on a per-block basis with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
48136263 build mode disables all safety checks in order to facilitate optimizations.
48146264 </p>
48156265 <p>
......@@ -4830,7 +6280,14 @@ fn assert(ok: bool) void {
48306280 if (!ok) unreachable; // assertion failure
48316281}
48326282 {#code_end#}
4833 <p>At runtime crashes with the message <code>reached unreachable code</code> and a stack trace.</p>
6283 <p>At runtime:</p>
6284 {#code_begin|exe_err#}
6285const std = @import("std");
6286
6287pub fn main() void {
6288 std.debug.assert(false);
6289}
6290 {#code_end#}
48346291 {#header_close#}
48356292 {#header_open|Index out of Bounds#}
48366293 <p>At compile-time:</p>
......@@ -4840,20 +6297,37 @@ comptime {
48406297 const garbage = array[5];
48416298}
48426299 {#code_end#}
4843 <p>At runtime crashes with the message <code>index out of bounds</code> and a stack trace.</p>
6300 <p>At runtime:</p>
6301 {#code_begin|exe_err#}
6302pub fn main() void {
6303 var x = foo("hello");
6304}
6305
6306fn foo(x: []const u8) u8 {
6307 return x[5];
6308}
6309 {#code_end#}
48446310 {#header_close#}
48456311 {#header_open|Cast Negative Number to Unsigned Integer#}
48466312 <p>At compile-time:</p>
48476313 {#code_begin|test_err|attempt to cast negative value to unsigned integer#}
48486314comptime {
48496315 const value: i32 = -1;
4850 const unsigned = u32(value);
6316 const unsigned = @intCast(u32, value);
6317}
6318 {#code_end#}
6319 <p>At runtime:</p>
6320 {#code_begin|exe_err#}
6321const std = @import("std");
6322
6323pub fn main() void {
6324 var value: i32 = -1;
6325 var unsigned = @intCast(u32, value);
6326 std.debug.warn("value: {}\n", unsigned);
48516327}
48526328 {#code_end#}
4853 <p>At runtime crashes with the message <code>attempt to cast negative value to unsigned integer</code> and a stack trace.</p>
48546329 <p>
4855 If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>,
4856 where <code>T</code> is the integer type, such as <code>u32</code>.
6330 To obtain the maximum value of an unsigned integer, use {#link|@maxValue#}.
48576331 </p>
48586332 {#header_close#}
48596333 {#header_open|Cast Truncates Data#}
......@@ -4861,14 +6335,21 @@ comptime {
48616335 {#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#}
48626336comptime {
48636337 const spartan_count: u16 = 300;
4864 const byte = u8(spartan_count);
6338 const byte = @intCast(u8, spartan_count);
6339}
6340 {#code_end#}
6341 <p>At runtime:</p>
6342 {#code_begin|exe_err#}
6343const std = @import("std");
6344
6345pub fn main() void {
6346 var spartan_count: u16 = 300;
6347 const byte = @intCast(u8, spartan_count);
6348 std.debug.warn("value: {}\n", byte);
48656349}
48666350 {#code_end#}
4867 <p>At runtime crashes with the message <code>integer cast truncated bits</code> and a stack trace.</p>
48686351 <p>
4869 If you are trying to truncate bits, use <code>@truncate(T, value)</code>,
4870 where <code>T</code> is the integer type, such as <code>u32</code>, and <code>value</code>
4871 is the value you want to truncate.
6352 To truncate bits, use {#link|@truncate#}.
48726353 </p>
48736354 {#header_close#}
48746355 {#header_open|Integer Overflow#}
......@@ -4880,9 +6361,9 @@ comptime {
48806361 <li><code>-</code> (negation)</li>
48816362 <li><code>*</code> (multiplication)</li>
48826363 <li><code>/</code> (division)</li>
4883 <li><code>@divTrunc</code> (division)</li>
4884 <li><code>@divFloor</code> (division)</li>
4885 <li><code>@divExact</code> (division)</li>
6364 <li>{#link|@divTrunc#} (division)</li>
6365 <li>{#link|@divFloor#} (division)</li>
6366 <li>{#link|@divExact#} (division)</li>
48866367 </ul>
48876368 <p>Example with addition at compile-time:</p>
48886369 {#code_begin|test_err|operation caused overflow#}
......@@ -4891,7 +6372,16 @@ comptime {
48916372 byte += 1;
48926373}
48936374 {#code_end#}
4894 <p>At runtime crashes with the message <code>integer overflow</code> and a stack trace.</p>
6375 <p>At runtime:</p>
6376 {#code_begin|exe_err#}
6377const std = @import("std");
6378
6379pub fn main() void {
6380 var byte: u8 = 255;
6381 byte += 1;
6382 std.debug.warn("value: {}\n", byte);
6383}
6384 {#code_end#}
48956385 {#header_close#}
48966386 {#header_open|Standard Library Math Functions#}
48976387 <p>These functions provided by the standard library return possible errors.</p>
......@@ -4926,13 +6416,13 @@ pub fn main() !void {
49266416 occurred, as well as returning the overflowed bits:
49276417 </p>
49286418 <ul>
4929 <li><code>@addWithOverflow</code></li>
4930 <li><code>@subWithOverflow</code></li>
4931 <li><code>@mulWithOverflow</code></li>
4932 <li><code>@shlWithOverflow</code></li>
6419 <li>{#link|@addWithOverflow#}</li>
6420 <li>{#link|@subWithOverflow#}</li>
6421 <li>{#link|@mulWithOverflow#}</li>
6422 <li>{#link|@shlWithOverflow#}</li>
49336423 </ul>
49346424 <p>
4935 Example of <code>@addWithOverflow</code>:
6425 Example of {#link|@addWithOverflow#}:
49366426 </p>
49376427 {#code_begin|exe#}
49386428const warn = @import("std").debug.warn;
......@@ -4978,7 +6468,16 @@ comptime {
49786468 const x = @shlExact(u8(0b01010101), 2);
49796469}
49806470 {#code_end#}
4981 <p>At runtime crashes with the message <code>left shift overflowed bits</code> and a stack trace.</p>
6471 <p>At runtime:</p>
6472 {#code_begin|exe_err#}
6473const std = @import("std");
6474
6475pub fn main() void {
6476 var x: u8 = 0b01010101;
6477 var y = @shlExact(x, 2);
6478 std.debug.warn("value: {}\n", y);
6479}
6480 {#code_end#}
49826481 {#header_close#}
49836482 {#header_open|Exact Right Shift Overflow#}
49846483 <p>At compile-time:</p>
......@@ -4987,7 +6486,16 @@ comptime {
49876486 const x = @shrExact(u8(0b10101010), 2);
49886487}
49896488 {#code_end#}
4990 <p>At runtime crashes with the message <code>right shift overflowed bits</code> and a stack trace.</p>
6489 <p>At runtime:</p>
6490 {#code_begin|exe_err#}
6491const std = @import("std");
6492
6493pub fn main() void {
6494 var x: u8 = 0b10101010;
6495 var y = @shrExact(x, 2);
6496 std.debug.warn("value: {}\n", y);
6497}
6498 {#code_end#}
49916499 {#header_close#}
49926500 {#header_open|Division by Zero#}
49936501 <p>At compile-time:</p>
......@@ -4998,8 +6506,17 @@ comptime {
49986506 const c = a / b;
49996507}
50006508 {#code_end#}
5001 <p>At runtime crashes with the message <code>division by zero</code> and a stack trace.</p>
6509 <p>At runtime:</p>
6510 {#code_begin|exe_err#}
6511const std = @import("std");
50026512
6513pub fn main() void {
6514 var a: u32 = 1;
6515 var b: u32 = 0;
6516 var c = a / b;
6517 std.debug.warn("value: {}\n", c);
6518}
6519 {#code_end#}
50036520 {#header_close#}
50046521 {#header_open|Remainder Division by Zero#}
50056522 <p>At compile-time:</p>
......@@ -5010,38 +6527,91 @@ comptime {
50106527 const c = a % b;
50116528}
50126529 {#code_end#}
5013 <p>At runtime crashes with the message <code>remainder division by zero</code> and a stack trace.</p>
6530 <p>At runtime:</p>
6531 {#code_begin|exe_err#}
6532const std = @import("std");
50146533
6534pub fn main() void {
6535 var a: u32 = 10;
6536 var b: u32 = 0;
6537 var c = a % b;
6538 std.debug.warn("value: {}\n", c);
6539}
6540 {#code_end#}
50156541 {#header_close#}
50166542 {#header_open|Exact Division Remainder#}
5017 <p>TODO</p>
6543 <p>At compile-time:</p>
6544 {#code_begin|test_err|exact division had a remainder#}
6545comptime {
6546 const a: u32 = 10;
6547 const b: u32 = 3;
6548 const c = @divExact(a, b);
6549}
6550 {#code_end#}
6551 <p>At runtime:</p>
6552 {#code_begin|exe_err#}
6553const std = @import("std");
6554
6555pub fn main() void {
6556 var a: u32 = 10;
6557 var b: u32 = 3;
6558 var c = @divExact(a, b);
6559 std.debug.warn("value: {}\n", c);
6560}
6561 {#code_end#}
50186562 {#header_close#}
50196563 {#header_open|Slice Widen Remainder#}
5020 <p>TODO</p>
6564 <p>At compile-time:</p>
6565 {#code_begin|test_err|unable to convert#}
6566comptime {
6567 var bytes = [5]u8{ 1, 2, 3, 4, 5 };
6568 var slice = @bytesToSlice(u32, bytes);
6569}
6570 {#code_end#}
6571 <p>At runtime:</p>
6572 {#code_begin|exe_err#}
6573const std = @import("std");
6574
6575pub fn main() void {
6576 var bytes = [5]u8{ 1, 2, 3, 4, 5 };
6577 var slice = @bytesToSlice(u32, bytes[0..]);
6578 std.debug.warn("value: {}\n", slice[0]);
6579}
6580 {#code_end#}
50216581 {#header_close#}
50226582 {#header_open|Attempt to Unwrap Null#}
50236583 <p>At compile-time:</p>
50246584 {#code_begin|test_err|unable to unwrap null#}
50256585comptime {
5026 const nullable_number: ?i32 = null;
5027 const number = ??nullable_number;
6586 const optional_number: ?i32 = null;
6587 const number = optional_number.?;
6588}
6589 {#code_end#}
6590 <p>At runtime:</p>
6591 {#code_begin|exe_err#}
6592const std = @import("std");
6593
6594pub fn main() void {
6595 var optional_number: ?i32 = null;
6596 var number = optional_number.?;
6597 std.debug.warn("value: {}\n", number);
50286598}
50296599 {#code_end#}
5030 <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p>
50316600 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
50326601 the <code>if</code> expression:</p>
50336602 {#code_begin|exe|test#}
50346603const warn = @import("std").debug.warn;
50356604pub fn main() void {
5036 const nullable_number: ?i32 = null;
6605 const optional_number: ?i32 = null;
50376606
5038 if (nullable_number) |number| {
6607 if (optional_number) |number| {
50396608 warn("got number: {}\n", number);
50406609 } else {
50416610 warn("it's null\n");
50426611 }
50436612}
50446613 {#code_end#}
6614 {#see_also|Optionals#}
50456615 {#header_close#}
50466616 {#header_open|Attempt to Unwrap Error#}
50476617 <p>At compile-time:</p>
......@@ -5054,7 +6624,19 @@ fn getNumberOrFail() !i32 {
50546624 return error.UnableToReturnNumber;
50556625}
50566626 {#code_end#}
5057 <p>At runtime crashes with the message <code>attempt to unwrap error: ErrorCode</code> and a stack trace.</p>
6627 <p>At runtime:</p>
6628 {#code_begin|exe_err#}
6629const std = @import("std");
6630
6631pub fn main() void {
6632 const number = getNumberOrFail() catch unreachable;
6633 std.debug.warn("value: {}\n", number);
6634}
6635
6636fn getNumberOrFail() !i32 {
6637 return error.UnableToReturnNumber;
6638}
6639 {#code_end#}
50586640 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
50596641 the <code>if</code> expression:</p>
50606642 {#code_begin|exe#}
......@@ -5074,30 +6656,204 @@ fn getNumberOrFail() !i32 {
50746656 return error.UnableToReturnNumber;
50756657}
50766658 {#code_end#}
6659 {#see_also|Errors#}
50776660 {#header_close#}
50786661 {#header_open|Invalid Error Code#}
50796662 <p>At compile-time:</p>
50806663 {#code_begin|test_err|integer value 11 represents no error#}
50816664comptime {
50826665 const err = error.AnError;
5083 const number = u32(err) + 10;
5084 const invalid_err = error(number);
6666 const number = @errorToInt(err) + 10;
6667 const invalid_err = @intToError(number);
6668}
6669 {#code_end#}
6670 <p>At runtime:</p>
6671 {#code_begin|exe_err#}
6672const std = @import("std");
6673
6674pub fn main() void {
6675 var err = error.AnError;
6676 var number = @errorToInt(err) + 500;
6677 var invalid_err = @intToError(number);
6678 std.debug.warn("value: {}\n", number);
50856679}
50866680 {#code_end#}
5087 <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>
50886681 {#header_close#}
50896682 {#header_open|Invalid Enum Cast#}
5090 <p>TODO</p>
6683 <p>At compile-time:</p>
6684 {#code_begin|test_err|has no tag matching integer value 3#}
6685const Foo = enum {
6686 A,
6687 B,
6688 C,
6689};
6690comptime {
6691 const a: u2 = 3;
6692 const b = @intToEnum(Foo, a);
6693}
6694 {#code_end#}
6695 <p>At runtime:</p>
6696 {#code_begin|exe_err#}
6697const std = @import("std");
50916698
6699const Foo = enum {
6700 A,
6701 B,
6702 C,
6703};
6704
6705pub fn main() void {
6706 var a: u2 = 3;
6707 var b = @intToEnum(Foo, a);
6708 std.debug.warn("value: {}\n", @tagName(b));
6709}
6710 {#code_end#}
50926711 {#header_close#}
5093 {#header_open|Incorrect Pointer Alignment#}
5094 <p>TODO</p>
50956712
6713 {#header_open|Invalid Error Set Cast#}
6714 <p>At compile-time:</p>
6715 {#code_begin|test_err|error.B not a member of error set 'Set2'#}
6716const Set1 = error{
6717 A,
6718 B,
6719};
6720const Set2 = error{
6721 A,
6722 C,
6723};
6724comptime {
6725 _ = @errSetCast(Set2, Set1.B);
6726}
6727 {#code_end#}
6728 <p>At runtime:</p>
6729 {#code_begin|exe_err#}
6730const std = @import("std");
6731
6732const Set1 = error{
6733 A,
6734 B,
6735};
6736const Set2 = error{
6737 A,
6738 C,
6739};
6740pub fn main() void {
6741 foo(Set1.B);
6742}
6743fn foo(set1: Set1) void {
6744 const x = @errSetCast(Set2, set1);
6745 std.debug.warn("value: {}\n", x);
6746}
6747 {#code_end#}
6748 {#header_close#}
6749
6750 {#header_open|Incorrect Pointer Alignment#}
6751 <p>At compile-time:</p>
6752 {#code_begin|test_err|pointer address 0x1 is not aligned to 4 bytes#}
6753comptime {
6754 const ptr = @intToPtr(*i32, 0x1);
6755 const aligned = @alignCast(4, ptr);
6756}
6757 {#code_end#}
6758 <p>At runtime:</p>
6759 {#code_begin|exe_err#}
6760pub fn main() !void {
6761 var array align(4) = []u32{ 0x11111111, 0x11111111 };
6762 const bytes = @sliceToBytes(array[0..]);
6763 if (foo(bytes) != 0x11111111) return error.Wrong;
6764}
6765fn foo(bytes: []u8) u32 {
6766 const slice4 = bytes[1..5];
6767 const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
6768 return int_slice[0];
6769}
6770 {#code_end#}
50966771 {#header_close#}
50976772 {#header_open|Wrong Union Field Access#}
5098 <p>TODO</p>
6773 <p>At compile-time:</p>
6774 {#code_begin|test_err|accessing union field 'float' while field 'int' is set#}
6775comptime {
6776 var f = Foo{ .int = 42 };
6777 f.float = 12.34;
6778}
6779
6780const Foo = union {
6781 float: f32,
6782 int: u32,
6783};
6784 {#code_end#}
6785 <p>At runtime:</p>
6786 {#code_begin|exe_err#}
6787const std = @import("std");
6788
6789const Foo = union {
6790 float: f32,
6791 int: u32,
6792};
6793
6794pub fn main() void {
6795 var f = Foo{ .int = 42 };
6796 bar(&f);
6797}
6798
6799fn bar(f: *Foo) void {
6800 f.float = 12.34;
6801 std.debug.warn("value: {}\n", f.float);
6802}
6803 {#code_end#}
6804 <p>
6805 This safety is not available for <code>extern</code> or <code>packed</code> unions.
6806 </p>
6807 <p>
6808 To change the active field of a union, assign the entire union, like this:
6809 </p>
6810 {#code_begin|exe#}
6811const std = @import("std");
6812
6813const Foo = union {
6814 float: f32,
6815 int: u32,
6816};
6817
6818pub fn main() void {
6819 var f = Foo{ .int = 42 };
6820 bar(&f);
6821}
6822
6823fn bar(f: *Foo) void {
6824 f.* = Foo{ .float = 12.34 };
6825 std.debug.warn("value: {}\n", f.float);
6826}
6827 {#code_end#}
6828 <p>
6829 To change the active field of a union when a meaningful value for the field is not known,
6830 use {#link|undefined#}, like this:
6831 </p>
6832 {#code_begin|exe#}
6833const std = @import("std");
6834
6835const Foo = union {
6836 float: f32,
6837 int: u32,
6838};
6839
6840pub fn main() void {
6841 var f = Foo{ .int = 42 };
6842 f = Foo{ .float = undefined };
6843 bar(&f);
6844 std.debug.warn("value: {}\n", f.float);
6845}
6846
6847fn bar(f: *Foo) void {
6848 f.float = 12.34;
6849}
6850 {#code_end#}
6851 {#header_close#}
50996852
6853 {#header_open|Out of Bounds Float To Integer Cast#}
6854 <p>TODO</p>
51006855 {#header_close#}
6856
51016857 {#header_close#}
51026858 {#header_open|Memory#}
51036859 <p>TODO: explain no default allocator in zig</p>
......@@ -5122,218 +6878,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
51226878 <p>
51236879 Example of what is imported with <code>@import("builtin")</code>:
51246880 </p>
5125 {#code_begin|syntax#}
5126pub const StackTrace = struct {
5127 index: usize,
5128 instruction_addresses: []usize,
5129};
5130
5131pub const Os = enum {
5132 freestanding,
5133 ananas,
5134 cloudabi,
5135 dragonfly,
5136 freebsd,
5137 fuchsia,
5138 ios,
5139 kfreebsd,
5140 linux,
5141 lv2,
5142 macosx,
5143 netbsd,
5144 openbsd,
5145 solaris,
5146 windows,
5147 haiku,
5148 minix,
5149 rtems,
5150 nacl,
5151 cnk,
5152 bitrig,
5153 aix,
5154 cuda,
5155 nvcl,
5156 amdhsa,
5157 ps4,
5158 elfiamcu,
5159 tvos,
5160 watchos,
5161 mesa3d,
5162 contiki,
5163 zen,
5164};
5165
5166pub const Arch = enum {
5167 armv8_2a,
5168 armv8_1a,
5169 armv8,
5170 armv8r,
5171 armv8m_baseline,
5172 armv8m_mainline,
5173 armv7,
5174 armv7em,
5175 armv7m,
5176 armv7s,
5177 armv7k,
5178 armv7ve,
5179 armv6,
5180 armv6m,
5181 armv6k,
5182 armv6t2,
5183 armv5,
5184 armv5te,
5185 armv4t,
5186 armeb,
5187 aarch64,
5188 aarch64_be,
5189 avr,
5190 bpfel,
5191 bpfeb,
5192 hexagon,
5193 mips,
5194 mipsel,
5195 mips64,
5196 mips64el,
5197 msp430,
5198 nios2,
5199 powerpc,
5200 powerpc64,
5201 powerpc64le,
5202 r600,
5203 amdgcn,
5204 riscv32,
5205 riscv64,
5206 sparc,
5207 sparcv9,
5208 sparcel,
5209 s390x,
5210 tce,
5211 tcele,
5212 thumb,
5213 thumbeb,
5214 i386,
5215 x86_64,
5216 xcore,
5217 nvptx,
5218 nvptx64,
5219 le32,
5220 le64,
5221 amdil,
5222 amdil64,
5223 hsail,
5224 hsail64,
5225 spir,
5226 spir64,
5227 kalimbav3,
5228 kalimbav4,
5229 kalimbav5,
5230 shave,
5231 lanai,
5232 wasm32,
5233 wasm64,
5234 renderscript32,
5235 renderscript64,
5236};
5237
5238pub const Environ = enum {
5239 unknown,
5240 gnu,
5241 gnuabi64,
5242 gnueabi,
5243 gnueabihf,
5244 gnux32,
5245 code16,
5246 eabi,
5247 eabihf,
5248 android,
5249 musl,
5250 musleabi,
5251 musleabihf,
5252 msvc,
5253 itanium,
5254 cygnus,
5255 amdopencl,
5256 coreclr,
5257 opencl,
5258};
5259
5260pub const ObjectFormat = enum {
5261 unknown,
5262 coff,
5263 elf,
5264 macho,
5265 wasm,
5266};
5267
5268pub const GlobalLinkage = enum {
5269 Internal,
5270 Strong,
5271 Weak,
5272 LinkOnce,
5273};
5274
5275pub const AtomicOrder = enum {
5276 Unordered,
5277 Monotonic,
5278 Acquire,
5279 Release,
5280 AcqRel,
5281 SeqCst,
5282};
5283
5284pub const Mode = enum {
5285 Debug,
5286 ReleaseSafe,
5287 ReleaseFast,
5288};
5289
5290pub const TypeId = enum {
5291 Type,
5292 Void,
5293 Bool,
5294 NoReturn,
5295 Int,
5296 Float,
5297 Pointer,
5298 Array,
5299 Struct,
5300 FloatLiteral,
5301 IntLiteral,
5302 UndefinedLiteral,
5303 NullLiteral,
5304 Nullable,
5305 ErrorUnion,
5306 Error,
5307 Enum,
5308 Union,
5309 Fn,
5310 Namespace,
5311 Block,
5312 BoundFn,
5313 ArgTuple,
5314 Opaque,
5315};
5316
5317pub const FloatMode = enum {
5318 Optimized,
5319 Strict,
5320};
5321
5322pub const Endian = enum {
5323 Big,
5324 Little,
5325};
5326
5327pub const endian = Endian.Little;
5328pub const is_test = false;
5329pub const os = Os.linux;
5330pub const arch = Arch.x86_64;
5331pub const environ = Environ.gnu;
5332pub const object_format = ObjectFormat.elf;
5333pub const mode = Mode.Debug;
5334pub const link_libc = false;
5335pub const have_error_return_tracing = true;
5336 {#code_end#}
6881 {#builtin#}
53376882 {#see_also|Build Mode#}
53386883 {#header_close#}
53396884 {#header_open|Root Source File#}
......@@ -5386,7 +6931,7 @@ pub const have_error_return_tracing = true;
53866931 {#header_open|C String Literals#}
53876932 {#code_begin|exe#}
53886933 {#link_libc#}
5389extern fn puts(&const u8) void;
6934extern fn puts([*]const u8) void;
53906935
53916936pub fn main() void {
53926937 puts(c"this has a null terminator");
......@@ -5407,7 +6952,7 @@ pub fn main() void {
54076952 {#code_begin|exe#}
54086953 {#link_libc#}
54096954const c = @cImport({
5410 // See https://github.com/zig-lang/zig/issues/515
6955 // See https://github.com/ziglang/zig/issues/515
54116956 @cDefine("_NO_CRT_STDIO_INLINE", "1");
54126957 @cInclude("stdio.h");
54136958});
......@@ -5445,9 +6990,12 @@ const c = @cImport({
54456990 {#code_begin|syntax#}
54466991const base64 = @import("std").base64;
54476992
5448export fn decode_base_64(dest_ptr: &u8, dest_len: usize,
5449 source_ptr: &const u8, source_len: usize) usize
5450{
6993export fn decode_base_64(
6994 dest_ptr: [*]u8,
6995 dest_len: usize,
6996 source_ptr: [*]const u8,
6997 source_len: usize,
6998) usize {
54516999 const src = source_ptr[0..source_len];
54527000 const dest = dest_ptr[0..dest_len];
54537001 const base64_decoder = base64.standard_decoder_unsafe;
......@@ -5477,7 +7025,7 @@ int main(int argc, char **argv) {
54777025 {#code_begin|syntax#}
54787026const Builder = @import("std").build.Builder;
54797027
5480pub fn build(b: &Builder) void {
7028pub fn build(b: *Builder) void {
54817029 const obj = b.addObject("base64", "base64.zig");
54827030
54837031 const exe = b.addCExecutable("test");
......@@ -5491,8 +7039,7 @@ pub fn build(b: &Builder) void {
54917039 b.default_step.dependOn(&exe.step);
54927040}
54937041 {#code_end#}
5494 {#header_close#}
5495 {#header_open|Terminal#}
7042 <p class="file">terminal</p>
54967043 <pre><code class="shell">$ zig build
54977044$ ./test
54987045all your base are belong to us</code></pre>
......@@ -5633,10 +7180,16 @@ Environments:
56337180 opencl</code></pre>
56347181 <p>
56357182 The Zig Standard Library (<code>@import("std")</code>) has architecture, environment, and operating sytsem
5636 abstractions, and thus takes additional work to support more platforms. It currently supports
5637 Linux x86_64. Not all standard library code requires operating system abstractions, however,
7183 abstractions, and thus takes additional work to support more platforms.
7184 Not all standard library code requires operating system abstractions, however,
56387185 so things such as generic data structures work an all above platforms.
56397186 </p>
7187 <p>The current list of targets supported by the Zig Standard Library is:</p>
7188 <ul>
7189 <li>Linux x86_64</li>
7190 <li>Windows x86_64</li>
7191 <li>MacOS x86_64</li>
7192 </ul>
56407193 {#header_close#}
56417194 {#header_open|Style Guide#}
56427195 <p>
......@@ -5750,7 +7303,7 @@ fn readU32Be() u32 {}
57507303 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
57517304 </ul>
57527305 <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>
5753 <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>
7306 <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/ziglang/zig/issues/663">issue #663</a></p>
57547307 {#header_close#}
57557308 {#header_open|Grammar#}
57567309 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF
......@@ -5805,9 +7358,9 @@ AsmInputItem = "[" Symbol "]" String "(" Expression ")"
58057358
58067359AsmClobbers= ":" list(String, ",")
58077360
5808UnwrapExpression = BoolOrExpression (UnwrapNullable | UnwrapError) | BoolOrExpression
7361UnwrapExpression = BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
58097362
5810UnwrapNullable = "??" Expression
7363UnwrapOptional = "orelse" Expression
58117364
58127365UnwrapError = "catch" option("|" Symbol "|") Expression
58137366
......@@ -5845,7 +7398,7 @@ Defer(body) = ("defer" | "deferror") body
58457398
58467399IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
58477400
5848SuspendExpression(body) = "suspend" option(("|" Symbol "|" body))
7401SuspendExpression(body) = "suspend" option( body )
58497402
58507403IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body)
58517404
......@@ -5881,7 +7434,7 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
58817434
58827435PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
58837436
5884SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
7437SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?")
58857438
58867439FieldAccessExpression = "." Symbol
58877440
......@@ -5897,7 +7450,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
58977450
58987451StructLiteralField = "." Symbol "=" Expression
58997452
5900PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
7453PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "-%" | "try" | "await"
59017454
59027455PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
59037456
......@@ -5990,8 +7543,8 @@ hljs.registerLanguage("zig", function(t) {
59907543 },
59917544 a = t.IR + "\\s*\\(",
59927545 c = {
5993 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
5994 built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate atomicRmw",
7546 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
7547 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz popCount import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",
59957548 literal: "true false null undefined"
59967549 },
59977550 n = [e, t.CLCM, t.CBCM, s, r];
doc/semantic_analysis.md deleted-74
......@@ -1,74 +0,0 @@
1# How Semantic Analysis Works
2
3We start with a set of files. Typically the user only has one entry point file,
4which imports the other files they want to use. However, the compiler may
5choose to add more files to the compilation, for example bootstrap.zig which
6contains the code that calls main.
7
8Our goal now is to treat everything that is marked with the `export` keyword
9as a root node, and then parse and semantically analyze as little as possible
10in order to fulfill these exports.
11
12So, some parts of the code very well may have uncaught semantic errors, but as
13long as the code is not referenced in any way, the compiler will not complain
14because the code may as well not exist. This is similar to the fact that code
15excluded from compilation with an `#ifdef` in C is not analyzed. Avoiding
16analyzing unused code will save compilation time - one of Zig's goals.
17
18So, for each file, we iterate over the top level declarations. The set of top
19level declarations are:
20
21 * Function Definition
22 * Global Variable Declaration
23 * Container Declaration (struct or enum)
24 * Error Value Declaration
25 * Use Declaration
26
27Each of these can have `export` attached to them except for error value
28declarations and use declarations.
29
30When we see a top level declaration during this iteration, we determine its
31unique name identifier within the file. For example, for a function definition,
32the unique name identifier is simply its name. Using this name we add the top
33level declaration to a map.
34
35If the top level declaration is exported, we add it to a set of exported top
36level identifiers.
37
38If the top level declaration is a use declaration, we add it to a set of use
39declarations.
40
41If the top level declaration is an error value declaration, we assign it a value
42and increment the count of error values.
43
44After this preliminary iteration over the top level declarations, we iterate
45over the use declarations and resolve them. To resolve a use declaration, we
46analyze the associated expression, verify that its type is the namespace type,
47and then add all the items from the namespace into the top level declaration
48map for the current file.
49
50To analyze an expression, we recurse the abstract syntax tree of the
51expression. Whenever we must look up a symbol, if the symbol exists already,
52we can use it. Otherwise, we look it up in the top level declaration map.
53If it exists, we can use it. Otherwise, we interrupt resolving this use
54declaration to resolve the next one. If a dependency loop is detected, emit
55an error. If all use declarations are resolved yet the symbol we need still
56does not exist, emit an error.
57
58To analyze an `@import` expression, find the referenced file, parse it, and
59add it to the set of files to perform semantic analysis on.
60
61Proceed through the rest of the use declarations the same way.
62
63If we make it through the use declarations without an error, then we have a
64complete map of all globals that exist in the current file.
65
66Next we iterate over the set of exported top level declarations.
67
68If it's a function definition, add it to the set of exported function
69definitions and resolve the function prototype only. Otherwise, resolve the
70top level declaration completely. This may involve recursively resolving other
71top level declarations that expressions depend on.
72
73Finally, iterate over the set of exported function definitions and analyze the
74bodies.
example/cat/main.zig+2-2
......@@ -7,7 +7,7 @@ const allocator = std.debug.global_allocator;
77
88pub fn main() !void {
99 var args_it = os.args();
10 const exe = try unwrapArg(??args_it.next(allocator));
10 const exe = try unwrapArg(args_it.next(allocator).?);
1111 var catted_anything = false;
1212 var stdout_file = try io.getStdOut();
1313
......@@ -41,7 +41,7 @@ fn usage(exe: []const u8) !void {
4141 return error.Invalid;
4242}
4343
44fn cat_file(stdout: &os.File, file: &os.File) !void {
44fn cat_file(stdout: *os.File, file: *os.File) !void {
4545 var buf: [1024 * 4]u8 = undefined;
4646
4747 while (true) {
example/guess_number/main.zig+1-1
......@@ -23,7 +23,7 @@ pub fn main() !void {
2323
2424 while (true) {
2525 try stdout.print("\nGuess a number between 1 and 100: ");
26 var line_buf : [20]u8 = undefined;
26 var line_buf: [20]u8 = undefined;
2727
2828 const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
2929 error.InputTooLong => {
example/hello_world/hello_libc.zig+3-4
......@@ -1,5 +1,5 @@
11const c = @cImport({
2 // See https://github.com/zig-lang/zig/issues/515
2 // See https://github.com/ziglang/zig/issues/515
33 @cDefine("_NO_CRT_STDIO_INLINE", "1");
44 @cInclude("stdio.h");
55 @cInclude("string.h");
......@@ -7,9 +7,8 @@ const c = @cImport({
77
88const msg = c"Hello, world!\n";
99
10export fn main(argc: c_int, argv: &&u8) c_int {
11 if (c.printf(msg) != c_int(c.strlen(msg)))
12 return -1;
10export fn main(argc: c_int, argv: **u8) c_int {
11 if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;
1312
1413 return 0;
1514}
example/mix_o_files/base64.zig+1-1
......@@ -1,6 +1,6 @@
11const base64 = @import("std").base64;
22
3export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) usize {
3export fn decode_base_64(dest_ptr: [*]u8, dest_len: usize, source_ptr: [*]const u8, source_len: usize) usize {
44 const src = source_ptr[0..source_len];
55 const dest = dest_ptr[0..dest_len];
66 const base64_decoder = base64.standard_decoder_unsafe;
example/mix_o_files/build.zig+2-4
......@@ -1,12 +1,10 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const obj = b.addObject("base64", "base64.zig");
55
66 const exe = b.addCExecutable("test");
7 exe.addCompileFlags([][]const u8 {
8 "-std=c99",
9 });
7 exe.addCompileFlags([][]const u8{"-std=c99"});
108 exe.addSourceFile("test.c");
119 exe.addObject(obj);
1210
example/shared_library/build.zig+2-4
......@@ -1,12 +1,10 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
66 const exe = b.addCExecutable("test");
7 exe.addCompileFlags([][]const u8 {
8 "-std=c99",
9 });
7 exe.addCompileFlags([][]const u8{"-std=c99"});
108 exe.addSourceFile("test.c");
119 exe.linkLibrary(lib);
1210
src-self-hosted/arg.zig+52-44
......@@ -30,24 +30,22 @@ fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
3030}
3131
3232// Modifies the current argument index during iteration
33fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,
34 allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
35
33fn readFlagArguments(allocator: *Allocator, args: []const []const u8, required: usize, allowed_set: ?[]const []const u8, index: *usize) !FlagArg {
3634 switch (required) {
37 0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?
35 0 => return FlagArg{ .None = undefined }, // TODO: Required to force non-tag but value?
3836 1 => {
39 if (*index + 1 >= args.len) {
37 if (index.* + 1 >= args.len) {
4038 return error.MissingFlagArguments;
4139 }
4240
43 *index += 1;
44 const arg = args[*index];
41 index.* += 1;
42 const arg = args[index.*];
4543
4644 if (!argInAllowedSet(allowed_set, arg)) {
4745 return error.ArgumentNotInAllowedSet;
4846 }
4947
50 return FlagArg { .Single = arg };
48 return FlagArg{ .Single = arg };
5149 },
5250 else => |needed| {
5351 var extra = ArrayList([]const u8).init(allocator);
......@@ -55,12 +53,12 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
5553
5654 var j: usize = 0;
5755 while (j < needed) : (j += 1) {
58 if (*index + 1 >= args.len) {
56 if (index.* + 1 >= args.len) {
5957 return error.MissingFlagArguments;
6058 }
6159
62 *index += 1;
63 const arg = args[*index];
60 index.* += 1;
61 const arg = args[index.*];
6462
6563 if (!argInAllowedSet(allowed_set, arg)) {
6664 return error.ArgumentNotInAllowedSet;
......@@ -69,7 +67,7 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
6967 try extra.append(arg);
7068 }
7169
72 return FlagArg { .Many = extra };
70 return FlagArg{ .Many = extra };
7371 },
7472 }
7573}
......@@ -81,8 +79,8 @@ pub const Args = struct {
8179 flags: HashMapFlags,
8280 positionals: ArrayList([]const u8),
8381
84 pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
85 var parsed = Args {
82 pub fn parse(allocator: *Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
83 var parsed = Args{
8684 .flags = HashMapFlags.init(allocator),
8785 .positionals = ArrayList([]const u8).init(allocator),
8886 };
......@@ -101,7 +99,7 @@ pub const Args = struct {
10199 error.ArgumentNotInAllowedSet => {
102100 std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
103101 std.debug.warn("allowed options are ");
104 for (??flag.allowed_set) |possible| {
102 for (flag.allowed_set.?) |possible| {
105103 std.debug.warn("'{}' ", possible);
106104 }
107105 std.debug.warn("\n");
......@@ -116,11 +114,7 @@ pub const Args = struct {
116114 };
117115
118116 if (flag.mergable) {
119 var prev =
120 if (parsed.flags.get(flag_name_trimmed)) |entry|
121 entry.value.Many
122 else
123 ArrayList([]const u8).init(allocator);
117 var prev = if (parsed.flags.get(flag_name_trimmed)) |entry| entry.value.Many else ArrayList([]const u8).init(allocator);
124118
125119 // MergeN creation disallows 0 length flag entry (doesn't make sense)
126120 switch (flag_args) {
......@@ -129,7 +123,7 @@ pub const Args = struct {
129123 FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
130124 }
131125
132 _ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });
126 _ = try parsed.flags.put(flag_name_trimmed, FlagArg{ .Many = prev });
133127 } else {
134128 _ = try parsed.flags.put(flag_name_trimmed, flag_args);
135129 }
......@@ -149,21 +143,23 @@ pub const Args = struct {
149143 return parsed;
150144 }
151145
152 pub fn deinit(self: &Args) void {
146 pub fn deinit(self: *Args) void {
153147 self.flags.deinit();
154148 self.positionals.deinit();
155149 }
156150
157151 // e.g. --help
158 pub fn present(self: &Args, name: []const u8) bool {
152 pub fn present(self: *Args, name: []const u8) bool {
159153 return self.flags.contains(name);
160154 }
161155
162156 // e.g. --name value
163 pub fn single(self: &Args, name: []const u8) ?[]const u8 {
157 pub fn single(self: *Args, name: []const u8) ?[]const u8 {
164158 if (self.flags.get(name)) |entry| {
165159 switch (entry.value) {
166 FlagArg.Single => |inner| { return inner; },
160 FlagArg.Single => |inner| {
161 return inner;
162 },
167163 else => @panic("attempted to retrieve flag with wrong type"),
168164 }
169165 } else {
......@@ -172,14 +168,16 @@ pub const Args = struct {
172168 }
173169
174170 // e.g. --names value1 value2 value3
175 pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
171 pub fn many(self: *Args, name: []const u8) []const []const u8 {
176172 if (self.flags.get(name)) |entry| {
177173 switch (entry.value) {
178 FlagArg.Many => |inner| { return inner.toSliceConst(); },
174 FlagArg.Many => |inner| {
175 return inner.toSliceConst();
176 },
179177 else => @panic("attempted to retrieve flag with wrong type"),
180178 }
181179 } else {
182 return null;
180 return []const []const u8{};
183181 }
184182 }
185183};
......@@ -207,7 +205,7 @@ pub const Flag = struct {
207205 }
208206
209207 pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
210 return Flag {
208 return Flag{
211209 .name = name,
212210 .required = n,
213211 .mergable = false,
......@@ -220,7 +218,7 @@ pub const Flag = struct {
220218 @compileError("n must be greater than 0");
221219 }
222220
223 return Flag {
221 return Flag{
224222 .name = name,
225223 .required = n,
226224 .mergable = true,
......@@ -229,7 +227,7 @@ pub const Flag = struct {
229227 }
230228
231229 pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
232 return Flag {
230 return Flag{
233231 .name = name,
234232 .required = 1,
235233 .mergable = false,
......@@ -239,26 +237,36 @@ pub const Flag = struct {
239237};
240238
241239test "parse arguments" {
242 const spec1 = comptime []const Flag {
240 const spec1 = comptime []const Flag{
243241 Flag.Bool("--help"),
244242 Flag.Bool("--init"),
245243 Flag.Arg1("--build-file"),
246 Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),
244 Flag.Option("--color", []const []const u8{
245 "on",
246 "off",
247 "auto",
248 }),
247249 Flag.ArgN("--pkg-begin", 2),
248250 Flag.ArgMergeN("--object", 1),
249251 Flag.ArgN("--library", 1),
250252 };
251253
252 const cliargs = []const []const u8 {
254 const cliargs = []const []const u8{
253255 "build",
254256 "--help",
255257 "pos1",
256 "--build-file", "build.zig",
257 "--object", "obj1",
258 "--object", "obj2",
259 "--library", "lib1",
260 "--library", "lib2",
261 "--color", "on",
258 "--build-file",
259 "build.zig",
260 "--object",
261 "obj1",
262 "--object",
263 "obj2",
264 "--library",
265 "lib1",
266 "--library",
267 "lib2",
268 "--color",
269 "on",
262270 "pos2",
263271 };
264272
......@@ -268,14 +276,14 @@ test "parse arguments" {
268276 debug.assert(!args.present("help2"));
269277 debug.assert(!args.present("init"));
270278
271 debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig"));
272 debug.assert(mem.eql(u8, ??args.single("color"), "on"));
279 debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig"));
280 debug.assert(mem.eql(u8, args.single("color").?, "on"));
273281
274 const objects = ??args.many("object");
282 const objects = args.many("object").?;
275283 debug.assert(mem.eql(u8, objects[0], "obj1"));
276284 debug.assert(mem.eql(u8, objects[1], "obj2"));
277285
278 debug.assert(mem.eql(u8, ??args.single("library"), "lib2"));
286 debug.assert(mem.eql(u8, args.single("library").?, "lib2"));
279287
280288 const pos = args.positionals.toSliceConst();
281289 debug.assert(mem.eql(u8, pos[0], "build"));
src-self-hosted/c.zig+3
......@@ -1,5 +1,8 @@
11pub use @cImport({
2 @cDefine("__STDC_CONSTANT_MACROS", "");
3 @cDefine("__STDC_LIMIT_MACROS", "");
24 @cInclude("inttypes.h");
35 @cInclude("config.h");
46 @cInclude("zig_llvm.h");
7 @cInclude("windows_sdk.h");
58});
src-self-hosted/c_int.zig created+68
......@@ -0,0 +1,68 @@
1pub const CInt = struct {
2 id: Id,
3 zig_name: []const u8,
4 c_name: []const u8,
5 is_signed: bool,
6
7 pub const Id = enum {
8 Short,
9 UShort,
10 Int,
11 UInt,
12 Long,
13 ULong,
14 LongLong,
15 ULongLong,
16 };
17
18 pub const list = []CInt{
19 CInt{
20 .id = Id.Short,
21 .zig_name = "c_short",
22 .c_name = "short",
23 .is_signed = true,
24 },
25 CInt{
26 .id = Id.UShort,
27 .zig_name = "c_ushort",
28 .c_name = "unsigned short",
29 .is_signed = false,
30 },
31 CInt{
32 .id = Id.Int,
33 .zig_name = "c_int",
34 .c_name = "int",
35 .is_signed = true,
36 },
37 CInt{
38 .id = Id.UInt,
39 .zig_name = "c_uint",
40 .c_name = "unsigned int",
41 .is_signed = false,
42 },
43 CInt{
44 .id = Id.Long,
45 .zig_name = "c_long",
46 .c_name = "long",
47 .is_signed = true,
48 },
49 CInt{
50 .id = Id.ULong,
51 .zig_name = "c_ulong",
52 .c_name = "unsigned long",
53 .is_signed = false,
54 },
55 CInt{
56 .id = Id.LongLong,
57 .zig_name = "c_longlong",
58 .c_name = "long long",
59 .is_signed = true,
60 },
61 CInt{
62 .id = Id.ULongLong,
63 .zig_name = "c_ulonglong",
64 .c_name = "unsigned long long",
65 .is_signed = false,
66 },
67 };
68};
src-self-hosted/codegen.zig created+450
......@@ -0,0 +1,450 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Compilation = @import("compilation.zig").Compilation;
4const llvm = @import("llvm.zig");
5const c = @import("c.zig");
6const ir = @import("ir.zig");
7const Value = @import("value.zig").Value;
8const Type = @import("type.zig").Type;
9const Scope = @import("scope.zig").Scope;
10const event = std.event;
11const assert = std.debug.assert;
12const DW = std.dwarf;
13
14pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) !void {
15 fn_val.base.ref();
16 defer fn_val.base.deref(comp);
17 defer code.destroy(comp.gpa());
18
19 var output_path = try await (async comp.createRandomOutputPath(comp.target.objFileExt()) catch unreachable);
20 errdefer output_path.deinit();
21
22 const llvm_handle = try comp.event_loop_local.getAnyLlvmContext();
23 defer llvm_handle.release(comp.event_loop_local);
24
25 const context = llvm_handle.node.data;
26
27 const module = llvm.ModuleCreateWithNameInContext(comp.name.ptr(), context) orelse return error.OutOfMemory;
28 defer llvm.DisposeModule(module);
29
30 llvm.SetTarget(module, comp.llvm_triple.ptr());
31 llvm.SetDataLayout(module, comp.target_layout_str);
32
33 if (comp.target.getObjectFormat() == builtin.ObjectFormat.coff) {
34 llvm.AddModuleCodeViewFlag(module);
35 } else {
36 llvm.AddModuleDebugInfoFlag(module);
37 }
38
39 const builder = llvm.CreateBuilderInContext(context) orelse return error.OutOfMemory;
40 defer llvm.DisposeBuilder(builder);
41
42 const dibuilder = llvm.CreateDIBuilder(module, true) orelse return error.OutOfMemory;
43 defer llvm.DisposeDIBuilder(dibuilder);
44
45 // Don't use ZIG_VERSION_STRING here. LLVM misparses it when it includes
46 // the git revision.
47 const producer = try std.Buffer.allocPrint(
48 &code.arena.allocator,
49 "zig {}.{}.{}",
50 u32(c.ZIG_VERSION_MAJOR),
51 u32(c.ZIG_VERSION_MINOR),
52 u32(c.ZIG_VERSION_PATCH),
53 );
54 const flags = c"";
55 const runtime_version = 0;
56 const compile_unit_file = llvm.CreateFile(
57 dibuilder,
58 comp.name.ptr(),
59 comp.root_package.root_src_dir.ptr(),
60 ) orelse return error.OutOfMemory;
61 const is_optimized = comp.build_mode != builtin.Mode.Debug;
62 const compile_unit = llvm.CreateCompileUnit(
63 dibuilder,
64 DW.LANG_C99,
65 compile_unit_file,
66 producer.ptr(),
67 is_optimized,
68 flags,
69 runtime_version,
70 c"",
71 0,
72 !comp.strip,
73 ) orelse return error.OutOfMemory;
74
75 var ofile = ObjectFile{
76 .comp = comp,
77 .module = module,
78 .builder = builder,
79 .dibuilder = dibuilder,
80 .context = context,
81 .lock = event.Lock.init(comp.loop),
82 .arena = &code.arena.allocator,
83 };
84
85 try renderToLlvmModule(&ofile, fn_val, code);
86
87 // TODO module level assembly
88 //if (buf_len(&g->global_asm) != 0) {
89 // LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm));
90 //}
91
92 llvm.DIBuilderFinalize(dibuilder);
93
94 if (comp.verbose_llvm_ir) {
95 std.debug.warn("raw module:\n");
96 llvm.DumpModule(ofile.module);
97 }
98
99 // verify the llvm module when safety is on
100 if (std.debug.runtime_safety) {
101 var error_ptr: ?[*]u8 = null;
102 _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr);
103 }
104
105 assert(comp.emit_file_type == Compilation.Emit.Binary); // TODO support other types
106
107 const is_small = comp.build_mode == builtin.Mode.ReleaseSmall;
108 const is_debug = comp.build_mode == builtin.Mode.Debug;
109
110 var err_msg: [*]u8 = undefined;
111 // TODO integrate this with evented I/O
112 if (llvm.TargetMachineEmitToFile(
113 comp.target_machine,
114 module,
115 output_path.ptr(),
116 llvm.EmitBinary,
117 &err_msg,
118 is_debug,
119 is_small,
120 )) {
121 if (std.debug.runtime_safety) {
122 std.debug.panic("unable to write object file {}: {s}\n", output_path.toSliceConst(), err_msg);
123 }
124 return error.WritingObjectFileFailed;
125 }
126 //validate_inline_fns(g); TODO
127 fn_val.containing_object = output_path;
128 if (comp.verbose_llvm_ir) {
129 std.debug.warn("optimized module:\n");
130 llvm.DumpModule(ofile.module);
131 }
132 if (comp.verbose_link) {
133 std.debug.warn("created {}\n", output_path.toSliceConst());
134 }
135}
136
137pub const ObjectFile = struct {
138 comp: *Compilation,
139 module: llvm.ModuleRef,
140 builder: llvm.BuilderRef,
141 dibuilder: *llvm.DIBuilder,
142 context: llvm.ContextRef,
143 lock: event.Lock,
144 arena: *std.mem.Allocator,
145
146 fn gpa(self: *ObjectFile) *std.mem.Allocator {
147 return self.comp.gpa();
148 }
149};
150
151pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {
152 // TODO audit more of codegen.cpp:fn_llvm_value and port more logic
153 const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context);
154 const llvm_fn = llvm.AddFunction(
155 ofile.module,
156 fn_val.symbol_name.ptr(),
157 llvm_fn_type,
158 ) orelse return error.OutOfMemory;
159
160 const want_fn_safety = fn_val.block_scope.?.safety.get(ofile.comp);
161 if (want_fn_safety and ofile.comp.haveLibC()) {
162 try addLLVMFnAttr(ofile, llvm_fn, "sspstrong");
163 try addLLVMFnAttrStr(ofile, llvm_fn, "stack-protector-buffer-size", "4");
164 }
165
166 // TODO
167 //if (fn_val.align_stack) |align_stack| {
168 // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);
169 //}
170
171 const fn_type = fn_val.base.typ.cast(Type.Fn).?;
172 const fn_type_normal = &fn_type.key.data.Normal;
173
174 try addLLVMFnAttr(ofile, llvm_fn, "nounwind");
175 //add_uwtable_attr(g, fn_table_entry->llvm_value);
176 try addLLVMFnAttr(ofile, llvm_fn, "nobuiltin");
177
178 //if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
179 // ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
180 // ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
181 //}
182
183 //if (fn_table_entry->section_name) {
184 // LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));
185 //}
186 //if (fn_table_entry->align_bytes > 0) {
187 // LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);
188 //} else {
189 // // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
190 // // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling
191 // // any of the functions for getting alignment. Not specifying the alignment should
192 // // use the ABI alignment, which is fine.
193 //}
194
195 //if (!type_has_bits(return_type)) {
196 // // nothing to do
197 //} else if (type_is_codegen_pointer(return_type)) {
198 // addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
199 //} else if (handle_is_ptr(return_type) &&
200 // calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
201 //{
202 // addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
203 // addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
204 //}
205
206 // TODO set parameter attributes
207
208 // TODO
209 //uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
210 //if (err_ret_trace_arg_index != UINT32_MAX) {
211 // addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
212 //}
213
214 const cur_ret_ptr = if (fn_type_normal.return_type.handleIsPtr()) llvm.GetParam(llvm_fn, 0) else null;
215
216 // build all basic blocks
217 for (code.basic_block_list.toSlice()) |bb| {
218 bb.llvm_block = llvm.AppendBasicBlockInContext(
219 ofile.context,
220 llvm_fn,
221 bb.name_hint,
222 ) orelse return error.OutOfMemory;
223 }
224 const entry_bb = code.basic_block_list.at(0);
225 llvm.PositionBuilderAtEnd(ofile.builder, entry_bb.llvm_block);
226
227 llvm.ClearCurrentDebugLocation(ofile.builder);
228
229 // TODO set up error return tracing
230 // TODO allocate temporary stack values
231
232 const var_list = fn_type.non_key.Normal.variable_list.toSliceConst();
233 // create debug variable declarations for variables and allocate all local variables
234 for (var_list) |var_scope, i| {
235 const var_type = switch (var_scope.data) {
236 Scope.Var.Data.Const => unreachable,
237 Scope.Var.Data.Param => |param| param.typ,
238 };
239 // if (!type_has_bits(var->value->type)) {
240 // continue;
241 // }
242 // if (ir_get_var_is_comptime(var))
243 // continue;
244 // if (type_requires_comptime(var->value->type))
245 // continue;
246 // if (var->src_arg_index == SIZE_MAX) {
247 // var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
248
249 // var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
250 // buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
251 // var->value->type->di_type, !g->strip_debug_symbols, 0);
252
253 // } else {
254 // it's a parameter
255 // assert(var->gen_arg_index != SIZE_MAX);
256 // TypeTableEntry *gen_type;
257 // FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
258
259 if (var_type.handleIsPtr()) {
260 // if (gen_info->is_byval) {
261 // gen_type = var->value->type;
262 // } else {
263 // gen_type = gen_info->type;
264 // }
265 var_scope.data.Param.llvm_value = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
266 } else {
267 // gen_type = var->value->type;
268 var_scope.data.Param.llvm_value = try renderAlloca(ofile, var_type, var_scope.name, Type.Pointer.Align.Abi);
269 }
270 // if (var->decl_node) {
271 // var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
272 // buf_ptr(&var->name), import->di_file,
273 // (unsigned)(var->decl_node->line + 1),
274 // gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
275 // }
276
277 // }
278 }
279
280 // TODO finishing error return trace setup. we have to do this after all the allocas.
281
282 // create debug variable declarations for parameters
283 // rely on the first variables in the variable_list being parameters.
284 //size_t next_var_i = 0;
285 for (fn_type.key.data.Normal.params) |param, i| {
286 //FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
287 //if (info->gen_index == SIZE_MAX)
288 // continue;
289 const scope_var = var_list[i];
290 //assert(variable->src_arg_index != SIZE_MAX);
291 //next_var_i += 1;
292 //assert(variable);
293 //assert(variable->value_ref);
294
295 if (!param.typ.handleIsPtr()) {
296 //clear_debug_source_node(g);
297 const llvm_param = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
298 _ = renderStoreUntyped(
299 ofile,
300 llvm_param,
301 scope_var.data.Param.llvm_value,
302 Type.Pointer.Align.Abi,
303 Type.Pointer.Vol.Non,
304 );
305 }
306
307 //if (variable->decl_node) {
308 // gen_var_debug_decl(g, variable);
309 //}
310 }
311
312 for (code.basic_block_list.toSlice()) |current_block| {
313 llvm.PositionBuilderAtEnd(ofile.builder, current_block.llvm_block);
314 for (current_block.instruction_list.toSlice()) |instruction| {
315 if (instruction.ref_count == 0 and !instruction.hasSideEffects()) continue;
316
317 instruction.llvm_value = try instruction.render(ofile, fn_val);
318 }
319 current_block.llvm_exit_block = llvm.GetInsertBlock(ofile.builder);
320 }
321}
322
323fn addLLVMAttr(
324 ofile: *ObjectFile,
325 val: llvm.ValueRef,
326 attr_index: llvm.AttributeIndex,
327 attr_name: []const u8,
328) !void {
329 const kind_id = llvm.GetEnumAttributeKindForName(attr_name.ptr, attr_name.len);
330 assert(kind_id != 0);
331 const llvm_attr = llvm.CreateEnumAttribute(ofile.context, kind_id, 0) orelse return error.OutOfMemory;
332 llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
333}
334
335fn addLLVMAttrStr(
336 ofile: *ObjectFile,
337 val: llvm.ValueRef,
338 attr_index: llvm.AttributeIndex,
339 attr_name: []const u8,
340 attr_val: []const u8,
341) !void {
342 const llvm_attr = llvm.CreateStringAttribute(
343 ofile.context,
344 attr_name.ptr,
345 @intCast(c_uint, attr_name.len),
346 attr_val.ptr,
347 @intCast(c_uint, attr_val.len),
348 ) orelse return error.OutOfMemory;
349 llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
350}
351
352fn addLLVMAttrInt(
353 val: llvm.ValueRef,
354 attr_index: llvm.AttributeIndex,
355 attr_name: []const u8,
356 attr_val: u64,
357) !void {
358 const kind_id = llvm.GetEnumAttributeKindForName(attr_name.ptr, attr_name.len);
359 assert(kind_id != 0);
360 const llvm_attr = llvm.CreateEnumAttribute(ofile.context, kind_id, attr_val) orelse return error.OutOfMemory;
361 llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
362}
363
364fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void {
365 return addLLVMAttr(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name);
366}
367
368fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void {
369 return addLLVMAttrStr(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);
370}
371
372fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
373 return addLLVMAttrInt(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);
374}
375
376fn renderLoadUntyped(
377 ofile: *ObjectFile,
378 ptr: llvm.ValueRef,
379 alignment: Type.Pointer.Align,
380 vol: Type.Pointer.Vol,
381 name: [*]const u8,
382) !llvm.ValueRef {
383 const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
384 switch (vol) {
385 Type.Pointer.Vol.Non => {},
386 Type.Pointer.Vol.Volatile => llvm.SetVolatile(result, 1),
387 }
388 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm.GetElementType(llvm.TypeOf(ptr))));
389 return result;
390}
391
392fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
393 return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
394}
395
396pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
397 const child_type = ptr_type.key.child_type;
398 if (!child_type.hasBits()) {
399 return null;
400 }
401 if (child_type.handleIsPtr()) {
402 return ptr;
403 }
404 return try renderLoad(ofile, ptr, ptr_type, c"");
405}
406
407pub fn renderStoreUntyped(
408 ofile: *ObjectFile,
409 value: llvm.ValueRef,
410 ptr: llvm.ValueRef,
411 alignment: Type.Pointer.Align,
412 vol: Type.Pointer.Vol,
413) !llvm.ValueRef {
414 const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
415 switch (vol) {
416 Type.Pointer.Vol.Non => {},
417 Type.Pointer.Vol.Volatile => llvm.SetVolatile(result, 1),
418 }
419 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm.TypeOf(value)));
420 return result;
421}
422
423pub fn renderStore(
424 ofile: *ObjectFile,
425 value: llvm.ValueRef,
426 ptr: llvm.ValueRef,
427 ptr_type: *Type.Pointer,
428) !llvm.ValueRef {
429 return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
430}
431
432pub fn renderAlloca(
433 ofile: *ObjectFile,
434 var_type: *Type,
435 name: []const u8,
436 alignment: Type.Pointer.Align,
437) !llvm.ValueRef {
438 const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
439 const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
440 const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
441 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type));
442 return result;
443}
444
445pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
446 return switch (alignment) {
447 Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
448 Type.Pointer.Align.Override => |a| a,
449 };
450}
src-self-hosted/compilation.zig created+1303
......@@ -0,0 +1,1303 @@
1const std = @import("std");
2const os = std.os;
3const io = std.io;
4const mem = std.mem;
5const Allocator = mem.Allocator;
6const Buffer = std.Buffer;
7const llvm = @import("llvm.zig");
8const c = @import("c.zig");
9const builtin = @import("builtin");
10const Target = @import("target.zig").Target;
11const warn = std.debug.warn;
12const Token = std.zig.Token;
13const ArrayList = std.ArrayList;
14const errmsg = @import("errmsg.zig");
15const ast = std.zig.ast;
16const event = std.event;
17const assert = std.debug.assert;
18const AtomicRmwOp = builtin.AtomicRmwOp;
19const AtomicOrder = builtin.AtomicOrder;
20const Scope = @import("scope.zig").Scope;
21const Decl = @import("decl.zig").Decl;
22const ir = @import("ir.zig");
23const Visib = @import("visib.zig").Visib;
24const Value = @import("value.zig").Value;
25const Type = Value.Type;
26const Span = errmsg.Span;
27const Msg = errmsg.Msg;
28const codegen = @import("codegen.zig");
29const Package = @import("package.zig").Package;
30const link = @import("link.zig").link;
31const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
32const CInt = @import("c_int.zig").CInt;
33
34/// Data that is local to the event loop.
35pub const EventLoopLocal = struct {
36 loop: *event.Loop,
37 llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
38 lld_lock: event.Lock,
39
40 /// TODO pool these so that it doesn't have to lock
41 prng: event.Locked(std.rand.DefaultPrng),
42
43 native_libc: event.Future(LibCInstallation),
44
45 var lazy_init_targets = std.lazyInit(void);
46
47 fn init(loop: *event.Loop) !EventLoopLocal {
48 lazy_init_targets.get() orelse {
49 Target.initializeAll();
50 lazy_init_targets.resolve();
51 };
52
53 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
54 try std.os.getRandomBytes(seed_bytes[0..]);
55 const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
56
57 return EventLoopLocal{
58 .loop = loop,
59 .lld_lock = event.Lock.init(loop),
60 .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
61 .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
62 .native_libc = event.Future(LibCInstallation).init(loop),
63 };
64 }
65
66 /// Must be called only after EventLoop.run completes.
67 fn deinit(self: *EventLoopLocal) void {
68 self.lld_lock.deinit();
69 while (self.llvm_handle_pool.pop()) |node| {
70 c.LLVMContextDispose(node.data);
71 self.loop.allocator.destroy(node);
72 }
73 }
74
75 /// Gets an exclusive handle on any LlvmContext.
76 /// Caller must release the handle when done.
77 pub fn getAnyLlvmContext(self: *EventLoopLocal) !LlvmHandle {
78 if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
79
80 const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
81 errdefer c.LLVMContextDispose(context_ref);
82
83 const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{
84 .next = undefined,
85 .data = context_ref,
86 });
87 errdefer self.loop.allocator.destroy(node);
88
89 return LlvmHandle{ .node = node };
90 }
91
92 pub async fn getNativeLibC(self: *EventLoopLocal) !*LibCInstallation {
93 if (await (async self.native_libc.start() catch unreachable)) |ptr| return ptr;
94 try await (async self.native_libc.data.findNative(self.loop) catch unreachable);
95 self.native_libc.resolve();
96 return &self.native_libc.data;
97 }
98};
99
100pub const LlvmHandle = struct {
101 node: *std.atomic.Stack(llvm.ContextRef).Node,
102
103 pub fn release(self: LlvmHandle, event_loop_local: *EventLoopLocal) void {
104 event_loop_local.llvm_handle_pool.push(self.node);
105 }
106};
107
108pub const Compilation = struct {
109 event_loop_local: *EventLoopLocal,
110 loop: *event.Loop,
111 name: Buffer,
112 llvm_triple: Buffer,
113 root_src_path: ?[]const u8,
114 target: Target,
115 llvm_target: llvm.TargetRef,
116 build_mode: builtin.Mode,
117 zig_lib_dir: []const u8,
118 zig_std_dir: []const u8,
119
120 /// lazily created when we need it
121 tmp_dir: event.Future(BuildError![]u8),
122
123 version_major: u32,
124 version_minor: u32,
125 version_patch: u32,
126
127 linker_script: ?[]const u8,
128 out_h_path: ?[]const u8,
129
130 is_test: bool,
131 each_lib_rpath: bool,
132 strip: bool,
133 is_static: bool,
134 linker_rdynamic: bool,
135
136 clang_argv: []const []const u8,
137 llvm_argv: []const []const u8,
138 lib_dirs: []const []const u8,
139 rpath_list: []const []const u8,
140 assembly_files: []const []const u8,
141
142 /// paths that are explicitly provided by the user to link against
143 link_objects: []const []const u8,
144
145 /// functions that have their own objects that we need to link
146 /// it uses an optional pointer so that tombstone removals are possible
147 fn_link_set: event.Locked(FnLinkSet),
148
149 pub const FnLinkSet = std.LinkedList(?*Value.Fn);
150
151 windows_subsystem_windows: bool,
152 windows_subsystem_console: bool,
153
154 link_libs_list: ArrayList(*LinkLib),
155 libc_link_lib: ?*LinkLib,
156
157 err_color: errmsg.Color,
158
159 verbose_tokenize: bool,
160 verbose_ast_tree: bool,
161 verbose_ast_fmt: bool,
162 verbose_cimport: bool,
163 verbose_ir: bool,
164 verbose_llvm_ir: bool,
165 verbose_link: bool,
166
167 darwin_frameworks: []const []const u8,
168 darwin_version_min: DarwinVersionMin,
169
170 test_filters: []const []const u8,
171 test_name_prefix: ?[]const u8,
172
173 emit_file_type: Emit,
174
175 kind: Kind,
176
177 link_out_file: ?[]const u8,
178 events: *event.Channel(Event),
179
180 exported_symbol_names: event.Locked(Decl.Table),
181
182 /// Before code generation starts, must wait on this group to make sure
183 /// the build is complete.
184 prelink_group: event.Group(BuildError!void),
185
186 compile_errors: event.Locked(CompileErrList),
187
188 meta_type: *Type.MetaType,
189 void_type: *Type.Void,
190 bool_type: *Type.Bool,
191 noreturn_type: *Type.NoReturn,
192 comptime_int_type: *Type.ComptimeInt,
193 u8_type: *Type.Int,
194
195 void_value: *Value.Void,
196 true_value: *Value.Bool,
197 false_value: *Value.Bool,
198 noreturn_value: *Value.NoReturn,
199
200 target_machine: llvm.TargetMachineRef,
201 target_data_ref: llvm.TargetDataRef,
202 target_layout_str: [*]u8,
203 target_ptr_bits: u32,
204
205 /// for allocating things which have the same lifetime as this Compilation
206 arena_allocator: std.heap.ArenaAllocator,
207
208 root_package: *Package,
209 std_package: *Package,
210
211 override_libc: ?*LibCInstallation,
212
213 /// need to wait on this group before deinitializing
214 deinit_group: event.Group(void),
215
216 destroy_handle: promise,
217
218 have_err_ret_tracing: bool,
219
220 /// not locked because it is read-only
221 primitive_type_table: TypeTable,
222
223 int_type_table: event.Locked(IntTypeTable),
224 array_type_table: event.Locked(ArrayTypeTable),
225 ptr_type_table: event.Locked(PtrTypeTable),
226 fn_type_table: event.Locked(FnTypeTable),
227
228 c_int_types: [CInt.list.len]*Type.Int,
229
230 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
231 const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
232 const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql);
233 const FnTypeTable = std.HashMap(*const Type.Fn.Key, *Type.Fn, Type.Fn.Key.hash, Type.Fn.Key.eql);
234 const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
235
236 const CompileErrList = std.ArrayList(*Msg);
237
238 // TODO handle some of these earlier and report them in a way other than error codes
239 pub const BuildError = error{
240 OutOfMemory,
241 EndOfStream,
242 BadFd,
243 Io,
244 IsDir,
245 Unexpected,
246 SystemResources,
247 SharingViolation,
248 PathAlreadyExists,
249 FileNotFound,
250 AccessDenied,
251 PipeBusy,
252 FileTooBig,
253 SymLinkLoop,
254 ProcessFdQuotaExceeded,
255 NameTooLong,
256 SystemFdQuotaExceeded,
257 NoDevice,
258 PathNotFound,
259 NoSpaceLeft,
260 NotDir,
261 FileSystem,
262 OperationAborted,
263 IoPending,
264 BrokenPipe,
265 WouldBlock,
266 FileClosed,
267 DestinationAddressRequired,
268 DiskQuota,
269 InputOutput,
270 NoStdHandles,
271 Overflow,
272 NotSupported,
273 BufferTooSmall,
274 Unimplemented, // TODO remove this one
275 SemanticAnalysisFailed, // TODO remove this one
276 ReadOnlyFileSystem,
277 LinkQuotaExceeded,
278 EnvironmentVariableNotFound,
279 AppDataDirUnavailable,
280 LinkFailed,
281 LibCRequiredButNotProvidedOrFound,
282 LibCMissingDynamicLinker,
283 InvalidDarwinVersionString,
284 UnsupportedLinkArchitecture,
285 };
286
287 pub const Event = union(enum) {
288 Ok,
289 Error: BuildError,
290 Fail: []*Msg,
291 };
292
293 pub const DarwinVersionMin = union(enum) {
294 None,
295 MacOS: []const u8,
296 Ios: []const u8,
297 };
298
299 pub const Kind = enum {
300 Exe,
301 Lib,
302 Obj,
303 };
304
305 pub const LinkLib = struct {
306 name: []const u8,
307 path: ?[]const u8,
308
309 /// the list of symbols we depend on from this lib
310 symbols: ArrayList([]u8),
311 provided_explicitly: bool,
312 };
313
314 pub const Emit = enum {
315 Binary,
316 Assembly,
317 LlvmIr,
318 };
319
320 pub fn create(
321 event_loop_local: *EventLoopLocal,
322 name: []const u8,
323 root_src_path: ?[]const u8,
324 target: Target,
325 kind: Kind,
326 build_mode: builtin.Mode,
327 is_static: bool,
328 zig_lib_dir: []const u8,
329 ) !*Compilation {
330 const loop = event_loop_local.loop;
331 const comp = try event_loop_local.loop.allocator.create(Compilation{
332 .loop = loop,
333 .arena_allocator = std.heap.ArenaAllocator.init(loop.allocator),
334 .event_loop_local = event_loop_local,
335 .events = undefined,
336 .root_src_path = root_src_path,
337 .target = target,
338 .llvm_target = undefined,
339 .kind = kind,
340 .build_mode = build_mode,
341 .zig_lib_dir = zig_lib_dir,
342 .zig_std_dir = undefined,
343 .tmp_dir = event.Future(BuildError![]u8).init(loop),
344
345 .name = undefined,
346 .llvm_triple = undefined,
347
348 .version_major = 0,
349 .version_minor = 0,
350 .version_patch = 0,
351
352 .verbose_tokenize = false,
353 .verbose_ast_tree = false,
354 .verbose_ast_fmt = false,
355 .verbose_cimport = false,
356 .verbose_ir = false,
357 .verbose_llvm_ir = false,
358 .verbose_link = false,
359
360 .linker_script = null,
361 .out_h_path = null,
362 .is_test = false,
363 .each_lib_rpath = false,
364 .strip = false,
365 .is_static = is_static,
366 .linker_rdynamic = false,
367 .clang_argv = [][]const u8{},
368 .llvm_argv = [][]const u8{},
369 .lib_dirs = [][]const u8{},
370 .rpath_list = [][]const u8{},
371 .assembly_files = [][]const u8{},
372 .link_objects = [][]const u8{},
373 .fn_link_set = event.Locked(FnLinkSet).init(loop, FnLinkSet.init()),
374 .windows_subsystem_windows = false,
375 .windows_subsystem_console = false,
376 .link_libs_list = undefined,
377 .libc_link_lib = null,
378 .err_color = errmsg.Color.Auto,
379 .darwin_frameworks = [][]const u8{},
380 .darwin_version_min = DarwinVersionMin.None,
381 .test_filters = [][]const u8{},
382 .test_name_prefix = null,
383 .emit_file_type = Emit.Binary,
384 .link_out_file = null,
385 .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)),
386 .prelink_group = event.Group(BuildError!void).init(loop),
387 .deinit_group = event.Group(void).init(loop),
388 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),
389 .int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)),
390 .array_type_table = event.Locked(ArrayTypeTable).init(loop, ArrayTypeTable.init(loop.allocator)),
391 .ptr_type_table = event.Locked(PtrTypeTable).init(loop, PtrTypeTable.init(loop.allocator)),
392 .fn_type_table = event.Locked(FnTypeTable).init(loop, FnTypeTable.init(loop.allocator)),
393 .c_int_types = undefined,
394
395 .meta_type = undefined,
396 .void_type = undefined,
397 .void_value = undefined,
398 .bool_type = undefined,
399 .true_value = undefined,
400 .false_value = undefined,
401 .noreturn_type = undefined,
402 .noreturn_value = undefined,
403 .comptime_int_type = undefined,
404 .u8_type = undefined,
405
406 .target_machine = undefined,
407 .target_data_ref = undefined,
408 .target_layout_str = undefined,
409 .target_ptr_bits = target.getArchPtrBitWidth(),
410
411 .root_package = undefined,
412 .std_package = undefined,
413
414 .override_libc = null,
415 .destroy_handle = undefined,
416 .have_err_ret_tracing = false,
417 .primitive_type_table = undefined,
418 });
419 errdefer {
420 comp.int_type_table.private_data.deinit();
421 comp.array_type_table.private_data.deinit();
422 comp.ptr_type_table.private_data.deinit();
423 comp.fn_type_table.private_data.deinit();
424 comp.arena_allocator.deinit();
425 comp.loop.allocator.destroy(comp);
426 }
427
428 comp.name = try Buffer.init(comp.arena(), name);
429 comp.llvm_triple = try target.getTriple(comp.arena());
430 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);
431 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());
432 comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");
433 comp.primitive_type_table = TypeTable.init(comp.arena());
434
435 const opt_level = switch (build_mode) {
436 builtin.Mode.Debug => llvm.CodeGenLevelNone,
437 else => llvm.CodeGenLevelAggressive,
438 };
439
440 const reloc_mode = if (is_static) llvm.RelocStatic else llvm.RelocPIC;
441
442 // LLVM creates invalid binaries on Windows sometimes.
443 // See https://github.com/ziglang/zig/issues/508
444 // As a workaround we do not use target native features on Windows.
445 var target_specific_cpu_args: ?[*]u8 = null;
446 var target_specific_cpu_features: ?[*]u8 = null;
447 errdefer llvm.DisposeMessage(target_specific_cpu_args);
448 errdefer llvm.DisposeMessage(target_specific_cpu_features);
449 if (target == Target.Native and !target.isWindows()) {
450 target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory;
451 target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory;
452 }
453
454 comp.target_machine = llvm.CreateTargetMachine(
455 comp.llvm_target,
456 comp.llvm_triple.ptr(),
457 target_specific_cpu_args orelse c"",
458 target_specific_cpu_features orelse c"",
459 opt_level,
460 reloc_mode,
461 llvm.CodeModelDefault,
462 ) orelse return error.OutOfMemory;
463 errdefer llvm.DisposeTargetMachine(comp.target_machine);
464
465 comp.target_data_ref = llvm.CreateTargetDataLayout(comp.target_machine) orelse return error.OutOfMemory;
466 errdefer llvm.DisposeTargetData(comp.target_data_ref);
467
468 comp.target_layout_str = llvm.CopyStringRepOfTargetData(comp.target_data_ref) orelse return error.OutOfMemory;
469 errdefer llvm.DisposeMessage(comp.target_layout_str);
470
471 comp.events = try event.Channel(Event).create(comp.loop, 0);
472 errdefer comp.events.destroy();
473
474 if (root_src_path) |root_src| {
475 const dirname = std.os.path.dirname(root_src) orelse ".";
476 const basename = std.os.path.basename(root_src);
477
478 comp.root_package = try Package.create(comp.arena(), dirname, basename);
479 comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "index.zig");
480 try comp.root_package.add("std", comp.std_package);
481 } else {
482 comp.root_package = try Package.create(comp.arena(), ".", "");
483 }
484
485 try comp.initTypes();
486
487 comp.destroy_handle = try async<loop.allocator> comp.internalDeinit();
488
489 return comp;
490 }
491
492 /// it does ref the result because it could be an arbitrary integer size
493 pub async fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type {
494 if (name.len >= 2) {
495 switch (name[0]) {
496 'i', 'u' => blk: {
497 for (name[1..]) |byte|
498 switch (byte) {
499 '0'...'9' => {},
500 else => break :blk,
501 };
502 const is_signed = name[0] == 'i';
503 const bit_count = std.fmt.parseUnsigned(u32, name[1..], 10) catch |err| switch (err) {
504 error.Overflow => return error.Overflow,
505 error.InvalidCharacter => unreachable, // we just checked the characters above
506 };
507 const int_type = try await (async Type.Int.get(comp, Type.Int.Key{
508 .bit_count = bit_count,
509 .is_signed = is_signed,
510 }) catch unreachable);
511 errdefer int_type.base.base.deref();
512 return &int_type.base;
513 },
514 else => {},
515 }
516 }
517
518 if (comp.primitive_type_table.get(name)) |entry| {
519 entry.value.base.ref();
520 return entry.value;
521 }
522
523 return null;
524 }
525
526 fn initTypes(comp: *Compilation) !void {
527 comp.meta_type = try comp.arena().create(Type.MetaType{
528 .base = Type{
529 .name = "type",
530 .base = Value{
531 .id = Value.Id.Type,
532 .typ = undefined,
533 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
534 },
535 .id = builtin.TypeId.Type,
536 .abi_alignment = Type.AbiAlignment.init(comp.loop),
537 },
538 .value = undefined,
539 });
540 comp.meta_type.value = &comp.meta_type.base;
541 comp.meta_type.base.base.typ = &comp.meta_type.base;
542 assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
543
544 comp.void_type = try comp.arena().create(Type.Void{
545 .base = Type{
546 .name = "void",
547 .base = Value{
548 .id = Value.Id.Type,
549 .typ = &Type.MetaType.get(comp).base,
550 .ref_count = std.atomic.Int(usize).init(1),
551 },
552 .id = builtin.TypeId.Void,
553 .abi_alignment = Type.AbiAlignment.init(comp.loop),
554 },
555 });
556 assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);
557
558 comp.noreturn_type = try comp.arena().create(Type.NoReturn{
559 .base = Type{
560 .name = "noreturn",
561 .base = Value{
562 .id = Value.Id.Type,
563 .typ = &Type.MetaType.get(comp).base,
564 .ref_count = std.atomic.Int(usize).init(1),
565 },
566 .id = builtin.TypeId.NoReturn,
567 .abi_alignment = Type.AbiAlignment.init(comp.loop),
568 },
569 });
570 assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);
571
572 comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{
573 .base = Type{
574 .name = "comptime_int",
575 .base = Value{
576 .id = Value.Id.Type,
577 .typ = &Type.MetaType.get(comp).base,
578 .ref_count = std.atomic.Int(usize).init(1),
579 },
580 .id = builtin.TypeId.ComptimeInt,
581 .abi_alignment = Type.AbiAlignment.init(comp.loop),
582 },
583 });
584 assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);
585
586 comp.bool_type = try comp.arena().create(Type.Bool{
587 .base = Type{
588 .name = "bool",
589 .base = Value{
590 .id = Value.Id.Type,
591 .typ = &Type.MetaType.get(comp).base,
592 .ref_count = std.atomic.Int(usize).init(1),
593 },
594 .id = builtin.TypeId.Bool,
595 .abi_alignment = Type.AbiAlignment.init(comp.loop),
596 },
597 });
598 assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);
599
600 comp.void_value = try comp.arena().create(Value.Void{
601 .base = Value{
602 .id = Value.Id.Void,
603 .typ = &Type.Void.get(comp).base,
604 .ref_count = std.atomic.Int(usize).init(1),
605 },
606 });
607
608 comp.true_value = try comp.arena().create(Value.Bool{
609 .base = Value{
610 .id = Value.Id.Bool,
611 .typ = &Type.Bool.get(comp).base,
612 .ref_count = std.atomic.Int(usize).init(1),
613 },
614 .x = true,
615 });
616
617 comp.false_value = try comp.arena().create(Value.Bool{
618 .base = Value{
619 .id = Value.Id.Bool,
620 .typ = &Type.Bool.get(comp).base,
621 .ref_count = std.atomic.Int(usize).init(1),
622 },
623 .x = false,
624 });
625
626 comp.noreturn_value = try comp.arena().create(Value.NoReturn{
627 .base = Value{
628 .id = Value.Id.NoReturn,
629 .typ = &Type.NoReturn.get(comp).base,
630 .ref_count = std.atomic.Int(usize).init(1),
631 },
632 });
633
634 for (CInt.list) |cint, i| {
635 const c_int_type = try comp.arena().create(Type.Int{
636 .base = Type{
637 .name = cint.zig_name,
638 .base = Value{
639 .id = Value.Id.Type,
640 .typ = &Type.MetaType.get(comp).base,
641 .ref_count = std.atomic.Int(usize).init(1),
642 },
643 .id = builtin.TypeId.Int,
644 .abi_alignment = Type.AbiAlignment.init(comp.loop),
645 },
646 .key = Type.Int.Key{
647 .is_signed = cint.is_signed,
648 .bit_count = comp.target.cIntTypeSizeInBits(cint.id),
649 },
650 .garbage_node = undefined,
651 });
652 comp.c_int_types[i] = c_int_type;
653 assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
654 }
655 comp.u8_type = try comp.arena().create(Type.Int{
656 .base = Type{
657 .name = "u8",
658 .base = Value{
659 .id = Value.Id.Type,
660 .typ = &Type.MetaType.get(comp).base,
661 .ref_count = std.atomic.Int(usize).init(1),
662 },
663 .id = builtin.TypeId.Int,
664 .abi_alignment = Type.AbiAlignment.init(comp.loop),
665 },
666 .key = Type.Int.Key{
667 .is_signed = false,
668 .bit_count = 8,
669 },
670 .garbage_node = undefined,
671 });
672 assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null);
673 }
674
675 /// This function can safely use async/await, because it manages Compilation's lifetime,
676 /// and EventLoopLocal.deinit will not be called until the event.Loop.run() completes.
677 async fn internalDeinit(self: *Compilation) void {
678 suspend;
679
680 await (async self.deinit_group.wait() catch unreachable);
681 if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {
682 // TODO evented I/O?
683 os.deleteTree(self.arena(), tmp_dir) catch {};
684 } else |_| {};
685
686 self.events.destroy();
687
688 llvm.DisposeMessage(self.target_layout_str);
689 llvm.DisposeTargetData(self.target_data_ref);
690 llvm.DisposeTargetMachine(self.target_machine);
691
692 self.primitive_type_table.deinit();
693
694 self.arena_allocator.deinit();
695 self.gpa().destroy(self);
696 }
697
698 pub fn destroy(self: *Compilation) void {
699 resume self.destroy_handle;
700 }
701
702 pub fn build(self: *Compilation) !void {
703 if (self.llvm_argv.len != 0) {
704 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.arena(), [][]const []const u8{
705 [][]const u8{"zig (LLVM option parsing)"},
706 self.llvm_argv,
707 });
708 defer c_compatible_args.deinit();
709 // TODO this sets global state
710 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
711 }
712
713 _ = try async<self.gpa()> self.buildAsync();
714 }
715
716 async fn buildAsync(self: *Compilation) void {
717 while (true) {
718 // TODO directly awaiting async should guarantee memory allocation elision
719 const build_result = await (async self.compileAndLink() catch unreachable);
720
721 // this makes a handy error return trace and stack trace in debug mode
722 if (std.debug.runtime_safety) {
723 build_result catch unreachable;
724 }
725
726 const compile_errors = blk: {
727 const held = await (async self.compile_errors.acquire() catch unreachable);
728 defer held.release();
729 break :blk held.value.toOwnedSlice();
730 };
731
732 if (build_result) |_| {
733 if (compile_errors.len == 0) {
734 await (async self.events.put(Event.Ok) catch unreachable);
735 } else {
736 await (async self.events.put(Event{ .Fail = compile_errors }) catch unreachable);
737 }
738 } else |err| {
739 // if there's an error then the compile errors have dangling references
740 self.gpa().free(compile_errors);
741
742 await (async self.events.put(Event{ .Error = err }) catch unreachable);
743 }
744
745 // for now we stop after 1
746 return;
747 }
748 }
749
750 async fn compileAndLink(self: *Compilation) !void {
751 if (self.root_src_path) |root_src_path| {
752 // TODO async/await os.path.real
753 const root_src_real_path = os.path.real(self.gpa(), root_src_path) catch |err| {
754 try printError("unable to get real path '{}': {}", root_src_path, err);
755 return err;
756 };
757 const root_scope = blk: {
758 errdefer self.gpa().free(root_src_real_path);
759
760 // TODO async/await readFileAlloc()
761 const source_code = io.readFileAlloc(self.gpa(), root_src_real_path) catch |err| {
762 try printError("unable to open '{}': {}", root_src_real_path, err);
763 return err;
764 };
765 errdefer self.gpa().free(source_code);
766
767 const tree = try self.gpa().createOne(ast.Tree);
768 tree.* = try std.zig.parse(self.gpa(), source_code);
769 errdefer {
770 tree.deinit();
771 self.gpa().destroy(tree);
772 }
773
774 break :blk try Scope.Root.create(self, tree, root_src_real_path);
775 };
776 defer root_scope.base.deref(self);
777 const tree = root_scope.tree;
778
779 var error_it = tree.errors.iterator(0);
780 while (error_it.next()) |parse_error| {
781 const msg = try Msg.createFromParseErrorAndScope(self, root_scope, parse_error);
782 errdefer msg.destroy();
783
784 try await (async self.addCompileErrorAsync(msg) catch unreachable);
785 }
786 if (tree.errors.len != 0) {
787 return;
788 }
789
790 const decls = try Scope.Decls.create(self, &root_scope.base);
791 defer decls.base.deref(self);
792
793 var decl_group = event.Group(BuildError!void).init(self.loop);
794 var decl_group_consumed = false;
795 errdefer if (!decl_group_consumed) decl_group.cancelAll();
796
797 var it = tree.root_node.decls.iterator(0);
798 while (it.next()) |decl_ptr| {
799 const decl = decl_ptr.*;
800 switch (decl.id) {
801 ast.Node.Id.Comptime => {
802 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl);
803
804 try self.prelink_group.call(addCompTimeBlock, self, &decls.base, comptime_node);
805 },
806 ast.Node.Id.VarDecl => @panic("TODO"),
807 ast.Node.Id.FnProto => {
808 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
809
810 const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else {
811 try self.addCompileError(root_scope, Span{
812 .first = fn_proto.fn_token,
813 .last = fn_proto.fn_token + 1,
814 }, "missing function name");
815 continue;
816 };
817
818 const fn_decl = try self.gpa().create(Decl.Fn{
819 .base = Decl{
820 .id = Decl.Id.Fn,
821 .name = name,
822 .visib = parseVisibToken(tree, fn_proto.visib_token),
823 .resolution = event.Future(BuildError!void).init(self.loop),
824 .parent_scope = &decls.base,
825 },
826 .value = Decl.Fn.Val{ .Unresolved = {} },
827 .fn_proto = fn_proto,
828 });
829 errdefer self.gpa().destroy(fn_decl);
830
831 try decl_group.call(addTopLevelDecl, self, decls, &fn_decl.base);
832 },
833 ast.Node.Id.TestDecl => @panic("TODO"),
834 else => unreachable,
835 }
836 }
837 decl_group_consumed = true;
838 try await (async decl_group.wait() catch unreachable);
839
840 // Now other code can rely on the decls scope having a complete list of names.
841 decls.name_future.resolve();
842 }
843
844 (await (async self.prelink_group.wait() catch unreachable)) catch |err| switch (err) {
845 error.SemanticAnalysisFailed => {},
846 else => return err,
847 };
848
849 const any_prelink_errors = blk: {
850 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
851 defer compile_errors.release();
852
853 break :blk compile_errors.value.len != 0;
854 };
855
856 if (!any_prelink_errors) {
857 try await (async link(self) catch unreachable);
858 }
859 }
860
861 /// caller takes ownership of resulting Code
862 async fn genAndAnalyzeCode(
863 comp: *Compilation,
864 scope: *Scope,
865 node: *ast.Node,
866 expected_type: ?*Type,
867 ) !*ir.Code {
868 const unanalyzed_code = try await (async ir.gen(
869 comp,
870 node,
871 scope,
872 ) catch unreachable);
873 defer unanalyzed_code.destroy(comp.gpa());
874
875 if (comp.verbose_ir) {
876 std.debug.warn("unanalyzed:\n");
877 unanalyzed_code.dump();
878 }
879
880 const analyzed_code = try await (async ir.analyze(
881 comp,
882 unanalyzed_code,
883 expected_type,
884 ) catch unreachable);
885 errdefer analyzed_code.destroy(comp.gpa());
886
887 if (comp.verbose_ir) {
888 std.debug.warn("analyzed:\n");
889 analyzed_code.dump();
890 }
891
892 return analyzed_code;
893 }
894
895 async fn addCompTimeBlock(
896 comp: *Compilation,
897 scope: *Scope,
898 comptime_node: *ast.Node.Comptime,
899 ) !void {
900 const void_type = Type.Void.get(comp);
901 defer void_type.base.base.deref(comp);
902
903 const analyzed_code = (await (async genAndAnalyzeCode(
904 comp,
905 scope,
906 comptime_node.expr,
907 &void_type.base,
908 ) catch unreachable)) catch |err| switch (err) {
909 // This poison value should not cause the errdefers to run. It simply means
910 // that comp.compile_errors is populated.
911 error.SemanticAnalysisFailed => return {},
912 else => return err,
913 };
914 analyzed_code.destroy(comp.gpa());
915 }
916
917 async fn addTopLevelDecl(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
918 const tree = decl.findRootScope().tree;
919 const is_export = decl.isExported(tree);
920
921 var add_to_table_resolved = false;
922 const add_to_table = async self.addDeclToTable(decls, decl) catch unreachable;
923 errdefer if (!add_to_table_resolved) cancel add_to_table; // TODO https://github.com/ziglang/zig/issues/1261
924
925 if (is_export) {
926 try self.prelink_group.call(verifyUniqueSymbol, self, decl);
927 try self.prelink_group.call(resolveDecl, self, decl);
928 }
929
930 add_to_table_resolved = true;
931 try await add_to_table;
932 }
933
934 async fn addDeclToTable(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
935 const held = await (async decls.table.acquire() catch unreachable);
936 defer held.release();
937
938 if (try held.value.put(decl.name, decl)) |other_decl| {
939 try self.addCompileError(decls.base.findRoot(), decl.getSpan(), "redefinition of '{}'", decl.name);
940 // TODO note: other definition here
941 }
942 }
943
944 fn addCompileError(self: *Compilation, root: *Scope.Root, span: Span, comptime fmt: []const u8, args: ...) !void {
945 const text = try std.fmt.allocPrint(self.gpa(), fmt, args);
946 errdefer self.gpa().free(text);
947
948 const msg = try Msg.createFromScope(self, root, span, text);
949 errdefer msg.destroy();
950
951 try self.prelink_group.call(addCompileErrorAsync, self, msg);
952 }
953
954 async fn addCompileErrorAsync(
955 self: *Compilation,
956 msg: *Msg,
957 ) !void {
958 errdefer msg.destroy();
959
960 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
961 defer compile_errors.release();
962
963 try compile_errors.value.append(msg);
964 }
965
966 async fn verifyUniqueSymbol(self: *Compilation, decl: *Decl) !void {
967 const exported_symbol_names = await (async self.exported_symbol_names.acquire() catch unreachable);
968 defer exported_symbol_names.release();
969
970 if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| {
971 try self.addCompileError(
972 decl.findRootScope(),
973 decl.getSpan(),
974 "exported symbol collision: '{}'",
975 decl.name,
976 );
977 // TODO add error note showing location of other symbol
978 }
979 }
980
981 pub fn haveLibC(self: *Compilation) bool {
982 return self.libc_link_lib != null;
983 }
984
985 pub fn addLinkLib(self: *Compilation, name: []const u8, provided_explicitly: bool) !*LinkLib {
986 const is_libc = mem.eql(u8, name, "c");
987
988 if (is_libc) {
989 if (self.libc_link_lib) |libc_link_lib| {
990 return libc_link_lib;
991 }
992 }
993
994 for (self.link_libs_list.toSliceConst()) |existing_lib| {
995 if (mem.eql(u8, name, existing_lib.name)) {
996 return existing_lib;
997 }
998 }
999
1000 const link_lib = try self.gpa().create(LinkLib{
1001 .name = name,
1002 .path = null,
1003 .provided_explicitly = provided_explicitly,
1004 .symbols = ArrayList([]u8).init(self.gpa()),
1005 });
1006 try self.link_libs_list.append(link_lib);
1007 if (is_libc) {
1008 self.libc_link_lib = link_lib;
1009
1010 // get a head start on looking for the native libc
1011 if (self.target == Target.Native and self.override_libc == null) {
1012 try self.deinit_group.call(startFindingNativeLibC, self);
1013 }
1014 }
1015 return link_lib;
1016 }
1017
1018 /// cancels itself so no need to await or cancel the promise.
1019 async fn startFindingNativeLibC(self: *Compilation) void {
1020 await (async self.loop.yield() catch unreachable);
1021 // we don't care if it fails, we're just trying to kick off the future resolution
1022 _ = (await (async self.event_loop_local.getNativeLibC() catch unreachable)) catch return;
1023 }
1024
1025 /// General Purpose Allocator. Must free when done.
1026 fn gpa(self: Compilation) *mem.Allocator {
1027 return self.loop.allocator;
1028 }
1029
1030 /// Arena Allocator. Automatically freed when the Compilation is destroyed.
1031 fn arena(self: *Compilation) *mem.Allocator {
1032 return &self.arena_allocator.allocator;
1033 }
1034
1035 /// If the temporary directory for this compilation has not been created, it creates it.
1036 /// Then it creates a random file name in that dir and returns it.
1037 pub async fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer {
1038 const tmp_dir = try await (async self.getTmpDir() catch unreachable);
1039 const file_prefix = await (async self.getRandomFileName() catch unreachable);
1040
1041 const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix);
1042 defer self.gpa().free(file_name);
1043
1044 const full_path = try os.path.join(self.gpa(), tmp_dir, file_name[0..]);
1045 errdefer self.gpa().free(full_path);
1046
1047 return Buffer.fromOwnedSlice(self.gpa(), full_path);
1048 }
1049
1050 /// If the temporary directory for this Compilation has not been created, creates it.
1051 /// Then returns it. The directory is unique to this Compilation and cleaned up when
1052 /// the Compilation deinitializes.
1053 async fn getTmpDir(self: *Compilation) ![]const u8 {
1054 if (await (async self.tmp_dir.start() catch unreachable)) |ptr| return ptr.*;
1055 self.tmp_dir.data = await (async self.getTmpDirImpl() catch unreachable);
1056 self.tmp_dir.resolve();
1057 return self.tmp_dir.data;
1058 }
1059
1060 async fn getTmpDirImpl(self: *Compilation) ![]u8 {
1061 const comp_dir_name = await (async self.getRandomFileName() catch unreachable);
1062 const zig_dir_path = try getZigDir(self.gpa());
1063 defer self.gpa().free(zig_dir_path);
1064
1065 const tmp_dir = try os.path.join(self.arena(), zig_dir_path, comp_dir_name[0..]);
1066 try os.makePath(self.gpa(), tmp_dir);
1067 return tmp_dir;
1068 }
1069
1070 async fn getRandomFileName(self: *Compilation) [12]u8 {
1071 // here we replace the standard +/ with -_ so that it can be used in a file name
1072 const b64_fs_encoder = std.base64.Base64Encoder.init(
1073 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
1074 std.base64.standard_pad_char,
1075 );
1076
1077 var rand_bytes: [9]u8 = undefined;
1078
1079 {
1080 const held = await (async self.event_loop_local.prng.acquire() catch unreachable);
1081 defer held.release();
1082
1083 held.value.random.bytes(rand_bytes[0..]);
1084 }
1085
1086 var result: [12]u8 = undefined;
1087 b64_fs_encoder.encode(result[0..], rand_bytes);
1088 return result;
1089 }
1090
1091 fn registerGarbage(comp: *Compilation, comptime T: type, node: *std.atomic.Stack(*T).Node) void {
1092 // TODO put the garbage somewhere
1093 }
1094
1095 /// Returns a value which has been ref()'d once
1096 async fn analyzeConstValue(comp: *Compilation, scope: *Scope, node: *ast.Node, expected_type: *Type) !*Value {
1097 const analyzed_code = try await (async comp.genAndAnalyzeCode(scope, node, expected_type) catch unreachable);
1098 defer analyzed_code.destroy(comp.gpa());
1099
1100 return analyzed_code.getCompTimeResult(comp);
1101 }
1102
1103 async fn analyzeTypeExpr(comp: *Compilation, scope: *Scope, node: *ast.Node) !*Type {
1104 const meta_type = &Type.MetaType.get(comp).base;
1105 defer meta_type.base.deref(comp);
1106
1107 const result_val = try await (async comp.analyzeConstValue(scope, node, meta_type) catch unreachable);
1108 errdefer result_val.base.deref(comp);
1109
1110 return result_val.cast(Type).?;
1111 }
1112
1113 /// This declaration has been blessed as going into the final code generation.
1114 pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {
1115 if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*;
1116
1117 decl.resolution.data = try await (async generateDecl(comp, decl) catch unreachable);
1118 decl.resolution.resolve();
1119 return decl.resolution.data;
1120 }
1121};
1122
1123fn printError(comptime format: []const u8, args: ...) !void {
1124 var stderr_file = try std.io.getStdErr();
1125 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
1126 const out_stream = &stderr_file_out_stream.stream;
1127 try out_stream.print(format, args);
1128}
1129
1130fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib {
1131 if (optional_token_index) |token_index| {
1132 const token = tree.tokens.at(token_index);
1133 assert(token.id == Token.Id.Keyword_pub);
1134 return Visib.Pub;
1135 } else {
1136 return Visib.Private;
1137 }
1138}
1139
1140/// The function that actually does the generation.
1141async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
1142 switch (decl.id) {
1143 Decl.Id.Var => @panic("TODO"),
1144 Decl.Id.Fn => {
1145 const fn_decl = @fieldParentPtr(Decl.Fn, "base", decl);
1146 return await (async generateDeclFn(comp, fn_decl) catch unreachable);
1147 },
1148 Decl.Id.CompTime => @panic("TODO"),
1149 }
1150}
1151
1152async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1153 const body_node = fn_decl.fn_proto.body_node orelse return await (async generateDeclFnProto(comp, fn_decl) catch unreachable);
1154
1155 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);
1156 defer fndef_scope.base.deref(comp);
1157
1158 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
1159 defer fn_type.base.base.deref(comp);
1160
1161 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);
1162 var symbol_name_consumed = false;
1163 errdefer if (!symbol_name_consumed) symbol_name.deinit();
1164
1165 // The Decl.Fn owns the initial 1 reference count
1166 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
1167 fn_decl.value = Decl.Fn.Val{ .Fn = fn_val };
1168 symbol_name_consumed = true;
1169
1170 // Define local parameter variables
1171 const root_scope = fn_decl.base.findRootScope();
1172 for (fn_type.key.data.Normal.params) |param, i| {
1173 //AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
1174 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", fn_decl.fn_proto.params.at(i).*);
1175 const name_token = param_decl.name_token orelse {
1176 try comp.addCompileError(root_scope, Span{
1177 .first = param_decl.firstToken(),
1178 .last = param_decl.type_node.firstToken(),
1179 }, "missing parameter name");
1180 return error.SemanticAnalysisFailed;
1181 };
1182 const param_name = root_scope.tree.tokenSlice(name_token);
1183
1184 // if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {
1185 // add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
1186 // }
1187
1188 // TODO check for shadowing
1189
1190 const var_scope = try Scope.Var.createParam(
1191 comp,
1192 fn_val.child_scope,
1193 param_name,
1194 &param_decl.base,
1195 i,
1196 param.typ,
1197 );
1198 fn_val.child_scope = &var_scope.base;
1199
1200 try fn_type.non_key.Normal.variable_list.append(var_scope);
1201 }
1202
1203 const analyzed_code = try await (async comp.genAndAnalyzeCode(
1204 fn_val.child_scope,
1205 body_node,
1206 fn_type.key.data.Normal.return_type,
1207 ) catch unreachable);
1208 errdefer analyzed_code.destroy(comp.gpa());
1209
1210 assert(fn_val.block_scope != null);
1211
1212 // Kick off rendering to LLVM module, but it doesn't block the fn decl
1213 // analysis from being complete.
1214 try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);
1215 try comp.prelink_group.call(addFnToLinkSet, comp, fn_val);
1216}
1217
1218async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
1219 fn_val.base.ref();
1220 defer fn_val.base.deref(comp);
1221
1222 fn_val.link_set_node.data = fn_val;
1223
1224 const held = await (async comp.fn_link_set.acquire() catch unreachable);
1225 defer held.release();
1226
1227 held.value.append(fn_val.link_set_node);
1228}
1229
1230fn getZigDir(allocator: *mem.Allocator) ![]u8 {
1231 return os.getAppDataDir(allocator, "zig");
1232}
1233
1234async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.FnProto) !*Type.Fn {
1235 const return_type_node = switch (fn_proto.return_type) {
1236 ast.Node.FnProto.ReturnType.Explicit => |n| n,
1237 ast.Node.FnProto.ReturnType.InferErrorSet => |n| n,
1238 };
1239 const return_type = try await (async comp.analyzeTypeExpr(scope, return_type_node) catch unreachable);
1240 return_type.base.deref(comp);
1241
1242 var params = ArrayList(Type.Fn.Param).init(comp.gpa());
1243 var params_consumed = false;
1244 defer if (!params_consumed) {
1245 for (params.toSliceConst()) |param| {
1246 param.typ.base.deref(comp);
1247 }
1248 params.deinit();
1249 };
1250
1251 {
1252 var it = fn_proto.params.iterator(0);
1253 while (it.next()) |param_node_ptr| {
1254 const param_node = param_node_ptr.*.cast(ast.Node.ParamDecl).?;
1255 const param_type = try await (async comp.analyzeTypeExpr(scope, param_node.type_node) catch unreachable);
1256 errdefer param_type.base.deref(comp);
1257 try params.append(Type.Fn.Param{
1258 .typ = param_type,
1259 .is_noalias = param_node.noalias_token != null,
1260 });
1261 }
1262 }
1263
1264 const key = Type.Fn.Key{
1265 .alignment = null,
1266 .data = Type.Fn.Key.Data{
1267 .Normal = Type.Fn.Key.Normal{
1268 .return_type = return_type,
1269 .params = params.toOwnedSlice(),
1270 .is_var_args = false, // TODO
1271 .cc = Type.Fn.CallingConvention.Auto, // TODO
1272 },
1273 },
1274 };
1275 params_consumed = true;
1276 var key_consumed = false;
1277 defer if (!key_consumed) {
1278 for (key.data.Normal.params) |param| {
1279 param.typ.base.deref(comp);
1280 }
1281 comp.gpa().free(key.data.Normal.params);
1282 };
1283
1284 const fn_type = try await (async Type.Fn.get(comp, key) catch unreachable);
1285 key_consumed = true;
1286 errdefer fn_type.base.base.deref(comp);
1287
1288 return fn_type;
1289}
1290
1291async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1292 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
1293 defer fn_type.base.base.deref(comp);
1294
1295 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);
1296 var symbol_name_consumed = false;
1297 defer if (!symbol_name_consumed) symbol_name.deinit();
1298
1299 // The Decl.Fn owns the initial 1 reference count
1300 const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name);
1301 fn_decl.value = Decl.Fn.Val{ .FnProto = fn_proto_val };
1302 symbol_name_consumed = true;
1303}
src-self-hosted/decl.zig created+98
......@@ -0,0 +1,98 @@
1const std = @import("std");
2const Allocator = mem.Allocator;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Visib = @import("visib.zig").Visib;
6const event = std.event;
7const Value = @import("value.zig").Value;
8const Token = std.zig.Token;
9const errmsg = @import("errmsg.zig");
10const Scope = @import("scope.zig").Scope;
11const Compilation = @import("compilation.zig").Compilation;
12
13pub const Decl = struct {
14 id: Id,
15 name: []const u8,
16 visib: Visib,
17 resolution: event.Future(Compilation.BuildError!void),
18 parent_scope: *Scope,
19
20 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);
21
22 pub fn isExported(base: *const Decl, tree: *ast.Tree) bool {
23 switch (base.id) {
24 Id.Fn => {
25 const fn_decl = @fieldParentPtr(Fn, "base", base);
26 return fn_decl.isExported(tree);
27 },
28 else => return false,
29 }
30 }
31
32 pub fn getSpan(base: *const Decl) errmsg.Span {
33 switch (base.id) {
34 Id.Fn => {
35 const fn_decl = @fieldParentPtr(Fn, "base", base);
36 const fn_proto = fn_decl.fn_proto;
37 const start = fn_proto.fn_token;
38 const end = fn_proto.name_token orelse start;
39 return errmsg.Span{
40 .first = start,
41 .last = end + 1,
42 };
43 },
44 else => @panic("TODO"),
45 }
46 }
47
48 pub fn findRootScope(base: *const Decl) *Scope.Root {
49 return base.parent_scope.findRoot();
50 }
51
52 pub const Id = enum {
53 Var,
54 Fn,
55 CompTime,
56 };
57
58 pub const Var = struct {
59 base: Decl,
60 };
61
62 pub const Fn = struct {
63 base: Decl,
64 value: Val,
65 fn_proto: *ast.Node.FnProto,
66
67 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous
68 pub const Val = union(enum) {
69 Unresolved: void,
70 Fn: *Value.Fn,
71 FnProto: *Value.FnProto,
72 };
73
74 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {
75 return if (self.fn_proto.extern_export_inline_token) |tok_index| x: {
76 const token = tree.tokens.at(tok_index);
77 break :x switch (token.id) {
78 Token.Id.Extern => tree.tokenSlicePtr(token),
79 else => null,
80 };
81 } else null;
82 }
83
84 pub fn isExported(self: Fn, tree: *ast.Tree) bool {
85 if (self.fn_proto.extern_export_inline_token) |tok_index| {
86 const token = tree.tokens.at(tok_index);
87 return token.id == Token.Id.Keyword_export;
88 } else {
89 return false;
90 }
91 }
92 };
93
94 pub const CompTime = struct {
95 base: Decl,
96 };
97};
98
src-self-hosted/errmsg.zig created+237
......@@ -0,0 +1,237 @@
1const std = @import("std");
2const mem = std.mem;
3const os = std.os;
4const Token = std.zig.Token;
5const ast = std.zig.ast;
6const TokenIndex = std.zig.ast.TokenIndex;
7const Compilation = @import("compilation.zig").Compilation;
8const Scope = @import("scope.zig").Scope;
9
10pub const Color = enum {
11 Auto,
12 Off,
13 On,
14};
15
16pub const Span = struct {
17 first: ast.TokenIndex,
18 last: ast.TokenIndex,
19
20 pub fn token(i: TokenIndex) Span {
21 return Span{
22 .first = i,
23 .last = i,
24 };
25 }
26
27 pub fn node(n: *ast.Node) Span {
28 return Span{
29 .first = n.firstToken(),
30 .last = n.lastToken(),
31 };
32 }
33};
34
35pub const Msg = struct {
36 span: Span,
37 text: []u8,
38 data: Data,
39
40 const Data = union(enum) {
41 PathAndTree: PathAndTree,
42 ScopeAndComp: ScopeAndComp,
43 };
44
45 const PathAndTree = struct {
46 realpath: []const u8,
47 tree: *ast.Tree,
48 allocator: *mem.Allocator,
49 };
50
51 const ScopeAndComp = struct {
52 root_scope: *Scope.Root,
53 compilation: *Compilation,
54 };
55
56 pub fn destroy(self: *Msg) void {
57 switch (self.data) {
58 Data.PathAndTree => |path_and_tree| {
59 path_and_tree.allocator.free(self.text);
60 path_and_tree.allocator.destroy(self);
61 },
62 Data.ScopeAndComp => |scope_and_comp| {
63 scope_and_comp.root_scope.base.deref(scope_and_comp.compilation);
64 scope_and_comp.compilation.gpa().free(self.text);
65 scope_and_comp.compilation.gpa().destroy(self);
66 },
67 }
68 }
69
70 fn getAllocator(self: *const Msg) *mem.Allocator {
71 switch (self.data) {
72 Data.PathAndTree => |path_and_tree| {
73 return path_and_tree.allocator;
74 },
75 Data.ScopeAndComp => |scope_and_comp| {
76 return scope_and_comp.compilation.gpa();
77 },
78 }
79 }
80
81 pub fn getRealPath(self: *const Msg) []const u8 {
82 switch (self.data) {
83 Data.PathAndTree => |path_and_tree| {
84 return path_and_tree.realpath;
85 },
86 Data.ScopeAndComp => |scope_and_comp| {
87 return scope_and_comp.root_scope.realpath;
88 },
89 }
90 }
91
92 pub fn getTree(self: *const Msg) *ast.Tree {
93 switch (self.data) {
94 Data.PathAndTree => |path_and_tree| {
95 return path_and_tree.tree;
96 },
97 Data.ScopeAndComp => |scope_and_comp| {
98 return scope_and_comp.root_scope.tree;
99 },
100 }
101 }
102
103 /// Takes ownership of text
104 /// References root_scope, and derefs when the msg is freed
105 pub fn createFromScope(comp: *Compilation, root_scope: *Scope.Root, span: Span, text: []u8) !*Msg {
106 const msg = try comp.gpa().create(Msg{
107 .text = text,
108 .span = span,
109 .data = Data{
110 .ScopeAndComp = ScopeAndComp{
111 .root_scope = root_scope,
112 .compilation = comp,
113 },
114 },
115 });
116 root_scope.base.ref();
117 return msg;
118 }
119
120 pub fn createFromParseErrorAndScope(
121 comp: *Compilation,
122 root_scope: *Scope.Root,
123 parse_error: *const ast.Error,
124 ) !*Msg {
125 const loc_token = parse_error.loc();
126 var text_buf = try std.Buffer.initSize(comp.gpa(), 0);
127 defer text_buf.deinit();
128
129 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
130 try parse_error.render(&root_scope.tree.tokens, out_stream);
131
132 const msg = try comp.gpa().create(Msg{
133 .text = undefined,
134 .span = Span{
135 .first = loc_token,
136 .last = loc_token,
137 },
138 .data = Data{
139 .ScopeAndComp = ScopeAndComp{
140 .root_scope = root_scope,
141 .compilation = comp,
142 },
143 },
144 });
145 root_scope.base.ref();
146 msg.text = text_buf.toOwnedSlice();
147 return msg;
148 }
149
150 /// `realpath` must outlive the returned Msg
151 /// `tree` must outlive the returned Msg
152 /// Caller owns returned Msg and must free with `allocator`
153 /// allocator will additionally be used for printing messages later.
154 pub fn createFromParseError(
155 allocator: *mem.Allocator,
156 parse_error: *const ast.Error,
157 tree: *ast.Tree,
158 realpath: []const u8,
159 ) !*Msg {
160 const loc_token = parse_error.loc();
161 var text_buf = try std.Buffer.initSize(allocator, 0);
162 defer text_buf.deinit();
163
164 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
165 try parse_error.render(&tree.tokens, out_stream);
166
167 const msg = try allocator.create(Msg{
168 .text = undefined,
169 .data = Data{
170 .PathAndTree = PathAndTree{
171 .allocator = allocator,
172 .realpath = realpath,
173 .tree = tree,
174 },
175 },
176 .span = Span{
177 .first = loc_token,
178 .last = loc_token,
179 },
180 });
181 msg.text = text_buf.toOwnedSlice();
182 errdefer allocator.destroy(msg);
183
184 return msg;
185 }
186
187 pub fn printToStream(msg: *const Msg, stream: var, color_on: bool) !void {
188 const allocator = msg.getAllocator();
189 const realpath = msg.getRealPath();
190 const tree = msg.getTree();
191
192 const cwd = try os.getCwd(allocator);
193 defer allocator.free(cwd);
194
195 const relpath = try os.path.relative(allocator, cwd, realpath);
196 defer allocator.free(relpath);
197
198 const path = if (relpath.len < realpath.len) relpath else realpath;
199
200 const first_token = tree.tokens.at(msg.span.first);
201 const last_token = tree.tokens.at(msg.span.last);
202 const start_loc = tree.tokenLocationPtr(0, first_token);
203 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
204 if (!color_on) {
205 try stream.print(
206 "{}:{}:{}: error: {}\n",
207 path,
208 start_loc.line + 1,
209 start_loc.column + 1,
210 msg.text,
211 );
212 return;
213 }
214
215 try stream.print(
216 "{}:{}:{}: error: {}\n{}\n",
217 path,
218 start_loc.line + 1,
219 start_loc.column + 1,
220 msg.text,
221 tree.source[start_loc.line_start..start_loc.line_end],
222 );
223 try stream.writeByteNTimes(' ', start_loc.column);
224 try stream.writeByteNTimes('~', last_token.end - first_token.start);
225 try stream.write("\n");
226 }
227
228 pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void {
229 const color_on = switch (color) {
230 Color.Auto => file.isTty(),
231 Color.On => true,
232 Color.Off => false,
233 };
234 var stream = &std.io.FileOutStream.init(file).stream;
235 return msg.printToStream(stream, color_on);
236 }
237};
src-self-hosted/introspect.zig+10-7
......@@ -7,7 +7,7 @@ const os = std.os;
77const warn = std.debug.warn;
88
99/// Caller must free result
10pub fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
10pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
1111 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
1212 errdefer allocator.free(test_zig_dir);
1313
......@@ -21,13 +21,13 @@ pub fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![
2121}
2222
2323/// Caller must free result
24pub fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
24pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
2525 const self_exe_path = try os.selfExeDirPath(allocator);
2626 defer allocator.free(self_exe_path);
2727
2828 var cur_path: []const u8 = self_exe_path;
2929 while (true) {
30 const test_dir = os.path.dirname(cur_path);
30 const test_dir = os.path.dirname(cur_path) orelse ".";
3131
3232 if (mem.eql(u8, test_dir, cur_path)) {
3333 break;
......@@ -42,16 +42,19 @@ pub fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
4242 return error.FileNotFound;
4343}
4444
45pub fn resolveZigLibDir(allocator: &mem.Allocator) ![]u8 {
45pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 {
4646 return findZigLibDir(allocator) catch |err| {
4747 warn(
4848 \\Unable to find zig lib directory: {}.
4949 \\Reinstall Zig or use --zig-install-prefix.
5050 \\
51 ,
52 @errorName(err)
53 );
51 , @errorName(err));
5452
5553 return error.ZigLibDirNotFound;
5654 };
5755}
56
57/// Caller must free result
58pub fn resolveZigCacheDir(allocator: *mem.Allocator) ![]u8 {
59 return std.mem.dupe(allocator, u8, "zig-cache");
60}
src-self-hosted/ir.zig+2587-101
......@@ -1,112 +1,2598 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Compilation = @import("compilation.zig").Compilation;
14const Scope = @import("scope.zig").Scope;
5const ast = std.zig.ast;
6const Allocator = std.mem.Allocator;
7const Value = @import("value.zig").Value;
8const Type = Value.Type;
9const assert = std.debug.assert;
10const Token = std.zig.Token;
11const Span = @import("errmsg.zig").Span;
12const llvm = @import("llvm.zig");
13const codegen = @import("codegen.zig");
14const ObjectFile = codegen.ObjectFile;
15const Decl = @import("decl.zig").Decl;
16const mem = std.mem;
217
3pub const Instruction = struct {
18pub const LVal = enum {
19 None,
20 Ptr,
21};
22
23pub const IrVal = union(enum) {
24 Unknown,
25 KnownType: *Type,
26 KnownValue: *Value,
27
28 const Init = enum {
29 Unknown,
30 NoReturn,
31 Void,
32 };
33
34 pub fn dump(self: IrVal) void {
35 switch (self) {
36 IrVal.Unknown => std.debug.warn("Unknown"),
37 IrVal.KnownType => |typ| {
38 std.debug.warn("KnownType(");
39 typ.dump();
40 std.debug.warn(")");
41 },
42 IrVal.KnownValue => |value| {
43 std.debug.warn("KnownValue(");
44 value.dump();
45 std.debug.warn(")");
46 },
47 }
48 }
49};
50
51pub const Inst = struct {
452 id: Id,
5 scope: &Scope,
53 scope: *Scope,
54 debug_id: usize,
55 val: IrVal,
56 ref_count: usize,
57 span: Span,
58 owner_bb: *BasicBlock,
59
60 /// true if this instruction was generated by zig and not from user code
61 is_generated: bool,
62
63 /// the instruction that is derived from this one in analysis
64 child: ?*Inst,
65
66 /// the instruction that this one derives from in analysis
67 parent: ?*Inst,
68
69 /// populated durign codegen
70 llvm_value: ?llvm.ValueRef,
71
72 pub fn cast(base: *Inst, comptime T: type) ?*T {
73 if (base.id == comptime typeToId(T)) {
74 return @fieldParentPtr(T, "base", base);
75 }
76 return null;
77 }
78
79 pub fn typeToId(comptime T: type) Id {
80 comptime var i = 0;
81 inline while (i < @memberCount(Id)) : (i += 1) {
82 if (T == @field(Inst, @memberName(Id, i))) {
83 return @field(Id, @memberName(Id, i));
84 }
85 }
86 unreachable;
87 }
88
89 pub fn dump(base: *const Inst) void {
90 comptime var i = 0;
91 inline while (i < @memberCount(Id)) : (i += 1) {
92 if (base.id == @field(Id, @memberName(Id, i))) {
93 const T = @field(Inst, @memberName(Id, i));
94 std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id));
95 @fieldParentPtr(T, "base", base).dump();
96 std.debug.warn(")");
97 return;
98 }
99 }
100 unreachable;
101 }
102
103 pub fn hasSideEffects(base: *const Inst) bool {
104 comptime var i = 0;
105 inline while (i < @memberCount(Id)) : (i += 1) {
106 if (base.id == @field(Id, @memberName(Id, i))) {
107 const T = @field(Inst, @memberName(Id, i));
108 return @fieldParentPtr(T, "base", base).hasSideEffects();
109 }
110 }
111 unreachable;
112 }
113
114 pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
115 switch (base.id) {
116 Id.Return => return @fieldParentPtr(Return, "base", base).analyze(ira),
117 Id.Const => return @fieldParentPtr(Const, "base", base).analyze(ira),
118 Id.Call => return @fieldParentPtr(Call, "base", base).analyze(ira),
119 Id.DeclRef => return await (async @fieldParentPtr(DeclRef, "base", base).analyze(ira) catch unreachable),
120 Id.Ref => return await (async @fieldParentPtr(Ref, "base", base).analyze(ira) catch unreachable),
121 Id.DeclVar => return @fieldParentPtr(DeclVar, "base", base).analyze(ira),
122 Id.CheckVoidStmt => return @fieldParentPtr(CheckVoidStmt, "base", base).analyze(ira),
123 Id.Phi => return @fieldParentPtr(Phi, "base", base).analyze(ira),
124 Id.Br => return @fieldParentPtr(Br, "base", base).analyze(ira),
125 Id.AddImplicitReturnType => return @fieldParentPtr(AddImplicitReturnType, "base", base).analyze(ira),
126 Id.PtrType => return await (async @fieldParentPtr(PtrType, "base", base).analyze(ira) catch unreachable),
127 Id.VarPtr => return await (async @fieldParentPtr(VarPtr, "base", base).analyze(ira) catch unreachable),
128 Id.LoadPtr => return await (async @fieldParentPtr(LoadPtr, "base", base).analyze(ira) catch unreachable),
129 }
130 }
131
132 pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
133 switch (base.id) {
134 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
135 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
136 Id.Call => return @fieldParentPtr(Call, "base", base).render(ofile, fn_val),
137 Id.VarPtr => return @fieldParentPtr(VarPtr, "base", base).render(ofile, fn_val),
138 Id.LoadPtr => return @fieldParentPtr(LoadPtr, "base", base).render(ofile, fn_val),
139 Id.DeclRef => unreachable,
140 Id.PtrType => unreachable,
141 Id.Ref => @panic("TODO"),
142 Id.DeclVar => @panic("TODO"),
143 Id.CheckVoidStmt => @panic("TODO"),
144 Id.Phi => @panic("TODO"),
145 Id.Br => @panic("TODO"),
146 Id.AddImplicitReturnType => @panic("TODO"),
147 }
148 }
149
150 fn ref(base: *Inst, builder: *Builder) void {
151 base.ref_count += 1;
152 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {
153 base.owner_bb.ref(builder);
154 }
155 }
156
157 fn copyVal(base: *Inst, comp: *Compilation) !*Value {
158 if (base.parent.?.ref_count == 0) {
159 return base.val.KnownValue.derefAndCopy(comp);
160 }
161 return base.val.KnownValue.copy(comp);
162 }
163
164 fn getAsParam(param: *Inst) !*Inst {
165 param.ref_count -= 1;
166 const child = param.child orelse return error.SemanticAnalysisFailed;
167 switch (child.val) {
168 IrVal.Unknown => return error.SemanticAnalysisFailed,
169 else => return child,
170 }
171 }
172
173 fn getConstVal(self: *Inst, ira: *Analyze) !*Value {
174 if (self.isCompTime()) {
175 return self.val.KnownValue;
176 } else {
177 try ira.addCompileError(self.span, "unable to evaluate constant expression");
178 return error.SemanticAnalysisFailed;
179 }
180 }
181
182 fn getAsConstType(param: *Inst, ira: *Analyze) !*Type {
183 const meta_type = Type.MetaType.get(ira.irb.comp);
184 meta_type.base.base.deref(ira.irb.comp);
185
186 const inst = try param.getAsParam();
187 const casted = try ira.implicitCast(inst, &meta_type.base);
188 const val = try casted.getConstVal(ira);
189 return val.cast(Value.Type).?;
190 }
191
192 fn getAsConstAlign(param: *Inst, ira: *Analyze) !u32 {
193 return error.Unimplemented;
194 //const align_type = Type.Int.get_align(ira.irb.comp);
195 //align_type.base.base.deref(ira.irb.comp);
196
197 //const inst = try param.getAsParam();
198 //const casted = try ira.implicitCast(inst, align_type);
199 //const val = try casted.getConstVal(ira);
200
201 //uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint);
202 //if (align_bytes == 0) {
203 // ir_add_error(ira, value, buf_sprintf("alignment must be >= 1"));
204 // return false;
205 //}
206
207 //if (!is_power_of_2(align_bytes)) {
208 // ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
209 // return false;
210 //}
211 }
212
213 /// asserts that the type is known
214 fn getKnownType(self: *Inst) *Type {
215 switch (self.val) {
216 IrVal.KnownType => |typ| return typ,
217 IrVal.KnownValue => |value| return value.typ,
218 IrVal.Unknown => unreachable,
219 }
220 }
221
222 pub fn setGenerated(base: *Inst) void {
223 base.is_generated = true;
224 }
225
226 pub fn isNoReturn(base: *const Inst) bool {
227 switch (base.val) {
228 IrVal.Unknown => return false,
229 IrVal.KnownValue => |x| return x.typ.id == Type.Id.NoReturn,
230 IrVal.KnownType => |typ| return typ.id == Type.Id.NoReturn,
231 }
232 }
233
234 pub fn isCompTime(base: *const Inst) bool {
235 return base.val == IrVal.KnownValue;
236 }
237
238 pub fn linkToParent(self: *Inst, parent: *Inst) void {
239 assert(self.parent == null);
240 assert(parent.child == null);
241 self.parent = parent;
242 parent.child = self;
243 }
6244
7245 pub const Id = enum {
8 Br,
9 CondBr,
10 SwitchBr,
11 SwitchVar,
12 SwitchTarget,
13 Phi,
14 UnOp,
15 BinOp,
16 DeclVar,
17 LoadPtr,
18 StorePtr,
19 FieldPtr,
20 StructFieldPtr,
21 UnionFieldPtr,
22 ElemPtr,
23 VarPtr,
24 Call,
25 Const,
26246 Return,
27 Cast,
28 ContainerInitList,
29 ContainerInitFields,
30 StructInit,
31 UnionInit,
32 Unreachable,
33 TypeOf,
34 ToPtrType,
35 PtrTypeChild,
36 SetRuntimeSafety,
37 SetFloatMode,
38 ArrayType,
39 SliceType,
40 Asm,
41 SizeOf,
42 TestNonNull,
43 UnwrapMaybe,
44 MaybeWrap,
45 UnionTag,
46 Clz,
47 Ctz,
48 Import,
49 CImport,
50 CInclude,
51 CDefine,
52 CUndef,
53 ArrayLen,
247 Const,
54248 Ref,
55 MinValue,
56 MaxValue,
57 CompileErr,
58 CompileLog,
59 ErrName,
60 EmbedFile,
61 Cmpxchg,
62 Fence,
63 Truncate,
64 IntType,
65 BoolNot,
66 Memset,
67 Memcpy,
68 Slice,
69 MemberCount,
70 MemberType,
71 MemberName,
72 Breakpoint,
73 ReturnAddress,
74 FrameAddress,
75 AlignOf,
76 OverflowOp,
77 TestErr,
78 UnwrapErrCode,
79 UnwrapErrPayload,
80 ErrWrapCode,
81 ErrWrapPayload,
82 FnProto,
83 TestComptime,
84 PtrCast,
85 BitCast,
86 WidenOrShorten,
87 IntToPtr,
88 PtrToInt,
89 IntToEnum,
90 IntToErr,
91 ErrToInt,
92 CheckSwitchProngs,
93 CheckStatementIsVoid,
94 TypeName,
95 CanImplicitCast,
249 DeclVar,
250 CheckVoidStmt,
251 Phi,
252 Br,
253 AddImplicitReturnType,
254 Call,
96255 DeclRef,
97 Panic,
98 TagName,
99 TagType,
100 FieldParentPtr,
101 OffsetOf,
102 TypeId,
103 SetEvalBranchQuota,
104 PtrTypeOf,
105 AlignCast,
106 OpaqueType,
107 SetAlignStack,
108 ArgType,
109 Export,
256 PtrType,
257 VarPtr,
258 LoadPtr,
259 };
260
261 pub const Call = struct {
262 base: Inst,
263 params: Params,
264
265 const Params = struct {
266 fn_ref: *Inst,
267 args: []*Inst,
268 };
269
270 const ir_val_init = IrVal.Init.Unknown;
271
272 pub fn dump(self: *const Call) void {
273 std.debug.warn("#{}(", self.params.fn_ref.debug_id);
274 for (self.params.args) |arg| {
275 std.debug.warn("#{},", arg.debug_id);
276 }
277 std.debug.warn(")");
278 }
279
280 pub fn hasSideEffects(self: *const Call) bool {
281 return true;
282 }
283
284 pub fn analyze(self: *const Call, ira: *Analyze) !*Inst {
285 const fn_ref = try self.params.fn_ref.getAsParam();
286 const fn_ref_type = fn_ref.getKnownType();
287 const fn_type = fn_ref_type.cast(Type.Fn) orelse {
288 try ira.addCompileError(fn_ref.span, "type '{}' not a function", fn_ref_type.name);
289 return error.SemanticAnalysisFailed;
290 };
291
292 const fn_type_param_count = fn_type.paramCount();
293
294 if (fn_type_param_count != self.params.args.len) {
295 try ira.addCompileError(
296 self.base.span,
297 "expected {} arguments, found {}",
298 fn_type_param_count,
299 self.params.args.len,
300 );
301 return error.SemanticAnalysisFailed;
302 }
303
304 const args = try ira.irb.arena().alloc(*Inst, self.params.args.len);
305 for (self.params.args) |arg, i| {
306 args[i] = try arg.getAsParam();
307 }
308 const new_inst = try ira.irb.build(Call, self.base.scope, self.base.span, Params{
309 .fn_ref = fn_ref,
310 .args = args,
311 });
312 new_inst.val = IrVal{ .KnownType = fn_type.key.data.Normal.return_type };
313 return new_inst;
314 }
315
316 pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
317 const fn_ref = self.params.fn_ref.llvm_value.?;
318
319 const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
320 for (self.params.args) |arg, i| {
321 args[i] = arg.llvm_value.?;
322 }
323
324 const llvm_cc = llvm.CCallConv;
325 const fn_inline = llvm.FnInline.Auto;
326
327 return llvm.BuildCall(
328 ofile.builder,
329 fn_ref,
330 args.ptr,
331 @intCast(c_uint, args.len),
332 llvm_cc,
333 fn_inline,
334 c"",
335 ) orelse error.OutOfMemory;
336 }
337 };
338
339 pub const Const = struct {
340 base: Inst,
341 params: Params,
342
343 const Params = struct {};
344
345 // Use Builder.buildConst* methods, or, after building a Const instruction,
346 // manually set the ir_val field.
347 const ir_val_init = IrVal.Init.Unknown;
348
349 pub fn dump(self: *const Const) void {
350 self.base.val.KnownValue.dump();
351 }
352
353 pub fn hasSideEffects(self: *const Const) bool {
354 return false;
355 }
356
357 pub fn analyze(self: *const Const, ira: *Analyze) !*Inst {
358 const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{});
359 new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };
360 return new_inst;
361 }
362
363 pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
364 return self.base.val.KnownValue.getLlvmConst(ofile);
365 }
366 };
367
368 pub const Return = struct {
369 base: Inst,
370 params: Params,
371
372 const Params = struct {
373 return_value: *Inst,
374 };
375
376 const ir_val_init = IrVal.Init.NoReturn;
377
378 pub fn dump(self: *const Return) void {
379 std.debug.warn("#{}", self.params.return_value.debug_id);
380 }
381
382 pub fn hasSideEffects(self: *const Return) bool {
383 return true;
384 }
385
386 pub fn analyze(self: *const Return, ira: *Analyze) !*Inst {
387 const value = try self.params.return_value.getAsParam();
388 const casted_value = try ira.implicitCast(value, ira.explicit_return_type);
389
390 // TODO detect returning local variable address
391
392 return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
393 }
394
395 pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
396 const value = self.params.return_value.llvm_value;
397 const return_type = self.params.return_value.getKnownType();
398
399 if (return_type.handleIsPtr()) {
400 @panic("TODO");
401 } else {
402 _ = llvm.BuildRet(ofile.builder, value) orelse return error.OutOfMemory;
403 }
404 return null;
405 }
406 };
407
408 pub const Ref = struct {
409 base: Inst,
410 params: Params,
411
412 const Params = struct {
413 target: *Inst,
414 mut: Type.Pointer.Mut,
415 volatility: Type.Pointer.Vol,
416 };
417
418 const ir_val_init = IrVal.Init.Unknown;
419
420 pub fn dump(inst: *const Ref) void {}
421
422 pub fn hasSideEffects(inst: *const Ref) bool {
423 return false;
424 }
425
426 pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
427 const target = try self.params.target.getAsParam();
428
429 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
430 return ira.getCompTimeRef(
431 val,
432 Value.Ptr.Mut.CompTimeConst,
433 self.params.mut,
434 self.params.volatility,
435 );
436 }
437
438 const new_inst = try ira.irb.build(Ref, self.base.scope, self.base.span, Params{
439 .target = target,
440 .mut = self.params.mut,
441 .volatility = self.params.volatility,
442 });
443 const elem_type = target.getKnownType();
444 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
445 .child_type = elem_type,
446 .mut = self.params.mut,
447 .vol = self.params.volatility,
448 .size = Type.Pointer.Size.One,
449 .alignment = Type.Pointer.Align.Abi,
450 }) catch unreachable);
451 // TODO: potentially set the hint that this is a stack pointer. But it might not be - this
452 // could be a ref of a global, for example
453 new_inst.val = IrVal{ .KnownType = &ptr_type.base };
454 // TODO potentially add an alloca entry here
455 return new_inst;
456 }
457 };
458
459 pub const DeclRef = struct {
460 base: Inst,
461 params: Params,
462
463 const Params = struct {
464 decl: *Decl,
465 lval: LVal,
466 };
467
468 const ir_val_init = IrVal.Init.Unknown;
469
470 pub fn dump(inst: *const DeclRef) void {}
471
472 pub fn hasSideEffects(inst: *const DeclRef) bool {
473 return false;
474 }
475
476 pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {
477 (await (async ira.irb.comp.resolveDecl(self.params.decl) catch unreachable)) catch |err| switch (err) {
478 error.OutOfMemory => return error.OutOfMemory,
479 else => return error.SemanticAnalysisFailed,
480 };
481 switch (self.params.decl.id) {
482 Decl.Id.CompTime => unreachable,
483 Decl.Id.Var => return error.Unimplemented,
484 Decl.Id.Fn => {
485 const fn_decl = @fieldParentPtr(Decl.Fn, "base", self.params.decl);
486 const decl_val = switch (fn_decl.value) {
487 Decl.Fn.Val.Unresolved => unreachable,
488 Decl.Fn.Val.Fn => |fn_val| &fn_val.base,
489 Decl.Fn.Val.FnProto => |fn_proto| &fn_proto.base,
490 };
491 switch (self.params.lval) {
492 LVal.None => {
493 return ira.irb.buildConstValue(self.base.scope, self.base.span, decl_val);
494 },
495 LVal.Ptr => return error.Unimplemented,
496 }
497 },
498 }
499 }
500 };
501
502 pub const VarPtr = struct {
503 base: Inst,
504 params: Params,
505
506 const Params = struct {
507 var_scope: *Scope.Var,
508 };
509
510 const ir_val_init = IrVal.Init.Unknown;
511
512 pub fn dump(inst: *const VarPtr) void {
513 std.debug.warn("{}", inst.params.var_scope.name);
514 }
515
516 pub fn hasSideEffects(inst: *const VarPtr) bool {
517 return false;
518 }
519
520 pub async fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst {
521 switch (self.params.var_scope.data) {
522 Scope.Var.Data.Const => @panic("TODO"),
523 Scope.Var.Data.Param => |param| {
524 const new_inst = try ira.irb.build(
525 Inst.VarPtr,
526 self.base.scope,
527 self.base.span,
528 Inst.VarPtr.Params{ .var_scope = self.params.var_scope },
529 );
530 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
531 .child_type = param.typ,
532 .mut = Type.Pointer.Mut.Const,
533 .vol = Type.Pointer.Vol.Non,
534 .size = Type.Pointer.Size.One,
535 .alignment = Type.Pointer.Align.Abi,
536 }) catch unreachable);
537 new_inst.val = IrVal{ .KnownType = &ptr_type.base };
538 return new_inst;
539 },
540 }
541 }
542
543 pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef {
544 switch (self.params.var_scope.data) {
545 Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
546 Scope.Var.Data.Param => |param| return param.llvm_value,
547 }
548 }
549 };
550
551 pub const LoadPtr = struct {
552 base: Inst,
553 params: Params,
554
555 const Params = struct {
556 target: *Inst,
557 };
558
559 const ir_val_init = IrVal.Init.Unknown;
560
561 pub fn dump(inst: *const LoadPtr) void {}
562
563 pub fn hasSideEffects(inst: *const LoadPtr) bool {
564 return false;
565 }
566
567 pub async fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst {
568 const target = try self.params.target.getAsParam();
569 const target_type = target.getKnownType();
570 if (target_type.id != Type.Id.Pointer) {
571 try ira.addCompileError(self.base.span, "dereference of non pointer type '{}'", target_type.name);
572 return error.SemanticAnalysisFailed;
573 }
574 const ptr_type = @fieldParentPtr(Type.Pointer, "base", target_type);
575 // if (instr_is_comptime(ptr)) {
576 // if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
577 // ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
578 // {
579 // ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &ptr->value);
580 // if (pointee->special != ConstValSpecialRuntime) {
581 // IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
582 // source_instruction->source_node, child_type);
583 // copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
584 // result->value.type = child_type;
585 // return result;
586 // }
587 // }
588 // }
589 const new_inst = try ira.irb.build(
590 Inst.LoadPtr,
591 self.base.scope,
592 self.base.span,
593 Inst.LoadPtr.Params{ .target = target },
594 );
595 new_inst.val = IrVal{ .KnownType = ptr_type.key.child_type };
596 return new_inst;
597 }
598
599 pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
600 const child_type = self.base.getKnownType();
601 if (!child_type.hasBits()) {
602 return null;
603 }
604 const ptr = self.params.target.llvm_value.?;
605 const ptr_type = self.params.target.getKnownType().cast(Type.Pointer).?;
606
607 return try codegen.getHandleValue(ofile, ptr, ptr_type);
608
609 //uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
610 //if (unaligned_bit_count == 0)
611 // return get_handle_value(g, ptr, child_type, ptr_type);
612
613 //bool big_endian = g->is_big_endian;
614
615 //assert(!handle_is_ptr(child_type));
616 //LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
617
618 //uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
619 //uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
620 //uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset;
621
622 //LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
623 //LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
624
625 //return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
626 }
627 };
628
629 pub const PtrType = struct {
630 base: Inst,
631 params: Params,
632
633 const Params = struct {
634 child_type: *Inst,
635 mut: Type.Pointer.Mut,
636 vol: Type.Pointer.Vol,
637 size: Type.Pointer.Size,
638 alignment: ?*Inst,
639 };
640
641 const ir_val_init = IrVal.Init.Unknown;
642
643 pub fn dump(inst: *const PtrType) void {}
644
645 pub fn hasSideEffects(inst: *const PtrType) bool {
646 return false;
647 }
648
649 pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {
650 const child_type = try self.params.child_type.getAsConstType(ira);
651 // if (child_type->id == TypeTableEntryIdUnreachable) {
652 // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
653 // return ira->codegen->builtin_types.entry_invalid;
654 // } else if (child_type->id == TypeTableEntryIdOpaque && instruction->ptr_len == PtrLenUnknown) {
655 // ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
656 // return ira->codegen->builtin_types.entry_invalid;
657 // }
658 const alignment = if (self.params.alignment) |align_inst| blk: {
659 const amt = try align_inst.getAsConstAlign(ira);
660 break :blk Type.Pointer.Align{ .Override = amt };
661 } else blk: {
662 break :blk Type.Pointer.Align{ .Abi = {} };
663 };
664 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
665 .child_type = child_type,
666 .mut = self.params.mut,
667 .vol = self.params.vol,
668 .size = self.params.size,
669 .alignment = alignment,
670 }) catch unreachable);
671 ptr_type.base.base.deref(ira.irb.comp);
672
673 return ira.irb.buildConstValue(self.base.scope, self.base.span, &ptr_type.base.base);
674 }
675 };
676
677 pub const DeclVar = struct {
678 base: Inst,
679 params: Params,
680
681 const Params = struct {
682 variable: *Variable,
683 };
684
685 const ir_val_init = IrVal.Init.Unknown;
686
687 pub fn dump(inst: *const DeclVar) void {}
688
689 pub fn hasSideEffects(inst: *const DeclVar) bool {
690 return true;
691 }
692
693 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Inst {
694 return error.Unimplemented; // TODO
695 }
696 };
697
698 pub const CheckVoidStmt = struct {
699 base: Inst,
700 params: Params,
701
702 const Params = struct {
703 target: *Inst,
704 };
705
706 const ir_val_init = IrVal.Init.Unknown;
707
708 pub fn dump(self: *const CheckVoidStmt) void {
709 std.debug.warn("#{}", self.params.target.debug_id);
710 }
711
712 pub fn hasSideEffects(inst: *const CheckVoidStmt) bool {
713 return true;
714 }
715
716 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {
717 const target = try self.params.target.getAsParam();
718 if (target.getKnownType().id != Type.Id.Void) {
719 try ira.addCompileError(self.base.span, "expression value is ignored");
720 return error.SemanticAnalysisFailed;
721 }
722 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
723 }
724 };
725
726 pub const Phi = struct {
727 base: Inst,
728 params: Params,
729
730 const Params = struct {
731 incoming_blocks: []*BasicBlock,
732 incoming_values: []*Inst,
733 };
734
735 const ir_val_init = IrVal.Init.Unknown;
736
737 pub fn dump(inst: *const Phi) void {}
738
739 pub fn hasSideEffects(inst: *const Phi) bool {
740 return false;
741 }
742
743 pub fn analyze(self: *const Phi, ira: *Analyze) !*Inst {
744 return error.Unimplemented; // TODO
745 }
746 };
747
748 pub const Br = struct {
749 base: Inst,
750 params: Params,
751
752 const Params = struct {
753 dest_block: *BasicBlock,
754 is_comptime: *Inst,
755 };
756
757 const ir_val_init = IrVal.Init.NoReturn;
758
759 pub fn dump(inst: *const Br) void {}
760
761 pub fn hasSideEffects(inst: *const Br) bool {
762 return true;
763 }
764
765 pub fn analyze(self: *const Br, ira: *Analyze) !*Inst {
766 return error.Unimplemented; // TODO
767 }
768 };
769
770 pub const CondBr = struct {
771 base: Inst,
772 params: Params,
773
774 const Params = struct {
775 condition: *Inst,
776 then_block: *BasicBlock,
777 else_block: *BasicBlock,
778 is_comptime: *Inst,
779 };
780
781 const ir_val_init = IrVal.Init.NoReturn;
782
783 pub fn dump(inst: *const CondBr) void {}
784
785 pub fn hasSideEffects(inst: *const CondBr) bool {
786 return true;
787 }
788
789 pub fn analyze(self: *const CondBr, ira: *Analyze) !*Inst {
790 return error.Unimplemented; // TODO
791 }
792 };
793
794 pub const AddImplicitReturnType = struct {
795 base: Inst,
796 params: Params,
797
798 pub const Params = struct {
799 target: *Inst,
800 };
801
802 const ir_val_init = IrVal.Init.Unknown;
803
804 pub fn dump(inst: *const AddImplicitReturnType) void {
805 std.debug.warn("#{}", inst.params.target.debug_id);
806 }
807
808 pub fn hasSideEffects(inst: *const AddImplicitReturnType) bool {
809 return true;
810 }
811
812 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Inst {
813 const target = try self.params.target.getAsParam();
814 try ira.src_implicit_return_type_list.append(target);
815 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
816 }
817 };
818
819 pub const TestErr = struct {
820 base: Inst,
821 params: Params,
822
823 pub const Params = struct {
824 target: *Inst,
825 };
826
827 const ir_val_init = IrVal.Init.Unknown;
828
829 pub fn dump(inst: *const TestErr) void {
830 std.debug.warn("#{}", inst.params.target.debug_id);
831 }
832
833 pub fn hasSideEffects(inst: *const TestErr) bool {
834 return false;
835 }
836
837 pub fn analyze(self: *const TestErr, ira: *Analyze) !*Inst {
838 const target = try self.params.target.getAsParam();
839 const target_type = target.getKnownType();
840 switch (target_type.id) {
841 Type.Id.ErrorUnion => {
842 return error.Unimplemented;
843 // if (instr_is_comptime(value)) {
844 // ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
845 // if (!err_union_val)
846 // return ira->codegen->builtin_types.entry_invalid;
847
848 // if (err_union_val->special != ConstValSpecialRuntime) {
849 // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
850 // out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);
851 // return ira->codegen->builtin_types.entry_bool;
852 // }
853 // }
854
855 // TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
856 // if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) {
857 // return ira->codegen->builtin_types.entry_invalid;
858 // }
859 // if (!type_is_global_error_set(err_set_type) &&
860 // err_set_type->data.error_set.err_count == 0)
861 // {
862 // assert(err_set_type->data.error_set.infer_fn == nullptr);
863 // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
864 // out_val->data.x_bool = false;
865 // return ira->codegen->builtin_types.entry_bool;
866 // }
867
868 // ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
869 // return ira->codegen->builtin_types.entry_bool;
870 },
871 Type.Id.ErrorSet => {
872 return ira.irb.buildConstBool(self.base.scope, self.base.span, true);
873 },
874 else => {
875 return ira.irb.buildConstBool(self.base.scope, self.base.span, false);
876 },
877 }
878 }
879 };
880
881 pub const TestCompTime = struct {
882 base: Inst,
883 params: Params,
884
885 pub const Params = struct {
886 target: *Inst,
887 };
888
889 const ir_val_init = IrVal.Init.Unknown;
890
891 pub fn dump(inst: *const TestCompTime) void {
892 std.debug.warn("#{}", inst.params.target.debug_id);
893 }
894
895 pub fn hasSideEffects(inst: *const TestCompTime) bool {
896 return false;
897 }
898
899 pub fn analyze(self: *const TestCompTime, ira: *Analyze) !*Inst {
900 const target = try self.params.target.getAsParam();
901 return ira.irb.buildConstBool(self.base.scope, self.base.span, target.isCompTime());
902 }
903 };
904
905 pub const SaveErrRetAddr = struct {
906 base: Inst,
907 params: Params,
908
909 const Params = struct {};
910
911 const ir_val_init = IrVal.Init.Unknown;
912
913 pub fn dump(inst: *const SaveErrRetAddr) void {}
914
915 pub fn hasSideEffects(inst: *const SaveErrRetAddr) bool {
916 return true;
917 }
918
919 pub fn analyze(self: *const SaveErrRetAddr, ira: *Analyze) !*Inst {
920 return ira.irb.build(Inst.SaveErrRetAddr, self.base.scope, self.base.span, Params{});
921 }
922 };
923};
924
925pub const Variable = struct {
926 child_scope: *Scope,
927};
928
929pub const BasicBlock = struct {
930 ref_count: usize,
931 name_hint: [*]const u8, // must be a C string literal
932 debug_id: usize,
933 scope: *Scope,
934 instruction_list: std.ArrayList(*Inst),
935 ref_instruction: ?*Inst,
936
937 /// for codegen
938 llvm_block: llvm.BasicBlockRef,
939 llvm_exit_block: llvm.BasicBlockRef,
940
941 /// the basic block that is derived from this one in analysis
942 child: ?*BasicBlock,
943
944 /// the basic block that this one derives from in analysis
945 parent: ?*BasicBlock,
946
947 pub fn ref(self: *BasicBlock, builder: *Builder) void {
948 self.ref_count += 1;
949 }
950
951 pub fn linkToParent(self: *BasicBlock, parent: *BasicBlock) void {
952 assert(self.parent == null);
953 assert(parent.child == null);
954 self.parent = parent;
955 parent.child = self;
956 }
957};
958
959/// Stuff that survives longer than Builder
960pub const Code = struct {
961 basic_block_list: std.ArrayList(*BasicBlock),
962 arena: std.heap.ArenaAllocator,
963 return_type: ?*Type,
964
965 /// allocator is comp.gpa()
966 pub fn destroy(self: *Code, allocator: *Allocator) void {
967 self.arena.deinit();
968 allocator.destroy(self);
969 }
970
971 pub fn dump(self: *Code) void {
972 var bb_i: usize = 0;
973 for (self.basic_block_list.toSliceConst()) |bb| {
974 std.debug.warn("{s}_{}:\n", bb.name_hint, bb.debug_id);
975 for (bb.instruction_list.toSliceConst()) |instr| {
976 std.debug.warn(" ");
977 instr.dump();
978 std.debug.warn("\n");
979 }
980 }
981 }
982
983 /// returns a ref-incremented value, or adds a compile error
984 pub fn getCompTimeResult(self: *Code, comp: *Compilation) !*Value {
985 const bb = self.basic_block_list.at(0);
986 for (bb.instruction_list.toSliceConst()) |inst| {
987 if (inst.cast(Inst.Return)) |ret_inst| {
988 const ret_value = ret_inst.params.return_value;
989 if (ret_value.isCompTime()) {
990 return ret_value.val.KnownValue.getRef();
991 }
992 try comp.addCompileError(
993 ret_value.scope.findRoot(),
994 ret_value.span,
995 "unable to evaluate constant expression",
996 );
997 return error.SemanticAnalysisFailed;
998 } else if (inst.hasSideEffects()) {
999 try comp.addCompileError(
1000 inst.scope.findRoot(),
1001 inst.span,
1002 "unable to evaluate constant expression",
1003 );
1004 return error.SemanticAnalysisFailed;
1005 }
1006 }
1007 unreachable;
1008 }
1009};
1010
1011pub const Builder = struct {
1012 comp: *Compilation,
1013 code: *Code,
1014 current_basic_block: *BasicBlock,
1015 next_debug_id: usize,
1016 root_scope: *Scope.Root,
1017 is_comptime: bool,
1018 is_async: bool,
1019 begin_scope: ?*Scope,
1020
1021 pub const Error = Analyze.Error;
1022
1023 pub fn init(comp: *Compilation, root_scope: *Scope.Root, begin_scope: ?*Scope) !Builder {
1024 const code = try comp.gpa().create(Code{
1025 .basic_block_list = undefined,
1026 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
1027 .return_type = null,
1028 });
1029 code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator);
1030 errdefer code.destroy(comp.gpa());
1031
1032 return Builder{
1033 .comp = comp,
1034 .root_scope = root_scope,
1035 .current_basic_block = undefined,
1036 .code = code,
1037 .next_debug_id = 0,
1038 .is_comptime = false,
1039 .is_async = false,
1040 .begin_scope = begin_scope,
1041 };
1042 }
1043
1044 pub fn abort(self: *Builder) void {
1045 self.code.destroy(self.comp.gpa());
1046 }
1047
1048 /// Call code.destroy() when done
1049 pub fn finish(self: *Builder) *Code {
1050 return self.code;
1051 }
1052
1053 /// No need to clean up resources thanks to the arena allocator.
1054 pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock {
1055 const basic_block = try self.arena().create(BasicBlock{
1056 .ref_count = 0,
1057 .name_hint = name_hint,
1058 .debug_id = self.next_debug_id,
1059 .scope = scope,
1060 .instruction_list = std.ArrayList(*Inst).init(self.arena()),
1061 .child = null,
1062 .parent = null,
1063 .ref_instruction = null,
1064 .llvm_block = undefined,
1065 .llvm_exit_block = undefined,
1066 });
1067 self.next_debug_id += 1;
1068 return basic_block;
1069 }
1070
1071 pub fn setCursorAtEndAndAppendBlock(self: *Builder, basic_block: *BasicBlock) !void {
1072 try self.code.basic_block_list.append(basic_block);
1073 self.setCursorAtEnd(basic_block);
1074 }
1075
1076 pub fn setCursorAtEnd(self: *Builder, basic_block: *BasicBlock) void {
1077 self.current_basic_block = basic_block;
1078 }
1079
1080 pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
1081 switch (node.id) {
1082 ast.Node.Id.Root => unreachable,
1083 ast.Node.Id.Use => unreachable,
1084 ast.Node.Id.TestDecl => unreachable,
1085 ast.Node.Id.VarDecl => return error.Unimplemented,
1086 ast.Node.Id.Defer => return error.Unimplemented,
1087 ast.Node.Id.InfixOp => return error.Unimplemented,
1088 ast.Node.Id.PrefixOp => {
1089 const prefix_op = @fieldParentPtr(ast.Node.PrefixOp, "base", node);
1090 switch (prefix_op.op) {
1091 ast.Node.PrefixOp.Op.AddressOf => return error.Unimplemented,
1092 ast.Node.PrefixOp.Op.ArrayType => |n| return error.Unimplemented,
1093 ast.Node.PrefixOp.Op.Await => return error.Unimplemented,
1094 ast.Node.PrefixOp.Op.BitNot => return error.Unimplemented,
1095 ast.Node.PrefixOp.Op.BoolNot => return error.Unimplemented,
1096 ast.Node.PrefixOp.Op.Cancel => return error.Unimplemented,
1097 ast.Node.PrefixOp.Op.OptionalType => return error.Unimplemented,
1098 ast.Node.PrefixOp.Op.Negation => return error.Unimplemented,
1099 ast.Node.PrefixOp.Op.NegationWrap => return error.Unimplemented,
1100 ast.Node.PrefixOp.Op.Resume => return error.Unimplemented,
1101 ast.Node.PrefixOp.Op.PtrType => |ptr_info| {
1102 const inst = try await (async irb.genPtrType(prefix_op, ptr_info, scope) catch unreachable);
1103 return irb.lvalWrap(scope, inst, lval);
1104 },
1105 ast.Node.PrefixOp.Op.SliceType => |ptr_info| return error.Unimplemented,
1106 ast.Node.PrefixOp.Op.Try => return error.Unimplemented,
1107 }
1108 },
1109 ast.Node.Id.SuffixOp => {
1110 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1111 switch (suffix_op.op) {
1112 @TagType(ast.Node.SuffixOp.Op).Call => |*call| {
1113 const inst = try await (async irb.genCall(suffix_op, call, scope) catch unreachable);
1114 return irb.lvalWrap(scope, inst, lval);
1115 },
1116 @TagType(ast.Node.SuffixOp.Op).ArrayAccess => |n| return error.Unimplemented,
1117 @TagType(ast.Node.SuffixOp.Op).Slice => |slice| return error.Unimplemented,
1118 @TagType(ast.Node.SuffixOp.Op).ArrayInitializer => |init_list| return error.Unimplemented,
1119 @TagType(ast.Node.SuffixOp.Op).StructInitializer => |init_list| return error.Unimplemented,
1120 @TagType(ast.Node.SuffixOp.Op).Deref => return error.Unimplemented,
1121 @TagType(ast.Node.SuffixOp.Op).UnwrapOptional => return error.Unimplemented,
1122 }
1123 },
1124 ast.Node.Id.Switch => return error.Unimplemented,
1125 ast.Node.Id.While => return error.Unimplemented,
1126 ast.Node.Id.For => return error.Unimplemented,
1127 ast.Node.Id.If => return error.Unimplemented,
1128 ast.Node.Id.ControlFlowExpression => {
1129 const control_flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", node);
1130 return await (async irb.genControlFlowExpr(control_flow_expr, scope, lval) catch unreachable);
1131 },
1132 ast.Node.Id.Suspend => return error.Unimplemented,
1133 ast.Node.Id.VarType => return error.Unimplemented,
1134 ast.Node.Id.ErrorType => return error.Unimplemented,
1135 ast.Node.Id.FnProto => return error.Unimplemented,
1136 ast.Node.Id.PromiseType => return error.Unimplemented,
1137 ast.Node.Id.IntegerLiteral => {
1138 const int_lit = @fieldParentPtr(ast.Node.IntegerLiteral, "base", node);
1139 return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval);
1140 },
1141 ast.Node.Id.FloatLiteral => return error.Unimplemented,
1142 ast.Node.Id.StringLiteral => {
1143 const str_lit = @fieldParentPtr(ast.Node.StringLiteral, "base", node);
1144 const inst = try await (async irb.genStrLit(str_lit, scope) catch unreachable);
1145 return irb.lvalWrap(scope, inst, lval);
1146 },
1147 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
1148 ast.Node.Id.CharLiteral => return error.Unimplemented,
1149 ast.Node.Id.BoolLiteral => return error.Unimplemented,
1150 ast.Node.Id.NullLiteral => return error.Unimplemented,
1151 ast.Node.Id.UndefinedLiteral => return error.Unimplemented,
1152 ast.Node.Id.ThisLiteral => return error.Unimplemented,
1153 ast.Node.Id.Unreachable => return error.Unimplemented,
1154 ast.Node.Id.Identifier => {
1155 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", node);
1156 return await (async irb.genIdentifier(identifier, scope, lval) catch unreachable);
1157 },
1158 ast.Node.Id.GroupedExpression => {
1159 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
1160 return await (async irb.genNode(grouped_expr.expr, scope, lval) catch unreachable);
1161 },
1162 ast.Node.Id.BuiltinCall => return error.Unimplemented,
1163 ast.Node.Id.ErrorSetDecl => return error.Unimplemented,
1164 ast.Node.Id.ContainerDecl => return error.Unimplemented,
1165 ast.Node.Id.Asm => return error.Unimplemented,
1166 ast.Node.Id.Comptime => return error.Unimplemented,
1167 ast.Node.Id.Block => {
1168 const block = @fieldParentPtr(ast.Node.Block, "base", node);
1169 const inst = try await (async irb.genBlock(block, scope) catch unreachable);
1170 return irb.lvalWrap(scope, inst, lval);
1171 },
1172 ast.Node.Id.DocComment => return error.Unimplemented,
1173 ast.Node.Id.SwitchCase => return error.Unimplemented,
1174 ast.Node.Id.SwitchElse => return error.Unimplemented,
1175 ast.Node.Id.Else => return error.Unimplemented,
1176 ast.Node.Id.Payload => return error.Unimplemented,
1177 ast.Node.Id.PointerPayload => return error.Unimplemented,
1178 ast.Node.Id.PointerIndexPayload => return error.Unimplemented,
1179 ast.Node.Id.StructField => return error.Unimplemented,
1180 ast.Node.Id.UnionTag => return error.Unimplemented,
1181 ast.Node.Id.EnumTag => return error.Unimplemented,
1182 ast.Node.Id.ErrorTag => return error.Unimplemented,
1183 ast.Node.Id.AsmInput => return error.Unimplemented,
1184 ast.Node.Id.AsmOutput => return error.Unimplemented,
1185 ast.Node.Id.AsyncAttribute => return error.Unimplemented,
1186 ast.Node.Id.ParamDecl => return error.Unimplemented,
1187 ast.Node.Id.FieldInitializer => return error.Unimplemented,
1188 }
1189 }
1190
1191 async fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
1192 const fn_ref = try await (async irb.genNode(suffix_op.lhs, scope, LVal.None) catch unreachable);
1193
1194 const args = try irb.arena().alloc(*Inst, call.params.len);
1195 var it = call.params.iterator(0);
1196 var i: usize = 0;
1197 while (it.next()) |arg_node_ptr| : (i += 1) {
1198 args[i] = try await (async irb.genNode(arg_node_ptr.*, scope, LVal.None) catch unreachable);
1199 }
1200
1201 //bool is_async = node->data.fn_call_expr.is_async;
1202 //IrInstruction *async_allocator = nullptr;
1203 //if (is_async) {
1204 // if (node->data.fn_call_expr.async_allocator) {
1205 // async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
1206 // if (async_allocator == irb->codegen->invalid_instruction)
1207 // return async_allocator;
1208 // }
1209 //}
1210
1211 return irb.build(Inst.Call, scope, Span.token(suffix_op.rtoken), Inst.Call.Params{
1212 .fn_ref = fn_ref,
1213 .args = args,
1214 });
1215 //IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
1216 //return ir_lval_wrap(irb, scope, fn_call, lval);
1217 }
1218
1219 async fn genPtrType(
1220 irb: *Builder,
1221 prefix_op: *ast.Node.PrefixOp,
1222 ptr_info: ast.Node.PrefixOp.PtrInfo,
1223 scope: *Scope,
1224 ) !*Inst {
1225 // TODO port more logic
1226
1227 //assert(node->type == NodeTypePointerType);
1228 //PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
1229 // node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown;
1230 //bool is_const = node->data.pointer_type.is_const;
1231 //bool is_volatile = node->data.pointer_type.is_volatile;
1232 //AstNode *expr_node = node->data.pointer_type.op_expr;
1233 //AstNode *align_expr = node->data.pointer_type.align_expr;
1234
1235 //IrInstruction *align_value;
1236 //if (align_expr != nullptr) {
1237 // align_value = ir_gen_node(irb, align_expr, scope);
1238 // if (align_value == irb->codegen->invalid_instruction)
1239 // return align_value;
1240 //} else {
1241 // align_value = nullptr;
1242 //}
1243 const child_type = try await (async irb.genNode(prefix_op.rhs, scope, LVal.None) catch unreachable);
1244
1245 //uint32_t bit_offset_start = 0;
1246 //if (node->data.pointer_type.bit_offset_start != nullptr) {
1247 // if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_start, 32, false)) {
1248 // Buf *val_buf = buf_alloc();
1249 // bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_start, 10);
1250 // exec_add_error_node(irb->codegen, irb->exec, node,
1251 // buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
1252 // return irb->codegen->invalid_instruction;
1253 // }
1254 // bit_offset_start = bigint_as_unsigned(node->data.pointer_type.bit_offset_start);
1255 //}
1256
1257 //uint32_t bit_offset_end = 0;
1258 //if (node->data.pointer_type.bit_offset_end != nullptr) {
1259 // if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_end, 32, false)) {
1260 // Buf *val_buf = buf_alloc();
1261 // bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_end, 10);
1262 // exec_add_error_node(irb->codegen, irb->exec, node,
1263 // buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
1264 // return irb->codegen->invalid_instruction;
1265 // }
1266 // bit_offset_end = bigint_as_unsigned(node->data.pointer_type.bit_offset_end);
1267 //}
1268
1269 //if ((bit_offset_start != 0 || bit_offset_end != 0) && bit_offset_start >= bit_offset_end) {
1270 // exec_add_error_node(irb->codegen, irb->exec, node,
1271 // buf_sprintf("bit offset start must be less than bit offset end"));
1272 // return irb->codegen->invalid_instruction;
1273 //}
1274
1275 return irb.build(Inst.PtrType, scope, Span.node(&prefix_op.base), Inst.PtrType.Params{
1276 .child_type = child_type,
1277 .mut = Type.Pointer.Mut.Mut,
1278 .vol = Type.Pointer.Vol.Non,
1279 .size = Type.Pointer.Size.Many,
1280 .alignment = null,
1281 });
1282 }
1283
1284 fn isCompTime(irb: *Builder, target_scope: *Scope) bool {
1285 if (irb.is_comptime)
1286 return true;
1287
1288 var scope = target_scope;
1289 while (true) {
1290 switch (scope.id) {
1291 Scope.Id.CompTime => return true,
1292 Scope.Id.FnDef => return false,
1293 Scope.Id.Decls => unreachable,
1294 Scope.Id.Root => unreachable,
1295 Scope.Id.Block,
1296 Scope.Id.Defer,
1297 Scope.Id.DeferExpr,
1298 Scope.Id.Var,
1299 => scope = scope.parent.?,
1300 }
1301 }
1302 }
1303
1304 pub fn genIntLit(irb: *Builder, int_lit: *ast.Node.IntegerLiteral, scope: *Scope) !*Inst {
1305 const int_token = irb.root_scope.tree.tokenSlice(int_lit.token);
1306
1307 var base: u8 = undefined;
1308 var rest: []const u8 = undefined;
1309 if (int_token.len >= 3 and int_token[0] == '0') {
1310 base = switch (int_token[1]) {
1311 'b' => u8(2),
1312 'o' => u8(8),
1313 'x' => u8(16),
1314 else => unreachable,
1315 };
1316 rest = int_token[2..];
1317 } else {
1318 base = 10;
1319 rest = int_token;
1320 }
1321
1322 const comptime_int_type = Type.ComptimeInt.get(irb.comp);
1323 defer comptime_int_type.base.base.deref(irb.comp);
1324
1325 const int_val = Value.Int.createFromString(
1326 irb.comp,
1327 &comptime_int_type.base,
1328 base,
1329 rest,
1330 ) catch |err| switch (err) {
1331 error.OutOfMemory => return error.OutOfMemory,
1332 error.InvalidBase => unreachable,
1333 error.InvalidCharForDigit => unreachable,
1334 error.DigitTooLargeForBase => unreachable,
1335 };
1336 errdefer int_val.base.deref(irb.comp);
1337
1338 const inst = try irb.build(Inst.Const, scope, Span.token(int_lit.token), Inst.Const.Params{});
1339 inst.val = IrVal{ .KnownValue = &int_val.base };
1340 return inst;
1341 }
1342
1343 pub async fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst {
1344 const str_token = irb.root_scope.tree.tokenSlice(str_lit.token);
1345 const src_span = Span.token(str_lit.token);
1346
1347 var bad_index: usize = undefined;
1348 var buf = std.zig.parseStringLiteral(irb.comp.gpa(), str_token, &bad_index) catch |err| switch (err) {
1349 error.OutOfMemory => return error.OutOfMemory,
1350 error.InvalidCharacter => {
1351 try irb.comp.addCompileError(
1352 irb.root_scope,
1353 src_span,
1354 "invalid character in string literal: '{c}'",
1355 str_token[bad_index],
1356 );
1357 return error.SemanticAnalysisFailed;
1358 },
1359 };
1360 var buf_cleaned = false;
1361 errdefer if (!buf_cleaned) irb.comp.gpa().free(buf);
1362
1363 if (str_token[0] == 'c') {
1364 // first we add a null
1365 buf = try irb.comp.gpa().realloc(u8, buf, buf.len + 1);
1366 buf[buf.len - 1] = 0;
1367
1368 // next make an array value
1369 const array_val = try await (async Value.Array.createOwnedBuffer(irb.comp, buf) catch unreachable);
1370 buf_cleaned = true;
1371 defer array_val.base.deref(irb.comp);
1372
1373 // then make a pointer value pointing at the first element
1374 const ptr_val = try await (async Value.Ptr.createArrayElemPtr(
1375 irb.comp,
1376 array_val,
1377 Type.Pointer.Mut.Const,
1378 Type.Pointer.Size.Many,
1379 0,
1380 ) catch unreachable);
1381 defer ptr_val.base.deref(irb.comp);
1382
1383 return irb.buildConstValue(scope, src_span, &ptr_val.base);
1384 } else {
1385 const array_val = try await (async Value.Array.createOwnedBuffer(irb.comp, buf) catch unreachable);
1386 buf_cleaned = true;
1387 defer array_val.base.deref(irb.comp);
1388
1389 return irb.buildConstValue(scope, src_span, &array_val.base);
1390 }
1391 }
1392
1393 pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
1394 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
1395
1396 const outer_block_scope = &block_scope.base;
1397 var child_scope = outer_block_scope;
1398
1399 if (parent_scope.findFnDef()) |fndef_scope| {
1400 if (fndef_scope.fn_val.?.block_scope == null) {
1401 fndef_scope.fn_val.?.block_scope = block_scope;
1402 }
1403 }
1404
1405 if (block.statements.len == 0) {
1406 // {}
1407 return irb.buildConstVoid(child_scope, Span.token(block.lbrace), false);
1408 }
1409
1410 if (block.label) |label| {
1411 block_scope.incoming_values = std.ArrayList(*Inst).init(irb.arena());
1412 block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());
1413 block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");
1414 block_scope.is_comptime = try irb.buildConstBool(
1415 parent_scope,
1416 Span.token(block.lbrace),
1417 irb.isCompTime(parent_scope),
1418 );
1419 }
1420
1421 var is_continuation_unreachable = false;
1422 var noreturn_return_value: ?*Inst = null;
1423
1424 var stmt_it = block.statements.iterator(0);
1425 while (stmt_it.next()) |statement_node_ptr| {
1426 const statement_node = statement_node_ptr.*;
1427
1428 if (statement_node.cast(ast.Node.Defer)) |defer_node| {
1429 // defer starts a new scope
1430 const defer_token = irb.root_scope.tree.tokens.at(defer_node.defer_token);
1431 const kind = switch (defer_token.id) {
1432 Token.Id.Keyword_defer => Scope.Defer.Kind.ScopeExit,
1433 Token.Id.Keyword_errdefer => Scope.Defer.Kind.ErrorExit,
1434 else => unreachable,
1435 };
1436 const defer_expr_scope = try Scope.DeferExpr.create(irb.comp, parent_scope, defer_node.expr);
1437 const defer_child_scope = try Scope.Defer.create(irb.comp, parent_scope, kind, defer_expr_scope);
1438 child_scope = &defer_child_scope.base;
1439 continue;
1440 }
1441 const statement_value = try await (async irb.genNode(statement_node, child_scope, LVal.None) catch unreachable);
1442
1443 is_continuation_unreachable = statement_value.isNoReturn();
1444 if (is_continuation_unreachable) {
1445 // keep the last noreturn statement value around in case we need to return it
1446 noreturn_return_value = statement_value;
1447 }
1448
1449 if (statement_value.cast(Inst.DeclVar)) |decl_var| {
1450 // variable declarations start a new scope
1451 child_scope = decl_var.params.variable.child_scope;
1452 } else if (!is_continuation_unreachable) {
1453 // this statement's value must be void
1454 _ = irb.build(
1455 Inst.CheckVoidStmt,
1456 child_scope,
1457 Span{
1458 .first = statement_node.firstToken(),
1459 .last = statement_node.lastToken(),
1460 },
1461 Inst.CheckVoidStmt.Params{ .target = statement_value },
1462 );
1463 }
1464 }
1465
1466 if (is_continuation_unreachable) {
1467 assert(noreturn_return_value != null);
1468 if (block.label == null or block_scope.incoming_blocks.len == 0) {
1469 return noreturn_return_value.?;
1470 }
1471
1472 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);
1473 return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{
1474 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
1475 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
1476 });
1477 }
1478
1479 if (block.label) |label| {
1480 try block_scope.incoming_blocks.append(irb.current_basic_block);
1481 try block_scope.incoming_values.append(
1482 try irb.buildConstVoid(parent_scope, Span.token(block.rbrace), true),
1483 );
1484 _ = try await (async irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1485
1486 _ = try irb.buildGen(Inst.Br, parent_scope, Span.token(block.rbrace), Inst.Br.Params{
1487 .dest_block = block_scope.end_block,
1488 .is_comptime = block_scope.is_comptime,
1489 });
1490
1491 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);
1492
1493 return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{
1494 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
1495 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
1496 });
1497 }
1498
1499 _ = try await (async irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1500 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);
1501 }
1502
1503 pub async fn genControlFlowExpr(
1504 irb: *Builder,
1505 control_flow_expr: *ast.Node.ControlFlowExpression,
1506 scope: *Scope,
1507 lval: LVal,
1508 ) !*Inst {
1509 switch (control_flow_expr.kind) {
1510 ast.Node.ControlFlowExpression.Kind.Break => |arg| return error.Unimplemented,
1511 ast.Node.ControlFlowExpression.Kind.Continue => |arg| return error.Unimplemented,
1512 ast.Node.ControlFlowExpression.Kind.Return => {
1513 const src_span = Span.token(control_flow_expr.ltoken);
1514 if (scope.findFnDef() == null) {
1515 try irb.comp.addCompileError(
1516 irb.root_scope,
1517 src_span,
1518 "return expression outside function definition",
1519 );
1520 return error.SemanticAnalysisFailed;
1521 }
1522
1523 if (scope.findDeferExpr()) |scope_defer_expr| {
1524 if (!scope_defer_expr.reported_err) {
1525 try irb.comp.addCompileError(
1526 irb.root_scope,
1527 src_span,
1528 "cannot return from defer expression",
1529 );
1530 scope_defer_expr.reported_err = true;
1531 }
1532 return error.SemanticAnalysisFailed;
1533 }
1534
1535 const outer_scope = irb.begin_scope.?;
1536 const return_value = if (control_flow_expr.rhs) |rhs| blk: {
1537 break :blk try await (async irb.genNode(rhs, scope, LVal.None) catch unreachable);
1538 } else blk: {
1539 break :blk try irb.buildConstVoid(scope, src_span, true);
1540 };
1541
1542 const defer_counts = irb.countDefers(scope, outer_scope);
1543 const have_err_defers = defer_counts.error_exit != 0;
1544 if (have_err_defers or irb.comp.have_err_ret_tracing) {
1545 const err_block = try irb.createBasicBlock(scope, c"ErrRetErr");
1546 const ok_block = try irb.createBasicBlock(scope, c"ErrRetOk");
1547 if (!have_err_defers) {
1548 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1549 }
1550
1551 const is_err = try irb.build(
1552 Inst.TestErr,
1553 scope,
1554 src_span,
1555 Inst.TestErr.Params{ .target = return_value },
1556 );
1557
1558 const err_is_comptime = try irb.buildTestCompTime(scope, src_span, is_err);
1559
1560 _ = try irb.buildGen(Inst.CondBr, scope, src_span, Inst.CondBr.Params{
1561 .condition = is_err,
1562 .then_block = err_block,
1563 .else_block = ok_block,
1564 .is_comptime = err_is_comptime,
1565 });
1566
1567 const ret_stmt_block = try irb.createBasicBlock(scope, c"RetStmt");
1568
1569 try irb.setCursorAtEndAndAppendBlock(err_block);
1570 if (have_err_defers) {
1571 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ErrorExit) catch unreachable);
1572 }
1573 if (irb.comp.have_err_ret_tracing and !irb.isCompTime(scope)) {
1574 _ = try irb.build(Inst.SaveErrRetAddr, scope, src_span, Inst.SaveErrRetAddr.Params{});
1575 }
1576 _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{
1577 .dest_block = ret_stmt_block,
1578 .is_comptime = err_is_comptime,
1579 });
1580
1581 try irb.setCursorAtEndAndAppendBlock(ok_block);
1582 if (have_err_defers) {
1583 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1584 }
1585 _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{
1586 .dest_block = ret_stmt_block,
1587 .is_comptime = err_is_comptime,
1588 });
1589
1590 try irb.setCursorAtEndAndAppendBlock(ret_stmt_block);
1591 return irb.genAsyncReturn(scope, src_span, return_value, false);
1592 } else {
1593 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1594 return irb.genAsyncReturn(scope, src_span, return_value, false);
1595 }
1596 },
1597 }
1598 }
1599
1600 pub async fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst {
1601 const src_span = Span.token(identifier.token);
1602 const name = irb.root_scope.tree.tokenSlice(identifier.token);
1603
1604 //if (buf_eql_str(variable_name, "_") && lval == LValPtr) {
1605 // IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, node);
1606 // const_instruction->base.value.type = get_pointer_to_type(irb->codegen,
1607 // irb->codegen->builtin_types.entry_void, false);
1608 // const_instruction->base.value.special = ConstValSpecialStatic;
1609 // const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard;
1610 // return &const_instruction->base;
1611 //}
1612
1613 if (await (async irb.comp.getPrimitiveType(name) catch unreachable)) |result| {
1614 if (result) |primitive_type| {
1615 defer primitive_type.base.deref(irb.comp);
1616 switch (lval) {
1617 // if (lval == LValPtr) {
1618 // return ir_build_ref(irb, scope, node, value, false, false);
1619 LVal.Ptr => return error.Unimplemented,
1620 LVal.None => return irb.buildConstValue(scope, src_span, &primitive_type.base),
1621 }
1622 }
1623 } else |err| switch (err) {
1624 error.Overflow => {
1625 try irb.comp.addCompileError(irb.root_scope, src_span, "integer too large");
1626 return error.SemanticAnalysisFailed;
1627 },
1628 error.OutOfMemory => return error.OutOfMemory,
1629 }
1630
1631 switch (await (async irb.findIdent(scope, name) catch unreachable)) {
1632 Ident.Decl => |decl| {
1633 return irb.build(Inst.DeclRef, scope, src_span, Inst.DeclRef.Params{
1634 .decl = decl,
1635 .lval = lval,
1636 });
1637 },
1638 Ident.VarScope => |var_scope| {
1639 const var_ptr = try irb.build(Inst.VarPtr, scope, src_span, Inst.VarPtr.Params{ .var_scope = var_scope });
1640 switch (lval) {
1641 LVal.Ptr => return var_ptr,
1642 LVal.None => {
1643 return irb.build(Inst.LoadPtr, scope, src_span, Inst.LoadPtr.Params{ .target = var_ptr });
1644 },
1645 }
1646 },
1647 Ident.NotFound => {},
1648 }
1649
1650 //if (node->owner->any_imports_failed) {
1651 // // skip the error message since we had a failing import in this file
1652 // // if an import breaks we don't need redundant undeclared identifier errors
1653 // return irb->codegen->invalid_instruction;
1654 //}
1655
1656 // TODO put a variable of same name with invalid type in global scope
1657 // so that future references to this same name will find a variable with an invalid type
1658
1659 try irb.comp.addCompileError(irb.root_scope, src_span, "unknown identifier '{}'", name);
1660 return error.SemanticAnalysisFailed;
1661 }
1662
1663 const DeferCounts = struct {
1664 scope_exit: usize,
1665 error_exit: usize,
1101666 };
1111667
1668 fn countDefers(irb: *Builder, inner_scope: *Scope, outer_scope: *Scope) DeferCounts {
1669 var result = DeferCounts{ .scope_exit = 0, .error_exit = 0 };
1670
1671 var scope = inner_scope;
1672 while (scope != outer_scope) {
1673 switch (scope.id) {
1674 Scope.Id.Defer => {
1675 const defer_scope = @fieldParentPtr(Scope.Defer, "base", scope);
1676 switch (defer_scope.kind) {
1677 Scope.Defer.Kind.ScopeExit => result.scope_exit += 1,
1678 Scope.Defer.Kind.ErrorExit => result.error_exit += 1,
1679 }
1680 scope = scope.parent orelse break;
1681 },
1682 Scope.Id.FnDef => break,
1683
1684 Scope.Id.CompTime,
1685 Scope.Id.Block,
1686 Scope.Id.Decls,
1687 Scope.Id.Root,
1688 Scope.Id.Var,
1689 => scope = scope.parent orelse break,
1690
1691 Scope.Id.DeferExpr => unreachable,
1692 }
1693 }
1694 return result;
1695 }
1696
1697 async fn genDefersForBlock(
1698 irb: *Builder,
1699 inner_scope: *Scope,
1700 outer_scope: *Scope,
1701 gen_kind: Scope.Defer.Kind,
1702 ) !bool {
1703 var scope = inner_scope;
1704 var is_noreturn = false;
1705 while (true) {
1706 switch (scope.id) {
1707 Scope.Id.Defer => {
1708 const defer_scope = @fieldParentPtr(Scope.Defer, "base", scope);
1709 const generate = switch (defer_scope.kind) {
1710 Scope.Defer.Kind.ScopeExit => true,
1711 Scope.Defer.Kind.ErrorExit => gen_kind == Scope.Defer.Kind.ErrorExit,
1712 };
1713 if (generate) {
1714 const defer_expr_scope = defer_scope.defer_expr_scope;
1715 const instruction = try await (async irb.genNode(
1716 defer_expr_scope.expr_node,
1717 &defer_expr_scope.base,
1718 LVal.None,
1719 ) catch unreachable);
1720 if (instruction.isNoReturn()) {
1721 is_noreturn = true;
1722 } else {
1723 _ = try irb.build(
1724 Inst.CheckVoidStmt,
1725 &defer_expr_scope.base,
1726 Span.token(defer_expr_scope.expr_node.lastToken()),
1727 Inst.CheckVoidStmt.Params{ .target = instruction },
1728 );
1729 }
1730 }
1731 },
1732 Scope.Id.FnDef,
1733 Scope.Id.Decls,
1734 Scope.Id.Root,
1735 => return is_noreturn,
1736
1737 Scope.Id.CompTime,
1738 Scope.Id.Block,
1739 Scope.Id.Var,
1740 => scope = scope.parent orelse return is_noreturn,
1741
1742 Scope.Id.DeferExpr => unreachable,
1743 }
1744 }
1745 }
1746
1747 pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Inst, lval: LVal) !*Inst {
1748 switch (lval) {
1749 LVal.None => return instruction,
1750 LVal.Ptr => {
1751 // We needed a pointer to a value, but we got a value. So we create
1752 // an instruction which just makes a const pointer of it.
1753 return irb.build(Inst.Ref, scope, instruction.span, Inst.Ref.Params{
1754 .target = instruction,
1755 .mut = Type.Pointer.Mut.Const,
1756 .volatility = Type.Pointer.Vol.Non,
1757 });
1758 },
1759 }
1760 }
1761
1762 fn arena(self: *Builder) *Allocator {
1763 return &self.code.arena.allocator;
1764 }
1765
1766 fn buildExtra(
1767 self: *Builder,
1768 comptime I: type,
1769 scope: *Scope,
1770 span: Span,
1771 params: I.Params,
1772 is_generated: bool,
1773 ) !*Inst {
1774 const inst = try self.arena().create(I{
1775 .base = Inst{
1776 .id = Inst.typeToId(I),
1777 .is_generated = is_generated,
1778 .scope = scope,
1779 .debug_id = self.next_debug_id,
1780 .val = switch (I.ir_val_init) {
1781 IrVal.Init.Unknown => IrVal.Unknown,
1782 IrVal.Init.NoReturn => IrVal{ .KnownValue = &Value.NoReturn.get(self.comp).base },
1783 IrVal.Init.Void => IrVal{ .KnownValue = &Value.Void.get(self.comp).base },
1784 },
1785 .ref_count = 0,
1786 .span = span,
1787 .child = null,
1788 .parent = null,
1789 .llvm_value = undefined,
1790 .owner_bb = self.current_basic_block,
1791 },
1792 .params = params,
1793 });
1794
1795 // Look at the params and ref() other instructions
1796 comptime var i = 0;
1797 inline while (i < @memberCount(I.Params)) : (i += 1) {
1798 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));
1799 switch (FieldType) {
1800 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
1801 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),
1802 ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),
1803 []*Inst => {
1804 // TODO https://github.com/ziglang/zig/issues/1269
1805 for (@field(inst.params, @memberName(I.Params, i))) |other|
1806 other.ref(self);
1807 },
1808 []*BasicBlock => {
1809 // TODO https://github.com/ziglang/zig/issues/1269
1810 for (@field(inst.params, @memberName(I.Params, i))) |other|
1811 other.ref(self);
1812 },
1813 Type.Pointer.Mut,
1814 Type.Pointer.Vol,
1815 Type.Pointer.Size,
1816 LVal,
1817 *Decl,
1818 *Scope.Var,
1819 => {},
1820 // it's ok to add more types here, just make sure that
1821 // any instructions and basic blocks are ref'd appropriately
1822 else => @compileError("unrecognized type in Params: " ++ @typeName(FieldType)),
1823 }
1824 }
1825
1826 self.next_debug_id += 1;
1827 try self.current_basic_block.instruction_list.append(&inst.base);
1828 return &inst.base;
1829 }
1830
1831 fn build(
1832 self: *Builder,
1833 comptime I: type,
1834 scope: *Scope,
1835 span: Span,
1836 params: I.Params,
1837 ) !*Inst {
1838 return self.buildExtra(I, scope, span, params, false);
1839 }
1840
1841 fn buildGen(
1842 self: *Builder,
1843 comptime I: type,
1844 scope: *Scope,
1845 span: Span,
1846 params: I.Params,
1847 ) !*Inst {
1848 return self.buildExtra(I, scope, span, params, true);
1849 }
1850
1851 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Inst {
1852 const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{});
1853 inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base };
1854 return inst;
1855 }
1856
1857 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Inst {
1858 const inst = try self.buildExtra(Inst.Const, scope, span, Inst.Const.Params{}, is_generated);
1859 inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base };
1860 return inst;
1861 }
1862
1863 fn buildConstValue(self: *Builder, scope: *Scope, span: Span, v: *Value) !*Inst {
1864 const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{});
1865 inst.val = IrVal{ .KnownValue = v.getRef() };
1866 return inst;
1867 }
1868
1869 /// If the code is explicitly set to be comptime, then builds a const bool,
1870 /// otherwise builds a TestCompTime instruction.
1871 fn buildTestCompTime(self: *Builder, scope: *Scope, span: Span, target: *Inst) !*Inst {
1872 if (self.isCompTime(scope)) {
1873 return self.buildConstBool(scope, span, true);
1874 } else {
1875 return self.build(
1876 Inst.TestCompTime,
1877 scope,
1878 span,
1879 Inst.TestCompTime.Params{ .target = target },
1880 );
1881 }
1882 }
1883
1884 fn genAsyncReturn(irb: *Builder, scope: *Scope, span: Span, result: *Inst, is_gen: bool) !*Inst {
1885 _ = irb.buildGen(
1886 Inst.AddImplicitReturnType,
1887 scope,
1888 span,
1889 Inst.AddImplicitReturnType.Params{ .target = result },
1890 );
1891
1892 if (!irb.is_async) {
1893 return irb.buildExtra(
1894 Inst.Return,
1895 scope,
1896 span,
1897 Inst.Return.Params{ .return_value = result },
1898 is_gen,
1899 );
1900 }
1901 return error.Unimplemented;
1902
1903 //ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
1904 //IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
1905 // get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
1906 //// TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
1907 //IrInstruction *replacement_value = irb->exec->coro_handle;
1908 //IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
1909 // promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr,
1910 // AtomicRmwOp_xchg, AtomicOrderSeqCst);
1911 //ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle);
1912 //IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle);
1913 //IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
1914 //return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final,
1915 // is_comptime);
1916 //// the above blocks are rendered by ir_gen after the rest of codegen
1917 }
1918
1919 const Ident = union(enum) {
1920 NotFound,
1921 Decl: *Decl,
1922 VarScope: *Scope.Var,
1923 };
1924
1925 async fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident {
1926 var s = scope;
1927 while (true) {
1928 switch (s.id) {
1929 Scope.Id.Root => return Ident.NotFound,
1930 Scope.Id.Decls => {
1931 const decls = @fieldParentPtr(Scope.Decls, "base", s);
1932 const table = await (async decls.getTableReadOnly() catch unreachable);
1933 if (table.get(name)) |entry| {
1934 return Ident{ .Decl = entry.value };
1935 }
1936 },
1937 Scope.Id.Var => {
1938 const var_scope = @fieldParentPtr(Scope.Var, "base", s);
1939 if (mem.eql(u8, var_scope.name, name)) {
1940 return Ident{ .VarScope = var_scope };
1941 }
1942 },
1943 else => {},
1944 }
1945 s = s.parent.?;
1946 }
1947 }
1121948};
1949
1950const Analyze = struct {
1951 irb: Builder,
1952 old_bb_index: usize,
1953 const_predecessor_bb: ?*BasicBlock,
1954 parent_basic_block: *BasicBlock,
1955 instruction_index: usize,
1956 src_implicit_return_type_list: std.ArrayList(*Inst),
1957 explicit_return_type: ?*Type,
1958
1959 pub const Error = error{
1960 /// This is only for when we have already reported a compile error. It is the poison value.
1961 SemanticAnalysisFailed,
1962
1963 /// This is a placeholder - it is useful to use instead of panicking but once the compiler is
1964 /// done this error code will be removed.
1965 Unimplemented,
1966
1967 OutOfMemory,
1968 };
1969
1970 pub fn init(comp: *Compilation, root_scope: *Scope.Root, explicit_return_type: ?*Type) !Analyze {
1971 var irb = try Builder.init(comp, root_scope, null);
1972 errdefer irb.abort();
1973
1974 return Analyze{
1975 .irb = irb,
1976 .old_bb_index = 0,
1977 .const_predecessor_bb = null,
1978 .parent_basic_block = undefined, // initialized with startBasicBlock
1979 .instruction_index = undefined, // initialized with startBasicBlock
1980 .src_implicit_return_type_list = std.ArrayList(*Inst).init(irb.arena()),
1981 .explicit_return_type = explicit_return_type,
1982 };
1983 }
1984
1985 pub fn abort(self: *Analyze) void {
1986 self.irb.abort();
1987 }
1988
1989 pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Inst) !*BasicBlock {
1990 if (old_bb.child) |child| {
1991 if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction)
1992 return child;
1993 }
1994
1995 const new_bb = try self.irb.createBasicBlock(old_bb.scope, old_bb.name_hint);
1996 new_bb.linkToParent(old_bb);
1997 new_bb.ref_instruction = ref_old_instruction;
1998 return new_bb;
1999 }
2000
2001 pub fn startBasicBlock(self: *Analyze, old_bb: *BasicBlock, const_predecessor_bb: ?*BasicBlock) void {
2002 self.instruction_index = 0;
2003 self.parent_basic_block = old_bb;
2004 self.const_predecessor_bb = const_predecessor_bb;
2005 }
2006
2007 pub fn finishBasicBlock(ira: *Analyze, old_code: *Code) !void {
2008 try ira.irb.code.basic_block_list.append(ira.irb.current_basic_block);
2009 ira.instruction_index += 1;
2010
2011 while (ira.instruction_index < ira.parent_basic_block.instruction_list.len) {
2012 const next_instruction = ira.parent_basic_block.instruction_list.at(ira.instruction_index);
2013
2014 if (!next_instruction.is_generated) {
2015 try ira.addCompileError(next_instruction.span, "unreachable code");
2016 break;
2017 }
2018 ira.instruction_index += 1;
2019 }
2020
2021 ira.old_bb_index += 1;
2022
2023 var need_repeat = true;
2024 while (true) {
2025 while (ira.old_bb_index < old_code.basic_block_list.len) {
2026 const old_bb = old_code.basic_block_list.at(ira.old_bb_index);
2027 const new_bb = old_bb.child orelse {
2028 ira.old_bb_index += 1;
2029 continue;
2030 };
2031 if (new_bb.instruction_list.len != 0) {
2032 ira.old_bb_index += 1;
2033 continue;
2034 }
2035 ira.irb.current_basic_block = new_bb;
2036
2037 ira.startBasicBlock(old_bb, null);
2038 return;
2039 }
2040 if (!need_repeat)
2041 return;
2042 need_repeat = false;
2043 ira.old_bb_index = 0;
2044 continue;
2045 }
2046 }
2047
2048 fn addCompileError(self: *Analyze, span: Span, comptime fmt: []const u8, args: ...) !void {
2049 return self.irb.comp.addCompileError(self.irb.root_scope, span, fmt, args);
2050 }
2051
2052 fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Inst) Analyze.Error!*Type {
2053 // TODO actual implementation
2054 return &Type.Void.get(self.irb.comp).base;
2055 }
2056
2057 fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst {
2058 const dest_type = optional_dest_type orelse return target;
2059 const from_type = target.getKnownType();
2060 if (from_type == dest_type or from_type.id == Type.Id.NoReturn) return target;
2061 return self.analyzeCast(target, target, dest_type);
2062 }
2063
2064 fn analyzeCast(ira: *Analyze, source_instr: *Inst, target: *Inst, dest_type: *Type) !*Inst {
2065 const from_type = target.getKnownType();
2066
2067 //if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
2068 // return ira->codegen->invalid_instruction;
2069 //}
2070
2071 //// perfect match or non-const to const
2072 //ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
2073 // source_node, false);
2074 //if (const_cast_result.id == ConstCastResultIdOk) {
2075 // return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
2076 //}
2077
2078 //// widening conversion
2079 //if (wanted_type->id == TypeTableEntryIdInt &&
2080 // actual_type->id == TypeTableEntryIdInt &&
2081 // wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
2082 // wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
2083 //{
2084 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
2085 //}
2086
2087 //// small enough unsigned ints can get casted to large enough signed ints
2088 //if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed &&
2089 // actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
2090 // wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count)
2091 //{
2092 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
2093 //}
2094
2095 //// float widening conversion
2096 //if (wanted_type->id == TypeTableEntryIdFloat &&
2097 // actual_type->id == TypeTableEntryIdFloat &&
2098 // wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
2099 //{
2100 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
2101 //}
2102
2103 //// cast from [N]T to []const T
2104 //if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
2105 // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
2106 // assert(ptr_type->id == TypeTableEntryIdPointer);
2107 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
2108 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
2109 // source_node, false).id == ConstCastResultIdOk)
2110 // {
2111 // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
2112 // }
2113 //}
2114
2115 //// cast from *const [N]T to []const T
2116 //if (is_slice(wanted_type) &&
2117 // actual_type->id == TypeTableEntryIdPointer &&
2118 // actual_type->data.pointer.is_const &&
2119 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
2120 //{
2121 // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
2122 // assert(ptr_type->id == TypeTableEntryIdPointer);
2123
2124 // TypeTableEntry *array_type = actual_type->data.pointer.child_type;
2125
2126 // if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
2127 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
2128 // source_node, false).id == ConstCastResultIdOk)
2129 // {
2130 // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
2131 // }
2132 //}
2133
2134 //// cast from [N]T to *const []const T
2135 //if (wanted_type->id == TypeTableEntryIdPointer &&
2136 // wanted_type->data.pointer.is_const &&
2137 // is_slice(wanted_type->data.pointer.child_type) &&
2138 // actual_type->id == TypeTableEntryIdArray)
2139 //{
2140 // TypeTableEntry *ptr_type =
2141 // wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
2142 // assert(ptr_type->id == TypeTableEntryIdPointer);
2143 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
2144 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
2145 // source_node, false).id == ConstCastResultIdOk)
2146 // {
2147 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
2148 // if (type_is_invalid(cast1->value.type))
2149 // return ira->codegen->invalid_instruction;
2150
2151 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2152 // if (type_is_invalid(cast2->value.type))
2153 // return ira->codegen->invalid_instruction;
2154
2155 // return cast2;
2156 // }
2157 //}
2158
2159 //// cast from [N]T to ?[]const T
2160 //if (wanted_type->id == TypeTableEntryIdOptional &&
2161 // is_slice(wanted_type->data.maybe.child_type) &&
2162 // actual_type->id == TypeTableEntryIdArray)
2163 //{
2164 // TypeTableEntry *ptr_type =
2165 // wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
2166 // assert(ptr_type->id == TypeTableEntryIdPointer);
2167 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
2168 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
2169 // source_node, false).id == ConstCastResultIdOk)
2170 // {
2171 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
2172 // if (type_is_invalid(cast1->value.type))
2173 // return ira->codegen->invalid_instruction;
2174
2175 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2176 // if (type_is_invalid(cast2->value.type))
2177 // return ira->codegen->invalid_instruction;
2178
2179 // return cast2;
2180 // }
2181 //}
2182
2183 //// *[N]T to [*]T
2184 //if (wanted_type->id == TypeTableEntryIdPointer &&
2185 // wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
2186 // actual_type->id == TypeTableEntryIdPointer &&
2187 // actual_type->data.pointer.ptr_len == PtrLenSingle &&
2188 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
2189 // actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
2190 // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
2191 // actual_type->data.pointer.child_type->data.array.child_type, source_node,
2192 // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
2193 //{
2194 // return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
2195 //}
2196
2197 //// *[N]T to []T
2198 //if (is_slice(wanted_type) &&
2199 // actual_type->id == TypeTableEntryIdPointer &&
2200 // actual_type->data.pointer.ptr_len == PtrLenSingle &&
2201 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
2202 //{
2203 // TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
2204 // assert(slice_ptr_type->id == TypeTableEntryIdPointer);
2205 // if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
2206 // actual_type->data.pointer.child_type->data.array.child_type, source_node,
2207 // !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
2208 // {
2209 // return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
2210 // }
2211 //}
2212
2213 //// cast from T to ?T
2214 //// note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
2215 //if (wanted_type->id == TypeTableEntryIdOptional) {
2216 // TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
2217 // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
2218 // false).id == ConstCastResultIdOk)
2219 // {
2220 // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
2221 // } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
2222 // actual_type->id == TypeTableEntryIdComptimeFloat)
2223 // {
2224 // if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
2225 // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
2226 // } else {
2227 // return ira->codegen->invalid_instruction;
2228 // }
2229 // } else if (wanted_child_type->id == TypeTableEntryIdPointer &&
2230 // wanted_child_type->data.pointer.is_const &&
2231 // (actual_type->id == TypeTableEntryIdPointer || is_container(actual_type)))
2232 // {
2233 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value);
2234 // if (type_is_invalid(cast1->value.type))
2235 // return ira->codegen->invalid_instruction;
2236
2237 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2238 // if (type_is_invalid(cast2->value.type))
2239 // return ira->codegen->invalid_instruction;
2240
2241 // return cast2;
2242 // }
2243 //}
2244
2245 //// cast from null literal to maybe type
2246 //if (wanted_type->id == TypeTableEntryIdOptional &&
2247 // actual_type->id == TypeTableEntryIdNull)
2248 //{
2249 // return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
2250 //}
2251
2252 //// cast from child type of error type to error type
2253 //if (wanted_type->id == TypeTableEntryIdErrorUnion) {
2254 // if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
2255 // source_node, false).id == ConstCastResultIdOk)
2256 // {
2257 // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
2258 // } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
2259 // actual_type->id == TypeTableEntryIdComptimeFloat)
2260 // {
2261 // if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) {
2262 // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
2263 // } else {
2264 // return ira->codegen->invalid_instruction;
2265 // }
2266 // }
2267 //}
2268
2269 //// cast from [N]T to E![]const T
2270 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
2271 // is_slice(wanted_type->data.error_union.payload_type) &&
2272 // actual_type->id == TypeTableEntryIdArray)
2273 //{
2274 // TypeTableEntry *ptr_type =
2275 // wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
2276 // assert(ptr_type->id == TypeTableEntryIdPointer);
2277 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
2278 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
2279 // source_node, false).id == ConstCastResultIdOk)
2280 // {
2281 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
2282 // if (type_is_invalid(cast1->value.type))
2283 // return ira->codegen->invalid_instruction;
2284
2285 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2286 // if (type_is_invalid(cast2->value.type))
2287 // return ira->codegen->invalid_instruction;
2288
2289 // return cast2;
2290 // }
2291 //}
2292
2293 //// cast from error set to error union type
2294 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
2295 // actual_type->id == TypeTableEntryIdErrorSet)
2296 //{
2297 // return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
2298 //}
2299
2300 //// cast from T to E!?T
2301 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
2302 // wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
2303 // actual_type->id != TypeTableEntryIdOptional)
2304 //{
2305 // TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
2306 // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
2307 // actual_type->id == TypeTableEntryIdNull ||
2308 // actual_type->id == TypeTableEntryIdComptimeInt ||
2309 // actual_type->id == TypeTableEntryIdComptimeFloat)
2310 // {
2311 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
2312 // if (type_is_invalid(cast1->value.type))
2313 // return ira->codegen->invalid_instruction;
2314
2315 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2316 // if (type_is_invalid(cast2->value.type))
2317 // return ira->codegen->invalid_instruction;
2318
2319 // return cast2;
2320 // }
2321 //}
2322
2323 // cast from comptime-known integer to another integer where the value fits
2324 if (target.isCompTime() and (from_type.id == Type.Id.Int or from_type.id == Type.Id.ComptimeInt)) cast: {
2325 const target_val = target.val.KnownValue;
2326 const from_int = &target_val.cast(Value.Int).?.big_int;
2327 const fits = fits: {
2328 if (dest_type.cast(Type.ComptimeInt)) |ctint| {
2329 break :fits true;
2330 }
2331 if (dest_type.cast(Type.Int)) |int| {
2332 break :fits from_int.fitsInTwosComp(int.key.is_signed, int.key.bit_count);
2333 }
2334 break :cast;
2335 };
2336 if (!fits) {
2337 try ira.addCompileError(
2338 source_instr.span,
2339 "integer value '{}' cannot be stored in type '{}'",
2340 from_int,
2341 dest_type.name,
2342 );
2343 return error.SemanticAnalysisFailed;
2344 }
2345
2346 const new_val = try target.copyVal(ira.irb.comp);
2347 new_val.setType(dest_type, ira.irb.comp);
2348 return ira.irb.buildConstValue(source_instr.scope, source_instr.span, new_val);
2349 }
2350
2351 // cast from number literal to another type
2352 // cast from number literal to *const integer
2353 //if (actual_type->id == TypeTableEntryIdComptimeFloat ||
2354 // actual_type->id == TypeTableEntryIdComptimeInt)
2355 //{
2356 // ensure_complete_type(ira->codegen, wanted_type);
2357 // if (type_is_invalid(wanted_type))
2358 // return ira->codegen->invalid_instruction;
2359 // if (wanted_type->id == TypeTableEntryIdEnum) {
2360 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
2361 // if (type_is_invalid(cast1->value.type))
2362 // return ira->codegen->invalid_instruction;
2363
2364 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2365 // if (type_is_invalid(cast2->value.type))
2366 // return ira->codegen->invalid_instruction;
2367
2368 // return cast2;
2369 // } else if (wanted_type->id == TypeTableEntryIdPointer &&
2370 // wanted_type->data.pointer.is_const)
2371 // {
2372 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
2373 // if (type_is_invalid(cast1->value.type))
2374 // return ira->codegen->invalid_instruction;
2375
2376 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2377 // if (type_is_invalid(cast2->value.type))
2378 // return ira->codegen->invalid_instruction;
2379
2380 // return cast2;
2381 // } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
2382 // CastOp op;
2383 // if ((actual_type->id == TypeTableEntryIdComptimeFloat &&
2384 // wanted_type->id == TypeTableEntryIdFloat) ||
2385 // (actual_type->id == TypeTableEntryIdComptimeInt &&
2386 // wanted_type->id == TypeTableEntryIdInt))
2387 // {
2388 // op = CastOpNumLitToConcrete;
2389 // } else if (wanted_type->id == TypeTableEntryIdInt) {
2390 // op = CastOpFloatToInt;
2391 // } else if (wanted_type->id == TypeTableEntryIdFloat) {
2392 // op = CastOpIntToFloat;
2393 // } else {
2394 // zig_unreachable();
2395 // }
2396 // return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false);
2397 // } else {
2398 // return ira->codegen->invalid_instruction;
2399 // }
2400 //}
2401
2402 //// cast from typed number to integer or float literal.
2403 //// works when the number is known at compile time
2404 //if (instr_is_comptime(value) &&
2405 // ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||
2406 // (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat)))
2407 //{
2408 // return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
2409 //}
2410
2411 //// cast from union to the enum type of the union
2412 //if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
2413 // type_ensure_zero_bits_known(ira->codegen, actual_type);
2414 // if (type_is_invalid(actual_type))
2415 // return ira->codegen->invalid_instruction;
2416
2417 // if (actual_type->data.unionation.tag_type == wanted_type) {
2418 // return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type);
2419 // }
2420 //}
2421
2422 //// enum to union which has the enum as the tag type
2423 //if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
2424 // (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
2425 // wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
2426 //{
2427 // type_ensure_zero_bits_known(ira->codegen, wanted_type);
2428 // if (wanted_type->data.unionation.tag_type == actual_type) {
2429 // return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
2430 // }
2431 //}
2432
2433 //// enum to &const union which has the enum as the tag type
2434 //if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {
2435 // TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
2436 // if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
2437 // union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
2438 // {
2439 // type_ensure_zero_bits_known(ira->codegen, union_type);
2440 // if (union_type->data.unionation.tag_type == actual_type) {
2441 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value);
2442 // if (type_is_invalid(cast1->value.type))
2443 // return ira->codegen->invalid_instruction;
2444
2445 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2446 // if (type_is_invalid(cast2->value.type))
2447 // return ira->codegen->invalid_instruction;
2448
2449 // return cast2;
2450 // }
2451 // }
2452 //}
2453
2454 //// cast from *T to *[1]T
2455 //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
2456 // actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
2457 //{
2458 // TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
2459 // if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 &&
2460 // types_match_const_cast_only(ira, array_type->data.array.child_type,
2461 // actual_type->data.pointer.child_type, source_node,
2462 // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
2463 // {
2464 // if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
2465 // ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
2466 // add_error_note(ira->codegen, msg, value->source_node,
2467 // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name),
2468 // actual_type->data.pointer.alignment));
2469 // add_error_note(ira->codegen, msg, source_instr->source_node,
2470 // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name),
2471 // wanted_type->data.pointer.alignment));
2472 // return ira->codegen->invalid_instruction;
2473 // }
2474 // return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type);
2475 // }
2476 //}
2477
2478 //// cast from T to *T where T is zero bits
2479 //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
2480 // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
2481 // actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
2482 //{
2483 // type_ensure_zero_bits_known(ira->codegen, actual_type);
2484 // if (type_is_invalid(actual_type)) {
2485 // return ira->codegen->invalid_instruction;
2486 // }
2487 // if (!type_has_bits(actual_type)) {
2488 // return ir_get_ref(ira, source_instr, value, false, false);
2489 // }
2490 //}
2491
2492 //// cast from undefined to anything
2493 //if (actual_type->id == TypeTableEntryIdUndefined) {
2494 // return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
2495 //}
2496
2497 //// cast from something to const pointer of it
2498 //if (!type_requires_comptime(actual_type)) {
2499 // TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
2500 // if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {
2501 // return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
2502 // }
2503 //}
2504
2505 try ira.addCompileError(
2506 source_instr.span,
2507 "expected type '{}', found '{}'",
2508 dest_type.name,
2509 from_type.name,
2510 );
2511 //ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
2512 // buf_sprintf("expected type '%s', found '%s'",
2513 // buf_ptr(&wanted_type->name),
2514 // buf_ptr(&actual_type->name)));
2515 //report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
2516 return error.SemanticAnalysisFailed;
2517 }
2518
2519 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value {
2520 @panic("TODO");
2521 }
2522
2523 fn getCompTimeRef(
2524 self: *Analyze,
2525 value: *Value,
2526 ptr_mut: Value.Ptr.Mut,
2527 mut: Type.Pointer.Mut,
2528 volatility: Type.Pointer.Vol,
2529 ) Analyze.Error!*Inst {
2530 return error.Unimplemented;
2531 }
2532};
2533
2534pub async fn gen(
2535 comp: *Compilation,
2536 body_node: *ast.Node,
2537 scope: *Scope,
2538) !*Code {
2539 var irb = try Builder.init(comp, scope.findRoot(), scope);
2540 errdefer irb.abort();
2541
2542 const entry_block = try irb.createBasicBlock(scope, c"Entry");
2543 entry_block.ref(&irb); // Entry block gets a reference because we enter it to begin.
2544 try irb.setCursorAtEndAndAppendBlock(entry_block);
2545
2546 const result = try await (async irb.genNode(body_node, scope, LVal.None) catch unreachable);
2547 if (!result.isNoReturn()) {
2548 // no need for save_err_ret_addr because this cannot return error
2549 _ = try irb.genAsyncReturn(scope, Span.token(body_node.lastToken()), result, true);
2550 }
2551
2552 return irb.finish();
2553}
2554
2555pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code {
2556 const old_entry_bb = old_code.basic_block_list.at(0);
2557 const root_scope = old_entry_bb.scope.findRoot();
2558
2559 var ira = try Analyze.init(comp, root_scope, expected_type);
2560 errdefer ira.abort();
2561
2562 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);
2563 new_entry_bb.ref(&ira.irb);
2564
2565 ira.irb.current_basic_block = new_entry_bb;
2566
2567 ira.startBasicBlock(old_entry_bb, null);
2568
2569 while (ira.old_bb_index < old_code.basic_block_list.len) {
2570 const old_instruction = ira.parent_basic_block.instruction_list.at(ira.instruction_index);
2571
2572 if (old_instruction.ref_count == 0 and !old_instruction.hasSideEffects()) {
2573 ira.instruction_index += 1;
2574 continue;
2575 }
2576
2577 const return_inst = try await (async old_instruction.analyze(&ira) catch unreachable);
2578 assert(return_inst.val != IrVal.Unknown); // at least the type should be known at this point
2579 return_inst.linkToParent(old_instruction);
2580 // Note: if we ever modify the above to handle error.CompileError by continuing analysis,
2581 // then here we want to check if ira.isCompTime() and return early if true
2582
2583 if (return_inst.isNoReturn()) {
2584 try ira.finishBasicBlock(old_code);
2585 continue;
2586 }
2587
2588 ira.instruction_index += 1;
2589 }
2590
2591 if (ira.src_implicit_return_type_list.len == 0) {
2592 ira.irb.code.return_type = &Type.NoReturn.get(comp).base;
2593 return ira.irb.finish();
2594 }
2595
2596 ira.irb.code.return_type = try ira.resolvePeerTypes(expected_type, ira.src_implicit_return_type_list.toSliceConst());
2597 return ira.irb.finish();
2598}
src-self-hosted/libc_installation.zig created+462
......@@ -0,0 +1,462 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const event = std.event;
4const Target = @import("target.zig").Target;
5const c = @import("c.zig");
6
7/// See the render function implementation for documentation of the fields.
8pub const LibCInstallation = struct {
9 include_dir: []const u8,
10 lib_dir: ?[]const u8,
11 static_lib_dir: ?[]const u8,
12 msvc_lib_dir: ?[]const u8,
13 kernel32_lib_dir: ?[]const u8,
14 dynamic_linker_path: ?[]const u8,
15
16 pub const FindError = error{
17 OutOfMemory,
18 FileSystem,
19 UnableToSpawnCCompiler,
20 CCompilerExitCode,
21 CCompilerCrashed,
22 CCompilerCannotFindHeaders,
23 LibCRuntimeNotFound,
24 LibCStdLibHeaderNotFound,
25 LibCKernel32LibNotFound,
26 UnsupportedArchitecture,
27 };
28
29 pub fn parse(
30 self: *LibCInstallation,
31 allocator: *std.mem.Allocator,
32 libc_file: []const u8,
33 stderr: *std.io.OutStream(std.io.FileOutStream.Error),
34 ) !void {
35 self.initEmpty();
36
37 const keys = []const []const u8{
38 "include_dir",
39 "lib_dir",
40 "static_lib_dir",
41 "msvc_lib_dir",
42 "kernel32_lib_dir",
43 "dynamic_linker_path",
44 };
45 const FoundKey = struct {
46 found: bool,
47 allocated: ?[]u8,
48 };
49 var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** keys.len;
50 errdefer {
51 self.initEmpty();
52 for (found_keys) |found_key| {
53 if (found_key.allocated) |s| allocator.free(s);
54 }
55 }
56
57 const contents = try std.io.readFileAlloc(allocator, libc_file);
58 defer allocator.free(contents);
59
60 var it = std.mem.split(contents, "\n");
61 while (it.next()) |line| {
62 if (line.len == 0 or line[0] == '#') continue;
63 var line_it = std.mem.split(line, "=");
64 const name = line_it.next() orelse {
65 try stderr.print("missing equal sign after field name\n");
66 return error.ParseError;
67 };
68 const value = line_it.rest();
69 inline for (keys) |key, i| {
70 if (std.mem.eql(u8, name, key)) {
71 found_keys[i].found = true;
72 switch (@typeInfo(@typeOf(@field(self, key)))) {
73 builtin.TypeId.Optional => {
74 if (value.len == 0) {
75 @field(self, key) = null;
76 } else {
77 found_keys[i].allocated = try std.mem.dupe(allocator, u8, value);
78 @field(self, key) = found_keys[i].allocated;
79 }
80 },
81 else => {
82 if (value.len == 0) {
83 try stderr.print("field cannot be empty: {}\n", key);
84 return error.ParseError;
85 }
86 const dupe = try std.mem.dupe(allocator, u8, value);
87 found_keys[i].allocated = dupe;
88 @field(self, key) = dupe;
89 },
90 }
91 break;
92 }
93 }
94 }
95 for (found_keys) |found_key, i| {
96 if (!found_key.found) {
97 try stderr.print("missing field: {}\n", keys[i]);
98 return error.ParseError;
99 }
100 }
101 }
102
103 pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(std.io.FileOutStream.Error)) !void {
104 @setEvalBranchQuota(4000);
105 try out.print(
106 \\# The directory that contains `stdlib.h`.
107 \\# On Linux, can be found with: `cc -E -Wp,-v -xc /dev/null`
108 \\include_dir={}
109 \\
110 \\# The directory that contains `crt1.o`.
111 \\# On Linux, can be found with `cc -print-file-name=crt1.o`.
112 \\# Not needed when targeting MacOS.
113 \\lib_dir={}
114 \\
115 \\# The directory that contains `crtbegin.o`.
116 \\# On Linux, can be found with `cc -print-file-name=crtbegin.o`.
117 \\# Not needed when targeting MacOS or Windows.
118 \\static_lib_dir={}
119 \\
120 \\# The directory that contains `vcruntime.lib`.
121 \\# Only needed when targeting Windows.
122 \\msvc_lib_dir={}
123 \\
124 \\# The directory that contains `kernel32.lib`.
125 \\# Only needed when targeting Windows.
126 \\kernel32_lib_dir={}
127 \\
128 \\# The full path to the dynamic linker, on the target system.
129 \\# Only needed when targeting Linux.
130 \\dynamic_linker_path={}
131 \\
132 ,
133 self.include_dir,
134 self.lib_dir orelse "",
135 self.static_lib_dir orelse "",
136 self.msvc_lib_dir orelse "",
137 self.kernel32_lib_dir orelse "",
138 self.dynamic_linker_path orelse Target(Target.Native).getDynamicLinkerPath(),
139 );
140 }
141
142 /// Finds the default, native libc.
143 pub async fn findNative(self: *LibCInstallation, loop: *event.Loop) !void {
144 self.initEmpty();
145 var group = event.Group(FindError!void).init(loop);
146 errdefer group.cancelAll();
147 var windows_sdk: ?*c.ZigWindowsSDK = null;
148 errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk));
149
150 switch (builtin.os) {
151 builtin.Os.windows => {
152 var sdk: *c.ZigWindowsSDK = undefined;
153 switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) {
154 c.ZigFindWindowsSdkError.None => {
155 windows_sdk = sdk;
156
157 if (sdk.msvc_lib_dir_ptr) |ptr| {
158 self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]);
159 }
160 try group.call(findNativeKernel32LibDir, self, loop, sdk);
161 try group.call(findNativeIncludeDirWindows, self, loop, sdk);
162 try group.call(findNativeLibDirWindows, self, loop, sdk);
163 },
164 c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory,
165 c.ZigFindWindowsSdkError.NotFound => return error.NotFound,
166 c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound,
167 }
168 },
169 builtin.Os.linux => {
170 try group.call(findNativeIncludeDirLinux, self, loop);
171 try group.call(findNativeLibDirLinux, self, loop);
172 try group.call(findNativeStaticLibDir, self, loop);
173 try group.call(findNativeDynamicLinker, self, loop);
174 },
175 builtin.Os.macosx => {
176 self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
177 },
178 else => @compileError("unimplemented: find libc for this OS"),
179 }
180 return await (async group.wait() catch unreachable);
181 }
182
183 async fn findNativeIncludeDirLinux(self: *LibCInstallation, loop: *event.Loop) !void {
184 const cc_exe = std.os.getEnvPosix("CC") orelse "cc";
185 const argv = []const []const u8{
186 cc_exe,
187 "-E",
188 "-Wp,-v",
189 "-xc",
190 "/dev/null",
191 };
192 // TODO make this use event loop
193 const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
194 const exec_result = if (std.debug.runtime_safety) blk: {
195 break :blk errorable_result catch unreachable;
196 } else blk: {
197 break :blk errorable_result catch |err| switch (err) {
198 error.OutOfMemory => return error.OutOfMemory,
199 else => return error.UnableToSpawnCCompiler,
200 };
201 };
202 defer {
203 loop.allocator.free(exec_result.stdout);
204 loop.allocator.free(exec_result.stderr);
205 }
206
207 switch (exec_result.term) {
208 std.os.ChildProcess.Term.Exited => |code| {
209 if (code != 0) return error.CCompilerExitCode;
210 },
211 else => {
212 return error.CCompilerCrashed;
213 },
214 }
215
216 var it = std.mem.split(exec_result.stderr, "\n\r");
217 var search_paths = std.ArrayList([]const u8).init(loop.allocator);
218 defer search_paths.deinit();
219 while (it.next()) |line| {
220 if (line.len != 0 and line[0] == ' ') {
221 try search_paths.append(line);
222 }
223 }
224 if (search_paths.len == 0) {
225 return error.CCompilerCannotFindHeaders;
226 }
227
228 // search in reverse order
229 var path_i: usize = 0;
230 while (path_i < search_paths.len) : (path_i += 1) {
231 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
232 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
233 const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h");
234 defer loop.allocator.free(stdlib_path);
235
236 if (try fileExists(loop.allocator, stdlib_path)) {
237 self.include_dir = try std.mem.dupe(loop.allocator, u8, search_path);
238 return;
239 }
240 }
241
242 return error.LibCStdLibHeaderNotFound;
243 }
244
245 async fn findNativeIncludeDirWindows(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) !void {
246 var search_buf: [2]Search = undefined;
247 const searches = fillSearch(&search_buf, sdk);
248
249 var result_buf = try std.Buffer.initSize(loop.allocator, 0);
250 defer result_buf.deinit();
251
252 for (searches) |search| {
253 result_buf.shrink(0);
254 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
255 try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);
256
257 const stdlib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "stdlib.h");
258 defer loop.allocator.free(stdlib_path);
259
260 if (try fileExists(loop.allocator, stdlib_path)) {
261 self.include_dir = result_buf.toOwnedSlice();
262 return;
263 }
264 }
265
266 return error.LibCStdLibHeaderNotFound;
267 }
268
269 async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) FindError!void {
270 var search_buf: [2]Search = undefined;
271 const searches = fillSearch(&search_buf, sdk);
272
273 var result_buf = try std.Buffer.initSize(loop.allocator, 0);
274 defer result_buf.deinit();
275
276 for (searches) |search| {
277 result_buf.shrink(0);
278 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
279 try stream.print("{}\\Lib\\{}\\ucrt\\", search.path, search.version);
280 switch (builtin.arch) {
281 builtin.Arch.i386 => try stream.write("x86"),
282 builtin.Arch.x86_64 => try stream.write("x64"),
283 builtin.Arch.aarch64 => try stream.write("arm"),
284 else => return error.UnsupportedArchitecture,
285 }
286 const ucrt_lib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "ucrt.lib");
287 defer loop.allocator.free(ucrt_lib_path);
288 if (try fileExists(loop.allocator, ucrt_lib_path)) {
289 self.lib_dir = result_buf.toOwnedSlice();
290 return;
291 }
292 }
293 return error.LibCRuntimeNotFound;
294 }
295
296 async fn findNativeLibDirLinux(self: *LibCInstallation, loop: *event.Loop) FindError!void {
297 self.lib_dir = try await (async ccPrintFileName(loop, "crt1.o", true) catch unreachable);
298 }
299
300 async fn findNativeStaticLibDir(self: *LibCInstallation, loop: *event.Loop) FindError!void {
301 self.static_lib_dir = try await (async ccPrintFileName(loop, "crtbegin.o", true) catch unreachable);
302 }
303
304 async fn findNativeDynamicLinker(self: *LibCInstallation, loop: *event.Loop) FindError!void {
305 var dyn_tests = []DynTest{
306 DynTest{
307 .name = "ld-linux-x86-64.so.2",
308 .result = null,
309 },
310 DynTest{
311 .name = "ld-musl-x86_64.so.1",
312 .result = null,
313 },
314 };
315 var group = event.Group(FindError!void).init(loop);
316 errdefer group.cancelAll();
317 for (dyn_tests) |*dyn_test| {
318 try group.call(testNativeDynamicLinker, self, loop, dyn_test);
319 }
320 try await (async group.wait() catch unreachable);
321 for (dyn_tests) |*dyn_test| {
322 if (dyn_test.result) |result| {
323 self.dynamic_linker_path = result;
324 return;
325 }
326 }
327 }
328
329 const DynTest = struct {
330 name: []const u8,
331 result: ?[]const u8,
332 };
333
334 async fn testNativeDynamicLinker(self: *LibCInstallation, loop: *event.Loop, dyn_test: *DynTest) FindError!void {
335 if (await (async ccPrintFileName(loop, dyn_test.name, false) catch unreachable)) |result| {
336 dyn_test.result = result;
337 return;
338 } else |err| switch (err) {
339 error.LibCRuntimeNotFound => return,
340 else => return err,
341 }
342 }
343
344
345 async fn findNativeKernel32LibDir(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) FindError!void {
346 var search_buf: [2]Search = undefined;
347 const searches = fillSearch(&search_buf, sdk);
348
349 var result_buf = try std.Buffer.initSize(loop.allocator, 0);
350 defer result_buf.deinit();
351
352 for (searches) |search| {
353 result_buf.shrink(0);
354 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
355 try stream.print("{}\\Lib\\{}\\um\\", search.path, search.version);
356 switch (builtin.arch) {
357 builtin.Arch.i386 => try stream.write("x86\\"),
358 builtin.Arch.x86_64 => try stream.write("x64\\"),
359 builtin.Arch.aarch64 => try stream.write("arm\\"),
360 else => return error.UnsupportedArchitecture,
361 }
362 const kernel32_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "kernel32.lib");
363 defer loop.allocator.free(kernel32_path);
364 if (try fileExists(loop.allocator, kernel32_path)) {
365 self.kernel32_lib_dir = result_buf.toOwnedSlice();
366 return;
367 }
368 }
369 return error.LibCKernel32LibNotFound;
370 }
371
372 fn initEmpty(self: *LibCInstallation) void {
373 self.* = LibCInstallation{
374 .include_dir = ([*]const u8)(undefined)[0..0],
375 .lib_dir = null,
376 .static_lib_dir = null,
377 .msvc_lib_dir = null,
378 .kernel32_lib_dir = null,
379 .dynamic_linker_path = null,
380 };
381 }
382};
383
384/// caller owns returned memory
385async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bool) ![]u8 {
386 const cc_exe = std.os.getEnvPosix("CC") orelse "cc";
387 const arg1 = try std.fmt.allocPrint(loop.allocator, "-print-file-name={}", o_file);
388 defer loop.allocator.free(arg1);
389 const argv = []const []const u8{ cc_exe, arg1 };
390
391 // TODO This simulates evented I/O for the child process exec
392 await (async loop.yield() catch unreachable);
393 const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
394 const exec_result = if (std.debug.runtime_safety) blk: {
395 break :blk errorable_result catch unreachable;
396 } else blk: {
397 break :blk errorable_result catch |err| switch (err) {
398 error.OutOfMemory => return error.OutOfMemory,
399 else => return error.UnableToSpawnCCompiler,
400 };
401 };
402 defer {
403 loop.allocator.free(exec_result.stdout);
404 loop.allocator.free(exec_result.stderr);
405 }
406 switch (exec_result.term) {
407 std.os.ChildProcess.Term.Exited => |code| {
408 if (code != 0) return error.CCompilerExitCode;
409 },
410 else => {
411 return error.CCompilerCrashed;
412 },
413 }
414 var it = std.mem.split(exec_result.stdout, "\n\r");
415 const line = it.next() orelse return error.LibCRuntimeNotFound;
416 const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;
417
418 if (want_dirname) {
419 return std.mem.dupe(loop.allocator, u8, dirname);
420 } else {
421 return std.mem.dupe(loop.allocator, u8, line);
422 }
423}
424
425const Search = struct {
426 path: []const u8,
427 version: []const u8,
428};
429
430fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
431 var search_end: usize = 0;
432 if (sdk.path10_ptr) |path10_ptr| {
433 if (sdk.version10_ptr) |ver10_ptr| {
434 search_buf[search_end] = Search{
435 .path = path10_ptr[0..sdk.path10_len],
436 .version = ver10_ptr[0..sdk.version10_len],
437 };
438 search_end += 1;
439 }
440 }
441 if (sdk.path81_ptr) |path81_ptr| {
442 if (sdk.version81_ptr) |ver81_ptr| {
443 search_buf[search_end] = Search{
444 .path = path81_ptr[0..sdk.path81_len],
445 .version = ver81_ptr[0..sdk.version81_len],
446 };
447 search_end += 1;
448 }
449 }
450 return search_buf[0..search_end];
451}
452
453
454fn fileExists(allocator: *std.mem.Allocator, path: []const u8) !bool {
455 if (std.os.File.access(allocator, path)) |_| {
456 return true;
457 } else |err| switch (err) {
458 error.NotFound, error.PermissionDenied => return false,
459 error.OutOfMemory => return error.OutOfMemory,
460 else => return error.FileSystem,
461 }
462}
src-self-hosted/link.zig created+737
......@@ -0,0 +1,737 @@
1const std = @import("std");
2const mem = std.mem;
3const c = @import("c.zig");
4const builtin = @import("builtin");
5const ObjectFormat = builtin.ObjectFormat;
6const Compilation = @import("compilation.zig").Compilation;
7const Target = @import("target.zig").Target;
8const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
9const assert = std.debug.assert;
10
11const Context = struct {
12 comp: *Compilation,
13 arena: std.heap.ArenaAllocator,
14 args: std.ArrayList([*]const u8),
15 link_in_crt: bool,
16
17 link_err: error{OutOfMemory}!void,
18 link_msg: std.Buffer,
19
20 libc: *LibCInstallation,
21 out_file_path: std.Buffer,
22};
23
24pub async fn link(comp: *Compilation) !void {
25 var ctx = Context{
26 .comp = comp,
27 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
28 .args = undefined,
29 .link_in_crt = comp.haveLibC() and comp.kind == Compilation.Kind.Exe,
30 .link_err = {},
31 .link_msg = undefined,
32 .libc = undefined,
33 .out_file_path = undefined,
34 };
35 defer ctx.arena.deinit();
36 ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator);
37 ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);
38
39 if (comp.link_out_file) |out_file| {
40 ctx.out_file_path = try std.Buffer.init(&ctx.arena.allocator, out_file);
41 } else {
42 ctx.out_file_path = try std.Buffer.init(&ctx.arena.allocator, comp.name.toSliceConst());
43 switch (comp.kind) {
44 Compilation.Kind.Exe => {
45 try ctx.out_file_path.append(comp.target.exeFileExt());
46 },
47 Compilation.Kind.Lib => {
48 try ctx.out_file_path.append(comp.target.libFileExt(comp.is_static));
49 },
50 Compilation.Kind.Obj => {
51 try ctx.out_file_path.append(comp.target.objFileExt());
52 },
53 }
54 }
55
56 // even though we're calling LLD as a library it thinks the first
57 // argument is its own exe name
58 try ctx.args.append(c"lld");
59
60 if (comp.haveLibC()) {
61 ctx.libc = ctx.comp.override_libc orelse blk: {
62 switch (comp.target) {
63 Target.Native => {
64 break :blk (await (async comp.event_loop_local.getNativeLibC() catch unreachable)) catch return error.LibCRequiredButNotProvidedOrFound;
65 },
66 else => return error.LibCRequiredButNotProvidedOrFound,
67 }
68 };
69 }
70
71 try constructLinkerArgs(&ctx);
72
73 if (comp.verbose_link) {
74 for (ctx.args.toSliceConst()) |arg, i| {
75 const space = if (i == 0) "" else " ";
76 std.debug.warn("{}{s}", space, arg);
77 }
78 std.debug.warn("\n");
79 }
80
81 const extern_ofmt = toExternObjectFormatType(comp.target.getObjectFormat());
82 const args_slice = ctx.args.toSlice();
83
84 {
85 // LLD is not thread-safe, so we grab a global lock.
86 const held = await (async comp.event_loop_local.lld_lock.acquire() catch unreachable);
87 defer held.release();
88
89 // Not evented I/O. LLD does its own multithreading internally.
90 if (!ZigLLDLink(extern_ofmt, args_slice.ptr, args_slice.len, linkDiagCallback, @ptrCast(*c_void, &ctx))) {
91 if (!ctx.link_msg.isNull()) {
92 // TODO capture these messages and pass them through the system, reporting them through the
93 // event system instead of printing them directly here.
94 // perhaps try to parse and understand them.
95 std.debug.warn("{}\n", ctx.link_msg.toSliceConst());
96 }
97 return error.LinkFailed;
98 }
99 }
100}
101
102extern fn ZigLLDLink(
103 oformat: c.ZigLLVM_ObjectFormatType,
104 args: [*]const [*]const u8,
105 arg_count: usize,
106 append_diagnostic: extern fn (*c_void, [*]const u8, usize) void,
107 context: *c_void,
108) bool;
109
110extern fn linkDiagCallback(context: *c_void, ptr: [*]const u8, len: usize) void {
111 const ctx = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
112 ctx.link_err = linkDiagCallbackErrorable(ctx, ptr[0..len]);
113}
114
115fn linkDiagCallbackErrorable(ctx: *Context, msg: []const u8) !void {
116 if (ctx.link_msg.isNull()) {
117 try ctx.link_msg.resize(0);
118 }
119 try ctx.link_msg.append(msg);
120}
121
122fn toExternObjectFormatType(ofmt: ObjectFormat) c.ZigLLVM_ObjectFormatType {
123 return switch (ofmt) {
124 ObjectFormat.unknown => c.ZigLLVM_UnknownObjectFormat,
125 ObjectFormat.coff => c.ZigLLVM_COFF,
126 ObjectFormat.elf => c.ZigLLVM_ELF,
127 ObjectFormat.macho => c.ZigLLVM_MachO,
128 ObjectFormat.wasm => c.ZigLLVM_Wasm,
129 };
130}
131
132fn constructLinkerArgs(ctx: *Context) !void {
133 switch (ctx.comp.target.getObjectFormat()) {
134 ObjectFormat.unknown => unreachable,
135 ObjectFormat.coff => return constructLinkerArgsCoff(ctx),
136 ObjectFormat.elf => return constructLinkerArgsElf(ctx),
137 ObjectFormat.macho => return constructLinkerArgsMachO(ctx),
138 ObjectFormat.wasm => return constructLinkerArgsWasm(ctx),
139 }
140}
141
142fn constructLinkerArgsElf(ctx: *Context) !void {
143 // TODO commented out code in this function
144 //if (g->linker_script) {
145 // lj->args.append("-T");
146 // lj->args.append(g->linker_script);
147 //}
148
149 //if (g->no_rosegment_workaround) {
150 // lj->args.append("--no-rosegment");
151 //}
152 try ctx.args.append(c"--gc-sections");
153
154 //lj->args.append("-m");
155 //lj->args.append(getLDMOption(&g->zig_target));
156
157 //bool is_lib = g->out_type == OutTypeLib;
158 //bool shared = !g->is_static && is_lib;
159 //Buf *soname = nullptr;
160 if (ctx.comp.is_static) {
161 if (ctx.comp.target.isArmOrThumb()) {
162 try ctx.args.append(c"-Bstatic");
163 } else {
164 try ctx.args.append(c"-static");
165 }
166 }
167 //} else if (shared) {
168 // lj->args.append("-shared");
169
170 // if (buf_len(&lj->out_file) == 0) {
171 // buf_appendf(&lj->out_file, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
172 // buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
173 // }
174 // soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
175 //}
176
177 try ctx.args.append(c"-o");
178 try ctx.args.append(ctx.out_file_path.ptr());
179
180 if (ctx.link_in_crt) {
181 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
182 const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o";
183 try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o);
184 try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o");
185 try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino);
186 }
187
188 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {
189 // Buf *rpath = g->rpath_list.at(i);
190 // add_rpath(lj, rpath);
191 //}
192 //if (g->each_lib_rpath) {
193 // for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
194 // const char *lib_dir = g->lib_dirs.at(i);
195 // for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
196 // LinkLib *link_lib = g->link_libs_list.at(i);
197 // if (buf_eql_str(link_lib->name, "c")) {
198 // continue;
199 // }
200 // bool does_exist;
201 // Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name));
202 // if (os_file_exists(test_path, &does_exist) != ErrorNone) {
203 // zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));
204 // }
205 // if (does_exist) {
206 // add_rpath(lj, buf_create_from_str(lib_dir));
207 // break;
208 // }
209 // }
210 // }
211 //}
212
213 //for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
214 // const char *lib_dir = g->lib_dirs.at(i);
215 // lj->args.append("-L");
216 // lj->args.append(lib_dir);
217 //}
218
219 if (ctx.comp.haveLibC()) {
220 try ctx.args.append(c"-L");
221 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr);
222
223 try ctx.args.append(c"-L");
224 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr);
225
226 if (!ctx.comp.is_static) {
227 const dl = blk: {
228 if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;
229 if (ctx.comp.target.getDynamicLinkerPath()) |dl| break :blk dl;
230 return error.LibCMissingDynamicLinker;
231 };
232 try ctx.args.append(c"-dynamic-linker");
233 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr);
234 }
235 }
236
237 //if (shared) {
238 // lj->args.append("-soname");
239 // lj->args.append(buf_ptr(soname));
240 //}
241
242 // .o files
243 for (ctx.comp.link_objects) |link_object| {
244 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
245 try ctx.args.append(link_obj_with_null.ptr);
246 }
247 try addFnObjects(ctx);
248
249 //if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
250 // if (g->libc_link_lib == nullptr) {
251 // Buf *builtin_o_path = build_o(g, "builtin");
252 // lj->args.append(buf_ptr(builtin_o_path));
253 // }
254
255 // // sometimes libgcc is missing stuff, so we still build compiler_rt and rely on weak linkage
256 // Buf *compiler_rt_o_path = build_compiler_rt(g);
257 // lj->args.append(buf_ptr(compiler_rt_o_path));
258 //}
259
260 //for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
261 // LinkLib *link_lib = g->link_libs_list.at(i);
262 // if (buf_eql_str(link_lib->name, "c")) {
263 // continue;
264 // }
265 // Buf *arg;
266 // if (buf_starts_with_str(link_lib->name, "/") || buf_ends_with_str(link_lib->name, ".a") ||
267 // buf_ends_with_str(link_lib->name, ".so"))
268 // {
269 // arg = link_lib->name;
270 // } else {
271 // arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
272 // }
273 // lj->args.append(buf_ptr(arg));
274 //}
275
276 // libc dep
277 if (ctx.comp.haveLibC()) {
278 if (ctx.comp.is_static) {
279 try ctx.args.append(c"--start-group");
280 try ctx.args.append(c"-lgcc");
281 try ctx.args.append(c"-lgcc_eh");
282 try ctx.args.append(c"-lc");
283 try ctx.args.append(c"-lm");
284 try ctx.args.append(c"--end-group");
285 } else {
286 try ctx.args.append(c"-lgcc");
287 try ctx.args.append(c"--as-needed");
288 try ctx.args.append(c"-lgcc_s");
289 try ctx.args.append(c"--no-as-needed");
290 try ctx.args.append(c"-lc");
291 try ctx.args.append(c"-lm");
292 try ctx.args.append(c"-lgcc");
293 try ctx.args.append(c"--as-needed");
294 try ctx.args.append(c"-lgcc_s");
295 try ctx.args.append(c"--no-as-needed");
296 }
297 }
298
299 // crt end
300 if (ctx.link_in_crt) {
301 try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o");
302 try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o");
303 }
304
305 if (ctx.comp.target != Target.Native) {
306 try ctx.args.append(c"--allow-shlib-undefined");
307 }
308
309 if (ctx.comp.target.getOs() == builtin.Os.zen) {
310 try ctx.args.append(c"-e");
311 try ctx.args.append(c"_start");
312
313 try ctx.args.append(c"--image-base=0x10000000");
314 }
315}
316
317fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
318 const full_path = try std.os.path.join(&ctx.arena.allocator, dirname, basename);
319 const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
320 try ctx.args.append(full_path_with_null.ptr);
321}
322
323fn constructLinkerArgsCoff(ctx: *Context) !void {
324 try ctx.args.append(c"-NOLOGO");
325
326 if (!ctx.comp.strip) {
327 try ctx.args.append(c"-DEBUG");
328 }
329
330 switch (ctx.comp.target.getArch()) {
331 builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"),
332 builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"),
333 builtin.Arch.aarch64 => try ctx.args.append(c"-MACHINE:ARM"),
334 else => return error.UnsupportedLinkArchitecture,
335 }
336
337 if (ctx.comp.windows_subsystem_windows) {
338 try ctx.args.append(c"/SUBSYSTEM:windows");
339 } else if (ctx.comp.windows_subsystem_console) {
340 try ctx.args.append(c"/SUBSYSTEM:console");
341 }
342
343 const is_library = ctx.comp.kind == Compilation.Kind.Lib;
344
345 const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst());
346 try ctx.args.append(out_arg.ptr);
347
348 if (ctx.comp.haveLibC()) {
349 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr);
350 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr);
351 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr);
352 }
353
354 if (ctx.link_in_crt) {
355 const lib_str = if (ctx.comp.is_static) "lib" else "";
356 const d_str = if (ctx.comp.build_mode == builtin.Mode.Debug) "d" else "";
357
358 if (ctx.comp.is_static) {
359 const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str);
360 try ctx.args.append(cmt_lib_name.ptr);
361 } else {
362 const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str);
363 try ctx.args.append(msvcrt_lib_name.ptr);
364 }
365
366 const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str);
367 try ctx.args.append(vcruntime_lib_name.ptr);
368
369 const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str);
370 try ctx.args.append(crt_lib_name.ptr);
371
372 // Visual C++ 2015 Conformance Changes
373 // https://msdn.microsoft.com/en-us/library/bb531344.aspx
374 try ctx.args.append(c"legacy_stdio_definitions.lib");
375
376 // msvcrt depends on kernel32
377 try ctx.args.append(c"kernel32.lib");
378 } else {
379 try ctx.args.append(c"-NODEFAULTLIB");
380 if (!is_library) {
381 try ctx.args.append(c"-ENTRY:WinMainCRTStartup");
382 // TODO
383 //if (g->have_winmain) {
384 // lj->args.append("-ENTRY:WinMain");
385 //} else {
386 // lj->args.append("-ENTRY:WinMainCRTStartup");
387 //}
388 }
389 }
390
391 if (is_library and !ctx.comp.is_static) {
392 try ctx.args.append(c"-DLL");
393 }
394
395 //for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
396 // const char *lib_dir = g->lib_dirs.at(i);
397 // lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
398 //}
399
400 for (ctx.comp.link_objects) |link_object| {
401 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
402 try ctx.args.append(link_obj_with_null.ptr);
403 }
404 try addFnObjects(ctx);
405
406 switch (ctx.comp.kind) {
407 Compilation.Kind.Exe, Compilation.Kind.Lib => {
408 if (!ctx.comp.haveLibC()) {
409 @panic("TODO");
410 //Buf *builtin_o_path = build_o(g, "builtin");
411 //lj->args.append(buf_ptr(builtin_o_path));
412 }
413
414 // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
415 // TODO
416 //Buf *compiler_rt_o_path = build_compiler_rt(g);
417 //lj->args.append(buf_ptr(compiler_rt_o_path));
418 },
419 Compilation.Kind.Obj => {},
420 }
421
422 //Buf *def_contents = buf_alloc();
423 //ZigList<const char *> gen_lib_args = {0};
424 //for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
425 // LinkLib *link_lib = g->link_libs_list.at(lib_i);
426 // if (buf_eql_str(link_lib->name, "c")) {
427 // continue;
428 // }
429 // if (link_lib->provided_explicitly) {
430 // if (lj->codegen->zig_target.env_type == ZigLLVM_GNU) {
431 // Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
432 // lj->args.append(buf_ptr(arg));
433 // }
434 // else {
435 // lj->args.append(buf_ptr(link_lib->name));
436 // }
437 // } else {
438 // buf_resize(def_contents, 0);
439 // buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
440 // for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
441 // Buf *symbol_name = link_lib->symbols.at(exp_i);
442 // buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
443 // }
444 // buf_appendf(def_contents, "\n");
445
446 // Buf *def_path = buf_alloc();
447 // os_path_join(g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
448 // os_write_file(def_path, def_contents);
449
450 // Buf *generated_lib_path = buf_alloc();
451 // os_path_join(g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
452
453 // gen_lib_args.resize(0);
454 // gen_lib_args.append("link");
455
456 // coff_append_machine_arg(g, &gen_lib_args);
457 // gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
458 // gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
459 // Buf diag = BUF_INIT;
460 // if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
461 // fprintf(stderr, "%s\n", buf_ptr(&diag));
462 // exit(1);
463 // }
464 // lj->args.append(buf_ptr(generated_lib_path));
465 // }
466 //}
467}
468
469fn constructLinkerArgsMachO(ctx: *Context) !void {
470 try ctx.args.append(c"-demangle");
471
472 if (ctx.comp.linker_rdynamic) {
473 try ctx.args.append(c"-export_dynamic");
474 }
475
476 const is_lib = ctx.comp.kind == Compilation.Kind.Lib;
477 const shared = !ctx.comp.is_static and is_lib;
478 if (ctx.comp.is_static) {
479 try ctx.args.append(c"-static");
480 } else {
481 try ctx.args.append(c"-dynamic");
482 }
483
484 //if (is_lib) {
485 // if (!g->is_static) {
486 // lj->args.append("-dylib");
487
488 // Buf *compat_vers = buf_sprintf("%" ZIG_PRI_usize ".0.0", g->version_major);
489 // lj->args.append("-compatibility_version");
490 // lj->args.append(buf_ptr(compat_vers));
491
492 // Buf *cur_vers = buf_sprintf("%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
493 // g->version_major, g->version_minor, g->version_patch);
494 // lj->args.append("-current_version");
495 // lj->args.append(buf_ptr(cur_vers));
496
497 // // TODO getting an error when running an executable when doing this rpath thing
498 // //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
499 // // buf_ptr(g->root_out_name), g->version_major);
500 // //lj->args.append("-install_name");
501 // //lj->args.append(buf_ptr(dylib_install_name));
502
503 // if (buf_len(&lj->out_file) == 0) {
504 // buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
505 // buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
506 // }
507 // }
508 //}
509
510 try ctx.args.append(c"-arch");
511 const darwin_arch_str = try std.cstr.addNullByte(
512 &ctx.arena.allocator,
513 ctx.comp.target.getDarwinArchString(),
514 );
515 try ctx.args.append(darwin_arch_str.ptr);
516
517 const platform = try DarwinPlatform.get(ctx.comp);
518 switch (platform.kind) {
519 DarwinPlatform.Kind.MacOS => try ctx.args.append(c"-macosx_version_min"),
520 DarwinPlatform.Kind.IPhoneOS => try ctx.args.append(c"-iphoneos_version_min"),
521 DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append(c"-ios_simulator_version_min"),
522 }
523 const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro);
524 try ctx.args.append(ver_str.ptr);
525
526 if (ctx.comp.kind == Compilation.Kind.Exe) {
527 if (ctx.comp.is_static) {
528 try ctx.args.append(c"-no_pie");
529 } else {
530 try ctx.args.append(c"-pie");
531 }
532 }
533
534 try ctx.args.append(c"-o");
535 try ctx.args.append(ctx.out_file_path.ptr());
536
537 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {
538 // Buf *rpath = g->rpath_list.at(i);
539 // add_rpath(lj, rpath);
540 //}
541 //add_rpath(lj, &lj->out_file);
542
543 if (shared) {
544 try ctx.args.append(c"-headerpad_max_install_names");
545 } else if (ctx.comp.is_static) {
546 try ctx.args.append(c"-lcrt0.o");
547 } else {
548 switch (platform.kind) {
549 DarwinPlatform.Kind.MacOS => {
550 if (platform.versionLessThan(10, 5)) {
551 try ctx.args.append(c"-lcrt1.o");
552 } else if (platform.versionLessThan(10, 6)) {
553 try ctx.args.append(c"-lcrt1.10.5.o");
554 } else if (platform.versionLessThan(10, 8)) {
555 try ctx.args.append(c"-lcrt1.10.6.o");
556 }
557 },
558 DarwinPlatform.Kind.IPhoneOS => {
559 if (ctx.comp.target.getArch() == builtin.Arch.aarch64) {
560 // iOS does not need any crt1 files for arm64
561 } else if (platform.versionLessThan(3, 1)) {
562 try ctx.args.append(c"-lcrt1.o");
563 } else if (platform.versionLessThan(6, 0)) {
564 try ctx.args.append(c"-lcrt1.3.1.o");
565 }
566 },
567 DarwinPlatform.Kind.IPhoneOSSimulator => {}, // no crt1.o needed
568 }
569 }
570
571 //for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
572 // const char *lib_dir = g->lib_dirs.at(i);
573 // lj->args.append("-L");
574 // lj->args.append(lib_dir);
575 //}
576
577 for (ctx.comp.link_objects) |link_object| {
578 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
579 try ctx.args.append(link_obj_with_null.ptr);
580 }
581 try addFnObjects(ctx);
582
583 //// compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
584 //if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
585 // Buf *compiler_rt_o_path = build_compiler_rt(g);
586 // lj->args.append(buf_ptr(compiler_rt_o_path));
587 //}
588
589 if (ctx.comp.target == Target.Native) {
590 for (ctx.comp.link_libs_list.toSliceConst()) |lib| {
591 if (mem.eql(u8, lib.name, "c")) {
592 // on Darwin, libSystem has libc in it, but also you have to use it
593 // to make syscalls because the syscall numbers are not documented
594 // and change between versions.
595 // so we always link against libSystem
596 try ctx.args.append(c"-lSystem");
597 } else {
598 if (mem.indexOfScalar(u8, lib.name, '/') == null) {
599 const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name);
600 try ctx.args.append(arg.ptr);
601 } else {
602 const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
603 try ctx.args.append(arg.ptr);
604 }
605 }
606 }
607 } else {
608 try ctx.args.append(c"-undefined");
609 try ctx.args.append(c"dynamic_lookup");
610 }
611
612 if (platform.kind == DarwinPlatform.Kind.MacOS) {
613 if (platform.versionLessThan(10, 5)) {
614 try ctx.args.append(c"-lgcc_s.10.4");
615 } else if (platform.versionLessThan(10, 6)) {
616 try ctx.args.append(c"-lgcc_s.10.5");
617 }
618 } else {
619 @panic("TODO");
620 }
621
622 //for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) {
623 // lj->args.append("-framework");
624 // lj->args.append(buf_ptr(g->darwin_frameworks.at(i)));
625 //}
626}
627
628fn constructLinkerArgsWasm(ctx: *Context) void {
629 @panic("TODO");
630}
631
632fn addFnObjects(ctx: *Context) !void {
633 // at this point it's guaranteed nobody else has this lock, so we circumvent it
634 // and avoid having to be a coroutine
635 const fn_link_set = &ctx.comp.fn_link_set.private_data;
636
637 var it = fn_link_set.first;
638 while (it) |node| {
639 const fn_val = node.data orelse {
640 // handle the tombstone. See Value.Fn.destroy.
641 it = node.next;
642 fn_link_set.remove(node);
643 ctx.comp.gpa().destroy(node);
644 continue;
645 };
646 try ctx.args.append(fn_val.containing_object.ptr());
647 it = node.next;
648 }
649}
650
651const DarwinPlatform = struct {
652 kind: Kind,
653 major: u32,
654 minor: u32,
655 micro: u32,
656
657 const Kind = enum {
658 MacOS,
659 IPhoneOS,
660 IPhoneOSSimulator,
661 };
662
663 fn get(comp: *Compilation) !DarwinPlatform {
664 var result: DarwinPlatform = undefined;
665 const ver_str = switch (comp.darwin_version_min) {
666 Compilation.DarwinVersionMin.MacOS => |ver| blk: {
667 result.kind = Kind.MacOS;
668 break :blk ver;
669 },
670 Compilation.DarwinVersionMin.Ios => |ver| blk: {
671 result.kind = Kind.IPhoneOS;
672 break :blk ver;
673 },
674 Compilation.DarwinVersionMin.None => blk: {
675 assert(comp.target.getOs() == builtin.Os.macosx);
676 result.kind = Kind.MacOS;
677 break :blk "10.10";
678 },
679 };
680
681 var had_extra: bool = undefined;
682 try darwinGetReleaseVersion(
683 ver_str,
684 &result.major,
685 &result.minor,
686 &result.micro,
687 &had_extra,
688 );
689 if (had_extra or result.major != 10 or result.minor >= 100 or result.micro >= 100) {
690 return error.InvalidDarwinVersionString;
691 }
692
693 if (result.kind == Kind.IPhoneOS) {
694 switch (comp.target.getArch()) {
695 builtin.Arch.i386,
696 builtin.Arch.x86_64,
697 => result.kind = Kind.IPhoneOSSimulator,
698 else => {},
699 }
700 }
701 return result;
702 }
703
704 fn versionLessThan(self: DarwinPlatform, major: u32, minor: u32) bool {
705 if (self.major < major)
706 return true;
707 if (self.major > major)
708 return false;
709 if (self.minor < minor)
710 return true;
711 return false;
712 }
713};
714
715/// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
716/// grouped values as integers. Numbers which are not provided are set to 0.
717/// return true if the entire string was parsed (9.2), or all groups were
718/// parsed (10.3.5extrastuff).
719fn darwinGetReleaseVersion(str: []const u8, major: *u32, minor: *u32, micro: *u32, had_extra: *bool) !void {
720 major.* = 0;
721 minor.* = 0;
722 micro.* = 0;
723 had_extra.* = false;
724
725 if (str.len == 0)
726 return error.InvalidDarwinVersionString;
727
728 var start_pos: usize = 0;
729 for ([]*u32{ major, minor, micro }) |v| {
730 const dot_pos = mem.indexOfScalarPos(u8, str, start_pos, '.');
731 const end_pos = dot_pos orelse str.len;
732 v.* = std.fmt.parseUnsigned(u32, str[start_pos..end_pos], 10) catch return error.InvalidDarwinVersionString;
733 start_pos = (dot_pos orelse return) + 1;
734 if (start_pos == str.len) return;
735 }
736 had_extra.* = true;
737}
src-self-hosted/llvm.zig+205-4
......@@ -2,12 +2,213 @@ const builtin = @import("builtin");
22const c = @import("c.zig");
33const assert = @import("std").debug.assert;
44
5pub const ValueRef = removeNullability(c.LLVMValueRef);
6pub const ModuleRef = removeNullability(c.LLVMModuleRef);
7pub const ContextRef = removeNullability(c.LLVMContextRef);
5// we wrap the c module for 3 reasons:
6// 1. to avoid accidentally calling the non-thread-safe functions
7// 2. patch up some of the types to remove nullability
8// 3. some functions have been augmented by zig_llvm.cpp to be more powerful,
9// such as ZigLLVMTargetMachineEmitToFile
10
11pub const AttributeIndex = c_uint;
12pub const Bool = c_int;
13
814pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
15pub const ContextRef = removeNullability(c.LLVMContextRef);
16pub const ModuleRef = removeNullability(c.LLVMModuleRef);
17pub const ValueRef = removeNullability(c.LLVMValueRef);
18pub const TypeRef = removeNullability(c.LLVMTypeRef);
19pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
20pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
21pub const TargetRef = removeNullability(c.LLVMTargetRef);
22pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
23pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
24pub const DIBuilder = c.ZigLLVMDIBuilder;
25
26pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
27pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
28pub const AddFunction = c.LLVMAddFunction;
29pub const AddGlobal = c.LLVMAddGlobal;
30pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
31pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
32pub const ArrayType = c.LLVMArrayType;
33pub const BuildLoad = c.LLVMBuildLoad;
34pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
35pub const ConstAllOnes = c.LLVMConstAllOnes;
36pub const ConstArray = c.LLVMConstArray;
37pub const ConstBitCast = c.LLVMConstBitCast;
38pub const ConstInt = c.LLVMConstInt;
39pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
40pub const ConstNeg = c.LLVMConstNeg;
41pub const ConstNull = c.LLVMConstNull;
42pub const ConstStringInContext = c.LLVMConstStringInContext;
43pub const ConstStructInContext = c.LLVMConstStructInContext;
44pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
45pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
46pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
47pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
48pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
49pub const CreateFile = c.ZigLLVMCreateFile;
50pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
51pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
52pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
53pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
54pub const DisposeBuilder = c.LLVMDisposeBuilder;
55pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
56pub const DisposeMessage = c.LLVMDisposeMessage;
57pub const DisposeModule = c.LLVMDisposeModule;
58pub const DisposeTargetData = c.LLVMDisposeTargetData;
59pub const DisposeTargetMachine = c.LLVMDisposeTargetMachine;
60pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext;
61pub const DumpModule = c.LLVMDumpModule;
62pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
63pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
64pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
65pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
66pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
67pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
68pub const GetUndef = c.LLVMGetUndef;
69pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
70pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
71pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
72pub const InitializeAllTargetInfos = c.LLVMInitializeAllTargetInfos;
73pub const InitializeAllTargetMCs = c.LLVMInitializeAllTargetMCs;
74pub const InitializeAllTargets = c.LLVMInitializeAllTargets;
75pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext;
76pub const Int128TypeInContext = c.LLVMInt128TypeInContext;
77pub const Int16TypeInContext = c.LLVMInt16TypeInContext;
78pub const Int1TypeInContext = c.LLVMInt1TypeInContext;
79pub const Int32TypeInContext = c.LLVMInt32TypeInContext;
80pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
81pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
82pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
83pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
84pub const IntTypeInContext = c.LLVMIntTypeInContext;
85pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
86pub const MDNodeInContext = c.LLVMMDNodeInContext;
87pub const MDStringInContext = c.LLVMMDStringInContext;
88pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
89pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
90pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
91pub const PointerType = c.LLVMPointerType;
92pub const SetAlignment = c.LLVMSetAlignment;
93pub const SetDataLayout = c.LLVMSetDataLayout;
94pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
95pub const SetInitializer = c.LLVMSetInitializer;
96pub const SetLinkage = c.LLVMSetLinkage;
97pub const SetTarget = c.LLVMSetTarget;
98pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
99pub const SetVolatile = c.LLVMSetVolatile;
100pub const StructTypeInContext = c.LLVMStructTypeInContext;
101pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
102pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
103pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
104pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
105
106pub const GetElementType = LLVMGetElementType;
107extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
108
109pub const TypeOf = LLVMTypeOf;
110extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
111
112pub const BuildStore = LLVMBuildStore;
113extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef;
114
115pub const BuildAlloca = LLVMBuildAlloca;
116extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef;
117
118pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
119pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
120
121pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
122extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
123
124pub const VerifyModule = LLVMVerifyModule;
125extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
126
127pub const GetInsertBlock = LLVMGetInsertBlock;
128extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
129
130pub const FunctionType = LLVMFunctionType;
131extern fn LLVMFunctionType(
132 ReturnType: TypeRef,
133 ParamTypes: [*]TypeRef,
134 ParamCount: c_uint,
135 IsVarArg: Bool,
136) ?TypeRef;
137
138pub const GetParam = LLVMGetParam;
139extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef;
140
141pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
142extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef;
143
144pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
145extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
146
147pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
148pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
149pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction;
150pub const VerifierFailureAction = c.LLVMVerifierFailureAction;
151
152pub const CodeGenLevelNone = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelNone;
153pub const CodeGenLevelLess = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelLess;
154pub const CodeGenLevelDefault = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault;
155pub const CodeGenLevelAggressive = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelAggressive;
156pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel;
157
158pub const RelocDefault = c.LLVMRelocMode.LLVMRelocDefault;
159pub const RelocStatic = c.LLVMRelocMode.LLVMRelocStatic;
160pub const RelocPIC = c.LLVMRelocMode.LLVMRelocPIC;
161pub const RelocDynamicNoPic = c.LLVMRelocMode.LLVMRelocDynamicNoPic;
162pub const RelocMode = c.LLVMRelocMode;
163
164pub const CodeModelDefault = c.LLVMCodeModel.LLVMCodeModelDefault;
165pub const CodeModelJITDefault = c.LLVMCodeModel.LLVMCodeModelJITDefault;
166pub const CodeModelSmall = c.LLVMCodeModel.LLVMCodeModelSmall;
167pub const CodeModelKernel = c.LLVMCodeModel.LLVMCodeModelKernel;
168pub const CodeModelMedium = c.LLVMCodeModel.LLVMCodeModelMedium;
169pub const CodeModelLarge = c.LLVMCodeModel.LLVMCodeModelLarge;
170pub const CodeModel = c.LLVMCodeModel;
171
172pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly;
173pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
174pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
175pub const EmitOutputType = c.ZigLLVM_EmitOutputType;
176
177pub const CCallConv = c.LLVMCCallConv;
178pub const FastCallConv = c.LLVMFastCallConv;
179pub const ColdCallConv = c.LLVMColdCallConv;
180pub const WebKitJSCallConv = c.LLVMWebKitJSCallConv;
181pub const AnyRegCallConv = c.LLVMAnyRegCallConv;
182pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv;
183pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv;
184pub const CallConv = c.LLVMCallConv;
185
186pub const FnInline = extern enum {
187 Auto,
188 Always,
189 Never,
190};
9191
10192fn removeNullability(comptime T: type) type {
11 comptime assert(@typeId(T) == builtin.TypeId.Nullable);
193 comptime assert(@typeId(T) == builtin.TypeId.Optional);
12194 return T.Child;
13195}
196
197pub const BuildRet = LLVMBuildRet;
198extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
199
200pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
201extern fn ZigLLVMTargetMachineEmitToFile(
202 targ_machine_ref: TargetMachineRef,
203 module_ref: ModuleRef,
204 filename: [*]const u8,
205 output_type: EmitOutputType,
206 error_message: *[*]u8,
207 is_debug: bool,
208 is_small: bool,
209) bool;
210
211pub const BuildCall = ZigLLVMBuildCall;
212extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
213
214pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
src-self-hosted/main.zig+473-579
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const builtin = @import("builtin");
33
4const event = std.event;
45const os = std.os;
56const io = std.io;
67const mem = std.mem;
......@@ -13,247 +14,118 @@ const c = @import("c.zig");
1314const introspect = @import("introspect.zig");
1415const Args = arg.Args;
1516const Flag = arg.Flag;
16const Module = @import("module.zig").Module;
17const EventLoopLocal = @import("compilation.zig").EventLoopLocal;
18const Compilation = @import("compilation.zig").Compilation;
1719const Target = @import("target.zig").Target;
20const errmsg = @import("errmsg.zig");
21const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
1822
19var stderr: &io.OutStream(io.FileOutStream.Error) = undefined;
20var stdout: &io.OutStream(io.FileOutStream.Error) = undefined;
23var stderr_file: os.File = undefined;
24var stderr: *io.OutStream(io.FileOutStream.Error) = undefined;
25var stdout: *io.OutStream(io.FileOutStream.Error) = undefined;
2126
2227const usage =
2328 \\usage: zig [command] [options]
2429 \\
2530 \\Commands:
2631 \\
27 \\ build Build project from build.zig
28 \\ build-exe [source] Create executable from source or object files
29 \\ build-lib [source] Create library from source or object files
30 \\ build-obj [source] Create object from source or assembly
31 \\ fmt [source] Parse file and render in canonical zig format
32 \\ run [source] Create executable and run immediately
33 \\ targets List available compilation targets
34 \\ test [source] Create and run a test build
35 \\ translate-c [source] Convert c code to zig code
36 \\ version Print version number and exit
37 \\ zen Print zen of zig and exit
32 \\ build-exe [source] Create executable from source or object files
33 \\ build-lib [source] Create library from source or object files
34 \\ build-obj [source] Create object from source or assembly
35 \\ fmt [source] Parse file and render in canonical zig format
36 \\ libc [paths_file] Display native libc paths file or validate one
37 \\ targets List available compilation targets
38 \\ version Print version number and exit
39 \\ zen Print zen of zig and exit
3840 \\
3941 \\
40 ;
42;
4143
4244const Command = struct {
4345 name: []const u8,
44 exec: fn(&Allocator, []const []const u8) error!void,
46 exec: fn (*Allocator, []const []const u8) error!void,
4547};
4648
4749pub fn main() !void {
48 var allocator = std.heap.c_allocator;
50 // This allocator needs to be thread-safe because we use it for the event.Loop
51 // which multiplexes coroutines onto kernel threads.
52 // libc allocator is guaranteed to have this property.
53 const allocator = std.heap.c_allocator;
4954
5055 var stdout_file = try std.io.getStdOut();
5156 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
5257 stdout = &stdout_out_stream.stream;
5358
54 var stderr_file = try std.io.getStdErr();
59 stderr_file = try std.io.getStdErr();
5560 var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);
5661 stderr = &stderr_out_stream.stream;
5762
5863 const args = try os.argsAlloc(allocator);
59 defer os.argsFree(allocator, args);
64 // TODO I'm getting unreachable code here, which shouldn't happen
65 //defer os.argsFree(allocator, args);
6066
6167 if (args.len <= 1) {
68 try stderr.write("expected command argument\n\n");
6269 try stderr.write(usage);
6370 os.exit(1);
6471 }
6572
66 const commands = []Command {
67 Command { .name = "build", .exec = cmdBuild },
68 Command { .name = "build-exe", .exec = cmdBuildExe },
69 Command { .name = "build-lib", .exec = cmdBuildLib },
70 Command { .name = "build-obj", .exec = cmdBuildObj },
71 Command { .name = "fmt", .exec = cmdFmt },
72 Command { .name = "run", .exec = cmdRun },
73 Command { .name = "targets", .exec = cmdTargets },
74 Command { .name = "test", .exec = cmdTest },
75 Command { .name = "translate-c", .exec = cmdTranslateC },
76 Command { .name = "version", .exec = cmdVersion },
77 Command { .name = "zen", .exec = cmdZen },
73 const commands = []Command{
74 Command{
75 .name = "build-exe",
76 .exec = cmdBuildExe,
77 },
78 Command{
79 .name = "build-lib",
80 .exec = cmdBuildLib,
81 },
82 Command{
83 .name = "build-obj",
84 .exec = cmdBuildObj,
85 },
86 Command{
87 .name = "fmt",
88 .exec = cmdFmt,
89 },
90 Command{
91 .name = "libc",
92 .exec = cmdLibC,
93 },
94 Command{
95 .name = "targets",
96 .exec = cmdTargets,
97 },
98 Command{
99 .name = "version",
100 .exec = cmdVersion,
101 },
102 Command{
103 .name = "zen",
104 .exec = cmdZen,
105 },
78106
79107 // undocumented commands
80 Command { .name = "help", .exec = cmdHelp },
81 Command { .name = "internal", .exec = cmdInternal },
108 Command{
109 .name = "help",
110 .exec = cmdHelp,
111 },
112 Command{
113 .name = "internal",
114 .exec = cmdInternal,
115 },
82116 };
83117
84118 for (commands) |command| {
85119 if (mem.eql(u8, command.name, args[1])) {
86 try command.exec(allocator, args[2..]);
87 return;
120 return command.exec(allocator, args[2..]);
88121 }
89122 }
90123
91124 try stderr.print("unknown command: {}\n\n", args[1]);
92125 try stderr.write(usage);
126 os.exit(1);
93127}
94128
95// cmd:build ///////////////////////////////////////////////////////////////////////////////////////
96
97const usage_build =
98 \\usage: zig build <options>
99 \\
100 \\General Options:
101 \\ --help Print this help and exit
102 \\ --init Generate a build.zig template
103 \\ --build-file [file] Override path to build.zig
104 \\ --cache-dir [path] Override path to cache directory
105 \\ --verbose Print commands before executing them
106 \\ --prefix [path] Override default install prefix
107 \\
108 \\Project-Specific Options:
109 \\
110 \\ Project-specific options become available when the build file is found.
111 \\
112 \\Advanced Options:
113 \\ --build-file [file] Override path to build.zig
114 \\ --cache-dir [path] Override path to cache directory
115 \\ --verbose-tokenize Enable compiler debug output for tokenization
116 \\ --verbose-ast Enable compiler debug output for parsing into an AST
117 \\ --verbose-link Enable compiler debug output for linking
118 \\ --verbose-ir Enable compiler debug output for Zig IR
119 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
120 \\ --verbose-cimport Enable compiler debug output for C imports
121 \\
122 \\
123 ;
124
125const args_build_spec = []Flag {
126 Flag.Bool("--help"),
127 Flag.Bool("--init"),
128 Flag.Arg1("--build-file"),
129 Flag.Arg1("--cache-dir"),
130 Flag.Bool("--verbose"),
131 Flag.Arg1("--prefix"),
132
133 Flag.Arg1("--build-file"),
134 Flag.Arg1("--cache-dir"),
135 Flag.Bool("--verbose-tokenize"),
136 Flag.Bool("--verbose-ast"),
137 Flag.Bool("--verbose-link"),
138 Flag.Bool("--verbose-ir"),
139 Flag.Bool("--verbose-llvm-ir"),
140 Flag.Bool("--verbose-cimport"),
141};
142
143const missing_build_file =
144 \\No 'build.zig' file found.
145 \\
146 \\Initialize a 'build.zig' template file with `zig build --init`,
147 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
148 \\
149 \\See: `zig build --help` or `zig help` for more options.
150 \\
151 ;
152
153fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void {
154 var flags = try Args.parse(allocator, args_build_spec, args);
155 defer flags.deinit();
156
157 if (flags.present("help")) {
158 try stderr.write(usage_build);
159 os.exit(0);
160 }
161
162 const zig_lib_dir = try introspect.resolveZigLibDir(allocator);
163 defer allocator.free(zig_lib_dir);
164
165 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
166 defer allocator.free(zig_std_dir);
167
168 const special_dir = try os.path.join(allocator, zig_std_dir, "special");
169 defer allocator.free(special_dir);
170
171 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
172 defer allocator.free(build_runner_path);
173
174 const build_file = flags.single("build-file") ?? "build.zig";
175 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
176 defer allocator.free(build_file_abs);
177
178 const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false;
179
180 if (flags.present("init")) {
181 if (build_file_exists) {
182 try stderr.print("build.zig already exists\n");
183 os.exit(1);
184 }
185
186 // need a new scope for proper defer scope finalization on exit
187 {
188 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
189 defer allocator.free(build_template_path);
190
191 try os.copyFile(allocator, build_template_path, build_file_abs);
192 try stderr.print("wrote build.zig template\n");
193 }
194
195 os.exit(0);
196 }
197
198 if (!build_file_exists) {
199 try stderr.write(missing_build_file);
200 os.exit(1);
201 }
202
203 // TODO: Invoke build.zig entrypoint directly?
204 var zig_exe_path = try os.selfExePath(allocator);
205 defer allocator.free(zig_exe_path);
206
207 var build_args = ArrayList([]const u8).init(allocator);
208 defer build_args.deinit();
209
210 const build_file_basename = os.path.basename(build_file_abs);
211 const build_file_dirname = os.path.dirname(build_file_abs);
212
213 var full_cache_dir: []u8 = undefined;
214 if (flags.single("cache-dir")) |cache_dir| {
215 full_cache_dir = try os.path.resolve(allocator, ".", cache_dir, full_cache_dir);
216 } else {
217 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
218 }
219 defer allocator.free(full_cache_dir);
220
221 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
222 defer allocator.free(path_to_build_exe);
223
224 try build_args.append(path_to_build_exe);
225 try build_args.append(zig_exe_path);
226 try build_args.append(build_file_dirname);
227 try build_args.append(full_cache_dir);
228
229 var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator);
230 defer proc.deinit();
231
232 var term = try proc.spawnAndWait();
233 switch (term) {
234 os.ChildProcess.Term.Exited => |status| {
235 if (status != 0) {
236 try stderr.print("{} exited with status {}\n", build_args.at(0), status);
237 os.exit(1);
238 }
239 },
240 os.ChildProcess.Term.Signal => |signal| {
241 try stderr.print("{} killed by signal {}\n", build_args.at(0), signal);
242 os.exit(1);
243 },
244 os.ChildProcess.Term.Stopped => |signal| {
245 try stderr.print("{} stopped by signal {}\n", build_args.at(0), signal);
246 os.exit(1);
247 },
248 os.ChildProcess.Term.Unknown => |status| {
249 try stderr.print("{} encountered unknown failure {}\n", build_args.at(0), status);
250 os.exit(1);
251 },
252 }
253}
254
255// cmd:build-exe ///////////////////////////////////////////////////////////////////////////////////
256
257129const usage_build_generic =
258130 \\usage: zig build-exe <options> [file]
259131 \\ zig build-lib <options> [file]
......@@ -264,18 +136,20 @@ const usage_build_generic =
264136 \\ --color [auto|off|on] Enable or disable colored error messages
265137 \\
266138 \\Compile Options:
139 \\ --libc [file] Provide a file which specifies libc paths
267140 \\ --assembly [source] Add assembly file to build
268 \\ --cache-dir [path] Override the cache directory
269141 \\ --emit [filetype] Emit a specific file format as compilation output
270142 \\ --enable-timing-info Print timing diagnostics
271 \\ --libc-include-dir [path] Directory where libc stdlib.h resides
272143 \\ --name [name] Override output name
273144 \\ --output [file] Override destination path
274145 \\ --output-h [file] Override generated header file path
275146 \\ --pkg-begin [name] [path] Make package available to import and push current pkg
276147 \\ --pkg-end Pop current pkg
277 \\ --release-fast Build with optimizations on and safety off
278 \\ --release-safe Build with optimizations on and safety on
148 \\ --mode [mode] Set the build mode
149 \\ debug (default) optimizations off, safety on
150 \\ release-fast optimizations on, safety off
151 \\ release-safe optimizations on, safety on
152 \\ release-small optimize for small binary, safety off
279153 \\ --static Output will be statically linked
280154 \\ --strip Exclude debug symbols
281155 \\ --target-arch [name] Specify target architecture
......@@ -294,12 +168,7 @@ const usage_build_generic =
294168 \\
295169 \\Link Options:
296170 \\ --ar-path [path] Set the path to ar
297 \\ --dynamic-linker [path] Set the path to ld.so
298171 \\ --each-lib-rpath Add rpath for each used dynamic library
299 \\ --libc-lib-dir [path] Directory where libc crt1.o resides
300 \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides
301 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
302 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
303172 \\ --library [lib] Link against lib
304173 \\ --forbid-library [lib] Make it an error to link against lib
305174 \\ --library-path [dir] Add a directory to the library search path
......@@ -317,25 +186,36 @@ const usage_build_generic =
317186 \\ --ver-patch [ver] Dynamic library semver patch version
318187 \\
319188 \\
320 ;
189;
321190
322const args_build_generic = []Flag {
191const args_build_generic = []Flag{
323192 Flag.Bool("--help"),
324 Flag.Option("--color", []const []const u8 { "auto", "off", "on" }),
193 Flag.Option("--color", []const []const u8{
194 "auto",
195 "off",
196 "on",
197 }),
198 Flag.Option("--mode", []const []const u8{
199 "debug",
200 "release-fast",
201 "release-safe",
202 "release-small",
203 }),
325204
326205 Flag.ArgMergeN("--assembly", 1),
327 Flag.Arg1("--cache-dir"),
328 Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }),
206 Flag.Option("--emit", []const []const u8{
207 "asm",
208 "bin",
209 "llvm-ir",
210 }),
329211 Flag.Bool("--enable-timing-info"),
330 Flag.Arg1("--libc-include-dir"),
212 Flag.Arg1("--libc"),
331213 Flag.Arg1("--name"),
332214 Flag.Arg1("--output"),
333215 Flag.Arg1("--output-h"),
334216 // NOTE: Parsed manually after initial check
335217 Flag.ArgN("--pkg-begin", 2),
336218 Flag.Bool("--pkg-end"),
337 Flag.Bool("--release-fast"),
338 Flag.Bool("--release-safe"),
339219 Flag.Bool("--static"),
340220 Flag.Bool("--strip"),
341221 Flag.Arg1("--target-arch"),
......@@ -353,12 +233,7 @@ const args_build_generic = []Flag {
353233 Flag.Arg1("-mllvm"),
354234
355235 Flag.Arg1("--ar-path"),
356 Flag.Arg1("--dynamic-linker"),
357236 Flag.Bool("--each-lib-rpath"),
358 Flag.Arg1("--libc-lib-dir"),
359 Flag.Arg1("--libc-static-lib-dir"),
360 Flag.Arg1("--msvc-lib-dir"),
361 Flag.Arg1("--kernel32-lib-dir"),
362237 Flag.ArgMergeN("--library", 1),
363238 Flag.ArgMergeN("--forbid-library", 1),
364239 Flag.ArgMergeN("--library-path", 1),
......@@ -377,49 +252,60 @@ const args_build_generic = []Flag {
377252 Flag.Arg1("--ver-patch"),
378253};
379254
380fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Module.Kind) !void {
255fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void {
381256 var flags = try Args.parse(allocator, args_build_generic, args);
382257 defer flags.deinit();
383258
384259 if (flags.present("help")) {
385 try stderr.write(usage_build_generic);
260 try stdout.write(usage_build_generic);
386261 os.exit(0);
387262 }
388263
389 var build_mode = builtin.Mode.Debug;
390 if (flags.present("release-fast")) {
391 build_mode = builtin.Mode.ReleaseFast;
392 } else if (flags.present("release-safe")) {
393 build_mode = builtin.Mode.ReleaseSafe;
394 }
264 const build_mode = blk: {
265 if (flags.single("mode")) |mode_flag| {
266 if (mem.eql(u8, mode_flag, "debug")) {
267 break :blk builtin.Mode.Debug;
268 } else if (mem.eql(u8, mode_flag, "release-fast")) {
269 break :blk builtin.Mode.ReleaseFast;
270 } else if (mem.eql(u8, mode_flag, "release-safe")) {
271 break :blk builtin.Mode.ReleaseSafe;
272 } else if (mem.eql(u8, mode_flag, "release-small")) {
273 break :blk builtin.Mode.ReleaseSmall;
274 } else unreachable;
275 } else {
276 break :blk builtin.Mode.Debug;
277 }
278 };
395279
396 var color = Module.ErrColor.Auto;
397 if (flags.single("color")) |color_flag| {
398 if (mem.eql(u8, color_flag, "auto")) {
399 color = Module.ErrColor.Auto;
400 } else if (mem.eql(u8, color_flag, "on")) {
401 color = Module.ErrColor.On;
402 } else if (mem.eql(u8, color_flag, "off")) {
403 color = Module.ErrColor.Off;
280 const color = blk: {
281 if (flags.single("color")) |color_flag| {
282 if (mem.eql(u8, color_flag, "auto")) {
283 break :blk errmsg.Color.Auto;
284 } else if (mem.eql(u8, color_flag, "on")) {
285 break :blk errmsg.Color.On;
286 } else if (mem.eql(u8, color_flag, "off")) {
287 break :blk errmsg.Color.Off;
288 } else unreachable;
404289 } else {
405 unreachable;
290 break :blk errmsg.Color.Auto;
406291 }
407 }
292 };
408293
409 var emit_type = Module.Emit.Binary;
410 if (flags.single("emit")) |emit_flag| {
411 if (mem.eql(u8, emit_flag, "asm")) {
412 emit_type = Module.Emit.Assembly;
413 } else if (mem.eql(u8, emit_flag, "bin")) {
414 emit_type = Module.Emit.Binary;
415 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
416 emit_type = Module.Emit.LlvmIr;
294 const emit_type = blk: {
295 if (flags.single("emit")) |emit_flag| {
296 if (mem.eql(u8, emit_flag, "asm")) {
297 break :blk Compilation.Emit.Assembly;
298 } else if (mem.eql(u8, emit_flag, "bin")) {
299 break :blk Compilation.Emit.Binary;
300 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
301 break :blk Compilation.Emit.LlvmIr;
302 } else unreachable;
417303 } else {
418 unreachable;
304 break :blk Compilation.Emit.Binary;
419305 }
420 }
306 };
421307
422 var cur_pkg = try Module.CliPkg.init(allocator, "", "", null); // TODO: Need a path, name?
308 var cur_pkg = try CliPkg.init(allocator, "", "", null);
423309 defer cur_pkg.deinit();
424310
425311 var i: usize = 0;
......@@ -432,15 +318,16 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
432318 i += 1;
433319 const new_pkg_path = args[i];
434320
435 var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg);
321 var new_cur_pkg = try CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg);
436322 try cur_pkg.children.append(new_cur_pkg);
437323 cur_pkg = new_cur_pkg;
438324 } else if (mem.eql(u8, "--pkg-end", arg_name)) {
439 if (cur_pkg.parent == null) {
325 if (cur_pkg.parent) |parent| {
326 cur_pkg = parent;
327 } else {
440328 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
441329 os.exit(1);
442330 }
443 cur_pkg = ??cur_pkg.parent;
444331 }
445332 }
446333
......@@ -449,138 +336,117 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
449336 os.exit(1);
450337 }
451338
452 var in_file: ?[]const u8 = undefined;
453 switch (flags.positionals.len) {
454 0 => {
455 try stderr.write("--name [name] not provided and unable to infer\n");
456 os.exit(1);
457 },
458 1 => {
459 in_file = flags.positionals.at(0);
460 },
339 const provided_name = flags.single("name");
340 const root_source_file = switch (flags.positionals.len) {
341 0 => null,
342 1 => flags.positionals.at(0),
461343 else => {
462 try stderr.write("only one zig input file is accepted during build\n");
344 try stderr.print("unexpected extra parameter: {}\n", flags.positionals.at(1));
463345 os.exit(1);
464346 },
465 }
347 };
466348
467 const basename = os.path.basename(??in_file);
468 var it = mem.split(basename, ".");
469 const root_name = it.next() ?? {
470 try stderr.write("file name cannot be empty\n");
471 os.exit(1);
349 const root_name = if (provided_name) |n| n else blk: {
350 if (root_source_file) |file| {
351 const basename = os.path.basename(file);
352 var it = mem.split(basename, ".");
353 break :blk it.next() orelse basename;
354 } else {
355 try stderr.write("--name [name] not provided and unable to infer\n");
356 os.exit(1);
357 }
472358 };
473359
474 const asm_a= flags.many("assembly");
475 const obj_a = flags.many("object");
476 if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) {
360 const is_static = flags.present("static");
361
362 const assembly_files = flags.many("assembly");
363 const link_objects = flags.many("object");
364 if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) {
477365 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
478366 os.exit(1);
479367 }
480368
481 if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) {
369 if (out_type == Compilation.Kind.Obj and link_objects.len != 0) {
482370 try stderr.write("When building an object file, --object arguments are invalid\n");
483371 os.exit(1);
484372 }
485373
486 const zig_root_source_file = in_file;
487
488 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch {
489 os.exit(1);
490 };
491 defer allocator.free(full_cache_dir);
492
493374 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
494375 defer allocator.free(zig_lib_dir);
495376
496 var module =
497 try Module.create(
498 allocator,
499 root_name,
500 zig_root_source_file,
501 Target.Native,
502 out_type,
503 build_mode,
504 zig_lib_dir,
505 full_cache_dir
506 );
507 defer module.destroy();
508
509 module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
510 module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10);
511 module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10);
512
513 module.is_test = false;
514
515 if (flags.single("linker-script")) |linker_script| {
516 module.linker_script = linker_script;
517 }
377 var override_libc: LibCInstallation = undefined;
518378
519 module.each_lib_rpath = flags.present("each-lib-rpath");
379 var loop: event.Loop = undefined;
380 try loop.initMultiThreaded(allocator);
381 defer loop.deinit();
520382
521 var clang_argv_buf = ArrayList([]const u8).init(allocator);
522 defer clang_argv_buf.deinit();
523 if (flags.many("mllvm")) |mllvm_flags| {
524 for (mllvm_flags) |mllvm| {
525 try clang_argv_buf.append("-mllvm");
526 try clang_argv_buf.append(mllvm);
527 }
383 var event_loop_local = try EventLoopLocal.init(&loop);
384 defer event_loop_local.deinit();
528385
529 module.llvm_argv = mllvm_flags;
530 module.clang_argv = clang_argv_buf.toSliceConst();
531 }
532
533 module.strip = flags.present("strip");
534 module.is_static = flags.present("static");
386 var comp = try Compilation.create(
387 &event_loop_local,
388 root_name,
389 root_source_file,
390 Target.Native,
391 out_type,
392 build_mode,
393 is_static,
394 zig_lib_dir,
395 );
396 defer comp.destroy();
535397
536 if (flags.single("libc-lib-dir")) |libc_lib_dir| {
537 module.libc_lib_dir = libc_lib_dir;
538 }
539 if (flags.single("libc-static-lib-dir")) |libc_static_lib_dir| {
540 module.libc_static_lib_dir = libc_static_lib_dir;
541 }
542 if (flags.single("libc-include-dir")) |libc_include_dir| {
543 module.libc_include_dir = libc_include_dir;
398 if (flags.single("libc")) |libc_path| {
399 parseLibcPaths(loop.allocator, &override_libc, libc_path);
400 comp.override_libc = &override_libc;
544401 }
545 if (flags.single("msvc-lib-dir")) |msvc_lib_dir| {
546 module.msvc_lib_dir = msvc_lib_dir;
547 }
548 if (flags.single("kernel32-lib-dir")) |kernel32_lib_dir| {
549 module.kernel32_lib_dir = kernel32_lib_dir;
550 }
551 if (flags.single("dynamic-linker")) |dynamic_linker| {
552 module.dynamic_linker = dynamic_linker;
402
403 for (flags.many("library")) |lib| {
404 _ = try comp.addLinkLib(lib, true);
553405 }
554406
555 module.verbose_tokenize = flags.present("verbose-tokenize");
556 module.verbose_ast_tree = flags.present("verbose-ast-tree");
557 module.verbose_ast_fmt = flags.present("verbose-ast-fmt");
558 module.verbose_link = flags.present("verbose-link");
559 module.verbose_ir = flags.present("verbose-ir");
560 module.verbose_llvm_ir = flags.present("verbose-llvm-ir");
561 module.verbose_cimport = flags.present("verbose-cimport");
407 comp.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") orelse "0", 10);
408 comp.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") orelse "0", 10);
409 comp.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") orelse "0", 10);
562410
563 module.err_color = color;
411 comp.is_test = false;
564412
565 if (flags.many("library-path")) |lib_dirs| {
566 module.lib_dirs = lib_dirs;
567 }
413 comp.linker_script = flags.single("linker-script");
414 comp.each_lib_rpath = flags.present("each-lib-rpath");
568415
569 if (flags.many("framework")) |frameworks| {
570 module.darwin_frameworks = frameworks;
571 }
416 var clang_argv_buf = ArrayList([]const u8).init(allocator);
417 defer clang_argv_buf.deinit();
572418
573 if (flags.many("rpath")) |rpath_list| {
574 module.rpath_list = rpath_list;
419 const mllvm_flags = flags.many("mllvm");
420 for (mllvm_flags) |mllvm| {
421 try clang_argv_buf.append("-mllvm");
422 try clang_argv_buf.append(mllvm);
575423 }
576424
425 comp.llvm_argv = mllvm_flags;
426 comp.clang_argv = clang_argv_buf.toSliceConst();
427
428 comp.strip = flags.present("strip");
429
430 comp.verbose_tokenize = flags.present("verbose-tokenize");
431 comp.verbose_ast_tree = flags.present("verbose-ast-tree");
432 comp.verbose_ast_fmt = flags.present("verbose-ast-fmt");
433 comp.verbose_link = flags.present("verbose-link");
434 comp.verbose_ir = flags.present("verbose-ir");
435 comp.verbose_llvm_ir = flags.present("verbose-llvm-ir");
436 comp.verbose_cimport = flags.present("verbose-cimport");
437
438 comp.err_color = color;
439 comp.lib_dirs = flags.many("library-path");
440 comp.darwin_frameworks = flags.many("framework");
441 comp.rpath_list = flags.many("rpath");
442
577443 if (flags.single("output-h")) |output_h| {
578 module.out_h_path = output_h;
444 comp.out_h_path = output_h;
579445 }
580446
581 module.windows_subsystem_windows = flags.present("mwindows");
582 module.windows_subsystem_console = flags.present("mconsole");
583 module.linker_rdynamic = flags.present("rdynamic");
447 comp.windows_subsystem_windows = flags.present("mwindows");
448 comp.windows_subsystem_console = flags.present("mconsole");
449 comp.linker_rdynamic = flags.present("rdynamic");
584450
585451 if (flags.single("mmacosx-version-min") != null and flags.single("mios-version-min") != null) {
586452 try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");
......@@ -588,48 +454,56 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
588454 }
589455
590456 if (flags.single("mmacosx-version-min")) |ver| {
591 module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
457 comp.darwin_version_min = Compilation.DarwinVersionMin{ .MacOS = ver };
592458 }
593459 if (flags.single("mios-version-min")) |ver| {
594 module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
460 comp.darwin_version_min = Compilation.DarwinVersionMin{ .Ios = ver };
595461 }
596462
597 module.emit_file_type = emit_type;
598 if (flags.many("object")) |objects| {
599 module.link_objects = objects;
600 }
601 if (flags.many("assembly")) |assembly_files| {
602 module.assembly_files = assembly_files;
603 }
463 comp.emit_file_type = emit_type;
464 comp.assembly_files = assembly_files;
465 comp.link_out_file = flags.single("output");
466 comp.link_objects = link_objects;
604467
605 try module.build();
606 try module.link(flags.single("out-file") ?? null);
468 try comp.build();
469 const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
470 defer cancel process_build_events_handle;
471 loop.run();
472}
607473
608 if (flags.present("print-timing-info")) {
609 // codegen_print_timing_info(g, stderr);
610 }
474async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
475 // TODO directly awaiting async should guarantee memory allocation elision
476 const build_event = await (async comp.events.get() catch unreachable);
611477
612 try stderr.print("building {}: {}\n", @tagName(out_type), in_file);
478 switch (build_event) {
479 Compilation.Event.Ok => {
480 return;
481 },
482 Compilation.Event.Error => |err| {
483 std.debug.warn("build failed: {}\n", @errorName(err));
484 os.exit(1);
485 },
486 Compilation.Event.Fail => |msgs| {
487 for (msgs) |msg| {
488 defer msg.destroy();
489 msg.printToFile(&stderr_file, color) catch os.exit(1);
490 }
491 },
492 }
613493}
614494
615fn cmdBuildExe(allocator: &Allocator, args: []const []const u8) !void {
616 try buildOutputType(allocator, args, Module.Kind.Exe);
495fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void {
496 return buildOutputType(allocator, args, Compilation.Kind.Exe);
617497}
618498
619// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
620
621fn cmdBuildLib(allocator: &Allocator, args: []const []const u8) !void {
622 try buildOutputType(allocator, args, Module.Kind.Lib);
499fn cmdBuildLib(allocator: *Allocator, args: []const []const u8) !void {
500 return buildOutputType(allocator, args, Compilation.Kind.Lib);
623501}
624502
625// cmd:build-obj ///////////////////////////////////////////////////////////////////////////////////
626
627fn cmdBuildObj(allocator: &Allocator, args: []const []const u8) !void {
628 try buildOutputType(allocator, args, Module.Kind.Obj);
503fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
504 return buildOutputType(allocator, args, Compilation.Kind.Obj);
629505}
630506
631// cmd:fmt /////////////////////////////////////////////////////////////////////////////////////////
632
633507const usage_fmt =
634508 \\usage: zig fmt [file]...
635509 \\
......@@ -637,82 +511,233 @@ const usage_fmt =
637511 \\
638512 \\Options:
639513 \\ --help Print this help and exit
640 \\ --keep-backups Retain backup entries for every file
514 \\ --color [auto|off|on] Enable or disable colored error messages
515 \\ --stdin Format code from stdin
641516 \\
642517 \\
643 ;
518;
644519
645const args_fmt_spec = []Flag {
520const args_fmt_spec = []Flag{
646521 Flag.Bool("--help"),
647 Flag.Bool("--keep-backups"),
522 Flag.Option("--color", []const []const u8{
523 "auto",
524 "off",
525 "on",
526 }),
527 Flag.Bool("--stdin"),
528};
529
530const Fmt = struct {
531 seen: std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8),
532 queue: std.LinkedList([]const u8),
533 any_error: bool,
534
535 // file_path must outlive Fmt
536 fn addToQueue(self: *Fmt, file_path: []const u8) !void {
537 const new_node = try self.seen.allocator.create(std.LinkedList([]const u8).Node{
538 .prev = undefined,
539 .next = undefined,
540 .data = file_path,
541 });
542
543 if (try self.seen.put(file_path, {})) |_| return;
544
545 self.queue.append(new_node);
546 }
547
548 fn addDirToQueue(self: *Fmt, file_path: []const u8) !void {
549 var dir = try std.os.Dir.open(self.seen.allocator, file_path);
550 defer dir.close();
551 while (try dir.next()) |entry| {
552 if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
553 const full_path = try os.path.join(self.seen.allocator, file_path, entry.name);
554 try self.addToQueue(full_path);
555 }
556 }
557 }
648558};
649559
650fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
560fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void {
561 libc.parse(allocator, libc_paths_file, stderr) catch |err| {
562 stderr.print(
563 "Unable to parse libc path file '{}': {}.\n" ++
564 "Try running `zig libc` to see an example for the native target.\n",
565 libc_paths_file,
566 @errorName(err),
567 ) catch os.exit(1);
568 os.exit(1);
569 };
570}
571
572fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
573 switch (args.len) {
574 0 => {},
575 1 => {
576 var libc_installation: LibCInstallation = undefined;
577 parseLibcPaths(allocator, &libc_installation, args[0]);
578 return;
579 },
580 else => {
581 try stderr.print("unexpected extra parameter: {}\n", args[1]);
582 os.exit(1);
583 },
584 }
585
586 var loop: event.Loop = undefined;
587 try loop.initMultiThreaded(allocator);
588 defer loop.deinit();
589
590 var event_loop_local = try EventLoopLocal.init(&loop);
591 defer event_loop_local.deinit();
592
593 const handle = try async<loop.allocator> findLibCAsync(&event_loop_local);
594 defer cancel handle;
595
596 loop.run();
597}
598
599async fn findLibCAsync(event_loop_local: *EventLoopLocal) void {
600 const libc = (await (async event_loop_local.getNativeLibC() catch unreachable)) catch |err| {
601 stderr.print("unable to find libc: {}\n", @errorName(err)) catch os.exit(1);
602 os.exit(1);
603 };
604 libc.render(stdout) catch os.exit(1);
605}
606
607fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
651608 var flags = try Args.parse(allocator, args_fmt_spec, args);
652609 defer flags.deinit();
653610
654611 if (flags.present("help")) {
655 try stderr.write(usage_fmt);
612 try stdout.write(usage_fmt);
656613 os.exit(0);
657614 }
658615
616 const color = blk: {
617 if (flags.single("color")) |color_flag| {
618 if (mem.eql(u8, color_flag, "auto")) {
619 break :blk errmsg.Color.Auto;
620 } else if (mem.eql(u8, color_flag, "on")) {
621 break :blk errmsg.Color.On;
622 } else if (mem.eql(u8, color_flag, "off")) {
623 break :blk errmsg.Color.Off;
624 } else unreachable;
625 } else {
626 break :blk errmsg.Color.Auto;
627 }
628 };
629
630 if (flags.present("stdin")) {
631 if (flags.positionals.len != 0) {
632 try stderr.write("cannot use --stdin with positional arguments\n");
633 os.exit(1);
634 }
635
636 var stdin_file = try io.getStdIn();
637 var stdin = io.FileInStream.init(&stdin_file);
638
639 const source_code = try stdin.stream.readAllAlloc(allocator, @maxValue(usize));
640 defer allocator.free(source_code);
641
642 var tree = std.zig.parse(allocator, source_code) catch |err| {
643 try stderr.print("error parsing stdin: {}\n", err);
644 os.exit(1);
645 };
646 defer tree.deinit();
647
648 var error_it = tree.errors.iterator(0);
649 while (error_it.next()) |parse_error| {
650 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
651 defer msg.destroy();
652
653 try msg.printToFile(&stderr_file, color);
654 }
655 if (tree.errors.len != 0) {
656 os.exit(1);
657 }
658
659 _ = try std.zig.render(allocator, stdout, &tree);
660 return;
661 }
662
659663 if (flags.positionals.len == 0) {
660664 try stderr.write("expected at least one source file argument\n");
661665 os.exit(1);
662666 }
663667
668 var fmt = Fmt{
669 .seen = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator),
670 .queue = std.LinkedList([]const u8).init(),
671 .any_error = false,
672 };
673
664674 for (flags.positionals.toSliceConst()) |file_path| {
675 try fmt.addToQueue(file_path);
676 }
677
678 while (fmt.queue.popFirst()) |node| {
679 const file_path = node.data;
680
665681 var file = try os.File.openRead(allocator, file_path);
666682 defer file.close();
667683
668 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
669 try stderr.print("unable to open '{}': {}", file_path, err);
670 continue;
684 const source_code = io.readFileAlloc(allocator, file_path) catch |err| switch (err) {
685 error.IsDir => {
686 try fmt.addDirToQueue(file_path);
687 continue;
688 },
689 else => {
690 try stderr.print("unable to open '{}': {}\n", file_path, err);
691 fmt.any_error = true;
692 continue;
693 },
671694 };
672695 defer allocator.free(source_code);
673696
674 var tokenizer = std.zig.Tokenizer.init(source_code);
675 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
676 defer parser.deinit();
677
678 var tree = parser.parse() catch |err| {
697 var tree = std.zig.parse(allocator, source_code) catch |err| {
679698 try stderr.print("error parsing file '{}': {}\n", file_path, err);
699 fmt.any_error = true;
680700 continue;
681701 };
682702 defer tree.deinit();
683703
684 var original_file_backup = try Buffer.init(allocator, file_path);
685 defer original_file_backup.deinit();
686 try original_file_backup.append(".backup");
704 var error_it = tree.errors.iterator(0);
705 while (error_it.next()) |parse_error| {
706 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, file_path);
707 defer msg.destroy();
687708
688 try os.rename(allocator, file_path, original_file_backup.toSliceConst());
689
690 try stderr.print("{}\n", file_path);
691
692 // TODO: BufferedAtomicFile has some access problems.
693 var out_file = try os.File.openWrite(allocator, file_path);
694 defer out_file.close();
709 try msg.printToFile(&stderr_file, color);
710 }
711 if (tree.errors.len != 0) {
712 fmt.any_error = true;
713 continue;
714 }
695715
696 var out_file_stream = io.FileOutStream.init(&out_file);
697 try parser.renderSource(out_file_stream.stream, tree.root_node);
716 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
717 defer baf.destroy();
698718
699 if (!flags.present("keep-backups")) {
700 try os.deleteFile(allocator, original_file_backup.toSliceConst());
719 const anything_changed = try std.zig.render(allocator, baf.stream(), &tree);
720 if (anything_changed) {
721 try stderr.print("{}\n", file_path);
722 try baf.finish();
701723 }
702724 }
725
726 if (fmt.any_error) {
727 os.exit(1);
728 }
703729}
704730
705731// cmd:targets /////////////////////////////////////////////////////////////////////////////////////
706732
707fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
733fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {
708734 try stdout.write("Architectures:\n");
709735 {
710736 comptime var i: usize = 0;
711737 inline while (i < @memberCount(builtin.Arch)) : (i += 1) {
712738 comptime const arch_tag = @memberName(builtin.Arch, i);
713739 // NOTE: Cannot use empty string, see #918.
714 comptime const native_str =
715 if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
740 comptime const native_str = if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
716741
717742 try stdout.print(" {}{}", arch_tag, native_str);
718743 }
......@@ -725,8 +750,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
725750 inline while (i < @memberCount(builtin.Os)) : (i += 1) {
726751 comptime const os_tag = @memberName(builtin.Os, i);
727752 // NOTE: Cannot use empty string, see #918.
728 comptime const native_str =
729 if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
753 comptime const native_str = if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
730754
731755 try stdout.print(" {}{}", os_tag, native_str);
732756 }
......@@ -739,176 +763,23 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
739763 inline while (i < @memberCount(builtin.Environ)) : (i += 1) {
740764 comptime const environ_tag = @memberName(builtin.Environ, i);
741765 // NOTE: Cannot use empty string, see #918.
742 comptime const native_str =
743 if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
766 comptime const native_str = if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
744767
745768 try stdout.print(" {}{}", environ_tag, native_str);
746769 }
747770 }
748771}
749772
750// cmd:version /////////////////////////////////////////////////////////////////////////////////////
751
752fn cmdVersion(allocator: &Allocator, args: []const []const u8) !void {
773fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
753774 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
754775}
755776
756// cmd:test ////////////////////////////////////////////////////////////////////////////////////////
757
758const usage_test =
759 \\usage: zig test [file]...
760 \\
761 \\Options:
762 \\ --help Print this help and exit
763 \\
764 \\
765 ;
766
767const args_test_spec = []Flag {
768 Flag.Bool("--help"),
769};
770
771
772fn cmdTest(allocator: &Allocator, args: []const []const u8) !void {
773 var flags = try Args.parse(allocator, args_build_spec, args);
774 defer flags.deinit();
775
776 if (flags.present("help")) {
777 try stderr.write(usage_test);
778 os.exit(0);
779 }
780
781 if (flags.positionals.len != 1) {
782 try stderr.write("expected exactly one zig source file\n");
783 os.exit(1);
784 }
785
786 // compile the test program into the cache and run
787
788 // NOTE: May be overlap with buildOutput, take the shared part out.
789 try stderr.print("testing file {}\n", flags.positionals.at(0));
790}
791
792// cmd:run /////////////////////////////////////////////////////////////////////////////////////////
793
794// Run should be simple and not expose the full set of arguments provided by build-exe. If specific
795// build requirements are need, the user should `build-exe` then `run` manually.
796const usage_run =
797 \\usage: zig run [file] -- <runtime args>
798 \\
799 \\Options:
800 \\ --help Print this help and exit
801 \\
802 \\
803 ;
804
805const args_run_spec = []Flag {
806 Flag.Bool("--help"),
807};
808
809
810fn cmdRun(allocator: &Allocator, args: []const []const u8) !void {
811 var compile_args = args;
812 var runtime_args: []const []const u8 = []const []const u8 {};
813
814 for (args) |argv, i| {
815 if (mem.eql(u8, argv, "--")) {
816 compile_args = args[0..i];
817 runtime_args = args[i+1..];
818 break;
819 }
820 }
821 var flags = try Args.parse(allocator, args_run_spec, compile_args);
822 defer flags.deinit();
823
824 if (flags.present("help")) {
825 try stderr.write(usage_run);
826 os.exit(0);
827 }
828
829 if (flags.positionals.len != 1) {
830 try stderr.write("expected exactly one zig source file\n");
831 os.exit(1);
832 }
833
834 try stderr.print("runtime args:\n");
835 for (runtime_args) |cargs| {
836 try stderr.print("{}\n", cargs);
837 }
838}
839
840// cmd:translate-c /////////////////////////////////////////////////////////////////////////////////
841
842const usage_translate_c =
843 \\usage: zig translate-c [file]
844 \\
845 \\Options:
846 \\ --help Print this help and exit
847 \\ --enable-timing-info Print timing diagnostics
848 \\ --output [path] Output file to write generated zig file (default: stdout)
849 \\
850 \\
851 ;
852
853const args_translate_c_spec = []Flag {
854 Flag.Bool("--help"),
855 Flag.Bool("--enable-timing-info"),
856 Flag.Arg1("--libc-include-dir"),
857 Flag.Arg1("--output"),
858};
859
860fn cmdTranslateC(allocator: &Allocator, args: []const []const u8) !void {
861 var flags = try Args.parse(allocator, args_translate_c_spec, args);
862 defer flags.deinit();
863
864 if (flags.present("help")) {
865 try stderr.write(usage_translate_c);
866 os.exit(0);
867 }
868
869 if (flags.positionals.len != 1) {
870 try stderr.write("expected exactly one c source file\n");
871 os.exit(1);
872 }
873
874 // set up codegen
875
876 const zig_root_source_file = null;
877
878 // NOTE: translate-c shouldn't require setting up the full codegen instance as it does in
879 // the C++ compiler.
880
881 // codegen_create(g);
882 // codegen_set_out_name(g, null);
883 // codegen_translate_c(g, flags.positional.at(0))
884
885 var output_stream = stdout;
886 if (flags.single("output")) |output_file| {
887 var file = try os.File.openWrite(allocator, output_file);
888 defer file.close();
889
890 var file_stream = io.FileOutStream.init(&file);
891 // TODO: Not being set correctly, still stdout
892 output_stream = &file_stream.stream;
893 }
894
895 // ast_render(g, output_stream, g->root_import->root, 4);
896 try output_stream.write("pub const example = 10;\n");
897
898 if (flags.present("enable-timing-info")) {
899 // codegen_print_timing_info(g, stdout);
900 try stderr.write("printing timing info for translate-c\n");
901 }
902}
903
904// cmd:help ////////////////////////////////////////////////////////////////////////////////////////
777const args_test_spec = []Flag{Flag.Bool("--help")};
905778
906fn cmdHelp(allocator: &Allocator, args: []const []const u8) !void {
907 try stderr.write(usage);
779fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
780 try stdout.write(usage);
908781}
909782
910// cmd:zen /////////////////////////////////////////////////////////////////////////////////////////
911
912783const info_zen =
913784 \\
914785 \\ * Communicate intent precisely.
......@@ -924,14 +795,12 @@ const info_zen =
924795 \\ * Together we serve end users.
925796 \\
926797 \\
927 ;
798;
928799
929fn cmdZen(allocator: &Allocator, args: []const []const u8) !void {
800fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {
930801 try stdout.write(info_zen);
931802}
932803
933// cmd:internal ////////////////////////////////////////////////////////////////////////////////////
934
935804const usage_internal =
936805 \\usage: zig internal [subcommand]
937806 \\
......@@ -939,17 +808,18 @@ const usage_internal =
939808 \\ build-info Print static compiler build-info
940809 \\
941810 \\
942 ;
811;
943812
944fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
813fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
945814 if (args.len == 0) {
946815 try stderr.write(usage_internal);
947816 os.exit(1);
948817 }
949818
950 const sub_commands = []Command {
951 Command { .name = "build-info", .exec = cmdInternalBuildInfo },
952 };
819 const sub_commands = []Command{Command{
820 .name = "build-info",
821 .exec = cmdInternalBuildInfo,
822 }};
953823
954824 for (sub_commands) |sub_command| {
955825 if (mem.eql(u8, sub_command.name, args[0])) {
......@@ -962,7 +832,7 @@ fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
962832 try stderr.write(usage_internal);
963833}
964834
965fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
835fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
966836 try stdout.print(
967837 \\ZIG_CMAKE_BINARY_DIR {}
968838 \\ZIG_CXX_COMPILER {}
......@@ -973,7 +843,7 @@ fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
973843 \\ZIG_C_HEADER_FILES {}
974844 \\ZIG_DIA_GUIDS_LIB {}
975845 \\
976 ,
846 ,
977847 std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
978848 std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
979849 std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE),
......@@ -984,3 +854,27 @@ fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
984854 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
985855 );
986856}
857
858const CliPkg = struct {
859 name: []const u8,
860 path: []const u8,
861 children: ArrayList(*CliPkg),
862 parent: ?*CliPkg,
863
864 pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg {
865 var pkg = try allocator.create(CliPkg{
866 .name = name,
867 .path = path,
868 .children = ArrayList(*CliPkg).init(allocator),
869 .parent = parent,
870 });
871 return pkg;
872 }
873
874 pub fn deinit(self: *CliPkg) void {
875 for (self.children.toSliceConst()) |child| {
876 child.deinit();
877 }
878 self.children.deinit();
879 }
880};
src-self-hosted/module.zig deleted-326
......@@ -1,326 +0,0 @@
1const std = @import("std");
2const os = std.os;
3const io = std.io;
4const mem = std.mem;
5const Buffer = std.Buffer;
6const llvm = @import("llvm.zig");
7const c = @import("c.zig");
8const builtin = @import("builtin");
9const Target = @import("target.zig").Target;
10const warn = std.debug.warn;
11const Tokenizer = std.zig.Tokenizer;
12const Token = std.zig.Token;
13const Parser = std.zig.Parser;
14const ArrayList = std.ArrayList;
15
16pub const Module = struct {
17 allocator: &mem.Allocator,
18 name: Buffer,
19 root_src_path: ?[]const u8,
20 module: llvm.ModuleRef,
21 context: llvm.ContextRef,
22 builder: llvm.BuilderRef,
23 target: Target,
24 build_mode: builtin.Mode,
25 zig_lib_dir: []const u8,
26
27 version_major: u32,
28 version_minor: u32,
29 version_patch: u32,
30
31 linker_script: ?[]const u8,
32 cache_dir: []const u8,
33 libc_lib_dir: ?[]const u8,
34 libc_static_lib_dir: ?[]const u8,
35 libc_include_dir: ?[]const u8,
36 msvc_lib_dir: ?[]const u8,
37 kernel32_lib_dir: ?[]const u8,
38 dynamic_linker: ?[]const u8,
39 out_h_path: ?[]const u8,
40
41 is_test: bool,
42 each_lib_rpath: bool,
43 strip: bool,
44 is_static: bool,
45 linker_rdynamic: bool,
46
47 clang_argv: []const []const u8,
48 llvm_argv: []const []const u8,
49 lib_dirs: []const []const u8,
50 rpath_list: []const []const u8,
51 assembly_files: []const []const u8,
52 link_objects: []const []const u8,
53
54 windows_subsystem_windows: bool,
55 windows_subsystem_console: bool,
56
57 link_libs_list: ArrayList(&LinkLib),
58 libc_link_lib: ?&LinkLib,
59
60 err_color: ErrColor,
61
62 verbose_tokenize: bool,
63 verbose_ast_tree: bool,
64 verbose_ast_fmt: bool,
65 verbose_cimport: bool,
66 verbose_ir: bool,
67 verbose_llvm_ir: bool,
68 verbose_link: bool,
69
70 darwin_frameworks: []const []const u8,
71 darwin_version_min: DarwinVersionMin,
72
73 test_filters: []const []const u8,
74 test_name_prefix: ?[]const u8,
75
76 emit_file_type: Emit,
77
78 kind: Kind,
79
80 pub const DarwinVersionMin = union(enum) {
81 None,
82 MacOS: []const u8,
83 Ios: []const u8,
84 };
85
86 pub const Kind = enum {
87 Exe,
88 Lib,
89 Obj,
90 };
91
92 pub const ErrColor = enum {
93 Auto,
94 Off,
95 On,
96 };
97
98 pub const LinkLib = struct {
99 name: []const u8,
100 path: ?[]const u8,
101 /// the list of symbols we depend on from this lib
102 symbols: ArrayList([]u8),
103 provided_explicitly: bool,
104 };
105
106 pub const Emit = enum {
107 Binary,
108 Assembly,
109 LlvmIr,
110 };
111
112 pub const CliPkg = struct {
113 name: []const u8,
114 path: []const u8,
115 children: ArrayList(&CliPkg),
116 parent: ?&CliPkg,
117
118 pub fn init(allocator: &mem.Allocator, name: []const u8, path: []const u8, parent: ?&CliPkg) !&CliPkg {
119 var pkg = try allocator.create(CliPkg);
120 pkg.name = name;
121 pkg.path = path;
122 pkg.children = ArrayList(&CliPkg).init(allocator);
123 pkg.parent = parent;
124 return pkg;
125 }
126
127 pub fn deinit(self: &CliPkg) void {
128 for (self.children.toSliceConst()) |child| {
129 child.deinit();
130 }
131 self.children.deinit();
132 }
133 };
134
135 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
136 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
137 {
138 var name_buffer = try Buffer.init(allocator, name);
139 errdefer name_buffer.deinit();
140
141 const context = c.LLVMContextCreate() ?? return error.OutOfMemory;
142 errdefer c.LLVMContextDispose(context);
143
144 const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory;
145 errdefer c.LLVMDisposeModule(module);
146
147 const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory;
148 errdefer c.LLVMDisposeBuilder(builder);
149
150 const module_ptr = try allocator.create(Module);
151 errdefer allocator.destroy(module_ptr);
152
153 *module_ptr = Module {
154 .allocator = allocator,
155 .name = name_buffer,
156 .root_src_path = root_src_path,
157 .module = module,
158 .context = context,
159 .builder = builder,
160 .target = *target,
161 .kind = kind,
162 .build_mode = build_mode,
163 .zig_lib_dir = zig_lib_dir,
164 .cache_dir = cache_dir,
165
166 .version_major = 0,
167 .version_minor = 0,
168 .version_patch = 0,
169
170 .verbose_tokenize = false,
171 .verbose_ast_tree = false,
172 .verbose_ast_fmt = false,
173 .verbose_cimport = false,
174 .verbose_ir = false,
175 .verbose_llvm_ir = false,
176 .verbose_link = false,
177
178 .linker_script = null,
179 .libc_lib_dir = null,
180 .libc_static_lib_dir = null,
181 .libc_include_dir = null,
182 .msvc_lib_dir = null,
183 .kernel32_lib_dir = null,
184 .dynamic_linker = null,
185 .out_h_path = null,
186 .is_test = false,
187 .each_lib_rpath = false,
188 .strip = false,
189 .is_static = false,
190 .linker_rdynamic = false,
191 .clang_argv = [][]const u8{},
192 .llvm_argv = [][]const u8{},
193 .lib_dirs = [][]const u8{},
194 .rpath_list = [][]const u8{},
195 .assembly_files = [][]const u8{},
196 .link_objects = [][]const u8{},
197 .windows_subsystem_windows = false,
198 .windows_subsystem_console = false,
199 .link_libs_list = ArrayList(&LinkLib).init(allocator),
200 .libc_link_lib = null,
201 .err_color = ErrColor.Auto,
202 .darwin_frameworks = [][]const u8{},
203 .darwin_version_min = DarwinVersionMin.None,
204 .test_filters = [][]const u8{},
205 .test_name_prefix = null,
206 .emit_file_type = Emit.Binary,
207 };
208 return module_ptr;
209 }
210
211 fn dump(self: &Module) void {
212 c.LLVMDumpModule(self.module);
213 }
214
215 pub fn destroy(self: &Module) void {
216 c.LLVMDisposeBuilder(self.builder);
217 c.LLVMDisposeModule(self.module);
218 c.LLVMContextDispose(self.context);
219 self.name.deinit();
220
221 self.allocator.destroy(self);
222 }
223
224 pub fn build(self: &Module) !void {
225 if (self.llvm_argv.len != 0) {
226 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
227 [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
228 defer c_compatible_args.deinit();
229 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
230 }
231
232 const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
233 const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
234 try printError("unable to get real path '{}': {}", root_src_path, err);
235 return err;
236 };
237 errdefer self.allocator.free(root_src_real_path);
238
239 const source_code = io.readFileAlloc(self.allocator, root_src_real_path) catch |err| {
240 try printError("unable to open '{}': {}", root_src_real_path, err);
241 return err;
242 };
243 errdefer self.allocator.free(source_code);
244
245 warn("====input:====\n");
246
247 warn("{}", source_code);
248
249 warn("====tokenization:====\n");
250 {
251 var tokenizer = Tokenizer.init(source_code);
252 while (true) {
253 const token = tokenizer.next();
254 tokenizer.dump(token);
255 if (token.id == Token.Id.Eof) {
256 break;
257 }
258 }
259 }
260
261 warn("====parse:====\n");
262
263 var tokenizer = Tokenizer.init(source_code);
264 var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);
265 defer parser.deinit();
266
267 var tree = try parser.parse();
268 defer tree.deinit();
269
270 var stderr_file = try std.io.getStdErr();
271 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
272 const out_stream = &stderr_file_out_stream.stream;
273 try parser.renderAst(out_stream, tree.root_node);
274
275 warn("====fmt:====\n");
276 try parser.renderSource(out_stream, tree.root_node);
277
278 warn("====ir:====\n");
279 warn("TODO\n\n");
280
281 warn("====llvm ir:====\n");
282 self.dump();
283
284 }
285
286 pub fn link(self: &Module, out_file: ?[]const u8) !void {
287 warn("TODO link");
288 return error.Todo;
289 }
290
291 pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) !&LinkLib {
292 const is_libc = mem.eql(u8, name, "c");
293
294 if (is_libc) {
295 if (self.libc_link_lib) |libc_link_lib| {
296 return libc_link_lib;
297 }
298 }
299
300 for (self.link_libs_list.toSliceConst()) |existing_lib| {
301 if (mem.eql(u8, name, existing_lib.name)) {
302 return existing_lib;
303 }
304 }
305
306 const link_lib = try self.allocator.create(LinkLib);
307 *link_lib = LinkLib {
308 .name = name,
309 .path = null,
310 .provided_explicitly = provided_explicitly,
311 .symbols = ArrayList([]u8).init(self.allocator),
312 };
313 try self.link_libs_list.append(link_lib);
314 if (is_libc) {
315 self.libc_link_lib = link_lib;
316 }
317 return link_lib;
318 }
319};
320
321fn printError(comptime format: []const u8, args: ...) !void {
322 var stderr_file = try std.io.getStdErr();
323 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
324 const out_stream = &stderr_file_out_stream.stream;
325 try out_stream.print(format, args);
326}
src-self-hosted/package.zig created+29
......@@ -0,0 +1,29 @@
1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const Buffer = std.Buffer;
5
6pub const Package = struct {
7 root_src_dir: Buffer,
8 root_src_path: Buffer,
9
10 /// relative to root_src_dir
11 table: Table,
12
13 pub const Table = std.HashMap([]const u8, *Package, mem.hash_slice_u8, mem.eql_slice_u8);
14
15 /// makes internal copies of root_src_dir and root_src_path
16 /// allocator should be an arena allocator because Package never frees anything
17 pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package {
18 return allocator.create(Package{
19 .root_src_dir = try Buffer.init(allocator, root_src_dir),
20 .root_src_path = try Buffer.init(allocator, root_src_path),
21 .table = Table.init(allocator),
22 });
23 }
24
25 pub fn add(self: *Package, name: []const u8, package: *Package) !void {
26 const entry = try self.table.put(try mem.dupe(self.table.allocator, u8, name), package);
27 assert(entry == null);
28 }
29};
src-self-hosted/scope.zig+386-6
......@@ -1,16 +1,396 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Allocator = mem.Allocator;
4const Decl = @import("decl.zig").Decl;
5const Compilation = @import("compilation.zig").Compilation;
6const mem = std.mem;
7const ast = std.zig.ast;
8const Value = @import("value.zig").Value;
9const Type = @import("type.zig").Type;
10const ir = @import("ir.zig");
11const Span = @import("errmsg.zig").Span;
12const assert = std.debug.assert;
13const event = std.event;
14const llvm = @import("llvm.zig");
15
116pub const Scope = struct {
217 id: Id,
3 parent: &Scope,
18 parent: ?*Scope,
19 ref_count: std.atomic.Int(usize),
20
21 /// Thread-safe
22 pub fn ref(base: *Scope) void {
23 _ = base.ref_count.incr();
24 }
25
26 /// Thread-safe
27 pub fn deref(base: *Scope, comp: *Compilation) void {
28 if (base.ref_count.decr() == 1) {
29 if (base.parent) |parent| parent.deref(comp);
30 switch (base.id) {
31 Id.Root => @fieldParentPtr(Root, "base", base).destroy(comp),
32 Id.Decls => @fieldParentPtr(Decls, "base", base).destroy(comp),
33 Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp),
34 Id.FnDef => @fieldParentPtr(FnDef, "base", base).destroy(comp),
35 Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),
36 Id.Defer => @fieldParentPtr(Defer, "base", base).destroy(comp),
37 Id.DeferExpr => @fieldParentPtr(DeferExpr, "base", base).destroy(comp),
38 Id.Var => @fieldParentPtr(Var, "base", base).destroy(comp),
39 }
40 }
41 }
42
43 pub fn findRoot(base: *Scope) *Root {
44 var scope = base;
45 while (scope.parent) |parent| {
46 scope = parent;
47 }
48 assert(scope.id == Id.Root);
49 return @fieldParentPtr(Root, "base", scope);
50 }
51
52 pub fn findFnDef(base: *Scope) ?*FnDef {
53 var scope = base;
54 while (true) {
55 switch (scope.id) {
56 Id.FnDef => return @fieldParentPtr(FnDef, "base", scope),
57 Id.Root, Id.Decls => return null,
58
59 Id.Block,
60 Id.Defer,
61 Id.DeferExpr,
62 Id.CompTime,
63 Id.Var,
64 => scope = scope.parent.?,
65 }
66 }
67 }
68
69 pub fn findDeferExpr(base: *Scope) ?*DeferExpr {
70 var scope = base;
71 while (true) {
72 switch (scope.id) {
73 Id.DeferExpr => return @fieldParentPtr(DeferExpr, "base", scope),
74
75 Id.FnDef,
76 Id.Decls,
77 => return null,
78
79 Id.Block,
80 Id.Defer,
81 Id.CompTime,
82 Id.Root,
83 Id.Var,
84 => scope = scope.parent orelse return null,
85 }
86 }
87 }
88
89 fn init(base: *Scope, id: Id, parent: *Scope) void {
90 base.* = Scope{
91 .id = id,
92 .parent = parent,
93 .ref_count = std.atomic.Int(usize).init(1),
94 };
95 parent.ref();
96 }
497
598 pub const Id = enum {
99 Root,
6100 Decls,
7101 Block,
8 Defer,
9 DeferExpr,
10 VarDecl,
11 CImport,
12 Loop,
13102 FnDef,
14103 CompTime,
104 Defer,
105 DeferExpr,
106 Var,
107 };
108
109 pub const Root = struct {
110 base: Scope,
111 tree: *ast.Tree,
112 realpath: []const u8,
113
114 /// Creates a Root scope with 1 reference
115 /// Takes ownership of realpath
116 /// Takes ownership of tree, will deinit and destroy when done.
117 pub fn create(comp: *Compilation, tree: *ast.Tree, realpath: []u8) !*Root {
118 const self = try comp.gpa().createOne(Root);
119 self.* = Root{
120 .base = Scope{
121 .id = Id.Root,
122 .parent = null,
123 .ref_count = std.atomic.Int(usize).init(1),
124 },
125 .tree = tree,
126 .realpath = realpath,
127 };
128
129 return self;
130 }
131
132 pub fn destroy(self: *Root, comp: *Compilation) void {
133 comp.gpa().free(self.tree.source);
134 self.tree.deinit();
135 comp.gpa().destroy(self.tree);
136 comp.gpa().free(self.realpath);
137 comp.gpa().destroy(self);
138 }
139 };
140
141 pub const Decls = struct {
142 base: Scope,
143
144 /// The lock must be respected for writing. However once name_future resolves,
145 /// readers can freely access it.
146 table: event.Locked(Decl.Table),
147
148 /// Once this future is resolved, the table is complete and available for unlocked
149 /// read-only access. It does not mean all the decls are resolved; it means only that
150 /// the table has all the names. Each decl in the table has its own resolution state.
151 name_future: event.Future(void),
152
153 /// Creates a Decls scope with 1 reference
154 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
155 const self = try comp.gpa().createOne(Decls);
156 self.* = Decls{
157 .base = undefined,
158 .table = event.Locked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),
159 .name_future = event.Future(void).init(comp.loop),
160 };
161 self.base.init(Id.Decls, parent);
162 return self;
163 }
164
165 pub fn destroy(self: *Decls, comp: *Compilation) void {
166 self.table.deinit();
167 comp.gpa().destroy(self);
168 }
169
170 pub async fn getTableReadOnly(self: *Decls) *Decl.Table {
171 _ = await (async self.name_future.get() catch unreachable);
172 return &self.table.private_data;
173 }
174 };
175
176 pub const Block = struct {
177 base: Scope,
178 incoming_values: std.ArrayList(*ir.Inst),
179 incoming_blocks: std.ArrayList(*ir.BasicBlock),
180 end_block: *ir.BasicBlock,
181 is_comptime: *ir.Inst,
182
183 safety: Safety,
184
185 const Safety = union(enum) {
186 Auto,
187 Manual: Manual,
188
189 const Manual = struct {
190 /// the source span that disabled the safety value
191 span: Span,
192
193 /// whether safety is enabled
194 enabled: bool,
195 };
196
197 fn get(self: Safety, comp: *Compilation) bool {
198 return switch (self) {
199 Safety.Auto => switch (comp.build_mode) {
200 builtin.Mode.Debug,
201 builtin.Mode.ReleaseSafe,
202 => true,
203 builtin.Mode.ReleaseFast,
204 builtin.Mode.ReleaseSmall,
205 => false,
206 },
207 @TagType(Safety).Manual => |man| man.enabled,
208 };
209 }
210 };
211
212 /// Creates a Block scope with 1 reference
213 pub fn create(comp: *Compilation, parent: *Scope) !*Block {
214 const self = try comp.gpa().createOne(Block);
215 self.* = Block{
216 .base = undefined,
217 .incoming_values = undefined,
218 .incoming_blocks = undefined,
219 .end_block = undefined,
220 .is_comptime = undefined,
221 .safety = Safety.Auto,
222 };
223 self.base.init(Id.Block, parent);
224 return self;
225 }
226
227 pub fn destroy(self: *Block, comp: *Compilation) void {
228 comp.gpa().destroy(self);
229 }
230 };
231
232 pub const FnDef = struct {
233 base: Scope,
234
235 /// This reference is not counted so that the scope can get destroyed with the function
236 fn_val: ?*Value.Fn,
237
238 /// Creates a FnDef scope with 1 reference
239 /// Must set the fn_val later
240 pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
241 const self = try comp.gpa().createOne(FnDef);
242 self.* = FnDef{
243 .base = undefined,
244 .fn_val = null,
245 };
246 self.base.init(Id.FnDef, parent);
247 return self;
248 }
249
250 pub fn destroy(self: *FnDef, comp: *Compilation) void {
251 comp.gpa().destroy(self);
252 }
253 };
254
255 pub const CompTime = struct {
256 base: Scope,
257
258 /// Creates a CompTime scope with 1 reference
259 pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {
260 const self = try comp.gpa().createOne(CompTime);
261 self.* = CompTime{ .base = undefined };
262 self.base.init(Id.CompTime, parent);
263 return self;
264 }
265
266 pub fn destroy(self: *CompTime, comp: *Compilation) void {
267 comp.gpa().destroy(self);
268 }
269 };
270
271 pub const Defer = struct {
272 base: Scope,
273 defer_expr_scope: *DeferExpr,
274 kind: Kind,
275
276 pub const Kind = enum {
277 ScopeExit,
278 ErrorExit,
279 };
280
281 /// Creates a Defer scope with 1 reference
282 pub fn create(
283 comp: *Compilation,
284 parent: *Scope,
285 kind: Kind,
286 defer_expr_scope: *DeferExpr,
287 ) !*Defer {
288 const self = try comp.gpa().createOne(Defer);
289 self.* = Defer{
290 .base = undefined,
291 .defer_expr_scope = defer_expr_scope,
292 .kind = kind,
293 };
294 self.base.init(Id.Defer, parent);
295 defer_expr_scope.base.ref();
296 return self;
297 }
298
299 pub fn destroy(self: *Defer, comp: *Compilation) void {
300 self.defer_expr_scope.base.deref(comp);
301 comp.gpa().destroy(self);
302 }
303 };
304
305 pub const DeferExpr = struct {
306 base: Scope,
307 expr_node: *ast.Node,
308 reported_err: bool,
309
310 /// Creates a DeferExpr scope with 1 reference
311 pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {
312 const self = try comp.gpa().createOne(DeferExpr);
313 self.* = DeferExpr{
314 .base = undefined,
315 .expr_node = expr_node,
316 .reported_err = false,
317 };
318 self.base.init(Id.DeferExpr, parent);
319 return self;
320 }
321
322 pub fn destroy(self: *DeferExpr, comp: *Compilation) void {
323 comp.gpa().destroy(self);
324 }
325 };
326
327 pub const Var = struct {
328 base: Scope,
329 name: []const u8,
330 src_node: *ast.Node,
331 data: Data,
332
333 pub const Data = union(enum) {
334 Param: Param,
335 Const: *Value,
336 };
337
338 pub const Param = struct {
339 index: usize,
340 typ: *Type,
341 llvm_value: llvm.ValueRef,
342 };
343
344 pub fn createParam(
345 comp: *Compilation,
346 parent: *Scope,
347 name: []const u8,
348 src_node: *ast.Node,
349 param_index: usize,
350 param_type: *Type,
351 ) !*Var {
352 const self = try create(comp, parent, name, src_node);
353 self.data = Data{
354 .Param = Param{
355 .index = param_index,
356 .typ = param_type,
357 .llvm_value = undefined,
358 },
359 };
360 return self;
361 }
362
363 pub fn createConst(
364 comp: *Compilation,
365 parent: *Scope,
366 name: []const u8,
367 src_node: *ast.Node,
368 value: *Value,
369 ) !*Var {
370 const self = try create(comp, parent, name, src_node);
371 self.data = Data{ .Const = value };
372 value.ref();
373 return self;
374 }
375
376 fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var {
377 const self = try comp.gpa().createOne(Var);
378 self.* = Var{
379 .base = undefined,
380 .name = name,
381 .src_node = src_node,
382 .data = undefined,
383 };
384 self.base.init(Id.Var, parent);
385 return self;
386 }
387
388 pub fn destroy(self: *Var, comp: *Compilation) void {
389 switch (self.data) {
390 Data.Param => {},
391 Data.Const => |value| value.deref(comp),
392 }
393 comp.gpa().destroy(self);
394 }
15395 };
16396};
src-self-hosted/target.zig+529-27
......@@ -1,60 +1,562 @@
1const std = @import("std");
12const builtin = @import("builtin");
2const c = @import("c.zig");
3const llvm = @import("llvm.zig");
4const CInt = @import("c_int.zig").CInt;
35
4pub const CrossTarget = struct {
5 arch: builtin.Arch,
6 os: builtin.Os,
7 environ: builtin.Environ,
6pub const FloatAbi = enum {
7 Hard,
8 Soft,
9 SoftFp,
810};
911
1012pub const Target = union(enum) {
1113 Native,
12 Cross: CrossTarget,
14 Cross: Cross,
1315
14 pub fn oFileExt(self: &const Target) []const u8 {
15 const environ = switch (*self) {
16 Target.Native => builtin.environ,
17 Target.Cross => |t| t.environ,
18 };
19 return switch (environ) {
20 builtin.Environ.msvc => ".obj",
16 pub const Cross = struct {
17 arch: builtin.Arch,
18 os: builtin.Os,
19 environ: builtin.Environ,
20 object_format: builtin.ObjectFormat,
21 };
22
23 pub fn objFileExt(self: Target) []const u8 {
24 return switch (self.getObjectFormat()) {
25 builtin.ObjectFormat.coff => ".obj",
2126 else => ".o",
2227 };
2328 }
2429
25 pub fn exeFileExt(self: &const Target) []const u8 {
30 pub fn exeFileExt(self: Target) []const u8 {
2631 return switch (self.getOs()) {
2732 builtin.Os.windows => ".exe",
2833 else => "",
2934 };
3035 }
3136
32 pub fn getOs(self: &const Target) builtin.Os {
33 return switch (*self) {
37 pub fn libFileExt(self: Target, is_static: bool) []const u8 {
38 return switch (self.getOs()) {
39 builtin.Os.windows => if (is_static) ".lib" else ".dll",
40 else => if (is_static) ".a" else ".so",
41 };
42 }
43
44 pub fn getOs(self: Target) builtin.Os {
45 return switch (self) {
3446 Target.Native => builtin.os,
35 Target.Cross => |t| t.os,
47 @TagType(Target).Cross => |t| t.os,
48 };
49 }
50
51 pub fn getArch(self: Target) builtin.Arch {
52 return switch (self) {
53 Target.Native => builtin.arch,
54 @TagType(Target).Cross => |t| t.arch,
55 };
56 }
57
58 pub fn getEnviron(self: Target) builtin.Environ {
59 return switch (self) {
60 Target.Native => builtin.environ,
61 @TagType(Target).Cross => |t| t.environ,
62 };
63 }
64
65 pub fn getObjectFormat(self: Target) builtin.ObjectFormat {
66 return switch (self) {
67 Target.Native => builtin.object_format,
68 @TagType(Target).Cross => |t| t.object_format,
69 };
70 }
71
72 pub fn isWasm(self: Target) bool {
73 return switch (self.getArch()) {
74 builtin.Arch.wasm32, builtin.Arch.wasm64 => true,
75 else => false,
3676 };
3777 }
3878
39 pub fn isDarwin(self: &const Target) bool {
79 pub fn isDarwin(self: Target) bool {
4080 return switch (self.getOs()) {
4181 builtin.Os.ios, builtin.Os.macosx => true,
4282 else => false,
4383 };
4484 }
4585
46 pub fn isWindows(self: &const Target) bool {
86 pub fn isWindows(self: Target) bool {
4787 return switch (self.getOs()) {
4888 builtin.Os.windows => true,
4989 else => false,
5090 };
5191 }
52};
5392
54pub fn initializeAll() void {
55 c.LLVMInitializeAllTargets();
56 c.LLVMInitializeAllTargetInfos();
57 c.LLVMInitializeAllTargetMCs();
58 c.LLVMInitializeAllAsmPrinters();
59 c.LLVMInitializeAllAsmParsers();
60}
93 /// TODO expose the arch and subarch separately
94 pub fn isArmOrThumb(self: Target) bool {
95 return switch (self.getArch()) {
96 builtin.Arch.armv8_3a,
97 builtin.Arch.armv8_2a,
98 builtin.Arch.armv8_1a,
99 builtin.Arch.armv8,
100 builtin.Arch.armv8r,
101 builtin.Arch.armv8m_baseline,
102 builtin.Arch.armv8m_mainline,
103 builtin.Arch.armv7,
104 builtin.Arch.armv7em,
105 builtin.Arch.armv7m,
106 builtin.Arch.armv7s,
107 builtin.Arch.armv7k,
108 builtin.Arch.armv7ve,
109 builtin.Arch.armv6,
110 builtin.Arch.armv6m,
111 builtin.Arch.armv6k,
112 builtin.Arch.armv6t2,
113 builtin.Arch.armv5,
114 builtin.Arch.armv5te,
115 builtin.Arch.armv4t,
116 builtin.Arch.armebv8_3a,
117 builtin.Arch.armebv8_2a,
118 builtin.Arch.armebv8_1a,
119 builtin.Arch.armebv8,
120 builtin.Arch.armebv8r,
121 builtin.Arch.armebv8m_baseline,
122 builtin.Arch.armebv8m_mainline,
123 builtin.Arch.armebv7,
124 builtin.Arch.armebv7em,
125 builtin.Arch.armebv7m,
126 builtin.Arch.armebv7s,
127 builtin.Arch.armebv7k,
128 builtin.Arch.armebv7ve,
129 builtin.Arch.armebv6,
130 builtin.Arch.armebv6m,
131 builtin.Arch.armebv6k,
132 builtin.Arch.armebv6t2,
133 builtin.Arch.armebv5,
134 builtin.Arch.armebv5te,
135 builtin.Arch.armebv4t,
136 builtin.Arch.thumb,
137 builtin.Arch.thumbeb,
138 => true,
139 else => false,
140 };
141 }
142
143 pub fn initializeAll() void {
144 llvm.InitializeAllTargets();
145 llvm.InitializeAllTargetInfos();
146 llvm.InitializeAllTargetMCs();
147 llvm.InitializeAllAsmPrinters();
148 llvm.InitializeAllAsmParsers();
149 }
150
151 pub fn getTriple(self: Target, allocator: *std.mem.Allocator) !std.Buffer {
152 var result = try std.Buffer.initSize(allocator, 0);
153 errdefer result.deinit();
154
155 // LLVM WebAssembly output support requires the target to be activated at
156 // build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
157 //
158 // LLVM determines the output format based on the environment suffix,
159 // defaulting to an object based on the architecture. The default format in
160 // LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
161 // explicitly set this ourself in order for it to work.
162 //
163 // This is fixed in LLVM 7 and you will be able to get wasm output by
164 // using the target triple `wasm32-unknown-unknown-unknown`.
165 const env_name = if (self.isWasm()) "wasm" else @tagName(self.getEnviron());
166
167 var out = &std.io.BufferOutStream.init(&result).stream;
168 try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name);
169
170 return result;
171 }
172
173 pub fn is64bit(self: Target) bool {
174 return self.getArchPtrBitWidth() == 64;
175 }
176
177 pub fn getArchPtrBitWidth(self: Target) u32 {
178 switch (self.getArch()) {
179 builtin.Arch.avr,
180 builtin.Arch.msp430,
181 => return 16,
182
183 builtin.Arch.arc,
184 builtin.Arch.armv8_3a,
185 builtin.Arch.armv8_2a,
186 builtin.Arch.armv8_1a,
187 builtin.Arch.armv8,
188 builtin.Arch.armv8r,
189 builtin.Arch.armv8m_baseline,
190 builtin.Arch.armv8m_mainline,
191 builtin.Arch.armv7,
192 builtin.Arch.armv7em,
193 builtin.Arch.armv7m,
194 builtin.Arch.armv7s,
195 builtin.Arch.armv7k,
196 builtin.Arch.armv7ve,
197 builtin.Arch.armv6,
198 builtin.Arch.armv6m,
199 builtin.Arch.armv6k,
200 builtin.Arch.armv6t2,
201 builtin.Arch.armv5,
202 builtin.Arch.armv5te,
203 builtin.Arch.armv4t,
204 builtin.Arch.armebv8_3a,
205 builtin.Arch.armebv8_2a,
206 builtin.Arch.armebv8_1a,
207 builtin.Arch.armebv8,
208 builtin.Arch.armebv8r,
209 builtin.Arch.armebv8m_baseline,
210 builtin.Arch.armebv8m_mainline,
211 builtin.Arch.armebv7,
212 builtin.Arch.armebv7em,
213 builtin.Arch.armebv7m,
214 builtin.Arch.armebv7s,
215 builtin.Arch.armebv7k,
216 builtin.Arch.armebv7ve,
217 builtin.Arch.armebv6,
218 builtin.Arch.armebv6m,
219 builtin.Arch.armebv6k,
220 builtin.Arch.armebv6t2,
221 builtin.Arch.armebv5,
222 builtin.Arch.armebv5te,
223 builtin.Arch.armebv4t,
224 builtin.Arch.hexagon,
225 builtin.Arch.le32,
226 builtin.Arch.mips,
227 builtin.Arch.mipsel,
228 builtin.Arch.nios2,
229 builtin.Arch.powerpc,
230 builtin.Arch.r600,
231 builtin.Arch.riscv32,
232 builtin.Arch.sparc,
233 builtin.Arch.sparcel,
234 builtin.Arch.tce,
235 builtin.Arch.tcele,
236 builtin.Arch.thumb,
237 builtin.Arch.thumbeb,
238 builtin.Arch.i386,
239 builtin.Arch.xcore,
240 builtin.Arch.nvptx,
241 builtin.Arch.amdil,
242 builtin.Arch.hsail,
243 builtin.Arch.spir,
244 builtin.Arch.kalimbav3,
245 builtin.Arch.kalimbav4,
246 builtin.Arch.kalimbav5,
247 builtin.Arch.shave,
248 builtin.Arch.lanai,
249 builtin.Arch.wasm32,
250 builtin.Arch.renderscript32,
251 => return 32,
252
253 builtin.Arch.aarch64,
254 builtin.Arch.aarch64_be,
255 builtin.Arch.mips64,
256 builtin.Arch.mips64el,
257 builtin.Arch.powerpc64,
258 builtin.Arch.powerpc64le,
259 builtin.Arch.riscv64,
260 builtin.Arch.x86_64,
261 builtin.Arch.nvptx64,
262 builtin.Arch.le64,
263 builtin.Arch.amdil64,
264 builtin.Arch.hsail64,
265 builtin.Arch.spir64,
266 builtin.Arch.wasm64,
267 builtin.Arch.renderscript64,
268 builtin.Arch.amdgcn,
269 builtin.Arch.bpfel,
270 builtin.Arch.bpfeb,
271 builtin.Arch.sparcv9,
272 builtin.Arch.s390x,
273 => return 64,
274 }
275 }
276
277 pub fn getFloatAbi(self: Target) FloatAbi {
278 return switch (self.getEnviron()) {
279 builtin.Environ.gnueabihf,
280 builtin.Environ.eabihf,
281 builtin.Environ.musleabihf,
282 => FloatAbi.Hard,
283 else => FloatAbi.Soft,
284 };
285 }
286
287 pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
288 const env = self.getEnviron();
289 const arch = self.getArch();
290 switch (env) {
291 builtin.Environ.android => {
292 if (self.is64bit()) {
293 return "/system/bin/linker64";
294 } else {
295 return "/system/bin/linker";
296 }
297 },
298 builtin.Environ.gnux32 => {
299 if (arch == builtin.Arch.x86_64) {
300 return "/libx32/ld-linux-x32.so.2";
301 }
302 },
303 builtin.Environ.musl,
304 builtin.Environ.musleabi,
305 builtin.Environ.musleabihf,
306 => {
307 if (arch == builtin.Arch.x86_64) {
308 return "/lib/ld-musl-x86_64.so.1";
309 }
310 },
311 else => {},
312 }
313 switch (arch) {
314 builtin.Arch.i386,
315 builtin.Arch.sparc,
316 builtin.Arch.sparcel,
317 => return "/lib/ld-linux.so.2",
318
319 builtin.Arch.aarch64 => return "/lib/ld-linux-aarch64.so.1",
320 builtin.Arch.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
321
322 builtin.Arch.armv8_3a,
323 builtin.Arch.armv8_2a,
324 builtin.Arch.armv8_1a,
325 builtin.Arch.armv8,
326 builtin.Arch.armv8r,
327 builtin.Arch.armv8m_baseline,
328 builtin.Arch.armv8m_mainline,
329 builtin.Arch.armv7,
330 builtin.Arch.armv7em,
331 builtin.Arch.armv7m,
332 builtin.Arch.armv7s,
333 builtin.Arch.armv7k,
334 builtin.Arch.armv7ve,
335 builtin.Arch.armv6,
336 builtin.Arch.armv6m,
337 builtin.Arch.armv6k,
338 builtin.Arch.armv6t2,
339 builtin.Arch.armv5,
340 builtin.Arch.armv5te,
341 builtin.Arch.armv4t,
342 builtin.Arch.thumb,
343 => return switch (self.getFloatAbi()) {
344 FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
345 else => return "/lib/ld-linux.so.3",
346 },
347
348 builtin.Arch.armebv8_3a,
349 builtin.Arch.armebv8_2a,
350 builtin.Arch.armebv8_1a,
351 builtin.Arch.armebv8,
352 builtin.Arch.armebv8r,
353 builtin.Arch.armebv8m_baseline,
354 builtin.Arch.armebv8m_mainline,
355 builtin.Arch.armebv7,
356 builtin.Arch.armebv7em,
357 builtin.Arch.armebv7m,
358 builtin.Arch.armebv7s,
359 builtin.Arch.armebv7k,
360 builtin.Arch.armebv7ve,
361 builtin.Arch.armebv6,
362 builtin.Arch.armebv6m,
363 builtin.Arch.armebv6k,
364 builtin.Arch.armebv6t2,
365 builtin.Arch.armebv5,
366 builtin.Arch.armebv5te,
367 builtin.Arch.armebv4t,
368 builtin.Arch.thumbeb,
369 => return switch (self.getFloatAbi()) {
370 FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
371 else => return "/lib/ld-linux.so.3",
372 },
373
374 builtin.Arch.mips,
375 builtin.Arch.mipsel,
376 builtin.Arch.mips64,
377 builtin.Arch.mips64el,
378 => return null,
379
380 builtin.Arch.powerpc => return "/lib/ld.so.1",
381 builtin.Arch.powerpc64 => return "/lib64/ld64.so.2",
382 builtin.Arch.powerpc64le => return "/lib64/ld64.so.2",
383 builtin.Arch.s390x => return "/lib64/ld64.so.1",
384 builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2",
385 builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2",
386
387 builtin.Arch.arc,
388 builtin.Arch.avr,
389 builtin.Arch.bpfel,
390 builtin.Arch.bpfeb,
391 builtin.Arch.hexagon,
392 builtin.Arch.msp430,
393 builtin.Arch.nios2,
394 builtin.Arch.r600,
395 builtin.Arch.amdgcn,
396 builtin.Arch.riscv32,
397 builtin.Arch.riscv64,
398 builtin.Arch.tce,
399 builtin.Arch.tcele,
400 builtin.Arch.xcore,
401 builtin.Arch.nvptx,
402 builtin.Arch.nvptx64,
403 builtin.Arch.le32,
404 builtin.Arch.le64,
405 builtin.Arch.amdil,
406 builtin.Arch.amdil64,
407 builtin.Arch.hsail,
408 builtin.Arch.hsail64,
409 builtin.Arch.spir,
410 builtin.Arch.spir64,
411 builtin.Arch.kalimbav3,
412 builtin.Arch.kalimbav4,
413 builtin.Arch.kalimbav5,
414 builtin.Arch.shave,
415 builtin.Arch.lanai,
416 builtin.Arch.wasm32,
417 builtin.Arch.wasm64,
418 builtin.Arch.renderscript32,
419 builtin.Arch.renderscript64,
420 => return null,
421 }
422 }
423
424 pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
425 var result: llvm.TargetRef = undefined;
426 var err_msg: [*]u8 = undefined;
427 if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
428 std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
429 return error.UnsupportedTarget;
430 }
431 return result;
432 }
433
434 pub fn cIntTypeSizeInBits(self: Target, id: CInt.Id) u32 {
435 const arch = self.getArch();
436 switch (self.getOs()) {
437 builtin.Os.freestanding => switch (self.getArch()) {
438 builtin.Arch.msp430 => switch (id) {
439 CInt.Id.Short,
440 CInt.Id.UShort,
441 CInt.Id.Int,
442 CInt.Id.UInt,
443 => return 16,
444 CInt.Id.Long,
445 CInt.Id.ULong,
446 => return 32,
447 CInt.Id.LongLong,
448 CInt.Id.ULongLong,
449 => return 64,
450 },
451 else => switch (id) {
452 CInt.Id.Short,
453 CInt.Id.UShort,
454 => return 16,
455 CInt.Id.Int,
456 CInt.Id.UInt,
457 => return 32,
458 CInt.Id.Long,
459 CInt.Id.ULong,
460 => return self.getArchPtrBitWidth(),
461 CInt.Id.LongLong,
462 CInt.Id.ULongLong,
463 => return 64,
464 },
465 },
466
467 builtin.Os.linux,
468 builtin.Os.macosx,
469 builtin.Os.openbsd,
470 builtin.Os.zen,
471 => switch (id) {
472 CInt.Id.Short,
473 CInt.Id.UShort,
474 => return 16,
475 CInt.Id.Int,
476 CInt.Id.UInt,
477 => return 32,
478 CInt.Id.Long,
479 CInt.Id.ULong,
480 => return self.getArchPtrBitWidth(),
481 CInt.Id.LongLong,
482 CInt.Id.ULongLong,
483 => return 64,
484 },
485
486 builtin.Os.windows => switch (id) {
487 CInt.Id.Short,
488 CInt.Id.UShort,
489 => return 16,
490 CInt.Id.Int,
491 CInt.Id.UInt,
492 => return 32,
493 CInt.Id.Long,
494 CInt.Id.ULong,
495 CInt.Id.LongLong,
496 CInt.Id.ULongLong,
497 => return 64,
498 },
499
500 builtin.Os.ananas,
501 builtin.Os.cloudabi,
502 builtin.Os.dragonfly,
503 builtin.Os.freebsd,
504 builtin.Os.fuchsia,
505 builtin.Os.ios,
506 builtin.Os.kfreebsd,
507 builtin.Os.lv2,
508 builtin.Os.netbsd,
509 builtin.Os.solaris,
510 builtin.Os.haiku,
511 builtin.Os.minix,
512 builtin.Os.rtems,
513 builtin.Os.nacl,
514 builtin.Os.cnk,
515 builtin.Os.aix,
516 builtin.Os.cuda,
517 builtin.Os.nvcl,
518 builtin.Os.amdhsa,
519 builtin.Os.ps4,
520 builtin.Os.elfiamcu,
521 builtin.Os.tvos,
522 builtin.Os.watchos,
523 builtin.Os.mesa3d,
524 builtin.Os.contiki,
525 builtin.Os.amdpal,
526 => @panic("TODO specify the C integer type sizes for this OS"),
527 }
528 }
529
530 pub fn getDarwinArchString(self: Target) []const u8 {
531 const arch = self.getArch();
532 switch (arch) {
533 builtin.Arch.aarch64 => return "arm64",
534 builtin.Arch.thumb,
535 builtin.Arch.armv8_3a,
536 builtin.Arch.armv8_2a,
537 builtin.Arch.armv8_1a,
538 builtin.Arch.armv8,
539 builtin.Arch.armv8r,
540 builtin.Arch.armv8m_baseline,
541 builtin.Arch.armv8m_mainline,
542 builtin.Arch.armv7,
543 builtin.Arch.armv7em,
544 builtin.Arch.armv7m,
545 builtin.Arch.armv7s,
546 builtin.Arch.armv7k,
547 builtin.Arch.armv7ve,
548 builtin.Arch.armv6,
549 builtin.Arch.armv6m,
550 builtin.Arch.armv6k,
551 builtin.Arch.armv6t2,
552 builtin.Arch.armv5,
553 builtin.Arch.armv5te,
554 builtin.Arch.armv4t,
555 => return "arm",
556 builtin.Arch.powerpc => return "ppc",
557 builtin.Arch.powerpc64 => return "ppc64",
558 builtin.Arch.powerpc64le => return "ppc64le",
559 else => return @tagName(arch),
560 }
561 }
562};
src-self-hosted/test.zig created+243
......@@ -0,0 +1,243 @@
1const std = @import("std");
2const mem = std.mem;
3const builtin = @import("builtin");
4const Target = @import("target.zig").Target;
5const Compilation = @import("compilation.zig").Compilation;
6const introspect = @import("introspect.zig");
7const assertOrPanic = std.debug.assertOrPanic;
8const errmsg = @import("errmsg.zig");
9const EventLoopLocal = @import("compilation.zig").EventLoopLocal;
10
11var ctx: TestContext = undefined;
12
13test "stage2" {
14 try ctx.init();
15 defer ctx.deinit();
16
17 try @import("../test/stage2/compile_errors.zig").addCases(&ctx);
18 try @import("../test/stage2/compare_output.zig").addCases(&ctx);
19
20 try ctx.run();
21}
22
23const file1 = "1.zig";
24const allocator = std.heap.c_allocator;
25
26pub const TestContext = struct {
27 loop: std.event.Loop,
28 event_loop_local: EventLoopLocal,
29 zig_lib_dir: []u8,
30 file_index: std.atomic.Int(usize),
31 group: std.event.Group(error!void),
32 any_err: error!void,
33
34 const tmp_dir_name = "stage2_test_tmp";
35
36 fn init(self: *TestContext) !void {
37 self.* = TestContext{
38 .any_err = {},
39 .loop = undefined,
40 .event_loop_local = undefined,
41 .zig_lib_dir = undefined,
42 .group = undefined,
43 .file_index = std.atomic.Int(usize).init(0),
44 };
45
46 try self.loop.initMultiThreaded(allocator);
47 errdefer self.loop.deinit();
48
49 self.event_loop_local = try EventLoopLocal.init(&self.loop);
50 errdefer self.event_loop_local.deinit();
51
52 self.group = std.event.Group(error!void).init(&self.loop);
53 errdefer self.group.cancelAll();
54
55 self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);
56 errdefer allocator.free(self.zig_lib_dir);
57
58 try std.os.makePath(allocator, tmp_dir_name);
59 errdefer std.os.deleteTree(allocator, tmp_dir_name) catch {};
60 }
61
62 fn deinit(self: *TestContext) void {
63 std.os.deleteTree(allocator, tmp_dir_name) catch {};
64 allocator.free(self.zig_lib_dir);
65 self.event_loop_local.deinit();
66 self.loop.deinit();
67 }
68
69 fn run(self: *TestContext) !void {
70 const handle = try self.loop.call(waitForGroup, self);
71 defer cancel handle;
72 self.loop.run();
73 return self.any_err;
74 }
75
76 async fn waitForGroup(self: *TestContext) void {
77 self.any_err = await (async self.group.wait() catch unreachable);
78 }
79
80 fn testCompileError(
81 self: *TestContext,
82 source: []const u8,
83 path: []const u8,
84 line: usize,
85 column: usize,
86 msg: []const u8,
87 ) !void {
88 var file_index_buf: [20]u8 = undefined;
89 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
90 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
91
92 if (std.os.path.dirname(file1_path)) |dirname| {
93 try std.os.makePath(allocator, dirname);
94 }
95
96 // TODO async I/O
97 try std.io.writeFile(allocator, file1_path, source);
98
99 var comp = try Compilation.create(
100 &self.event_loop_local,
101 "test",
102 file1_path,
103 Target.Native,
104 Compilation.Kind.Obj,
105 builtin.Mode.Debug,
106 true, // is_static
107 self.zig_lib_dir,
108 );
109 errdefer comp.destroy();
110
111 try comp.build();
112
113 try self.group.call(getModuleEvent, comp, source, path, line, column, msg);
114 }
115
116 fn testCompareOutputLibC(
117 self: *TestContext,
118 source: []const u8,
119 expected_output: []const u8,
120 ) !void {
121 var file_index_buf: [20]u8 = undefined;
122 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
123 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
124
125 const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt());
126 if (std.os.path.dirname(file1_path)) |dirname| {
127 try std.os.makePath(allocator, dirname);
128 }
129
130 // TODO async I/O
131 try std.io.writeFile(allocator, file1_path, source);
132
133 var comp = try Compilation.create(
134 &self.event_loop_local,
135 "test",
136 file1_path,
137 Target.Native,
138 Compilation.Kind.Exe,
139 builtin.Mode.Debug,
140 false,
141 self.zig_lib_dir,
142 );
143 errdefer comp.destroy();
144
145 _ = try comp.addLinkLib("c", true);
146 comp.link_out_file = output_file;
147 try comp.build();
148
149 try self.group.call(getModuleEventSuccess, comp, output_file, expected_output);
150 }
151
152 async fn getModuleEventSuccess(
153 comp: *Compilation,
154 exe_file: []const u8,
155 expected_output: []const u8,
156 ) !void {
157 // TODO this should not be necessary
158 const exe_file_2 = try std.mem.dupe(allocator, u8, exe_file);
159
160 defer comp.destroy();
161 const build_event = await (async comp.events.get() catch unreachable);
162
163 switch (build_event) {
164 Compilation.Event.Ok => {
165 const argv = []const []const u8{exe_file_2};
166 // TODO use event loop
167 const child = try std.os.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
168 switch (child.term) {
169 std.os.ChildProcess.Term.Exited => |code| {
170 if (code != 0) {
171 return error.BadReturnCode;
172 }
173 },
174 else => {
175 return error.Crashed;
176 },
177 }
178 if (!mem.eql(u8, child.stdout, expected_output)) {
179 return error.OutputMismatch;
180 }
181 },
182 Compilation.Event.Error => |err| return err,
183 Compilation.Event.Fail => |msgs| {
184 var stderr = try std.io.getStdErr();
185 try stderr.write("build incorrectly failed:\n");
186 for (msgs) |msg| {
187 defer msg.destroy();
188 try msg.printToFile(&stderr, errmsg.Color.Auto);
189 }
190 },
191 }
192 }
193
194 async fn getModuleEvent(
195 comp: *Compilation,
196 source: []const u8,
197 path: []const u8,
198 line: usize,
199 column: usize,
200 text: []const u8,
201 ) !void {
202 defer comp.destroy();
203 const build_event = await (async comp.events.get() catch unreachable);
204
205 switch (build_event) {
206 Compilation.Event.Ok => {
207 @panic("build incorrectly succeeded");
208 },
209 Compilation.Event.Error => |err| {
210 @panic("build incorrectly failed");
211 },
212 Compilation.Event.Fail => |msgs| {
213 assertOrPanic(msgs.len != 0);
214 for (msgs) |msg| {
215 if (mem.endsWith(u8, msg.getRealPath(), path) and mem.eql(u8, msg.text, text)) {
216 const first_token = msg.getTree().tokens.at(msg.span.first);
217 const last_token = msg.getTree().tokens.at(msg.span.first);
218 const start_loc = msg.getTree().tokenLocationPtr(0, first_token);
219 if (start_loc.line + 1 == line and start_loc.column + 1 == column) {
220 return;
221 }
222 }
223 }
224 std.debug.warn(
225 "\n=====source:=======\n{}\n====expected:========\n{}:{}:{}: error: {}\n",
226 source,
227 path,
228 line,
229 column,
230 text,
231 );
232 std.debug.warn("\n====found:========\n");
233 var stderr = try std.io.getStdErr();
234 for (msgs) |msg| {
235 defer msg.destroy();
236 try msg.printToFile(&stderr, errmsg.Color.Auto);
237 }
238 std.debug.warn("============\n");
239 return error.TestFailed;
240 },
241 }
242 }
243};
src-self-hosted/type.zig created+1101
......@@ -0,0 +1,1101 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Scope = @import("scope.zig").Scope;
4const Compilation = @import("compilation.zig").Compilation;
5const Value = @import("value.zig").Value;
6const llvm = @import("llvm.zig");
7const event = std.event;
8const Allocator = std.mem.Allocator;
9const assert = std.debug.assert;
10
11pub const Type = struct {
12 base: Value,
13 id: Id,
14 name: []const u8,
15 abi_alignment: AbiAlignment,
16
17 pub const AbiAlignment = event.Future(error{OutOfMemory}!u32);
18
19 pub const Id = builtin.TypeId;
20
21 pub fn destroy(base: *Type, comp: *Compilation) void {
22 switch (base.id) {
23 Id.Struct => @fieldParentPtr(Struct, "base", base).destroy(comp),
24 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),
25 Id.Type => @fieldParentPtr(MetaType, "base", base).destroy(comp),
26 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),
27 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),
28 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),
29 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),
30 Id.Float => @fieldParentPtr(Float, "base", base).destroy(comp),
31 Id.Pointer => @fieldParentPtr(Pointer, "base", base).destroy(comp),
32 Id.Array => @fieldParentPtr(Array, "base", base).destroy(comp),
33 Id.ComptimeFloat => @fieldParentPtr(ComptimeFloat, "base", base).destroy(comp),
34 Id.ComptimeInt => @fieldParentPtr(ComptimeInt, "base", base).destroy(comp),
35 Id.Undefined => @fieldParentPtr(Undefined, "base", base).destroy(comp),
36 Id.Null => @fieldParentPtr(Null, "base", base).destroy(comp),
37 Id.Optional => @fieldParentPtr(Optional, "base", base).destroy(comp),
38 Id.ErrorUnion => @fieldParentPtr(ErrorUnion, "base", base).destroy(comp),
39 Id.ErrorSet => @fieldParentPtr(ErrorSet, "base", base).destroy(comp),
40 Id.Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),
41 Id.Union => @fieldParentPtr(Union, "base", base).destroy(comp),
42 Id.Namespace => @fieldParentPtr(Namespace, "base", base).destroy(comp),
43 Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp),
44 Id.BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),
45 Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
46 Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
47 Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp),
48 }
49 }
50
51 pub fn getLlvmType(
52 base: *Type,
53 allocator: *Allocator,
54 llvm_context: llvm.ContextRef,
55 ) (error{OutOfMemory}!llvm.TypeRef) {
56 switch (base.id) {
57 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
58 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
59 Id.Type => unreachable,
60 Id.Void => unreachable,
61 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(allocator, llvm_context),
62 Id.NoReturn => unreachable,
63 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(allocator, llvm_context),
64 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(allocator, llvm_context),
65 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(allocator, llvm_context),
66 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(allocator, llvm_context),
67 Id.ComptimeFloat => unreachable,
68 Id.ComptimeInt => unreachable,
69 Id.Undefined => unreachable,
70 Id.Null => unreachable,
71 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(allocator, llvm_context),
72 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(allocator, llvm_context),
73 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
74 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
75 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
76 Id.Namespace => unreachable,
77 Id.Block => unreachable,
78 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
79 Id.ArgTuple => unreachable,
80 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
81 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
82 }
83 }
84
85 pub fn handleIsPtr(base: *Type) bool {
86 switch (base.id) {
87 Id.Type,
88 Id.ComptimeFloat,
89 Id.ComptimeInt,
90 Id.Undefined,
91 Id.Null,
92 Id.Namespace,
93 Id.Block,
94 Id.BoundFn,
95 Id.ArgTuple,
96 Id.Opaque,
97 => unreachable,
98
99 Id.NoReturn,
100 Id.Void,
101 Id.Bool,
102 Id.Int,
103 Id.Float,
104 Id.Pointer,
105 Id.ErrorSet,
106 Id.Enum,
107 Id.Fn,
108 Id.Promise,
109 => return false,
110
111 Id.Struct => @panic("TODO"),
112 Id.Array => @panic("TODO"),
113 Id.Optional => @panic("TODO"),
114 Id.ErrorUnion => @panic("TODO"),
115 Id.Union => @panic("TODO"),
116 }
117 }
118
119 pub fn hasBits(base: *Type) bool {
120 switch (base.id) {
121 Id.Type,
122 Id.ComptimeFloat,
123 Id.ComptimeInt,
124 Id.Undefined,
125 Id.Null,
126 Id.Namespace,
127 Id.Block,
128 Id.BoundFn,
129 Id.ArgTuple,
130 Id.Opaque,
131 => unreachable,
132
133 Id.Void,
134 Id.NoReturn,
135 => return false,
136
137 Id.Bool,
138 Id.Int,
139 Id.Float,
140 Id.Fn,
141 Id.Promise,
142 => return true,
143
144 Id.Pointer => {
145 const ptr_type = @fieldParentPtr(Pointer, "base", base);
146 return ptr_type.key.child_type.hasBits();
147 },
148
149 Id.ErrorSet => @panic("TODO"),
150 Id.Enum => @panic("TODO"),
151 Id.Struct => @panic("TODO"),
152 Id.Array => @panic("TODO"),
153 Id.Optional => @panic("TODO"),
154 Id.ErrorUnion => @panic("TODO"),
155 Id.Union => @panic("TODO"),
156 }
157 }
158
159 pub fn cast(base: *Type, comptime T: type) ?*T {
160 if (base.id != @field(Id, @typeName(T))) return null;
161 return @fieldParentPtr(T, "base", base);
162 }
163
164 pub fn dump(base: *const Type) void {
165 std.debug.warn("{}", @tagName(base.id));
166 }
167
168 fn init(base: *Type, comp: *Compilation, id: Id, name: []const u8) void {
169 base.* = Type{
170 .base = Value{
171 .id = Value.Id.Type,
172 .typ = &MetaType.get(comp).base,
173 .ref_count = std.atomic.Int(usize).init(1),
174 },
175 .id = id,
176 .name = name,
177 .abi_alignment = AbiAlignment.init(comp.loop),
178 };
179 }
180
181 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
182 /// Otherwise, this one will grab one from the pool and then release it.
183 pub async fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 {
184 if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
185
186 {
187 const held = try comp.event_loop_local.getAnyLlvmContext();
188 defer held.release(comp.event_loop_local);
189
190 const llvm_context = held.node.data;
191
192 base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
193 }
194 base.abi_alignment.resolve();
195 return base.abi_alignment.data;
196 }
197
198 /// If you have an llvm conext handy, you can use it here.
199 pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
200 if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
201
202 base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
203 base.abi_alignment.resolve();
204 return base.abi_alignment.data;
205 }
206
207 /// Lower level function that does the work. See getAbiAlignment.
208 async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
209 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
210 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
211 }
212
213 pub const Struct = struct {
214 base: Type,
215 decls: *Scope.Decls,
216
217 pub fn destroy(self: *Struct, comp: *Compilation) void {
218 comp.gpa().destroy(self);
219 }
220
221 pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
222 @panic("TODO");
223 }
224 };
225
226 pub const Fn = struct {
227 base: Type,
228 key: Key,
229 non_key: NonKey,
230 garbage_node: std.atomic.Stack(*Fn).Node,
231
232 pub const Kind = enum {
233 Normal,
234 Generic,
235 };
236
237 pub const NonKey = union {
238 Normal: Normal,
239 Generic: void,
240
241 pub const Normal = struct {
242 variable_list: std.ArrayList(*Scope.Var),
243 };
244 };
245
246 pub const Key = struct {
247 data: Data,
248 alignment: ?u32,
249
250 pub const Data = union(Kind) {
251 Generic: Generic,
252 Normal: Normal,
253 };
254
255 pub const Normal = struct {
256 params: []Param,
257 return_type: *Type,
258 is_var_args: bool,
259 cc: CallingConvention,
260 };
261
262 pub const Generic = struct {
263 param_count: usize,
264 cc: CC,
265
266 pub const CC = union(CallingConvention) {
267 Auto,
268 C,
269 Cold,
270 Naked,
271 Stdcall,
272 Async: *Type, // allocator type
273 };
274 };
275
276 pub fn hash(self: *const Key) u32 {
277 var result: u32 = 0;
278 result +%= hashAny(self.alignment, 0);
279 switch (self.data) {
280 Kind.Generic => |generic| {
281 result +%= hashAny(generic.param_count, 1);
282 switch (generic.cc) {
283 CallingConvention.Async => |allocator_type| result +%= hashAny(allocator_type, 2),
284 else => result +%= hashAny(CallingConvention(generic.cc), 3),
285 }
286 },
287 Kind.Normal => |normal| {
288 result +%= hashAny(normal.return_type, 4);
289 result +%= hashAny(normal.is_var_args, 5);
290 result +%= hashAny(normal.cc, 6);
291 for (normal.params) |param| {
292 result +%= hashAny(param.is_noalias, 7);
293 result +%= hashAny(param.typ, 8);
294 }
295 },
296 }
297 return result;
298 }
299
300 pub fn eql(self: *const Key, other: *const Key) bool {
301 if ((self.alignment == null) != (other.alignment == null)) return false;
302 if (self.alignment) |self_align| {
303 if (self_align != other.alignment.?) return false;
304 }
305 if (@TagType(Data)(self.data) != @TagType(Data)(other.data)) return false;
306 switch (self.data) {
307 Kind.Generic => |*self_generic| {
308 const other_generic = &other.data.Generic;
309 if (self_generic.param_count != other_generic.param_count) return false;
310 if (CallingConvention(self_generic.cc) != CallingConvention(other_generic.cc)) return false;
311 switch (self_generic.cc) {
312 CallingConvention.Async => |self_allocator_type| {
313 const other_allocator_type = other_generic.cc.Async;
314 if (self_allocator_type != other_allocator_type) return false;
315 },
316 else => {},
317 }
318 },
319 Kind.Normal => |*self_normal| {
320 const other_normal = &other.data.Normal;
321 if (self_normal.cc != other_normal.cc) return false;
322 if (self_normal.is_var_args != other_normal.is_var_args) return false;
323 if (self_normal.return_type != other_normal.return_type) return false;
324 for (self_normal.params) |*self_param, i| {
325 const other_param = &other_normal.params[i];
326 if (self_param.is_noalias != other_param.is_noalias) return false;
327 if (self_param.typ != other_param.typ) return false;
328 }
329 },
330 }
331 return true;
332 }
333
334 pub fn deref(key: Key, comp: *Compilation) void {
335 switch (key.data) {
336 Kind.Generic => |generic| {
337 switch (generic.cc) {
338 CallingConvention.Async => |allocator_type| allocator_type.base.deref(comp),
339 else => {},
340 }
341 },
342 Kind.Normal => |normal| {
343 normal.return_type.base.deref(comp);
344 for (normal.params) |param| {
345 param.typ.base.deref(comp);
346 }
347 },
348 }
349 }
350
351 pub fn ref(key: Key) void {
352 switch (key.data) {
353 Kind.Generic => |generic| {
354 switch (generic.cc) {
355 CallingConvention.Async => |allocator_type| allocator_type.base.ref(),
356 else => {},
357 }
358 },
359 Kind.Normal => |normal| {
360 normal.return_type.base.ref();
361 for (normal.params) |param| {
362 param.typ.base.ref();
363 }
364 },
365 }
366 }
367 };
368
369 pub const CallingConvention = enum {
370 Auto,
371 C,
372 Cold,
373 Naked,
374 Stdcall,
375 Async,
376 };
377
378 pub const Param = struct {
379 is_noalias: bool,
380 typ: *Type,
381 };
382
383 fn ccFnTypeStr(cc: CallingConvention) []const u8 {
384 return switch (cc) {
385 CallingConvention.Auto => "",
386 CallingConvention.C => "extern ",
387 CallingConvention.Cold => "coldcc ",
388 CallingConvention.Naked => "nakedcc ",
389 CallingConvention.Stdcall => "stdcallcc ",
390 CallingConvention.Async => unreachable,
391 };
392 }
393
394 pub fn paramCount(self: *Fn) usize {
395 return switch (self.key.data) {
396 Kind.Generic => |generic| generic.param_count,
397 Kind.Normal => |normal| normal.params.len,
398 };
399 }
400
401 /// takes ownership of key.Normal.params on success
402 pub async fn get(comp: *Compilation, key: Key) !*Fn {
403 {
404 const held = await (async comp.fn_type_table.acquire() catch unreachable);
405 defer held.release();
406
407 if (held.value.get(&key)) |entry| {
408 entry.value.base.base.ref();
409 return entry.value;
410 }
411 }
412
413 key.ref();
414 errdefer key.deref(comp);
415
416 const self = try comp.gpa().createOne(Fn);
417 self.* = Fn{
418 .base = undefined,
419 .key = key,
420 .non_key = undefined,
421 .garbage_node = undefined,
422 };
423 errdefer comp.gpa().destroy(self);
424
425 var name_buf = try std.Buffer.initSize(comp.gpa(), 0);
426 defer name_buf.deinit();
427
428 const name_stream = &std.io.BufferOutStream.init(&name_buf).stream;
429
430 switch (key.data) {
431 Kind.Generic => |generic| {
432 self.non_key = NonKey{ .Generic = {} };
433 switch (generic.cc) {
434 CallingConvention.Async => |async_allocator_type| {
435 try name_stream.print("async<{}> ", async_allocator_type.name);
436 },
437 else => {
438 const cc_str = ccFnTypeStr(generic.cc);
439 try name_stream.write(cc_str);
440 },
441 }
442 try name_stream.write("fn(");
443 var param_i: usize = 0;
444 while (param_i < generic.param_count) : (param_i += 1) {
445 const arg = if (param_i == 0) "var" else ", var";
446 try name_stream.write(arg);
447 }
448 try name_stream.write(")");
449 if (key.alignment) |alignment| {
450 try name_stream.print(" align<{}>", alignment);
451 }
452 try name_stream.write(" var");
453 },
454 Kind.Normal => |normal| {
455 self.non_key = NonKey{
456 .Normal = NonKey.Normal{ .variable_list = std.ArrayList(*Scope.Var).init(comp.gpa()) },
457 };
458 const cc_str = ccFnTypeStr(normal.cc);
459 try name_stream.print("{}fn(", cc_str);
460 for (normal.params) |param, i| {
461 if (i != 0) try name_stream.write(", ");
462 if (param.is_noalias) try name_stream.write("noalias ");
463 try name_stream.write(param.typ.name);
464 }
465 if (normal.is_var_args) {
466 if (normal.params.len != 0) try name_stream.write(", ");
467 try name_stream.write("...");
468 }
469 try name_stream.write(")");
470 if (key.alignment) |alignment| {
471 try name_stream.print(" align<{}>", alignment);
472 }
473 try name_stream.print(" {}", normal.return_type.name);
474 },
475 }
476
477 self.base.init(comp, Id.Fn, name_buf.toOwnedSlice());
478
479 {
480 const held = await (async comp.fn_type_table.acquire() catch unreachable);
481 defer held.release();
482
483 _ = try held.value.put(&self.key, self);
484 }
485 return self;
486 }
487
488 pub fn destroy(self: *Fn, comp: *Compilation) void {
489 self.key.deref(comp);
490 switch (self.key.data) {
491 Kind.Generic => {},
492 Kind.Normal => {
493 self.non_key.Normal.variable_list.deinit();
494 },
495 }
496 comp.gpa().destroy(self);
497 }
498
499 pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
500 const normal = &self.key.data.Normal;
501 const llvm_return_type = switch (normal.return_type.id) {
502 Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
503 else => try normal.return_type.getLlvmType(allocator, llvm_context),
504 };
505 const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len);
506 defer allocator.free(llvm_param_types);
507 for (llvm_param_types) |*llvm_param_type, i| {
508 llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
509 }
510
511 return llvm.FunctionType(
512 llvm_return_type,
513 llvm_param_types.ptr,
514 @intCast(c_uint, llvm_param_types.len),
515 @boolToInt(normal.is_var_args),
516 ) orelse error.OutOfMemory;
517 }
518 };
519
520 pub const MetaType = struct {
521 base: Type,
522 value: *Type,
523
524 /// Adds 1 reference to the resulting type
525 pub fn get(comp: *Compilation) *MetaType {
526 comp.meta_type.base.base.ref();
527 return comp.meta_type;
528 }
529
530 pub fn destroy(self: *MetaType, comp: *Compilation) void {
531 comp.gpa().destroy(self);
532 }
533 };
534
535 pub const Void = struct {
536 base: Type,
537
538 /// Adds 1 reference to the resulting type
539 pub fn get(comp: *Compilation) *Void {
540 comp.void_type.base.base.ref();
541 return comp.void_type;
542 }
543
544 pub fn destroy(self: *Void, comp: *Compilation) void {
545 comp.gpa().destroy(self);
546 }
547 };
548
549 pub const Bool = struct {
550 base: Type,
551
552 /// Adds 1 reference to the resulting type
553 pub fn get(comp: *Compilation) *Bool {
554 comp.bool_type.base.base.ref();
555 return comp.bool_type;
556 }
557
558 pub fn destroy(self: *Bool, comp: *Compilation) void {
559 comp.gpa().destroy(self);
560 }
561
562 pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
563 @panic("TODO");
564 }
565 };
566
567 pub const NoReturn = struct {
568 base: Type,
569
570 /// Adds 1 reference to the resulting type
571 pub fn get(comp: *Compilation) *NoReturn {
572 comp.noreturn_type.base.base.ref();
573 return comp.noreturn_type;
574 }
575
576 pub fn destroy(self: *NoReturn, comp: *Compilation) void {
577 comp.gpa().destroy(self);
578 }
579 };
580
581 pub const Int = struct {
582 base: Type,
583 key: Key,
584 garbage_node: std.atomic.Stack(*Int).Node,
585
586 pub const Key = struct {
587 bit_count: u32,
588 is_signed: bool,
589
590 pub fn hash(self: *const Key) u32 {
591 var result: u32 = 0;
592 result +%= hashAny(self.is_signed, 0);
593 result +%= hashAny(self.bit_count, 1);
594 return result;
595 }
596
597 pub fn eql(self: *const Key, other: *const Key) bool {
598 return self.bit_count == other.bit_count and self.is_signed == other.is_signed;
599 }
600 };
601
602 pub fn get_u8(comp: *Compilation) *Int {
603 comp.u8_type.base.base.ref();
604 return comp.u8_type;
605 }
606
607 pub async fn get(comp: *Compilation, key: Key) !*Int {
608 {
609 const held = await (async comp.int_type_table.acquire() catch unreachable);
610 defer held.release();
611
612 if (held.value.get(&key)) |entry| {
613 entry.value.base.base.ref();
614 return entry.value;
615 }
616 }
617
618 const self = try comp.gpa().create(Int{
619 .base = undefined,
620 .key = key,
621 .garbage_node = undefined,
622 });
623 errdefer comp.gpa().destroy(self);
624
625 const u_or_i = "ui"[@boolToInt(key.is_signed)];
626 const name = try std.fmt.allocPrint(comp.gpa(), "{c}{}", u_or_i, key.bit_count);
627 errdefer comp.gpa().free(name);
628
629 self.base.init(comp, Id.Int, name);
630
631 {
632 const held = await (async comp.int_type_table.acquire() catch unreachable);
633 defer held.release();
634
635 _ = try held.value.put(&self.key, self);
636 }
637 return self;
638 }
639
640 pub fn destroy(self: *Int, comp: *Compilation) void {
641 self.garbage_node = std.atomic.Stack(*Int).Node{
642 .data = self,
643 .next = undefined,
644 };
645 comp.registerGarbage(Int, &self.garbage_node);
646 }
647
648 pub async fn gcDestroy(self: *Int, comp: *Compilation) void {
649 {
650 const held = await (async comp.int_type_table.acquire() catch unreachable);
651 defer held.release();
652
653 _ = held.value.remove(&self.key).?;
654 }
655 // we allocated the name
656 comp.gpa().free(self.base.name);
657 comp.gpa().destroy(self);
658 }
659
660 pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
661 return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
662 }
663 };
664
665 pub const Float = struct {
666 base: Type,
667
668 pub fn destroy(self: *Float, comp: *Compilation) void {
669 comp.gpa().destroy(self);
670 }
671
672 pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
673 @panic("TODO");
674 }
675 };
676 pub const Pointer = struct {
677 base: Type,
678 key: Key,
679 garbage_node: std.atomic.Stack(*Pointer).Node,
680
681 pub const Key = struct {
682 child_type: *Type,
683 mut: Mut,
684 vol: Vol,
685 size: Size,
686 alignment: Align,
687
688 pub fn hash(self: *const Key) u32 {
689 var result: u32 = 0;
690 result +%= switch (self.alignment) {
691 Align.Abi => 0xf201c090,
692 Align.Override => |x| hashAny(x, 0),
693 };
694 result +%= hashAny(self.child_type, 1);
695 result +%= hashAny(self.mut, 2);
696 result +%= hashAny(self.vol, 3);
697 result +%= hashAny(self.size, 4);
698 return result;
699 }
700
701 pub fn eql(self: *const Key, other: *const Key) bool {
702 if (self.child_type != other.child_type or
703 self.mut != other.mut or
704 self.vol != other.vol or
705 self.size != other.size or
706 @TagType(Align)(self.alignment) != @TagType(Align)(other.alignment))
707 {
708 return false;
709 }
710 switch (self.alignment) {
711 Align.Abi => return true,
712 Align.Override => |x| return x == other.alignment.Override,
713 }
714 }
715 };
716
717 pub const Mut = enum {
718 Mut,
719 Const,
720 };
721
722 pub const Vol = enum {
723 Non,
724 Volatile,
725 };
726
727 pub const Align = union(enum) {
728 Abi,
729 Override: u32,
730 };
731
732 pub const Size = builtin.TypeInfo.Pointer.Size;
733
734 pub fn destroy(self: *Pointer, comp: *Compilation) void {
735 self.garbage_node = std.atomic.Stack(*Pointer).Node{
736 .data = self,
737 .next = undefined,
738 };
739 comp.registerGarbage(Pointer, &self.garbage_node);
740 }
741
742 pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void {
743 {
744 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
745 defer held.release();
746
747 _ = held.value.remove(&self.key).?;
748 }
749 self.key.child_type.base.deref(comp);
750 comp.gpa().destroy(self);
751 }
752
753 pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
754 switch (self.key.alignment) {
755 Align.Abi => return await (async self.key.child_type.getAbiAlignment(comp) catch unreachable),
756 Align.Override => |alignment| return alignment,
757 }
758 }
759
760 pub async fn get(
761 comp: *Compilation,
762 key: Key,
763 ) !*Pointer {
764 var normal_key = key;
765 switch (key.alignment) {
766 Align.Abi => {},
767 Align.Override => |alignment| {
768 const abi_align = try await (async key.child_type.getAbiAlignment(comp) catch unreachable);
769 if (abi_align == alignment) {
770 normal_key.alignment = Align.Abi;
771 }
772 },
773 }
774 {
775 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
776 defer held.release();
777
778 if (held.value.get(&normal_key)) |entry| {
779 entry.value.base.base.ref();
780 return entry.value;
781 }
782 }
783
784 const self = try comp.gpa().create(Pointer{
785 .base = undefined,
786 .key = normal_key,
787 .garbage_node = undefined,
788 });
789 errdefer comp.gpa().destroy(self);
790
791 const size_str = switch (self.key.size) {
792 Size.One => "*",
793 Size.Many => "[*]",
794 Size.Slice => "[]",
795 };
796 const mut_str = switch (self.key.mut) {
797 Mut.Const => "const ",
798 Mut.Mut => "",
799 };
800 const vol_str = switch (self.key.vol) {
801 Vol.Volatile => "volatile ",
802 Vol.Non => "",
803 };
804 const name = switch (self.key.alignment) {
805 Align.Abi => try std.fmt.allocPrint(
806 comp.gpa(),
807 "{}{}{}{}",
808 size_str,
809 mut_str,
810 vol_str,
811 self.key.child_type.name,
812 ),
813 Align.Override => |alignment| try std.fmt.allocPrint(
814 comp.gpa(),
815 "{}align<{}> {}{}{}",
816 size_str,
817 alignment,
818 mut_str,
819 vol_str,
820 self.key.child_type.name,
821 ),
822 };
823 errdefer comp.gpa().free(name);
824
825 self.base.init(comp, Id.Pointer, name);
826
827 {
828 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
829 defer held.release();
830
831 _ = try held.value.put(&self.key, self);
832 }
833 return self;
834 }
835
836 pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
837 const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
838 return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
839 }
840 };
841
842 pub const Array = struct {
843 base: Type,
844 key: Key,
845 garbage_node: std.atomic.Stack(*Array).Node,
846
847 pub const Key = struct {
848 elem_type: *Type,
849 len: usize,
850
851 pub fn hash(self: *const Key) u32 {
852 var result: u32 = 0;
853 result +%= hashAny(self.elem_type, 0);
854 result +%= hashAny(self.len, 1);
855 return result;
856 }
857
858 pub fn eql(self: *const Key, other: *const Key) bool {
859 return self.elem_type == other.elem_type and self.len == other.len;
860 }
861 };
862
863 pub fn destroy(self: *Array, comp: *Compilation) void {
864 self.key.elem_type.base.deref(comp);
865 comp.gpa().destroy(self);
866 }
867
868 pub async fn get(comp: *Compilation, key: Key) !*Array {
869 key.elem_type.base.ref();
870 errdefer key.elem_type.base.deref(comp);
871
872 {
873 const held = await (async comp.array_type_table.acquire() catch unreachable);
874 defer held.release();
875
876 if (held.value.get(&key)) |entry| {
877 entry.value.base.base.ref();
878 return entry.value;
879 }
880 }
881
882 const self = try comp.gpa().create(Array{
883 .base = undefined,
884 .key = key,
885 .garbage_node = undefined,
886 });
887 errdefer comp.gpa().destroy(self);
888
889 const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name);
890 errdefer comp.gpa().free(name);
891
892 self.base.init(comp, Id.Array, name);
893
894 {
895 const held = await (async comp.array_type_table.acquire() catch unreachable);
896 defer held.release();
897
898 _ = try held.value.put(&self.key, self);
899 }
900 return self;
901 }
902
903 pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
904 const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
905 return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
906 }
907 };
908
909 pub const ComptimeFloat = struct {
910 base: Type,
911
912 pub fn destroy(self: *ComptimeFloat, comp: *Compilation) void {
913 comp.gpa().destroy(self);
914 }
915 };
916
917 pub const ComptimeInt = struct {
918 base: Type,
919
920 /// Adds 1 reference to the resulting type
921 pub fn get(comp: *Compilation) *ComptimeInt {
922 comp.comptime_int_type.base.base.ref();
923 return comp.comptime_int_type;
924 }
925
926 pub fn destroy(self: *ComptimeInt, comp: *Compilation) void {
927 comp.gpa().destroy(self);
928 }
929 };
930
931 pub const Undefined = struct {
932 base: Type,
933
934 pub fn destroy(self: *Undefined, comp: *Compilation) void {
935 comp.gpa().destroy(self);
936 }
937 };
938
939 pub const Null = struct {
940 base: Type,
941
942 pub fn destroy(self: *Null, comp: *Compilation) void {
943 comp.gpa().destroy(self);
944 }
945 };
946
947 pub const Optional = struct {
948 base: Type,
949
950 pub fn destroy(self: *Optional, comp: *Compilation) void {
951 comp.gpa().destroy(self);
952 }
953
954 pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
955 @panic("TODO");
956 }
957 };
958
959 pub const ErrorUnion = struct {
960 base: Type,
961
962 pub fn destroy(self: *ErrorUnion, comp: *Compilation) void {
963 comp.gpa().destroy(self);
964 }
965
966 pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
967 @panic("TODO");
968 }
969 };
970
971 pub const ErrorSet = struct {
972 base: Type,
973
974 pub fn destroy(self: *ErrorSet, comp: *Compilation) void {
975 comp.gpa().destroy(self);
976 }
977
978 pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
979 @panic("TODO");
980 }
981 };
982
983 pub const Enum = struct {
984 base: Type,
985
986 pub fn destroy(self: *Enum, comp: *Compilation) void {
987 comp.gpa().destroy(self);
988 }
989
990 pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
991 @panic("TODO");
992 }
993 };
994
995 pub const Union = struct {
996 base: Type,
997
998 pub fn destroy(self: *Union, comp: *Compilation) void {
999 comp.gpa().destroy(self);
1000 }
1001
1002 pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
1003 @panic("TODO");
1004 }
1005 };
1006
1007 pub const Namespace = struct {
1008 base: Type,
1009
1010 pub fn destroy(self: *Namespace, comp: *Compilation) void {
1011 comp.gpa().destroy(self);
1012 }
1013 };
1014
1015 pub const Block = struct {
1016 base: Type,
1017
1018 pub fn destroy(self: *Block, comp: *Compilation) void {
1019 comp.gpa().destroy(self);
1020 }
1021 };
1022
1023 pub const BoundFn = struct {
1024 base: Type,
1025
1026 pub fn destroy(self: *BoundFn, comp: *Compilation) void {
1027 comp.gpa().destroy(self);
1028 }
1029
1030 pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
1031 @panic("TODO");
1032 }
1033 };
1034
1035 pub const ArgTuple = struct {
1036 base: Type,
1037
1038 pub fn destroy(self: *ArgTuple, comp: *Compilation) void {
1039 comp.gpa().destroy(self);
1040 }
1041 };
1042
1043 pub const Opaque = struct {
1044 base: Type,
1045
1046 pub fn destroy(self: *Opaque, comp: *Compilation) void {
1047 comp.gpa().destroy(self);
1048 }
1049
1050 pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
1051 @panic("TODO");
1052 }
1053 };
1054
1055 pub const Promise = struct {
1056 base: Type,
1057
1058 pub fn destroy(self: *Promise, comp: *Compilation) void {
1059 comp.gpa().destroy(self);
1060 }
1061
1062 pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
1063 @panic("TODO");
1064 }
1065 };
1066};
1067
1068fn hashAny(x: var, comptime seed: u64) u32 {
1069 switch (@typeInfo(@typeOf(x))) {
1070 builtin.TypeId.Int => |info| {
1071 comptime var rng = comptime std.rand.DefaultPrng.init(seed);
1072 const unsigned_x = @bitCast(@IntType(false, info.bits), x);
1073 if (info.bits <= 32) {
1074 return u32(unsigned_x) *% comptime rng.random.scalar(u32);
1075 } else {
1076 return @truncate(u32, unsigned_x *% comptime rng.random.scalar(@typeOf(unsigned_x)));
1077 }
1078 },
1079 builtin.TypeId.Pointer => |info| {
1080 switch (info.size) {
1081 builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed),
1082 builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"),
1083 builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"),
1084 }
1085 },
1086 builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed),
1087 builtin.TypeId.Bool => {
1088 comptime var rng = comptime std.rand.DefaultPrng.init(seed);
1089 const vals = comptime [2]u32{ rng.random.scalar(u32), rng.random.scalar(u32) };
1090 return vals[@boolToInt(x)];
1091 },
1092 builtin.TypeId.Optional => {
1093 if (x) |non_opt| {
1094 return hashAny(non_opt, seed);
1095 } else {
1096 return hashAny(u32(1), seed);
1097 }
1098 },
1099 else => @compileError("implement hash function for " ++ @typeName(@typeOf(x))),
1100 }
1101}
src-self-hosted/value.zig created+581
......@@ -0,0 +1,581 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Scope = @import("scope.zig").Scope;
4const Compilation = @import("compilation.zig").Compilation;
5const ObjectFile = @import("codegen.zig").ObjectFile;
6const llvm = @import("llvm.zig");
7const Buffer = std.Buffer;
8const assert = std.debug.assert;
9
10/// Values are ref-counted, heap-allocated, and copy-on-write
11/// If there is only 1 ref then write need not copy
12pub const Value = struct {
13 id: Id,
14 typ: *Type,
15 ref_count: std.atomic.Int(usize),
16
17 /// Thread-safe
18 pub fn ref(base: *Value) void {
19 _ = base.ref_count.incr();
20 }
21
22 /// Thread-safe
23 pub fn deref(base: *Value, comp: *Compilation) void {
24 if (base.ref_count.decr() == 1) {
25 base.typ.base.deref(comp);
26 switch (base.id) {
27 Id.Type => @fieldParentPtr(Type, "base", base).destroy(comp),
28 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),
29 Id.FnProto => @fieldParentPtr(FnProto, "base", base).destroy(comp),
30 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),
31 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),
32 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),
33 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),
34 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),
35 Id.Array => @fieldParentPtr(Array, "base", base).destroy(comp),
36 }
37 }
38 }
39
40 pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void {
41 base.typ.base.deref(comp);
42 new_type.base.ref();
43 base.typ = new_type;
44 }
45
46 pub fn getRef(base: *Value) *Value {
47 base.ref();
48 return base;
49 }
50
51 pub fn cast(base: *Value, comptime T: type) ?*T {
52 if (base.id != @field(Id, @typeName(T))) return null;
53 return @fieldParentPtr(T, "base", base);
54 }
55
56 pub fn dump(base: *const Value) void {
57 std.debug.warn("{}", @tagName(base.id));
58 }
59
60 pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
61 switch (base.id) {
62 Id.Type => unreachable,
63 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
64 Id.FnProto => return @fieldParentPtr(FnProto, "base", base).getLlvmConst(ofile),
65 Id.Void => return null,
66 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
67 Id.NoReturn => unreachable,
68 Id.Ptr => return @fieldParentPtr(Ptr, "base", base).getLlvmConst(ofile),
69 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile),
70 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmConst(ofile),
71 }
72 }
73
74 pub fn derefAndCopy(self: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) {
75 if (self.ref_count.get() == 1) {
76 // ( ͡° ͜ʖ ͡°)
77 return self;
78 }
79
80 assert(self.ref_count.decr() != 1);
81 return self.copy(comp);
82 }
83
84 pub fn copy(base: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) {
85 switch (base.id) {
86 Id.Type => unreachable,
87 Id.Fn => unreachable,
88 Id.FnProto => unreachable,
89 Id.Void => unreachable,
90 Id.Bool => unreachable,
91 Id.NoReturn => unreachable,
92 Id.Ptr => unreachable,
93 Id.Array => unreachable,
94 Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base,
95 }
96 }
97
98 pub const Parent = union(enum) {
99 None,
100 BaseStruct: BaseStruct,
101 BaseArray: BaseArray,
102 BaseUnion: *Value,
103 BaseScalar: *Value,
104
105 pub const BaseStruct = struct {
106 val: *Value,
107 field_index: usize,
108 };
109
110 pub const BaseArray = struct {
111 val: *Value,
112 elem_index: usize,
113 };
114 };
115
116 pub const Id = enum {
117 Type,
118 Fn,
119 Void,
120 Bool,
121 NoReturn,
122 Array,
123 Ptr,
124 Int,
125 FnProto,
126 };
127
128 pub const Type = @import("type.zig").Type;
129
130 pub const FnProto = struct {
131 base: Value,
132
133 /// The main external name that is used in the .o file.
134 /// TODO https://github.com/ziglang/zig/issues/265
135 symbol_name: Buffer,
136
137 pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto {
138 const self = try comp.gpa().create(FnProto{
139 .base = Value{
140 .id = Value.Id.FnProto,
141 .typ = &fn_type.base,
142 .ref_count = std.atomic.Int(usize).init(1),
143 },
144 .symbol_name = symbol_name,
145 });
146 fn_type.base.base.ref();
147 return self;
148 }
149
150 pub fn destroy(self: *FnProto, comp: *Compilation) void {
151 self.symbol_name.deinit();
152 comp.gpa().destroy(self);
153 }
154
155 pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
156 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
157 const llvm_fn = llvm.AddFunction(
158 ofile.module,
159 self.symbol_name.ptr(),
160 llvm_fn_type,
161 ) orelse return error.OutOfMemory;
162
163 // TODO port more logic from codegen.cpp:fn_llvm_value
164
165 return llvm_fn;
166 }
167 };
168
169 pub const Fn = struct {
170 base: Value,
171
172 /// The main external name that is used in the .o file.
173 /// TODO https://github.com/ziglang/zig/issues/265
174 symbol_name: Buffer,
175
176 /// parent should be the top level decls or container decls
177 fndef_scope: *Scope.FnDef,
178
179 /// parent is scope for last parameter
180 child_scope: *Scope,
181
182 /// parent is child_scope
183 block_scope: ?*Scope.Block,
184
185 /// Path to the object file that contains this function
186 containing_object: Buffer,
187
188 link_set_node: *std.LinkedList(?*Value.Fn).Node,
189
190 /// Creates a Fn value with 1 ref
191 /// Takes ownership of symbol_name
192 pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn {
193 const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node{
194 .data = null,
195 .next = undefined,
196 .prev = undefined,
197 });
198 errdefer comp.gpa().destroy(link_set_node);
199
200 const self = try comp.gpa().create(Fn{
201 .base = Value{
202 .id = Value.Id.Fn,
203 .typ = &fn_type.base,
204 .ref_count = std.atomic.Int(usize).init(1),
205 },
206 .fndef_scope = fndef_scope,
207 .child_scope = &fndef_scope.base,
208 .block_scope = null,
209 .symbol_name = symbol_name,
210 .containing_object = Buffer.initNull(comp.gpa()),
211 .link_set_node = link_set_node,
212 });
213 fn_type.base.base.ref();
214 fndef_scope.fn_val = self;
215 fndef_scope.base.ref();
216 return self;
217 }
218
219 pub fn destroy(self: *Fn, comp: *Compilation) void {
220 // remove with a tombstone so that we do not have to grab a lock
221 if (self.link_set_node.data != null) {
222 // it's now the job of the link step to find this tombstone and
223 // deallocate it.
224 self.link_set_node.data = null;
225 } else {
226 comp.gpa().destroy(self.link_set_node);
227 }
228
229 self.containing_object.deinit();
230 self.fndef_scope.base.deref(comp);
231 self.symbol_name.deinit();
232 comp.gpa().destroy(self);
233 }
234
235 /// We know that the function definition will end up in an .o file somewhere.
236 /// Here, all we have to do is generate a global prototype.
237 /// TODO cache the prototype per ObjectFile
238 pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef {
239 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
240 const llvm_fn = llvm.AddFunction(
241 ofile.module,
242 self.symbol_name.ptr(),
243 llvm_fn_type,
244 ) orelse return error.OutOfMemory;
245
246 // TODO port more logic from codegen.cpp:fn_llvm_value
247
248 return llvm_fn;
249 }
250 };
251
252 pub const Void = struct {
253 base: Value,
254
255 pub fn get(comp: *Compilation) *Void {
256 comp.void_value.base.ref();
257 return comp.void_value;
258 }
259
260 pub fn destroy(self: *Void, comp: *Compilation) void {
261 comp.gpa().destroy(self);
262 }
263 };
264
265 pub const Bool = struct {
266 base: Value,
267 x: bool,
268
269 pub fn get(comp: *Compilation, x: bool) *Bool {
270 if (x) {
271 comp.true_value.base.ref();
272 return comp.true_value;
273 } else {
274 comp.false_value.base.ref();
275 return comp.false_value;
276 }
277 }
278
279 pub fn destroy(self: *Bool, comp: *Compilation) void {
280 comp.gpa().destroy(self);
281 }
282
283 pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
284 const llvm_type = llvm.Int1TypeInContext(ofile.context);
285 if (self.x) {
286 return llvm.ConstAllOnes(llvm_type);
287 } else {
288 return llvm.ConstNull(llvm_type);
289 }
290 }
291 };
292
293 pub const NoReturn = struct {
294 base: Value,
295
296 pub fn get(comp: *Compilation) *NoReturn {
297 comp.noreturn_value.base.ref();
298 return comp.noreturn_value;
299 }
300
301 pub fn destroy(self: *NoReturn, comp: *Compilation) void {
302 comp.gpa().destroy(self);
303 }
304 };
305
306 pub const Ptr = struct {
307 base: Value,
308 special: Special,
309 mut: Mut,
310
311 pub const Mut = enum {
312 CompTimeConst,
313 CompTimeVar,
314 RunTime,
315 };
316
317 pub const Special = union(enum) {
318 Scalar: *Value,
319 BaseArray: BaseArray,
320 BaseStruct: BaseStruct,
321 HardCodedAddr: u64,
322 Discard,
323 };
324
325 pub const BaseArray = struct {
326 val: *Value,
327 elem_index: usize,
328 };
329
330 pub const BaseStruct = struct {
331 val: *Value,
332 field_index: usize,
333 };
334
335 pub async fn createArrayElemPtr(
336 comp: *Compilation,
337 array_val: *Array,
338 mut: Type.Pointer.Mut,
339 size: Type.Pointer.Size,
340 elem_index: usize,
341 ) !*Ptr {
342 array_val.base.ref();
343 errdefer array_val.base.deref(comp);
344
345 const elem_type = array_val.base.typ.cast(Type.Array).?.key.elem_type;
346 const ptr_type = try await (async Type.Pointer.get(comp, Type.Pointer.Key{
347 .child_type = elem_type,
348 .mut = mut,
349 .vol = Type.Pointer.Vol.Non,
350 .size = size,
351 .alignment = Type.Pointer.Align.Abi,
352 }) catch unreachable);
353 var ptr_type_consumed = false;
354 errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
355
356 const self = try comp.gpa().create(Value.Ptr{
357 .base = Value{
358 .id = Value.Id.Ptr,
359 .typ = &ptr_type.base,
360 .ref_count = std.atomic.Int(usize).init(1),
361 },
362 .special = Special{
363 .BaseArray = BaseArray{
364 .val = &array_val.base,
365 .elem_index = 0,
366 },
367 },
368 .mut = Mut.CompTimeConst,
369 });
370 ptr_type_consumed = true;
371 errdefer comp.gpa().destroy(self);
372
373 return self;
374 }
375
376 pub fn destroy(self: *Ptr, comp: *Compilation) void {
377 comp.gpa().destroy(self);
378 }
379
380 pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
381 const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
382 // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
383 switch (self.special) {
384 Special.Scalar => |scalar| @panic("TODO"),
385 Special.BaseArray => |base_array| {
386 // TODO put this in one .o file only, and after that, generate extern references to it
387 const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
388 const ptr_bit_count = ofile.comp.target_ptr_bits;
389 const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
390 const indices = []llvm.ValueRef{
391 llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
392 llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
393 };
394 return llvm.ConstInBoundsGEP(
395 array_llvm_value,
396 &indices,
397 @intCast(c_uint, indices.len),
398 ) orelse return error.OutOfMemory;
399 },
400 Special.BaseStruct => |base_struct| @panic("TODO"),
401 Special.HardCodedAddr => |addr| @panic("TODO"),
402 Special.Discard => unreachable,
403 }
404 }
405 };
406
407 pub const Array = struct {
408 base: Value,
409 special: Special,
410
411 pub const Special = union(enum) {
412 Undefined,
413 OwnedBuffer: []u8,
414 Explicit: Data,
415 };
416
417 pub const Data = struct {
418 parent: Parent,
419 elements: []*Value,
420 };
421
422 /// Takes ownership of buffer
423 pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {
424 const u8_type = Type.Int.get_u8(comp);
425 defer u8_type.base.base.deref(comp);
426
427 const array_type = try await (async Type.Array.get(comp, Type.Array.Key{
428 .elem_type = &u8_type.base,
429 .len = buffer.len,
430 }) catch unreachable);
431 errdefer array_type.base.base.deref(comp);
432
433 const self = try comp.gpa().create(Value.Array{
434 .base = Value{
435 .id = Value.Id.Array,
436 .typ = &array_type.base,
437 .ref_count = std.atomic.Int(usize).init(1),
438 },
439 .special = Special{ .OwnedBuffer = buffer },
440 });
441 errdefer comp.gpa().destroy(self);
442
443 return self;
444 }
445
446 pub fn destroy(self: *Array, comp: *Compilation) void {
447 switch (self.special) {
448 Special.Undefined => {},
449 Special.OwnedBuffer => |buf| {
450 comp.gpa().free(buf);
451 },
452 Special.Explicit => {},
453 }
454 comp.gpa().destroy(self);
455 }
456
457 pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
458 switch (self.special) {
459 Special.Undefined => {
460 const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
461 return llvm.GetUndef(llvm_type);
462 },
463 Special.OwnedBuffer => |buf| {
464 const dont_null_terminate = 1;
465 const llvm_str_init = llvm.ConstStringInContext(
466 ofile.context,
467 buf.ptr,
468 @intCast(c_uint, buf.len),
469 dont_null_terminate,
470 ) orelse return error.OutOfMemory;
471 const str_init_type = llvm.TypeOf(llvm_str_init);
472 const global = llvm.AddGlobal(ofile.module, str_init_type, c"") orelse return error.OutOfMemory;
473 llvm.SetInitializer(global, llvm_str_init);
474 llvm.SetLinkage(global, llvm.PrivateLinkage);
475 llvm.SetGlobalConstant(global, 1);
476 llvm.SetUnnamedAddr(global, 1);
477 llvm.SetAlignment(global, llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, str_init_type));
478 return global;
479 },
480 Special.Explicit => @panic("TODO"),
481 }
482
483 //{
484 // uint64_t len = type_entry->data.array.len;
485 // if (const_val->data.x_array.special == ConstArraySpecialUndef) {
486 // return LLVMGetUndef(type_entry->type_ref);
487 // }
488
489 // LLVMValueRef *values = allocate<LLVMValueRef>(len);
490 // LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref;
491 // bool make_unnamed_struct = false;
492 // for (uint64_t i = 0; i < len; i += 1) {
493 // ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i];
494 // LLVMValueRef val = gen_const_val(g, elem_value, "");
495 // values[i] = val;
496 // make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val);
497 // }
498 // if (make_unnamed_struct) {
499 // return LLVMConstStruct(values, len, true);
500 // } else {
501 // return LLVMConstArray(element_type_ref, values, (unsigned)len);
502 // }
503 //}
504 }
505 };
506
507 pub const Int = struct {
508 base: Value,
509 big_int: std.math.big.Int,
510
511 pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int {
512 const self = try comp.gpa().create(Value.Int{
513 .base = Value{
514 .id = Value.Id.Int,
515 .typ = typ,
516 .ref_count = std.atomic.Int(usize).init(1),
517 },
518 .big_int = undefined,
519 });
520 typ.base.ref();
521 errdefer comp.gpa().destroy(self);
522
523 self.big_int = try std.math.big.Int.init(comp.gpa());
524 errdefer self.big_int.deinit();
525
526 try self.big_int.setString(base, value);
527
528 return self;
529 }
530
531 pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
532 switch (self.base.typ.id) {
533 Type.Id.Int => {
534 const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
535 if (self.big_int.len == 0) {
536 return llvm.ConstNull(type_ref);
537 }
538 const unsigned_val = if (self.big_int.len == 1) blk: {
539 break :blk llvm.ConstInt(type_ref, self.big_int.limbs[0], @boolToInt(false));
540 } else if (@sizeOf(std.math.big.Limb) == @sizeOf(u64)) blk: {
541 break :blk llvm.ConstIntOfArbitraryPrecision(
542 type_ref,
543 @intCast(c_uint, self.big_int.len),
544 @ptrCast([*]u64, self.big_int.limbs.ptr),
545 );
546 } else {
547 @compileError("std.math.Big.Int.Limb size does not match LLVM");
548 };
549 return if (self.big_int.positive) unsigned_val else llvm.ConstNeg(unsigned_val);
550 },
551 Type.Id.ComptimeInt => unreachable,
552 else => unreachable,
553 }
554 }
555
556 pub fn copy(old: *Int, comp: *Compilation) !*Int {
557 old.base.typ.base.ref();
558 errdefer old.base.typ.base.deref(comp);
559
560 const new = try comp.gpa().create(Value.Int{
561 .base = Value{
562 .id = Value.Id.Int,
563 .typ = old.base.typ,
564 .ref_count = std.atomic.Int(usize).init(1),
565 },
566 .big_int = undefined,
567 });
568 errdefer comp.gpa().destroy(new);
569
570 new.big_int = try old.big_int.clone();
571 errdefer new.big_int.deinit();
572
573 return new;
574 }
575
576 pub fn destroy(self: *Int, comp: *Compilation) void {
577 self.big_int.deinit();
578 comp.gpa().destroy(self);
579 }
580 };
581};
src-self-hosted/visib.zig created+4
......@@ -0,0 +1,4 @@
1pub const Visib = enum {
2 Private,
3 Pub,
4};
src/all_types.hpp+264-69
......@@ -60,7 +60,7 @@ struct IrExecutable {
6060 ZigList<Tld *> tld_list;
6161
6262 IrInstruction *coro_handle;
63 IrInstruction *coro_awaiter_field_ptr; // this one is shared and in the promise
63 IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
6464 IrInstruction *coro_result_ptr_field_ptr;
6565 IrInstruction *coro_result_field_ptr;
6666 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
......@@ -83,6 +83,7 @@ enum ConstParentId {
8383 ConstParentIdStruct,
8484 ConstParentIdArray,
8585 ConstParentIdUnion,
86 ConstParentIdScalar,
8687};
8788
8889struct ConstParent {
......@@ -100,6 +101,9 @@ struct ConstParent {
100101 struct {
101102 ConstExprValue *union_val;
102103 } p_union;
104 struct {
105 ConstExprValue *scalar_val;
106 } p_scalar;
103107 } data;
104108};
105109
......@@ -140,6 +144,9 @@ enum ConstPtrSpecial {
140144 // understand the value of pointee at compile time. However, we will still
141145 // emit a binary with a compile time known address.
142146 // In this case index is the numeric address value.
147 // We also use this for null pointer. We need the data layout for ConstCastOnly == true
148 // types to be the same, so all optionals of pointer types use x_ptr
149 // instead of x_optional
143150 ConstPtrSpecialHardCodedAddr,
144151 // This means that the pointer represents memory of assigning to _.
145152 // That is, storing discards the data, and loading is invalid.
......@@ -215,10 +222,10 @@ enum RuntimeHintErrorUnion {
215222 RuntimeHintErrorUnionNonError,
216223};
217224
218enum RuntimeHintMaybe {
219 RuntimeHintMaybeUnknown,
220 RuntimeHintMaybeNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
221 RuntimeHintMaybeNonNull,
225enum RuntimeHintOptional {
226 RuntimeHintOptionalUnknown,
227 RuntimeHintOptionalNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
228 RuntimeHintOptionalNonNull,
222229};
223230
224231enum RuntimeHintPtr {
......@@ -227,6 +234,16 @@ enum RuntimeHintPtr {
227234 RuntimeHintPtrNonStack,
228235};
229236
237enum RuntimeHintSliceId {
238 RuntimeHintSliceIdUnknown,
239 RuntimeHintSliceIdLen,
240};
241
242struct RuntimeHintSlice {
243 enum RuntimeHintSliceId id;
244 uint64_t len;
245};
246
230247struct ConstGlobalRefs {
231248 LLVMValueRef llvm_value;
232249 LLVMValueRef llvm_global;
......@@ -241,13 +258,14 @@ struct ConstExprValue {
241258 // populated if special == ConstValSpecialStatic
242259 BigInt x_bigint;
243260 BigFloat x_bigfloat;
261 float16_t x_f16;
244262 float x_f32;
245263 double x_f64;
246264 float128_t x_f128;
247265 bool x_bool;
248266 ConstBoundFnValue x_bound_fn;
249267 TypeTableEntry *x_type;
250 ConstExprValue *x_maybe;
268 ConstExprValue *x_optional;
251269 ConstErrValue x_err_union;
252270 ErrorTableEntry *x_err_set;
253271 BigInt x_enum_tag;
......@@ -261,8 +279,9 @@ struct ConstExprValue {
261279
262280 // populated if special == ConstValSpecialRuntime
263281 RuntimeHintErrorUnion rh_error_union;
264 RuntimeHintMaybe rh_maybe;
282 RuntimeHintOptional rh_maybe;
265283 RuntimeHintPtr rh_ptr;
284 RuntimeHintSlice rh_slice;
266285 } data;
267286};
268287
......@@ -374,11 +393,13 @@ enum NodeType {
374393 NodeTypeCharLiteral,
375394 NodeTypeSymbol,
376395 NodeTypePrefixOpExpr,
377 NodeTypeAddrOfExpr,
396 NodeTypePointerType,
378397 NodeTypeFnCallExpr,
379398 NodeTypeArrayAccessExpr,
380399 NodeTypeSliceExpr,
381400 NodeTypeFieldAccessExpr,
401 NodeTypePtrDeref,
402 NodeTypeUnwrapOptional,
382403 NodeTypeUse,
383404 NodeTypeBoolLiteral,
384405 NodeTypeNullLiteral,
......@@ -548,7 +569,7 @@ enum BinOpType {
548569 BinOpTypeMultWrap,
549570 BinOpTypeDiv,
550571 BinOpTypeMod,
551 BinOpTypeUnwrapMaybe,
572 BinOpTypeUnwrapOptional,
552573 BinOpTypeArrayCat,
553574 BinOpTypeArrayMult,
554575 BinOpTypeErrorUnion,
......@@ -567,6 +588,10 @@ struct AstNodeCatchExpr {
567588 AstNode *op2;
568589};
569590
591struct AstNodeUnwrapOptional {
592 AstNode *expr;
593};
594
570595enum CastOp {
571596 CastOpNoCast, // signifies the function call expression is not a cast
572597 CastOpNoop, // fn call expr is a cast, but does nothing
......@@ -577,6 +602,8 @@ enum CastOp {
577602 CastOpBytesToSlice,
578603 CastOpNumLitToConcrete,
579604 CastOpErrSet,
605 CastOpBitCast,
606 CastOpPtrOfArrayToSlice,
580607};
581608
582609struct AstNodeFnCallExpr {
......@@ -603,15 +630,18 @@ struct AstNodeFieldAccessExpr {
603630 Buf *field_name;
604631};
605632
633struct AstNodePtrDerefExpr {
634 AstNode *target;
635};
636
606637enum PrefixOp {
607638 PrefixOpInvalid,
608639 PrefixOpBoolNot,
609640 PrefixOpBinNot,
610641 PrefixOpNegation,
611642 PrefixOpNegationWrap,
612 PrefixOpDereference,
613 PrefixOpMaybe,
614 PrefixOpUnwrapMaybe,
643 PrefixOpOptional,
644 PrefixOpAddrOf,
615645};
616646
617647struct AstNodePrefixOpExpr {
......@@ -619,7 +649,8 @@ struct AstNodePrefixOpExpr {
619649 AstNode *primary_expr;
620650};
621651
622struct AstNodeAddrOfExpr {
652struct AstNodePointerType {
653 Token *star_token;
623654 AstNode *align_expr;
624655 BigInt *bit_offset_start;
625656 BigInt *bit_offset_end;
......@@ -868,7 +899,6 @@ struct AstNodeAwaitExpr {
868899
869900struct AstNodeSuspend {
870901 AstNode *block;
871 AstNode *promise_symbol;
872902};
873903
874904struct AstNodePromiseType {
......@@ -893,8 +923,9 @@ struct AstNode {
893923 AstNodeTestDecl test_decl;
894924 AstNodeBinOpExpr bin_op_expr;
895925 AstNodeCatchExpr unwrap_err_expr;
926 AstNodeUnwrapOptional unwrap_optional;
896927 AstNodePrefixOpExpr prefix_op_expr;
897 AstNodeAddrOfExpr addr_of_expr;
928 AstNodePointerType pointer_type;
898929 AstNodeFnCallExpr fn_call_expr;
899930 AstNodeArrayAccessExpr array_access_expr;
900931 AstNodeSliceExpr slice_expr;
......@@ -910,6 +941,7 @@ struct AstNode {
910941 AstNodeCompTime comptime_expr;
911942 AstNodeAsmExpr asm_expr;
912943 AstNodeFieldAccessExpr field_access_expr;
944 AstNodePtrDerefExpr ptr_deref_expr;
913945 AstNodeContainerDecl container_decl;
914946 AstNodeStructField struct_field;
915947 AstNodeStringLiteral string_literal;
......@@ -966,8 +998,14 @@ struct FnTypeId {
966998uint32_t fn_type_id_hash(FnTypeId*);
967999bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
9681000
1001enum PtrLen {
1002 PtrLenUnknown,
1003 PtrLenSingle,
1004};
1005
9691006struct TypeTableEntryPointer {
9701007 TypeTableEntry *child_type;
1008 PtrLen ptr_len;
9711009 bool is_const;
9721010 bool is_volatile;
9731011 uint32_t alignment;
......@@ -1018,6 +1056,10 @@ struct TypeTableEntryStruct {
10181056 // whether we've finished resolving it
10191057 bool complete;
10201058
1059 // whether any of the fields require comptime
1060 // the value is not valid until zero_bits_known == true
1061 bool requires_comptime;
1062
10211063 bool zero_bits_loop_flag;
10221064 bool zero_bits_known;
10231065 uint32_t abi_alignment; // also figured out with zero_bits pass
......@@ -1025,7 +1067,7 @@ struct TypeTableEntryStruct {
10251067 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
10261068};
10271069
1028struct TypeTableEntryMaybe {
1070struct TypeTableEntryOptional {
10291071 TypeTableEntry *child_type;
10301072};
10311073
......@@ -1059,8 +1101,7 @@ struct TypeTableEntryEnum {
10591101 bool zero_bits_loop_flag;
10601102 bool zero_bits_known;
10611103
1062 bool generate_name_table;
1063 LLVMValueRef name_table;
1104 LLVMValueRef name_function;
10641105
10651106 HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
10661107};
......@@ -1086,6 +1127,10 @@ struct TypeTableEntryUnion {
10861127 // whether we've finished resolving it
10871128 bool complete;
10881129
1130 // whether any of the fields require comptime
1131 // the value is not valid until zero_bits_known == true
1132 bool requires_comptime;
1133
10891134 bool zero_bits_loop_flag;
10901135 bool zero_bits_known;
10911136 uint32_t abi_alignment; // also figured out with zero_bits pass
......@@ -1140,11 +1185,11 @@ enum TypeTableEntryId {
11401185 TypeTableEntryIdPointer,
11411186 TypeTableEntryIdArray,
11421187 TypeTableEntryIdStruct,
1143 TypeTableEntryIdNumLitFloat,
1144 TypeTableEntryIdNumLitInt,
1145 TypeTableEntryIdUndefLit,
1146 TypeTableEntryIdNullLit,
1147 TypeTableEntryIdMaybe,
1188 TypeTableEntryIdComptimeFloat,
1189 TypeTableEntryIdComptimeInt,
1190 TypeTableEntryIdUndefined,
1191 TypeTableEntryIdNull,
1192 TypeTableEntryIdOptional,
11481193 TypeTableEntryIdErrorUnion,
11491194 TypeTableEntryIdErrorSet,
11501195 TypeTableEntryIdEnum,
......@@ -1175,7 +1220,7 @@ struct TypeTableEntry {
11751220 TypeTableEntryFloat floating;
11761221 TypeTableEntryArray array;
11771222 TypeTableEntryStruct structure;
1178 TypeTableEntryMaybe maybe;
1223 TypeTableEntryOptional maybe;
11791224 TypeTableEntryErrorUnion error_union;
11801225 TypeTableEntryErrorSet error_set;
11811226 TypeTableEntryEnum enumeration;
......@@ -1187,7 +1232,7 @@ struct TypeTableEntry {
11871232
11881233 // use these fields to make sure we don't duplicate type table entries for the same type
11891234 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
1190 TypeTableEntry *maybe_parent;
1235 TypeTableEntry *optional_parent;
11911236 TypeTableEntry *promise_parent;
11921237 TypeTableEntry *promise_frame_parent;
11931238 // If we generate a constant name value for this type, we memoize it here.
......@@ -1291,6 +1336,8 @@ enum BuiltinFnId {
12911336 BuiltinFnIdMemberCount,
12921337 BuiltinFnIdMemberType,
12931338 BuiltinFnIdMemberName,
1339 BuiltinFnIdField,
1340 BuiltinFnIdTypeInfo,
12941341 BuiltinFnIdTypeof,
12951342 BuiltinFnIdAddWithOverflow,
12961343 BuiltinFnIdSubWithOverflow,
......@@ -1303,27 +1350,42 @@ enum BuiltinFnId {
13031350 BuiltinFnIdCompileLog,
13041351 BuiltinFnIdCtz,
13051352 BuiltinFnIdClz,
1353 BuiltinFnIdPopCount,
13061354 BuiltinFnIdImport,
13071355 BuiltinFnIdCImport,
13081356 BuiltinFnIdErrName,
13091357 BuiltinFnIdBreakpoint,
13101358 BuiltinFnIdReturnAddress,
13111359 BuiltinFnIdFrameAddress,
1360 BuiltinFnIdHandle,
13121361 BuiltinFnIdEmbedFile,
1313 BuiltinFnIdCmpExchange,
1362 BuiltinFnIdCmpxchgWeak,
1363 BuiltinFnIdCmpxchgStrong,
13141364 BuiltinFnIdFence,
13151365 BuiltinFnIdDivExact,
13161366 BuiltinFnIdDivTrunc,
13171367 BuiltinFnIdDivFloor,
13181368 BuiltinFnIdRem,
13191369 BuiltinFnIdMod,
1370 BuiltinFnIdSqrt,
13201371 BuiltinFnIdTruncate,
1372 BuiltinFnIdIntCast,
1373 BuiltinFnIdFloatCast,
1374 BuiltinFnIdErrSetCast,
1375 BuiltinFnIdToBytes,
1376 BuiltinFnIdFromBytes,
1377 BuiltinFnIdIntToFloat,
1378 BuiltinFnIdFloatToInt,
1379 BuiltinFnIdBoolToInt,
1380 BuiltinFnIdErrToInt,
1381 BuiltinFnIdIntToErr,
1382 BuiltinFnIdEnumToInt,
1383 BuiltinFnIdIntToEnum,
13211384 BuiltinFnIdIntType,
13221385 BuiltinFnIdSetCold,
13231386 BuiltinFnIdSetRuntimeSafety,
13241387 BuiltinFnIdSetFloatMode,
13251388 BuiltinFnIdTypeName,
1326 BuiltinFnIdCanImplicitCast,
13271389 BuiltinFnIdPanic,
13281390 BuiltinFnIdPtrCast,
13291391 BuiltinFnIdBitCast,
......@@ -1335,6 +1397,7 @@ enum BuiltinFnId {
13351397 BuiltinFnIdOffsetOf,
13361398 BuiltinFnIdInlineCall,
13371399 BuiltinFnIdNoInlineCall,
1400 BuiltinFnIdNewStackCall,
13381401 BuiltinFnIdTypeId,
13391402 BuiltinFnIdShlExact,
13401403 BuiltinFnIdShrExact,
......@@ -1346,6 +1409,7 @@ enum BuiltinFnId {
13461409 BuiltinFnIdExport,
13471410 BuiltinFnIdErrorReturnTrace,
13481411 BuiltinFnIdAtomicRmw,
1412 BuiltinFnIdAtomicLoad,
13491413};
13501414
13511415struct BuiltinFnEntry {
......@@ -1366,10 +1430,12 @@ enum PanicMsgId {
13661430 PanicMsgIdRemainderDivisionByZero,
13671431 PanicMsgIdExactDivisionRemainder,
13681432 PanicMsgIdSliceWidenRemainder,
1369 PanicMsgIdUnwrapMaybeFail,
1433 PanicMsgIdUnwrapOptionalFail,
13701434 PanicMsgIdInvalidErrorCode,
13711435 PanicMsgIdIncorrectAlignment,
13721436 PanicMsgIdBadUnionField,
1437 PanicMsgIdBadEnumValue,
1438 PanicMsgIdFloatToInt,
13731439
13741440 PanicMsgIdCount,
13751441};
......@@ -1383,6 +1449,7 @@ struct TypeId {
13831449 union {
13841450 struct {
13851451 TypeTableEntry *child_type;
1452 PtrLen ptr_len;
13861453 bool is_const;
13871454 bool is_volatile;
13881455 uint32_t alignment;
......@@ -1410,9 +1477,11 @@ bool type_id_eql(TypeId a, TypeId b);
14101477enum ZigLLVMFnId {
14111478 ZigLLVMFnIdCtz,
14121479 ZigLLVMFnIdClz,
1480 ZigLLVMFnIdPopCount,
14131481 ZigLLVMFnIdOverflowArithmetic,
14141482 ZigLLVMFnIdFloor,
14151483 ZigLLVMFnIdCeil,
1484 ZigLLVMFnIdSqrt,
14161485};
14171486
14181487enum AddSubMul {
......@@ -1433,7 +1502,10 @@ struct ZigLLVMFnKey {
14331502 } clz;
14341503 struct {
14351504 uint32_t bit_count;
1436 } floor_ceil;
1505 } pop_count;
1506 struct {
1507 uint32_t bit_count;
1508 } floating;
14371509 struct {
14381510 AddSubMul add_sub_mul;
14391511 uint32_t bit_count;
......@@ -1454,6 +1526,7 @@ enum BuildMode {
14541526 BuildModeDebug,
14551527 BuildModeFastRelease,
14561528 BuildModeSafeRelease,
1529 BuildModeSmallRelease,
14571530};
14581531
14591532enum EmitFileType {
......@@ -1499,6 +1572,7 @@ struct CodeGen {
14991572 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
15001573 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
15011574 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
1575 HashMap<const TypeTableEntry *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
15021576
15031577
15041578 ZigList<ImportTableEntry *> import_queue;
......@@ -1512,7 +1586,6 @@ struct CodeGen {
15121586
15131587 struct {
15141588 TypeTableEntry *entry_bool;
1515 TypeTableEntry *entry_int[2][12]; // [signed,unsigned][2,3,4,5,6,7,8,16,29,32,64,128]
15161589 TypeTableEntry *entry_c_int[CIntTypeCount];
15171590 TypeTableEntry *entry_c_longdouble;
15181591 TypeTableEntry *entry_c_void;
......@@ -1521,14 +1594,12 @@ struct CodeGen {
15211594 TypeTableEntry *entry_u32;
15221595 TypeTableEntry *entry_u29;
15231596 TypeTableEntry *entry_u64;
1524 TypeTableEntry *entry_u128;
15251597 TypeTableEntry *entry_i8;
1526 TypeTableEntry *entry_i16;
15271598 TypeTableEntry *entry_i32;
15281599 TypeTableEntry *entry_i64;
1529 TypeTableEntry *entry_i128;
15301600 TypeTableEntry *entry_isize;
15311601 TypeTableEntry *entry_usize;
1602 TypeTableEntry *entry_f16;
15321603 TypeTableEntry *entry_f32;
15331604 TypeTableEntry *entry_f64;
15341605 TypeTableEntry *entry_f128;
......@@ -1645,10 +1716,16 @@ struct CodeGen {
16451716 LLVMValueRef coro_save_fn_val;
16461717 LLVMValueRef coro_promise_fn_val;
16471718 LLVMValueRef coro_alloc_helper_fn_val;
1719 LLVMValueRef coro_frame_fn_val;
16481720 LLVMValueRef merge_err_ret_traces_fn_val;
16491721 LLVMValueRef add_error_return_trace_addr_fn_val;
1722 LLVMValueRef stacksave_fn_val;
1723 LLVMValueRef stackrestore_fn_val;
1724 LLVMValueRef write_register_fn_val;
16501725 bool error_during_imports;
16511726
1727 LLVMValueRef sp_md_node;
1728
16521729 const char **clang_argv;
16531730 size_t clang_argv_len;
16541731 ZigList<const char *> lib_dirs;
......@@ -1680,8 +1757,6 @@ struct CodeGen {
16801757 ZigList<Buf *> link_objects;
16811758 ZigList<Buf *> assembly_files;
16821759
1683 ZigList<TypeTableEntry *> name_table_enums;
1684
16851760 Buf *test_filter;
16861761 Buf *test_name_prefix;
16871762
......@@ -1700,6 +1775,8 @@ struct CodeGen {
17001775 ZigList<ZigLLVMDIType **> error_di_types;
17011776
17021777 ZigList<Buf *> forbidden_libs;
1778
1779 bool no_rosegment_workaround;
17031780};
17041781
17051782enum VarLinkage {
......@@ -1750,6 +1827,7 @@ enum ScopeId {
17501827 ScopeIdVarDecl,
17511828 ScopeIdCImport,
17521829 ScopeIdLoop,
1830 ScopeIdSuspend,
17531831 ScopeIdFnDef,
17541832 ScopeIdCompTime,
17551833 ScopeIdCoroPrelude,
......@@ -1845,6 +1923,16 @@ struct ScopeLoop {
18451923 ZigList<IrBasicBlock *> *incoming_blocks;
18461924};
18471925
1926// This scope is created for a suspend block in order to have labeled
1927// suspend for breaking out of a suspend and for detecting if a suspend
1928// block is inside a suspend block.
1929struct ScopeSuspend {
1930 Scope base;
1931
1932 IrBasicBlock *resume_block;
1933 bool reported_err;
1934};
1935
18481936// This scope is created for a comptime expression.
18491937// NodeTypeCompTime, NodeTypeSwitchExpr
18501938struct ScopeCompTime {
......@@ -1912,12 +2000,6 @@ struct IrBasicBlock {
19122000 IrInstruction *must_be_comptime_source_instr;
19132001};
19142002
1915struct LVal {
1916 bool is_ptr;
1917 bool is_const;
1918 bool is_volatile;
1919};
1920
19212003enum IrInstructionId {
19222004 IrInstructionIdInvalid,
19232005 IrInstructionIdBr,
......@@ -1957,11 +2039,12 @@ enum IrInstructionId {
19572039 IrInstructionIdAsm,
19582040 IrInstructionIdSizeOf,
19592041 IrInstructionIdTestNonNull,
1960 IrInstructionIdUnwrapMaybe,
1961 IrInstructionIdMaybeWrap,
2042 IrInstructionIdUnwrapOptional,
2043 IrInstructionIdOptionalWrap,
19622044 IrInstructionIdUnionTag,
19632045 IrInstructionIdClz,
19642046 IrInstructionIdCtz,
2047 IrInstructionIdPopCount,
19652048 IrInstructionIdImport,
19662049 IrInstructionIdCImport,
19672050 IrInstructionIdCInclude,
......@@ -1978,6 +2061,11 @@ enum IrInstructionId {
19782061 IrInstructionIdCmpxchg,
19792062 IrInstructionIdFence,
19802063 IrInstructionIdTruncate,
2064 IrInstructionIdIntCast,
2065 IrInstructionIdFloatCast,
2066 IrInstructionIdIntToFloat,
2067 IrInstructionIdFloatToInt,
2068 IrInstructionIdBoolToInt,
19812069 IrInstructionIdIntType,
19822070 IrInstructionIdBoolNot,
19832071 IrInstructionIdMemset,
......@@ -1989,6 +2077,7 @@ enum IrInstructionId {
19892077 IrInstructionIdBreakpoint,
19902078 IrInstructionIdReturnAddress,
19912079 IrInstructionIdFrameAddress,
2080 IrInstructionIdHandle,
19922081 IrInstructionIdAlignOf,
19932082 IrInstructionIdOverflowOp,
19942083 IrInstructionIdTestErr,
......@@ -2004,21 +2093,22 @@ enum IrInstructionId {
20042093 IrInstructionIdIntToPtr,
20052094 IrInstructionIdPtrToInt,
20062095 IrInstructionIdIntToEnum,
2096 IrInstructionIdEnumToInt,
20072097 IrInstructionIdIntToErr,
20082098 IrInstructionIdErrToInt,
20092099 IrInstructionIdCheckSwitchProngs,
20102100 IrInstructionIdCheckStatementIsVoid,
20112101 IrInstructionIdTypeName,
2012 IrInstructionIdCanImplicitCast,
20132102 IrInstructionIdDeclRef,
20142103 IrInstructionIdPanic,
20152104 IrInstructionIdTagName,
20162105 IrInstructionIdTagType,
20172106 IrInstructionIdFieldParentPtr,
20182107 IrInstructionIdOffsetOf,
2108 IrInstructionIdTypeInfo,
20192109 IrInstructionIdTypeId,
20202110 IrInstructionIdSetEvalBranchQuota,
2021 IrInstructionIdPtrTypeOf,
2111 IrInstructionIdPtrType,
20222112 IrInstructionIdAlignCast,
20232113 IrInstructionIdOpaqueType,
20242114 IrInstructionIdSetAlignStack,
......@@ -2041,12 +2131,17 @@ enum IrInstructionId {
20412131 IrInstructionIdCoroPromise,
20422132 IrInstructionIdCoroAllocHelper,
20432133 IrInstructionIdAtomicRmw,
2134 IrInstructionIdAtomicLoad,
20442135 IrInstructionIdPromiseResultType,
20452136 IrInstructionIdAwaitBookkeeping,
20462137 IrInstructionIdSaveErrRetAddr,
20472138 IrInstructionIdAddImplicitReturnType,
20482139 IrInstructionIdMergeErrRetTraces,
20492140 IrInstructionIdMarkErrRetTracePtr,
2141 IrInstructionIdSqrt,
2142 IrInstructionIdErrSetCast,
2143 IrInstructionIdToBytes,
2144 IrInstructionIdFromBytes,
20502145};
20512146
20522147struct IrInstruction {
......@@ -2094,6 +2189,7 @@ struct IrInstructionSwitchBr {
20942189 size_t case_count;
20952190 IrInstructionSwitchBrCase *cases;
20962191 IrInstruction *is_comptime;
2192 IrInstruction *switch_prongs_void;
20972193};
20982194
20992195struct IrInstructionSwitchVar {
......@@ -2123,7 +2219,7 @@ enum IrUnOp {
21232219 IrUnOpNegation,
21242220 IrUnOpNegationWrap,
21252221 IrUnOpDereference,
2126 IrUnOpMaybe,
2222 IrUnOpOptional,
21272223};
21282224
21292225struct IrInstructionUnOp {
......@@ -2203,7 +2299,8 @@ struct IrInstructionFieldPtr {
22032299 IrInstruction base;
22042300
22052301 IrInstruction *container_ptr;
2206 Buf *field_name;
2302 Buf *field_name_buffer;
2303 IrInstruction *field_name_expr;
22072304 bool is_const;
22082305};
22092306
......@@ -2228,6 +2325,7 @@ struct IrInstructionElemPtr {
22282325
22292326 IrInstruction *array_ptr;
22302327 IrInstruction *elem_index;
2328 PtrLen ptr_len;
22312329 bool is_const;
22322330 bool safety_check_on;
22332331};
......@@ -2236,8 +2334,6 @@ struct IrInstructionVarPtr {
22362334 IrInstruction base;
22372335
22382336 VariableTableEntry *var;
2239 bool is_const;
2240 bool is_volatile;
22412337};
22422338
22432339struct IrInstructionCall {
......@@ -2253,6 +2349,7 @@ struct IrInstructionCall {
22532349 bool is_async;
22542350
22552351 IrInstruction *async_allocator;
2352 IrInstruction *new_stack;
22562353};
22572354
22582355struct IrInstructionConst {
......@@ -2373,6 +2470,18 @@ struct IrInstructionArrayType {
23732470 IrInstruction *child_type;
23742471};
23752472
2473struct IrInstructionPtrType {
2474 IrInstruction base;
2475
2476 IrInstruction *align_value;
2477 IrInstruction *child_type;
2478 uint32_t bit_offset_start;
2479 uint32_t bit_offset_end;
2480 PtrLen ptr_len;
2481 bool is_const;
2482 bool is_volatile;
2483};
2484
23762485struct IrInstructionPromiseType {
23772486 IrInstruction base;
23782487
......@@ -2413,7 +2522,7 @@ struct IrInstructionTestNonNull {
24132522 IrInstruction *value;
24142523};
24152524
2416struct IrInstructionUnwrapMaybe {
2525struct IrInstructionUnwrapOptional {
24172526 IrInstruction base;
24182527
24192528 IrInstruction *value;
......@@ -2432,6 +2541,12 @@ struct IrInstructionClz {
24322541 IrInstruction *value;
24332542};
24342543
2544struct IrInstructionPopCount {
2545 IrInstruction base;
2546
2547 IrInstruction *value;
2548};
2549
24352550struct IrInstructionUnionTag {
24362551 IrInstruction base;
24372552
......@@ -2522,6 +2637,7 @@ struct IrInstructionEmbedFile {
25222637struct IrInstructionCmpxchg {
25232638 IrInstruction base;
25242639
2640 IrInstruction *type_value;
25252641 IrInstruction *ptr;
25262642 IrInstruction *cmp_value;
25272643 IrInstruction *new_value;
......@@ -2529,8 +2645,13 @@ struct IrInstructionCmpxchg {
25292645 IrInstruction *failure_order_value;
25302646
25312647 // if this instruction gets to runtime then we know these values:
2648 TypeTableEntry *type;
25322649 AtomicOrder success_order;
25332650 AtomicOrder failure_order;
2651
2652 bool is_weak;
2653
2654 LLVMValueRef tmp_ptr;
25342655};
25352656
25362657struct IrInstructionFence {
......@@ -2549,6 +2670,60 @@ struct IrInstructionTruncate {
25492670 IrInstruction *target;
25502671};
25512672
2673struct IrInstructionIntCast {
2674 IrInstruction base;
2675
2676 IrInstruction *dest_type;
2677 IrInstruction *target;
2678};
2679
2680struct IrInstructionFloatCast {
2681 IrInstruction base;
2682
2683 IrInstruction *dest_type;
2684 IrInstruction *target;
2685};
2686
2687struct IrInstructionErrSetCast {
2688 IrInstruction base;
2689
2690 IrInstruction *dest_type;
2691 IrInstruction *target;
2692};
2693
2694struct IrInstructionToBytes {
2695 IrInstruction base;
2696
2697 IrInstruction *target;
2698};
2699
2700struct IrInstructionFromBytes {
2701 IrInstruction base;
2702
2703 IrInstruction *dest_child_type;
2704 IrInstruction *target;
2705};
2706
2707struct IrInstructionIntToFloat {
2708 IrInstruction base;
2709
2710 IrInstruction *dest_type;
2711 IrInstruction *target;
2712};
2713
2714struct IrInstructionFloatToInt {
2715 IrInstruction base;
2716
2717 IrInstruction *dest_type;
2718 IrInstruction *target;
2719};
2720
2721struct IrInstructionBoolToInt {
2722 IrInstruction base;
2723
2724 IrInstruction *target;
2725};
2726
25522727struct IrInstructionIntType {
25532728 IrInstruction base;
25542729
......@@ -2620,6 +2795,10 @@ struct IrInstructionFrameAddress {
26202795 IrInstruction base;
26212796};
26222797
2798struct IrInstructionHandle {
2799 IrInstruction base;
2800};
2801
26232802enum IrOverflowOp {
26242803 IrOverflowOpAdd,
26252804 IrOverflowOpSub,
......@@ -2665,7 +2844,7 @@ struct IrInstructionUnwrapErrPayload {
26652844 bool safety_check_on;
26662845};
26672846
2668struct IrInstructionMaybeWrap {
2847struct IrInstructionOptionalWrap {
26692848 IrInstruction base;
26702849
26712850 IrInstruction *value;
......@@ -2739,6 +2918,13 @@ struct IrInstructionIntToPtr {
27392918struct IrInstructionIntToEnum {
27402919 IrInstruction base;
27412920
2921 IrInstruction *dest_type;
2922 IrInstruction *target;
2923};
2924
2925struct IrInstructionEnumToInt {
2926 IrInstruction base;
2927
27422928 IrInstruction *target;
27432929};
27442930
......@@ -2780,11 +2966,9 @@ struct IrInstructionTypeName {
27802966 IrInstruction *type_value;
27812967};
27822968
2783struct IrInstructionCanImplicitCast {
2784 IrInstruction base;
2785
2786 IrInstruction *type_value;
2787 IrInstruction *target_value;
2969enum LVal {
2970 LValNone,
2971 LValPtr,
27882972};
27892973
27902974struct IrInstructionDeclRef {
......@@ -2828,27 +3012,22 @@ struct IrInstructionOffsetOf {
28283012 IrInstruction *field_name;
28293013};
28303014
2831struct IrInstructionTypeId {
3015struct IrInstructionTypeInfo {
28323016 IrInstruction base;
28333017
28343018 IrInstruction *type_value;
28353019};
28363020
2837struct IrInstructionSetEvalBranchQuota {
3021struct IrInstructionTypeId {
28383022 IrInstruction base;
28393023
2840 IrInstruction *new_quota;
3024 IrInstruction *type_value;
28413025};
28423026
2843struct IrInstructionPtrTypeOf {
3027struct IrInstructionSetEvalBranchQuota {
28443028 IrInstruction base;
28453029
2846 IrInstruction *align_value;
2847 IrInstruction *child_type;
2848 uint32_t bit_offset_start;
2849 uint32_t bit_offset_end;
2850 bool is_const;
2851 bool is_volatile;
3030 IrInstruction *new_quota;
28523031};
28533032
28543033struct IrInstructionAlignCast {
......@@ -2886,10 +3065,10 @@ struct IrInstructionExport {
28863065struct IrInstructionErrorReturnTrace {
28873066 IrInstruction base;
28883067
2889 enum Nullable {
3068 enum Optional {
28903069 Null,
28913070 NonNull,
2892 } nullable;
3071 } optional;
28933072};
28943073
28953074struct IrInstructionErrorUnion {
......@@ -3000,6 +3179,15 @@ struct IrInstructionAtomicRmw {
30003179 AtomicOrder resolved_ordering;
30013180};
30023181
3182struct IrInstructionAtomicLoad {
3183 IrInstruction base;
3184
3185 IrInstruction *operand_type;
3186 IrInstruction *ptr;
3187 IrInstruction *ordering;
3188 AtomicOrder resolved_ordering;
3189};
3190
30033191struct IrInstructionPromiseResultType {
30043192 IrInstruction base;
30053193
......@@ -3036,6 +3224,13 @@ struct IrInstructionMarkErrRetTracePtr {
30363224 IrInstruction *err_ret_trace_ptr;
30373225};
30383226
3227struct IrInstructionSqrt {
3228 IrInstruction base;
3229
3230 IrInstruction *type;
3231 IrInstruction *op;
3232};
3233
30393234static const size_t slice_ptr_index = 0;
30403235static const size_t slice_len_index = 1;
30413236
......@@ -3054,7 +3249,7 @@ static const size_t stack_trace_ptr_count = 30;
30543249#define RESULT_FIELD_NAME "result"
30553250#define ASYNC_ALLOC_FIELD_NAME "allocFn"
30563251#define ASYNC_FREE_FIELD_NAME "freeFn"
3057#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
3252#define ATOMIC_STATE_FIELD_NAME "atomic_state"
30583253// these point to data belonging to the awaiter
30593254#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
30603255#define RESULT_PTR_FIELD_NAME "result_ptr"
src/analyze.cpp+582-387
......@@ -25,6 +25,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type);
2525static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type);
2626static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type);
2727static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type);
28static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
2829
2930ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
3031 if (node->owner->c_import_node != nullptr) {
......@@ -156,6 +157,13 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) {
156157 return scope;
157158}
158159
160ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent) {
161 assert(node->type == NodeTypeSuspend);
162 ScopeSuspend *scope = allocate<ScopeSuspend>(1);
163 init_scope(&scope->base, ScopeIdSuspend, node, parent);
164 return scope;
165}
166
159167ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) {
160168 ScopeFnDef *scope = allocate<ScopeFnDef>(1);
161169 init_scope(&scope->base, ScopeIdFnDef, node, parent);
......@@ -203,6 +211,43 @@ static uint8_t bits_needed_for_unsigned(uint64_t x) {
203211 return (upper >= x) ? base : (base + 1);
204212}
205213
214AstNode *type_decl_node(TypeTableEntry *type_entry) {
215 switch (type_entry->id) {
216 case TypeTableEntryIdInvalid:
217 zig_unreachable();
218 case TypeTableEntryIdStruct:
219 return type_entry->data.structure.decl_node;
220 case TypeTableEntryIdEnum:
221 return type_entry->data.enumeration.decl_node;
222 case TypeTableEntryIdUnion:
223 return type_entry->data.unionation.decl_node;
224 case TypeTableEntryIdOpaque:
225 case TypeTableEntryIdMetaType:
226 case TypeTableEntryIdVoid:
227 case TypeTableEntryIdBool:
228 case TypeTableEntryIdUnreachable:
229 case TypeTableEntryIdInt:
230 case TypeTableEntryIdFloat:
231 case TypeTableEntryIdPointer:
232 case TypeTableEntryIdArray:
233 case TypeTableEntryIdComptimeFloat:
234 case TypeTableEntryIdComptimeInt:
235 case TypeTableEntryIdUndefined:
236 case TypeTableEntryIdNull:
237 case TypeTableEntryIdOptional:
238 case TypeTableEntryIdErrorUnion:
239 case TypeTableEntryIdErrorSet:
240 case TypeTableEntryIdFn:
241 case TypeTableEntryIdNamespace:
242 case TypeTableEntryIdBlock:
243 case TypeTableEntryIdBoundFn:
244 case TypeTableEntryIdArgTuple:
245 case TypeTableEntryIdPromise:
246 return nullptr;
247 }
248 zig_unreachable();
249}
250
206251bool type_is_complete(TypeTableEntry *type_entry) {
207252 switch (type_entry->id) {
208253 case TypeTableEntryIdInvalid:
......@@ -223,11 +268,11 @@ bool type_is_complete(TypeTableEntry *type_entry) {
223268 case TypeTableEntryIdFloat:
224269 case TypeTableEntryIdPointer:
225270 case TypeTableEntryIdArray:
226 case TypeTableEntryIdNumLitFloat:
227 case TypeTableEntryIdNumLitInt:
228 case TypeTableEntryIdUndefLit:
229 case TypeTableEntryIdNullLit:
230 case TypeTableEntryIdMaybe:
271 case TypeTableEntryIdComptimeFloat:
272 case TypeTableEntryIdComptimeInt:
273 case TypeTableEntryIdUndefined:
274 case TypeTableEntryIdNull:
275 case TypeTableEntryIdOptional:
231276 case TypeTableEntryIdErrorUnion:
232277 case TypeTableEntryIdErrorSet:
233278 case TypeTableEntryIdFn:
......@@ -259,11 +304,11 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
259304 case TypeTableEntryIdFloat:
260305 case TypeTableEntryIdPointer:
261306 case TypeTableEntryIdArray:
262 case TypeTableEntryIdNumLitFloat:
263 case TypeTableEntryIdNumLitInt:
264 case TypeTableEntryIdUndefLit:
265 case TypeTableEntryIdNullLit:
266 case TypeTableEntryIdMaybe:
307 case TypeTableEntryIdComptimeFloat:
308 case TypeTableEntryIdComptimeInt:
309 case TypeTableEntryIdUndefined:
310 case TypeTableEntryIdNull:
311 case TypeTableEntryIdOptional:
267312 case TypeTableEntryIdErrorUnion:
268313 case TypeTableEntryIdErrorSet:
269314 case TypeTableEntryIdFn:
......@@ -372,14 +417,15 @@ TypeTableEntry *get_promise_type(CodeGen *g, TypeTableEntry *result_type) {
372417}
373418
374419TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
375 bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
420 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
376421{
377422 assert(!type_is_invalid(child_type));
423 assert(ptr_len == PtrLenSingle || child_type->id != TypeTableEntryIdOpaque);
378424
379425 TypeId type_id = {};
380426 TypeTableEntry **parent_pointer = nullptr;
381427 uint32_t abi_alignment = get_abi_alignment(g, child_type);
382 if (unaligned_bit_count != 0 || is_volatile || byte_alignment != abi_alignment) {
428 if (unaligned_bit_count != 0 || is_volatile || byte_alignment != abi_alignment || ptr_len != PtrLenSingle) {
383429 type_id.id = TypeTableEntryIdPointer;
384430 type_id.data.pointer.child_type = child_type;
385431 type_id.data.pointer.is_const = is_const;
......@@ -387,6 +433,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
387433 type_id.data.pointer.alignment = byte_alignment;
388434 type_id.data.pointer.bit_offset = bit_offset;
389435 type_id.data.pointer.unaligned_bit_count = unaligned_bit_count;
436 type_id.data.pointer.ptr_len = ptr_len;
390437
391438 auto existing_entry = g->type_table.maybe_get(type_id);
392439 if (existing_entry)
......@@ -405,16 +452,17 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
405452 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
406453 entry->is_copyable = true;
407454
455 const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]";
408456 const char *const_str = is_const ? "const " : "";
409457 const char *volatile_str = is_volatile ? "volatile " : "";
410458 buf_resize(&entry->name, 0);
411459 if (unaligned_bit_count == 0 && byte_alignment == abi_alignment) {
412 buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
460 buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name));
413461 } else if (unaligned_bit_count == 0) {
414 buf_appendf(&entry->name, "&align(%" PRIu32 ") %s%s%s", byte_alignment,
462 buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
415463 const_str, volatile_str, buf_ptr(&child_type->name));
416464 } else {
417 buf_appendf(&entry->name, "&align(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", byte_alignment,
465 buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
418466 bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
419467 }
420468
......@@ -424,7 +472,9 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
424472
425473 if (!entry->zero_bits) {
426474 assert(byte_alignment > 0);
427 if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != abi_alignment) {
475 if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != abi_alignment ||
476 ptr_len != PtrLenSingle)
477 {
428478 TypeTableEntry *peer_type = get_pointer_to_type(g, child_type, false);
429479 entry->type_ref = peer_type->type_ref;
430480 entry->di_type = peer_type->di_type;
......@@ -442,6 +492,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
442492 entry->di_type = g->builtin_types.entry_void->di_type;
443493 }
444494
495 entry->data.pointer.ptr_len = ptr_len;
445496 entry->data.pointer.child_type = child_type;
446497 entry->data.pointer.is_const = is_const;
447498 entry->data.pointer.is_volatile = is_volatile;
......@@ -458,7 +509,8 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
458509}
459510
460511TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
461 return get_pointer_to_type_extra(g, child_type, is_const, false, get_abi_alignment(g, child_type), 0, 0);
512 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle,
513 get_abi_alignment(g, child_type), 0, 0);
462514}
463515
464516TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) {
......@@ -466,11 +518,11 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
466518 return return_type->promise_frame_parent;
467519 }
468520
469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
521 TypeTableEntry *atomic_state_type = g->builtin_types.entry_usize;
470522 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
471523
472524 ZigList<const char *> field_names = {};
473 field_names.append(AWAITER_HANDLE_FIELD_NAME);
525 field_names.append(ATOMIC_STATE_FIELD_NAME);
474526 field_names.append(RESULT_FIELD_NAME);
475527 field_names.append(RESULT_PTR_FIELD_NAME);
476528 if (g->have_err_ret_tracing) {
......@@ -480,7 +532,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
480532 }
481533
482534 ZigList<TypeTableEntry *> field_types = {};
483 field_types.append(awaiter_handle_type);
535 field_types.append(atomic_state_type);
484536 field_types.append(return_type);
485537 field_types.append(result_ptr_type);
486538 if (g->have_err_ret_tracing) {
......@@ -497,16 +549,15 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
497549 return entry;
498550}
499551
500TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
501 if (child_type->maybe_parent) {
502 TypeTableEntry *entry = child_type->maybe_parent;
552TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type) {
553 if (child_type->optional_parent) {
554 TypeTableEntry *entry = child_type->optional_parent;
503555 return entry;
504556 } else {
505557 ensure_complete_type(g, child_type);
506558
507 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
559 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdOptional);
508560 assert(child_type->type_ref || child_type->zero_bits);
509 assert(child_type->di_type);
510561 entry->is_copyable = type_is_copyable(g, child_type);
511562
512563 buf_resize(&entry->name, 0);
......@@ -516,12 +567,14 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
516567 entry->type_ref = LLVMInt1Type();
517568 entry->di_type = g->builtin_types.entry_bool->di_type;
518569 } else if (type_is_codegen_pointer(child_type)) {
570 assert(child_type->di_type);
519571 // this is an optimization but also is necessary for calling C
520572 // functions where all pointers are maybe pointers
521573 // function types are technically pointers
522574 entry->type_ref = child_type->type_ref;
523575 entry->di_type = child_type->di_type;
524576 } else {
577 assert(child_type->di_type);
525578 // create a struct with a boolean whether this is the null value
526579 LLVMTypeRef elem_types[] = {
527580 child_type->type_ref,
......@@ -575,7 +628,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
575628
576629 entry->data.maybe.child_type = child_type;
577630
578 child_type->maybe_parent = entry;
631 child_type->optional_parent = entry;
579632 return entry;
580633 }
581634}
......@@ -748,6 +801,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *pointer_type, Typ
748801
749802TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) {
750803 assert(ptr_type->id == TypeTableEntryIdPointer);
804 assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown);
751805
752806 TypeTableEntry **parent_pointer = &ptr_type->data.pointer.slice_parent;
753807 if (*parent_pointer) {
......@@ -759,14 +813,16 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) {
759813
760814 // replace the & with [] to go from a ptr type name to a slice type name
761815 buf_resize(&entry->name, 0);
762 buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + 1);
816 size_t name_offset = (ptr_type->data.pointer.ptr_len == PtrLenSingle) ? 1 : 3;
817 buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset);
763818
764819 TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
765 uint32_t abi_alignment;
820 uint32_t abi_alignment = get_abi_alignment(g, child_type);
766821 if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
767 ptr_type->data.pointer.alignment != (abi_alignment = get_abi_alignment(g, child_type)))
822 ptr_type->data.pointer.alignment != abi_alignment)
768823 {
769 TypeTableEntry *peer_ptr_type = get_pointer_to_type(g, child_type, false);
824 TypeTableEntry *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
825 PtrLenUnknown, abi_alignment, 0, 0);
770826 TypeTableEntry *peer_slice_type = get_slice_type(g, peer_ptr_type);
771827
772828 slice_type_common_init(g, ptr_type, entry);
......@@ -790,9 +846,11 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) {
790846 if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
791847 child_ptr_type->data.pointer.alignment != get_abi_alignment(g, grand_child_type))
792848 {
793 TypeTableEntry *bland_child_ptr_type = get_pointer_to_type(g, grand_child_type, false);
849 TypeTableEntry *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
850 PtrLenUnknown, get_abi_alignment(g, grand_child_type), 0, 0);
794851 TypeTableEntry *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
795 TypeTableEntry *peer_ptr_type = get_pointer_to_type(g, bland_child_slice, false);
852 TypeTableEntry *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
853 PtrLenUnknown, get_abi_alignment(g, bland_child_slice), 0, 0);
796854 TypeTableEntry *peer_slice_type = get_slice_type(g, peer_ptr_type);
797855
798856 entry->type_ref = peer_slice_type->type_ref;
......@@ -998,8 +1056,11 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
9981056 }
9991057 if (fn_type_id->return_type != nullptr) {
10001058 ensure_complete_type(g, fn_type_id->return_type);
1059 if (type_is_invalid(fn_type_id->return_type))
1060 return g->builtin_types.entry_invalid;
1061 assert(fn_type_id->return_type->id != TypeTableEntryIdOpaque);
10011062 } else {
1002 zig_panic("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447");
1063 zig_panic("TODO implement inferred return types https://github.com/ziglang/zig/issues/447");
10031064 }
10041065
10051066 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
......@@ -1111,7 +1172,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11111172 gen_param_info->src_index = i;
11121173 gen_param_info->gen_index = SIZE_MAX;
11131174
1114 type_ensure_zero_bits_known(g, type_entry);
1175 ensure_complete_type(g, type_entry);
1176 if (type_is_invalid(type_entry))
1177 return g->builtin_types.entry_invalid;
1178
11151179 if (type_has_bits(type_entry)) {
11161180 TypeTableEntry *gen_type;
11171181 if (handle_is_ptr(type_entry)) {
......@@ -1250,7 +1314,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
12501314 }
12511315
12521316 fn_type_id->param_count = fn_proto->params.length;
1253 fn_type_id->param_info = allocate_nonzero<FnTypeParamInfo>(param_count_alloc);
1317 fn_type_id->param_info = allocate<FnTypeParamInfo>(param_count_alloc);
12541318 fn_type_id->next_param_index = 0;
12551319 fn_type_id->is_var_args = fn_proto->is_var_args;
12561320}
......@@ -1275,7 +1339,8 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_
12751339}
12761340
12771341static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) {
1278 TypeTableEntry *ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
1342 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
1343 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
12791344 TypeTableEntry *str_type = get_slice_type(g, ptr_type);
12801345 IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr);
12811346 if (type_is_invalid(instr->value.type))
......@@ -1312,10 +1377,10 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
13121377 zig_unreachable();
13131378 case TypeTableEntryIdMetaType:
13141379 case TypeTableEntryIdUnreachable:
1315 case TypeTableEntryIdNumLitFloat:
1316 case TypeTableEntryIdNumLitInt:
1317 case TypeTableEntryIdUndefLit:
1318 case TypeTableEntryIdNullLit:
1380 case TypeTableEntryIdComptimeFloat:
1381 case TypeTableEntryIdComptimeInt:
1382 case TypeTableEntryIdUndefined:
1383 case TypeTableEntryIdNull:
13191384 case TypeTableEntryIdErrorUnion:
13201385 case TypeTableEntryIdErrorSet:
13211386 case TypeTableEntryIdNamespace:
......@@ -1337,7 +1402,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
13371402 return type_entry->data.structure.layout == ContainerLayoutPacked;
13381403 case TypeTableEntryIdUnion:
13391404 return type_entry->data.unionation.layout == ContainerLayoutPacked;
1340 case TypeTableEntryIdMaybe:
1405 case TypeTableEntryIdOptional:
13411406 {
13421407 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
13431408 return type_is_codegen_pointer(child_type);
......@@ -1353,10 +1418,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
13531418 case TypeTableEntryIdInvalid:
13541419 zig_unreachable();
13551420 case TypeTableEntryIdMetaType:
1356 case TypeTableEntryIdNumLitFloat:
1357 case TypeTableEntryIdNumLitInt:
1358 case TypeTableEntryIdUndefLit:
1359 case TypeTableEntryIdNullLit:
1421 case TypeTableEntryIdComptimeFloat:
1422 case TypeTableEntryIdComptimeInt:
1423 case TypeTableEntryIdUndefined:
1424 case TypeTableEntryIdNull:
13601425 case TypeTableEntryIdErrorUnion:
13611426 case TypeTableEntryIdErrorSet:
13621427 case TypeTableEntryIdNamespace:
......@@ -1364,10 +1429,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
13641429 case TypeTableEntryIdBoundFn:
13651430 case TypeTableEntryIdArgTuple:
13661431 case TypeTableEntryIdPromise:
1432 case TypeTableEntryIdVoid:
13671433 return false;
13681434 case TypeTableEntryIdOpaque:
13691435 case TypeTableEntryIdUnreachable:
1370 case TypeTableEntryIdVoid:
13711436 case TypeTableEntryIdBool:
13721437 return true;
13731438 case TypeTableEntryIdInt:
......@@ -1388,13 +1453,18 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
13881453 case TypeTableEntryIdFn:
13891454 return type_entry->data.fn.fn_type_id.cc == CallingConventionC;
13901455 case TypeTableEntryIdPointer:
1391 return type_allowed_in_extern(g, type_entry->data.pointer.child_type);
1456 if (type_size(g, type_entry) == 0)
1457 return false;
1458 return true;
13921459 case TypeTableEntryIdStruct:
13931460 return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked;
1394 case TypeTableEntryIdMaybe:
1461 case TypeTableEntryIdOptional:
13951462 {
13961463 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1397 return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
1464 if (child_type->id != TypeTableEntryIdPointer && child_type->id != TypeTableEntryIdFn) {
1465 return false;
1466 }
1467 return type_allowed_in_extern(g, child_type);
13981468 }
13991469 case TypeTableEntryIdEnum:
14001470 return type_entry->data.enumeration.layout == ContainerLayoutExtern || type_entry->data.enumeration.layout == ContainerLayoutPacked;
......@@ -1441,6 +1511,17 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
14411511 calling_convention_name(fn_type_id.cc)));
14421512 return g->builtin_types.entry_invalid;
14431513 }
1514 if (param_node->data.param_decl.type != nullptr) {
1515 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
1516 if (type_is_invalid(type_entry)) {
1517 return g->builtin_types.entry_invalid;
1518 }
1519 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
1520 param_info->type = type_entry;
1521 param_info->is_noalias = param_node->data.param_decl.is_noalias;
1522 fn_type_id.next_param_index += 1;
1523 }
1524
14441525 return get_generic_fn_type(g, &fn_type_id);
14451526 } else if (param_is_var_args) {
14461527 if (fn_type_id.cc == CallingConventionC) {
......@@ -1490,23 +1571,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
14901571 case TypeTableEntryIdInvalid:
14911572 return g->builtin_types.entry_invalid;
14921573 case TypeTableEntryIdUnreachable:
1493 case TypeTableEntryIdUndefLit:
1494 case TypeTableEntryIdNullLit:
1574 case TypeTableEntryIdUndefined:
1575 case TypeTableEntryIdNull:
14951576 case TypeTableEntryIdArgTuple:
14961577 case TypeTableEntryIdOpaque:
14971578 add_node_error(g, param_node->data.param_decl.type,
14981579 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
14991580 return g->builtin_types.entry_invalid;
1500 case TypeTableEntryIdNumLitFloat:
1501 case TypeTableEntryIdNumLitInt:
1581 case TypeTableEntryIdComptimeFloat:
1582 case TypeTableEntryIdComptimeInt:
15021583 case TypeTableEntryIdNamespace:
15031584 case TypeTableEntryIdBlock:
15041585 case TypeTableEntryIdBoundFn:
15051586 case TypeTableEntryIdMetaType:
1506 add_node_error(g, param_node->data.param_decl.type,
1507 buf_sprintf("parameter of type '%s' must be declared comptime",
1508 buf_ptr(&type_entry->name)));
1509 return g->builtin_types.entry_invalid;
15101587 case TypeTableEntryIdVoid:
15111588 case TypeTableEntryIdBool:
15121589 case TypeTableEntryIdInt:
......@@ -1514,17 +1591,18 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15141591 case TypeTableEntryIdPointer:
15151592 case TypeTableEntryIdArray:
15161593 case TypeTableEntryIdStruct:
1517 case TypeTableEntryIdMaybe:
1594 case TypeTableEntryIdOptional:
15181595 case TypeTableEntryIdErrorUnion:
15191596 case TypeTableEntryIdErrorSet:
15201597 case TypeTableEntryIdEnum:
15211598 case TypeTableEntryIdUnion:
15221599 case TypeTableEntryIdFn:
15231600 case TypeTableEntryIdPromise:
1524 ensure_complete_type(g, type_entry);
1525 if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
1601 type_ensure_zero_bits_known(g, type_entry);
1602 if (type_requires_comptime(type_entry)) {
15261603 add_node_error(g, param_node->data.param_decl.type,
1527 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
1604 buf_sprintf("parameter of type '%s' must be declared comptime",
1605 buf_ptr(&type_entry->name)));
15281606 return g->builtin_types.entry_invalid;
15291607 }
15301608 break;
......@@ -1548,7 +1626,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15481626 return g->builtin_types.entry_invalid;
15491627 }
15501628 add_node_error(g, proto_node,
1551 buf_sprintf("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447"));
1629 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
15521630 return g->builtin_types.entry_invalid;
15531631 //return get_generic_fn_type(g, &fn_type_id);
15541632 }
......@@ -1566,7 +1644,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15661644 fn_type_id.return_type = specified_return_type;
15671645 }
15681646
1569 if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, fn_type_id.return_type)) {
1647 if (!calling_convention_allows_zig_types(fn_type_id.cc) &&
1648 fn_type_id.return_type->id != TypeTableEntryIdVoid &&
1649 !type_allowed_in_extern(g, fn_type_id.return_type))
1650 {
15701651 add_node_error(g, fn_proto->return_type,
15711652 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
15721653 buf_ptr(&fn_type_id.return_type->name),
......@@ -1578,16 +1659,16 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15781659 case TypeTableEntryIdInvalid:
15791660 zig_unreachable();
15801661
1581 case TypeTableEntryIdUndefLit:
1582 case TypeTableEntryIdNullLit:
1662 case TypeTableEntryIdUndefined:
1663 case TypeTableEntryIdNull:
15831664 case TypeTableEntryIdArgTuple:
15841665 case TypeTableEntryIdOpaque:
15851666 add_node_error(g, fn_proto->return_type,
15861667 buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
15871668 return g->builtin_types.entry_invalid;
15881669
1589 case TypeTableEntryIdNumLitFloat:
1590 case TypeTableEntryIdNumLitInt:
1670 case TypeTableEntryIdComptimeFloat:
1671 case TypeTableEntryIdComptimeInt:
15911672 case TypeTableEntryIdNamespace:
15921673 case TypeTableEntryIdBlock:
15931674 case TypeTableEntryIdBoundFn:
......@@ -1608,7 +1689,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
16081689 case TypeTableEntryIdPointer:
16091690 case TypeTableEntryIdArray:
16101691 case TypeTableEntryIdStruct:
1611 case TypeTableEntryIdMaybe:
1692 case TypeTableEntryIdOptional:
16121693 case TypeTableEntryIdErrorUnion:
16131694 case TypeTableEntryIdErrorSet:
16141695 case TypeTableEntryIdEnum:
......@@ -1839,7 +1920,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
18391920 }
18401921
18411922 assert(!struct_type->data.structure.zero_bits_loop_flag);
1842 assert(struct_type->data.structure.fields);
1923 assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0);
18431924 assert(decl_node->type == NodeTypeContainerDecl);
18441925
18451926 size_t field_count = struct_type->data.structure.src_field_count;
......@@ -1868,6 +1949,17 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
18681949 break;
18691950 }
18701951
1952 if (struct_type->data.structure.layout == ContainerLayoutExtern) {
1953 if (!type_allowed_in_extern(g, field_type)) {
1954 AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
1955 add_node_error(g, field_source_node,
1956 buf_sprintf("extern structs cannot contain fields of type '%s'",
1957 buf_ptr(&field_type->name)));
1958 struct_type->data.structure.is_invalid = true;
1959 break;
1960 }
1961 }
1962
18711963 if (!type_has_bits(field_type))
18721964 continue;
18731965
......@@ -2284,8 +2376,9 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
22842376 return;
22852377
22862378 if (enum_type->data.enumeration.zero_bits_loop_flag) {
2287 enum_type->data.enumeration.zero_bits_known = true;
2288 enum_type->data.enumeration.zero_bits_loop_flag = false;
2379 add_node_error(g, enum_type->data.enumeration.decl_node,
2380 buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
2381 enum_type->data.enumeration.is_invalid = true;
22892382 return;
22902383 }
22912384
......@@ -2317,8 +2410,14 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
23172410 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
23182411 occupied_tag_values.init(field_count);
23192412
2320 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2413 TypeTableEntry *tag_int_type;
2414 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
2415 tag_int_type = get_c_int_type(g, CIntTypeInt);
2416 } else {
2417 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2418 }
23212419
2420 // TODO: Are extern enums allowed to have an init_arg_expr?
23222421 if (decl_node->data.container_decl.init_arg_expr != nullptr) {
23232422 TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
23242423 if (type_is_invalid(wanted_tag_int_type)) {
......@@ -2503,6 +2602,10 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
25032602 continue;
25042603 }
25052604
2605 if (type_requires_comptime(field_type)) {
2606 struct_type->data.structure.requires_comptime = true;
2607 }
2608
25062609 if (!type_has_bits(field_type))
25072610 continue;
25082611
......@@ -2650,8 +2753,8 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
26502753 return;
26512754 }
26522755 tag_type = enum_type;
2756 abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count
26532757 covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
2654 abi_alignment_so_far = get_abi_alignment(g, enum_type);
26552758 } else {
26562759 tag_type = nullptr;
26572760 abi_alignment_so_far = 0;
......@@ -2694,6 +2797,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
26942797 }
26952798 union_field->type_entry = field_type;
26962799
2800 if (type_requires_comptime(field_type)) {
2801 union_type->data.unionation.requires_comptime = true;
2802 }
2803
2804
26972805 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
26982806 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
26992807 buf_sprintf("non-enum union field assignment"));
......@@ -2939,14 +3047,15 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
29393047 if (fn_type_id->param_count != 2) {
29403048 return wrong_panic_prototype(g, proto_node, fn_type);
29413049 }
2942 TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
3050 TypeTableEntry *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
3051 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
29433052 TypeTableEntry *const_u8_slice = get_slice_type(g, const_u8_ptr);
29443053 if (fn_type_id->param_info[0].type != const_u8_slice) {
29453054 return wrong_panic_prototype(g, proto_node, fn_type);
29463055 }
29473056
2948 TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2949 if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) {
3057 TypeTableEntry *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g));
3058 if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
29503059 return wrong_panic_prototype(g, proto_node, fn_type);
29513060 }
29523061
......@@ -3122,9 +3231,8 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
31223231 }
31233232
31243233 {
3125 auto entry = g->primitive_type_table.maybe_get(tld->name);
3126 if (entry) {
3127 TypeTableEntry *type = entry->value;
3234 TypeTableEntry *type = get_primitive_type(g, tld->name);
3235 if (type != nullptr) {
31283236 add_node_error(g, tld->source_node,
31293237 buf_sprintf("declaration shadows type '%s'", buf_ptr(&type->name)));
31303238 }
......@@ -3255,7 +3363,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
32553363 case NodeTypeThisLiteral:
32563364 case NodeTypeSymbol:
32573365 case NodeTypePrefixOpExpr:
3258 case NodeTypeAddrOfExpr:
3366 case NodeTypePointerType:
32593367 case NodeTypeIfBoolExpr:
32603368 case NodeTypeWhileExpr:
32613369 case NodeTypeForExpr:
......@@ -3267,6 +3375,8 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
32673375 case NodeTypeUnreachable:
32683376 case NodeTypeAsmExpr:
32693377 case NodeTypeFieldAccessExpr:
3378 case NodeTypePtrDeref:
3379 case NodeTypeUnwrapOptional:
32703380 case NodeTypeStructField:
32713381 case NodeTypeContainerInitExpr:
32723382 case NodeTypeStructValueField:
......@@ -3308,16 +3418,16 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
33083418 case TypeTableEntryIdInvalid:
33093419 return g->builtin_types.entry_invalid;
33103420 case TypeTableEntryIdUnreachable:
3311 case TypeTableEntryIdNumLitFloat:
3312 case TypeTableEntryIdNumLitInt:
3313 case TypeTableEntryIdUndefLit:
3314 case TypeTableEntryIdNullLit:
3421 case TypeTableEntryIdUndefined:
3422 case TypeTableEntryIdNull:
33153423 case TypeTableEntryIdBlock:
33163424 case TypeTableEntryIdArgTuple:
33173425 case TypeTableEntryIdOpaque:
33183426 add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",
33193427 buf_ptr(&type_entry->name)));
33203428 return g->builtin_types.entry_invalid;
3429 case TypeTableEntryIdComptimeFloat:
3430 case TypeTableEntryIdComptimeInt:
33213431 case TypeTableEntryIdNamespace:
33223432 case TypeTableEntryIdMetaType:
33233433 case TypeTableEntryIdVoid:
......@@ -3327,7 +3437,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
33273437 case TypeTableEntryIdPointer:
33283438 case TypeTableEntryIdArray:
33293439 case TypeTableEntryIdStruct:
3330 case TypeTableEntryIdMaybe:
3440 case TypeTableEntryIdOptional:
33313441 case TypeTableEntryIdErrorUnion:
33323442 case TypeTableEntryIdErrorSet:
33333443 case TypeTableEntryIdEnum:
......@@ -3367,9 +3477,8 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent
33673477 add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
33683478 variable_entry->value->type = g->builtin_types.entry_invalid;
33693479 } else {
3370 auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
3371 if (primitive_table_entry) {
3372 TypeTableEntry *type = primitive_table_entry->value;
3480 TypeTableEntry *type = get_primitive_type(g, name);
3481 if (type != nullptr) {
33733482 add_node_error(g, source_node,
33743483 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
33753484 variable_entry->value->type = g->builtin_types.entry_invalid;
......@@ -3451,12 +3560,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
34513560 add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
34523561 implicit_type = g->builtin_types.entry_invalid;
34533562 } else if ((!is_const || linkage == VarLinkageExternal) &&
3454 (implicit_type->id == TypeTableEntryIdNumLitFloat ||
3455 implicit_type->id == TypeTableEntryIdNumLitInt))
3563 (implicit_type->id == TypeTableEntryIdComptimeFloat ||
3564 implicit_type->id == TypeTableEntryIdComptimeInt))
34563565 {
34573566 add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
34583567 implicit_type = g->builtin_types.entry_invalid;
3459 } else if (implicit_type->id == TypeTableEntryIdNullLit) {
3568 } else if (implicit_type->id == TypeTableEntryIdNull) {
34603569 add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
34613570 implicit_type = g->builtin_types.entry_invalid;
34623571 } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
......@@ -3616,6 +3725,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
36163725 case ScopeIdVarDecl:
36173726 case ScopeIdCImport:
36183727 case ScopeIdLoop:
3728 case ScopeIdSuspend:
36193729 case ScopeIdCompTime:
36203730 case ScopeIdCoroPrelude:
36213731 scope = scope->parent;
......@@ -3674,6 +3784,7 @@ TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt
36743784}
36753785
36763786TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) {
3787 assert(enum_type->data.enumeration.zero_bits_known);
36773788 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
36783789 TypeEnumField *field = &enum_type->data.enumeration.fields[i];
36793790 if (bigint_cmp(&field->value, tag) == CmpEQ) {
......@@ -3700,11 +3811,11 @@ static bool is_container(TypeTableEntry *type_entry) {
37003811 case TypeTableEntryIdInt:
37013812 case TypeTableEntryIdFloat:
37023813 case TypeTableEntryIdArray:
3703 case TypeTableEntryIdNumLitFloat:
3704 case TypeTableEntryIdNumLitInt:
3705 case TypeTableEntryIdUndefLit:
3706 case TypeTableEntryIdNullLit:
3707 case TypeTableEntryIdMaybe:
3814 case TypeTableEntryIdComptimeFloat:
3815 case TypeTableEntryIdComptimeInt:
3816 case TypeTableEntryIdUndefined:
3817 case TypeTableEntryIdNull:
3818 case TypeTableEntryIdOptional:
37083819 case TypeTableEntryIdErrorUnion:
37093820 case TypeTableEntryIdErrorSet:
37103821 case TypeTableEntryIdFn:
......@@ -3719,14 +3830,24 @@ static bool is_container(TypeTableEntry *type_entry) {
37193830 zig_unreachable();
37203831}
37213832
3833bool is_ref(TypeTableEntry *type_entry) {
3834 return type_entry->id == TypeTableEntryIdPointer && type_entry->data.pointer.ptr_len == PtrLenSingle;
3835}
3836
3837bool is_array_ref(TypeTableEntry *type_entry) {
3838 TypeTableEntry *array = is_ref(type_entry) ?
3839 type_entry->data.pointer.child_type : type_entry;
3840 return array->id == TypeTableEntryIdArray;
3841}
3842
37223843bool is_container_ref(TypeTableEntry *type_entry) {
3723 return (type_entry->id == TypeTableEntryIdPointer) ?
3844 return is_ref(type_entry) ?
37243845 is_container(type_entry->data.pointer.child_type) : is_container(type_entry);
37253846}
37263847
37273848TypeTableEntry *container_ref_type(TypeTableEntry *type_entry) {
37283849 assert(is_container_ref(type_entry));
3729 return (type_entry->id == TypeTableEntryIdPointer) ?
3850 return is_ref(type_entry) ?
37303851 type_entry->data.pointer.child_type : type_entry;
37313852}
37323853
......@@ -3749,11 +3870,11 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
37493870 case TypeTableEntryIdInt:
37503871 case TypeTableEntryIdFloat:
37513872 case TypeTableEntryIdArray:
3752 case TypeTableEntryIdNumLitFloat:
3753 case TypeTableEntryIdNumLitInt:
3754 case TypeTableEntryIdUndefLit:
3755 case TypeTableEntryIdNullLit:
3756 case TypeTableEntryIdMaybe:
3873 case TypeTableEntryIdComptimeFloat:
3874 case TypeTableEntryIdComptimeInt:
3875 case TypeTableEntryIdUndefined:
3876 case TypeTableEntryIdNull:
3877 case TypeTableEntryIdOptional:
37573878 case TypeTableEntryIdErrorUnion:
37583879 case TypeTableEntryIdErrorSet:
37593880 case TypeTableEntryIdFn:
......@@ -3772,7 +3893,7 @@ TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) {
37723893 if (type->id == TypeTableEntryIdPointer) return type;
37733894 if (type->id == TypeTableEntryIdFn) return type;
37743895 if (type->id == TypeTableEntryIdPromise) return type;
3775 if (type->id == TypeTableEntryIdMaybe) {
3896 if (type->id == TypeTableEntryIdOptional) {
37763897 if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;
37773898 if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;
37783899 if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type;
......@@ -3819,7 +3940,7 @@ AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) {
38193940 return nullptr;
38203941}
38213942
3822static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars) {
3943static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry) {
38233944 TypeTableEntry *fn_type = fn_table_entry->type_entry;
38243945 assert(!fn_type->data.fn.is_generic);
38253946 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -3857,14 +3978,10 @@ static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entr
38573978 if (fn_type->data.fn.gen_param_info) {
38583979 var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
38593980 }
3860
3861 if (arg_vars) {
3862 arg_vars[i] = var;
3863 }
38643981 }
38653982}
38663983
3867static bool analyze_resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
3984bool resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
38683985 FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
38693986 if (infer_fn != nullptr) {
38703987 if (infer_fn->anal_state == FnAnalStateInvalid) {
......@@ -3916,7 +4033,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
39164033 }
39174034
39184035 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
3919 if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
4036 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
39204037 fn_table_entry->anal_state = FnAnalStateInvalid;
39214038 return;
39224039 }
......@@ -3938,7 +4055,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
39384055 }
39394056
39404057 if (g->verbose_ir) {
3941 fprintf(stderr, "{ // (analyzed)\n");
4058 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));
39424059 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
39434060 fprintf(stderr, "}\n");
39444061 }
......@@ -3946,7 +4063,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
39464063 fn_table_entry->anal_state = FnAnalStateComplete;
39474064}
39484065
3949void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
4066static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
39504067 assert(fn_table_entry->anal_state != FnAnalStateProbing);
39514068 if (fn_table_entry->anal_state != FnAnalStateReady)
39524069 return;
......@@ -3960,7 +4077,7 @@ void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
39604077 if (!fn_table_entry->child_scope)
39614078 fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base;
39624079
3963 define_local_param_variables(g, fn_table_entry, nullptr);
4080 define_local_param_variables(g, fn_table_entry);
39644081
39654082 TypeTableEntry *fn_type = fn_table_entry->type_entry;
39664083 assert(!fn_type->data.fn.is_generic);
......@@ -4188,43 +4305,7 @@ void semantic_analyze(CodeGen *g) {
41884305 }
41894306}
41904307
4191TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
4192 size_t index;
4193 if (size_in_bits == 2) {
4194 index = 0;
4195 } else if (size_in_bits == 3) {
4196 index = 1;
4197 } else if (size_in_bits == 4) {
4198 index = 2;
4199 } else if (size_in_bits == 5) {
4200 index = 3;
4201 } else if (size_in_bits == 6) {
4202 index = 4;
4203 } else if (size_in_bits == 7) {
4204 index = 5;
4205 } else if (size_in_bits == 8) {
4206 index = 6;
4207 } else if (size_in_bits == 16) {
4208 index = 7;
4209 } else if (size_in_bits == 29) {
4210 index = 8;
4211 } else if (size_in_bits == 32) {
4212 index = 9;
4213 } else if (size_in_bits == 64) {
4214 index = 10;
4215 } else if (size_in_bits == 128) {
4216 index = 11;
4217 } else {
4218 return nullptr;
4219 }
4220 return &g->builtin_types.entry_int[is_signed ? 0 : 1][index];
4221}
4222
42234308TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
4224 TypeTableEntry **common_entry = get_int_type_ptr(g, is_signed, size_in_bits);
4225 if (common_entry)
4226 return *common_entry;
4227
42284309 TypeId type_id = {};
42294310 type_id.id = TypeTableEntryIdInt;
42304311 type_id.data.integer.is_signed = is_signed;
......@@ -4253,10 +4334,10 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
42534334 switch (type_entry->id) {
42544335 case TypeTableEntryIdInvalid:
42554336 case TypeTableEntryIdMetaType:
4256 case TypeTableEntryIdNumLitFloat:
4257 case TypeTableEntryIdNumLitInt:
4258 case TypeTableEntryIdUndefLit:
4259 case TypeTableEntryIdNullLit:
4337 case TypeTableEntryIdComptimeFloat:
4338 case TypeTableEntryIdComptimeInt:
4339 case TypeTableEntryIdUndefined:
4340 case TypeTableEntryIdNull:
42604341 case TypeTableEntryIdNamespace:
42614342 case TypeTableEntryIdBlock:
42624343 case TypeTableEntryIdBoundFn:
......@@ -4279,7 +4360,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
42794360 return type_has_bits(type_entry);
42804361 case TypeTableEntryIdErrorUnion:
42814362 return type_has_bits(type_entry->data.error_union.payload_type);
4282 case TypeTableEntryIdMaybe:
4363 case TypeTableEntryIdOptional:
42834364 return type_has_bits(type_entry->data.maybe.child_type) &&
42844365 !type_is_codegen_pointer(type_entry->data.maybe.child_type);
42854366 case TypeTableEntryIdUnion:
......@@ -4296,8 +4377,9 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
42964377
42974378static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
42984379 if (g->win_sdk == nullptr) {
4299 if (os_find_windows_sdk(&g->win_sdk)) {
4300 zig_panic("Unable to determine Windows SDK path.");
4380 if (zig_find_windows_sdk(&g->win_sdk)) {
4381 fprintf(stderr, "unable to determine windows sdk path\n");
4382 exit(1);
43014383 }
43024384 }
43034385 assert(g->win_sdk != nullptr);
......@@ -4351,22 +4433,14 @@ Buf *get_linux_libc_include_path(void) {
43514433 }
43524434 char *prev_newline = buf_ptr(out_stderr);
43534435 ZigList<const char *> search_paths = {};
4354 bool found_search_paths = false;
43554436 for (;;) {
43564437 char *newline = strchr(prev_newline, '\n');
43574438 if (newline == nullptr) {
4358 zig_panic("unable to determine libc include path: bad output from C compiler command");
4439 break;
43594440 }
43604441 *newline = 0;
4361 if (found_search_paths) {
4362 if (strcmp(prev_newline, "End of search list.") == 0) {
4363 break;
4364 }
4442 if (prev_newline[0] == ' ') {
43654443 search_paths.append(prev_newline);
4366 } else {
4367 if (strcmp(prev_newline, "#include <...> search starts here:") == 0) {
4368 found_search_paths = true;
4369 }
43704444 }
43714445 prev_newline = newline + 1;
43724446 }
......@@ -4399,7 +4473,8 @@ void find_libc_include_path(CodeGen *g) {
43994473 ZigWindowsSDK *sdk = get_windows_sdk(g);
44004474 g->libc_include_dir = buf_alloc();
44014475 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
4402 zig_panic("Unable to determine libc include path.");
4476 fprintf(stderr, "Unable to determine libc include path. --libc-include-dir");
4477 exit(1);
44034478 }
44044479 } else if (g->zig_target.os == OsLinux) {
44054480 g->libc_include_dir = get_linux_libc_include_path();
......@@ -4421,24 +4496,32 @@ void find_libc_lib_path(CodeGen *g) {
44214496 if (g->zig_target.os == OsWindows) {
44224497 ZigWindowsSDK *sdk = get_windows_sdk(g);
44234498
4424 Buf* vc_lib_dir = buf_alloc();
4425 if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) {
4426 zig_panic("Unable to determine vcruntime path.");
4499 if (g->msvc_lib_dir == nullptr) {
4500 if (sdk->msvc_lib_dir_ptr == nullptr) {
4501 fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
4502 exit(1);
4503 }
4504 g->msvc_lib_dir = buf_create_from_mem(sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
44274505 }
44284506
4429 Buf* ucrt_lib_path = buf_alloc();
4430 if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
4431 zig_panic("Unable to determine ucrt path.");
4507 if (g->libc_lib_dir == nullptr) {
4508 Buf* ucrt_lib_path = buf_alloc();
4509 if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
4510 fprintf(stderr, "Unable to determine ucrt path. --libc-lib-dir");
4511 exit(1);
4512 }
4513 g->libc_lib_dir = ucrt_lib_path;
44324514 }
44334515
4434 Buf* kern_lib_path = buf_alloc();
4435 if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
4436 zig_panic("Unable to determine kernel32 path.");
4516 if (g->kernel32_lib_dir == nullptr) {
4517 Buf* kern_lib_path = buf_alloc();
4518 if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
4519 fprintf(stderr, "Unable to determine kernel32 path. --kernel32-lib-dir");
4520 exit(1);
4521 }
4522 g->kernel32_lib_dir = kern_lib_path;
44374523 }
44384524
4439 g->msvc_lib_dir = vc_lib_dir;
4440 g->libc_lib_dir = ucrt_lib_path;
4441 g->kernel32_lib_dir = kern_lib_path;
44424525 } else if (g->zig_target.os == OsLinux) {
44434526 g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
44444527 } else {
......@@ -4515,6 +4598,52 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
45154598 return true;
45164599}
45174600
4601static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
4602 uint32_t hash_val = 0;
4603 switch (const_val->data.x_ptr.mut) {
4604 case ConstPtrMutRuntimeVar:
4605 hash_val += (uint32_t)3500721036;
4606 break;
4607 case ConstPtrMutComptimeConst:
4608 hash_val += (uint32_t)4214318515;
4609 break;
4610 case ConstPtrMutComptimeVar:
4611 hash_val += (uint32_t)1103195694;
4612 break;
4613 }
4614 switch (const_val->data.x_ptr.special) {
4615 case ConstPtrSpecialInvalid:
4616 zig_unreachable();
4617 case ConstPtrSpecialRef:
4618 hash_val += (uint32_t)2478261866;
4619 hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee);
4620 return hash_val;
4621 case ConstPtrSpecialBaseArray:
4622 hash_val += (uint32_t)1764906839;
4623 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
4624 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
4625 hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
4626 return hash_val;
4627 case ConstPtrSpecialBaseStruct:
4628 hash_val += (uint32_t)3518317043;
4629 hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
4630 hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
4631 return hash_val;
4632 case ConstPtrSpecialHardCodedAddr:
4633 hash_val += (uint32_t)4048518294;
4634 hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
4635 return hash_val;
4636 case ConstPtrSpecialDiscard:
4637 hash_val += 2010123162;
4638 return hash_val;
4639 case ConstPtrSpecialFunction:
4640 hash_val += (uint32_t)2590901619;
4641 hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
4642 return hash_val;
4643 }
4644 zig_unreachable();
4645}
4646
45184647static uint32_t hash_const_val(ConstExprValue *const_val) {
45194648 assert(const_val->special == ConstValSpecialStatic);
45204649 switch (const_val->type->id) {
......@@ -4527,7 +4656,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
45274656 case TypeTableEntryIdVoid:
45284657 return (uint32_t)4149439618;
45294658 case TypeTableEntryIdInt:
4530 case TypeTableEntryIdNumLitInt:
4659 case TypeTableEntryIdComptimeInt:
45314660 {
45324661 uint32_t result = 1331471175;
45334662 for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) {
......@@ -4547,6 +4676,13 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
45474676 }
45484677 case TypeTableEntryIdFloat:
45494678 switch (const_val->type->data.floating.bit_count) {
4679 case 16:
4680 {
4681 uint16_t result;
4682 static_assert(sizeof(result) == sizeof(const_val->data.x_f16), "");
4683 memcpy(&result, &const_val->data.x_f16, sizeof(result));
4684 return result * 65537u;
4685 }
45504686 case 32:
45514687 {
45524688 uint32_t result;
......@@ -4568,7 +4704,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
45684704 default:
45694705 zig_unreachable();
45704706 }
4571 case TypeTableEntryIdNumLitFloat:
4707 case TypeTableEntryIdComptimeFloat:
45724708 {
45734709 float128_t f128 = bigfloat_to_f128(&const_val->data.x_bigfloat);
45744710 uint32_t ints[4];
......@@ -4583,57 +4719,13 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
45834719 assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
45844720 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
45854721 case TypeTableEntryIdPointer:
4586 {
4587 uint32_t hash_val = 0;
4588 switch (const_val->data.x_ptr.mut) {
4589 case ConstPtrMutRuntimeVar:
4590 hash_val += (uint32_t)3500721036;
4591 break;
4592 case ConstPtrMutComptimeConst:
4593 hash_val += (uint32_t)4214318515;
4594 break;
4595 case ConstPtrMutComptimeVar:
4596 hash_val += (uint32_t)1103195694;
4597 break;
4598 }
4599 switch (const_val->data.x_ptr.special) {
4600 case ConstPtrSpecialInvalid:
4601 zig_unreachable();
4602 case ConstPtrSpecialRef:
4603 hash_val += (uint32_t)2478261866;
4604 hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee);
4605 return hash_val;
4606 case ConstPtrSpecialBaseArray:
4607 hash_val += (uint32_t)1764906839;
4608 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
4609 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
4610 hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
4611 return hash_val;
4612 case ConstPtrSpecialBaseStruct:
4613 hash_val += (uint32_t)3518317043;
4614 hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
4615 hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
4616 return hash_val;
4617 case ConstPtrSpecialHardCodedAddr:
4618 hash_val += (uint32_t)4048518294;
4619 hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
4620 return hash_val;
4621 case ConstPtrSpecialDiscard:
4622 hash_val += 2010123162;
4623 return hash_val;
4624 case ConstPtrSpecialFunction:
4625 hash_val += (uint32_t)2590901619;
4626 hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
4627 return hash_val;
4628 }
4629 zig_unreachable();
4630 }
4722 return hash_const_val_ptr(const_val);
46314723 case TypeTableEntryIdPromise:
46324724 // TODO better hashing algorithm
46334725 return 223048345;
4634 case TypeTableEntryIdUndefLit:
4726 case TypeTableEntryIdUndefined:
46354727 return 162837799;
4636 case TypeTableEntryIdNullLit:
4728 case TypeTableEntryIdNull:
46374729 return 844854567;
46384730 case TypeTableEntryIdArray:
46394731 // TODO better hashing algorithm
......@@ -4644,11 +4736,15 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
46444736 case TypeTableEntryIdUnion:
46454737 // TODO better hashing algorithm
46464738 return 2709806591;
4647 case TypeTableEntryIdMaybe:
4648 if (const_val->data.x_maybe) {
4649 return hash_const_val(const_val->data.x_maybe) * 1992916303;
4739 case TypeTableEntryIdOptional:
4740 if (get_codegen_ptr_type(const_val->type) != nullptr) {
4741 return hash_const_val(const_val) * 1992916303;
46504742 } else {
4651 return 4016830364;
4743 if (const_val->data.x_optional) {
4744 return hash_const_val(const_val->data.x_optional) * 1992916303;
4745 } else {
4746 return 4016830364;
4747 }
46524748 }
46534749 case TypeTableEntryIdErrorUnion:
46544750 // TODO better hashing algorithm
......@@ -4713,10 +4809,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
47134809 case TypeTableEntryIdUnreachable:
47144810 case TypeTableEntryIdInt:
47154811 case TypeTableEntryIdFloat:
4716 case TypeTableEntryIdNumLitFloat:
4717 case TypeTableEntryIdNumLitInt:
4718 case TypeTableEntryIdUndefLit:
4719 case TypeTableEntryIdNullLit:
4812 case TypeTableEntryIdComptimeFloat:
4813 case TypeTableEntryIdComptimeInt:
4814 case TypeTableEntryIdUndefined:
4815 case TypeTableEntryIdNull:
47204816 case TypeTableEntryIdNamespace:
47214817 case TypeTableEntryIdBoundFn:
47224818 case TypeTableEntryIdFn:
......@@ -4748,10 +4844,12 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
47484844 }
47494845 return false;
47504846
4751 case TypeTableEntryIdMaybe:
4752 if (value->data.x_maybe == nullptr)
4847 case TypeTableEntryIdOptional:
4848 if (get_codegen_ptr_type(value->type) != nullptr)
4849 return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
4850 if (value->data.x_optional == nullptr)
47534851 return false;
4754 return can_mutate_comptime_var_state(value->data.x_maybe);
4852 return can_mutate_comptime_var_state(value->data.x_optional);
47554853
47564854 case TypeTableEntryIdErrorUnion:
47574855 if (value->data.x_err_union.err != nullptr)
......@@ -4778,10 +4876,10 @@ static bool return_type_is_cacheable(TypeTableEntry *return_type) {
47784876 case TypeTableEntryIdUnreachable:
47794877 case TypeTableEntryIdInt:
47804878 case TypeTableEntryIdFloat:
4781 case TypeTableEntryIdNumLitFloat:
4782 case TypeTableEntryIdNumLitInt:
4783 case TypeTableEntryIdUndefLit:
4784 case TypeTableEntryIdNullLit:
4879 case TypeTableEntryIdComptimeFloat:
4880 case TypeTableEntryIdComptimeInt:
4881 case TypeTableEntryIdUndefined:
4882 case TypeTableEntryIdNull:
47854883 case TypeTableEntryIdNamespace:
47864884 case TypeTableEntryIdBoundFn:
47874885 case TypeTableEntryIdFn:
......@@ -4798,7 +4896,7 @@ static bool return_type_is_cacheable(TypeTableEntry *return_type) {
47984896 case TypeTableEntryIdUnion:
47994897 return false;
48004898
4801 case TypeTableEntryIdMaybe:
4899 case TypeTableEntryIdOptional:
48024900 return return_type_is_cacheable(return_type->data.maybe.child_type);
48034901
48044902 case TypeTableEntryIdErrorUnion:
......@@ -4816,6 +4914,8 @@ bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type) {
48164914 while (scope) {
48174915 if (scope->id == ScopeIdVarDecl) {
48184916 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
4917 if (type_is_invalid(var_scope->var->value->type))
4918 return false;
48194919 if (can_mutate_comptime_var_state(var_scope->var->value))
48204920 return false;
48214921 } else if (scope->id == ScopeIdFnDef) {
......@@ -4889,10 +4989,10 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
48894989 case TypeTableEntryIdInvalid:
48904990 case TypeTableEntryIdOpaque:
48914991 zig_unreachable();
4892 case TypeTableEntryIdNumLitFloat:
4893 case TypeTableEntryIdNumLitInt:
4894 case TypeTableEntryIdUndefLit:
4895 case TypeTableEntryIdNullLit:
4992 case TypeTableEntryIdComptimeFloat:
4993 case TypeTableEntryIdComptimeInt:
4994 case TypeTableEntryIdUndefined:
4995 case TypeTableEntryIdNull:
48964996 case TypeTableEntryIdMetaType:
48974997 case TypeTableEntryIdNamespace:
48984998 case TypeTableEntryIdBlock:
......@@ -4900,17 +5000,30 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
49005000 case TypeTableEntryIdArgTuple:
49015001 return true;
49025002 case TypeTableEntryIdArray:
5003 return type_requires_comptime(type_entry->data.array.child_type);
49035004 case TypeTableEntryIdStruct:
5005 assert(type_has_zero_bits_known(type_entry));
5006 return type_entry->data.structure.requires_comptime;
49045007 case TypeTableEntryIdUnion:
4905 case TypeTableEntryIdMaybe:
5008 assert(type_has_zero_bits_known(type_entry));
5009 return type_entry->data.unionation.requires_comptime;
5010 case TypeTableEntryIdOptional:
5011 return type_requires_comptime(type_entry->data.maybe.child_type);
49065012 case TypeTableEntryIdErrorUnion:
5013 return type_requires_comptime(type_entry->data.error_union.payload_type);
5014 case TypeTableEntryIdPointer:
5015 if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
5016 return false;
5017 } else {
5018 return type_requires_comptime(type_entry->data.pointer.child_type);
5019 }
5020 case TypeTableEntryIdFn:
5021 return type_entry->data.fn.is_generic;
49075022 case TypeTableEntryIdEnum:
49085023 case TypeTableEntryIdErrorSet:
4909 case TypeTableEntryIdFn:
49105024 case TypeTableEntryIdBool:
49115025 case TypeTableEntryIdInt:
49125026 case TypeTableEntryIdFloat:
4913 case TypeTableEntryIdPointer:
49145027 case TypeTableEntryIdVoid:
49155028 case TypeTableEntryIdUnreachable:
49165029 case TypeTableEntryIdPromise:
......@@ -4966,7 +5079,9 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
49665079
49675080 // then make the pointer point to it
49685081 const_val->special = ConstValSpecialStatic;
4969 const_val->type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
5082 // TODO make this `[*]null u8` instead of `[*]u8`
5083 const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
5084 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
49705085 const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
49715086 const_val->data.x_ptr.data.base_array.array_val = array_val;
49725087 const_val->data.x_ptr.data.base_array.elem_index = 0;
......@@ -5027,10 +5142,13 @@ ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
50275142void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) {
50285143 const_val->special = ConstValSpecialStatic;
50295144 const_val->type = type;
5030 if (type->id == TypeTableEntryIdNumLitFloat) {
5145 if (type->id == TypeTableEntryIdComptimeFloat) {
50315146 bigfloat_init_64(&const_val->data.x_bigfloat, value);
50325147 } else if (type->id == TypeTableEntryIdFloat) {
50335148 switch (type->data.floating.bit_count) {
5149 case 16:
5150 const_val->data.x_f16 = zig_double_to_f16(value);
5151 break;
50345152 case 32:
50355153 const_val->data.x_f32 = value;
50365154 break;
......@@ -5107,13 +5225,16 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
51075225{
51085226 assert(array_val->type->id == TypeTableEntryIdArray);
51095227
5110 TypeTableEntry *ptr_type = get_pointer_to_type(g, array_val->type->data.array.child_type, is_const);
5228 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, array_val->type->data.array.child_type,
5229 is_const, false, PtrLenUnknown, get_abi_alignment(g, array_val->type->data.array.child_type),
5230 0, 0);
51115231
51125232 const_val->special = ConstValSpecialStatic;
51135233 const_val->type = get_slice_type(g, ptr_type);
51145234 const_val->data.x_struct.fields = create_const_vals(2);
51155235
5116 init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const);
5236 init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const,
5237 PtrLenUnknown);
51175238 init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);
51185239}
51195240
......@@ -5124,21 +5245,24 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t
51245245}
51255246
51265247void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
5127 size_t elem_index, bool is_const)
5248 size_t elem_index, bool is_const, PtrLen ptr_len)
51285249{
51295250 assert(array_val->type->id == TypeTableEntryIdArray);
51305251 TypeTableEntry *child_type = array_val->type->data.array.child_type;
51315252
51325253 const_val->special = ConstValSpecialStatic;
5133 const_val->type = get_pointer_to_type(g, child_type, is_const);
5254 const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false,
5255 ptr_len, get_abi_alignment(g, child_type), 0, 0);
51345256 const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
51355257 const_val->data.x_ptr.data.base_array.array_val = array_val;
51365258 const_val->data.x_ptr.data.base_array.elem_index = elem_index;
51375259}
51385260
5139ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const) {
5261ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const,
5262 PtrLen ptr_len)
5263{
51405264 ConstExprValue *const_val = create_const_vals(1);
5141 init_const_ptr_array(g, const_val, array_val, elem_index, is_const);
5265 init_const_ptr_array(g, const_val, array_val, elem_index, is_const, ptr_len);
51425266 return const_val;
51435267}
51445268
......@@ -5257,6 +5381,52 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) {
52575381 return var->is_comptime->value.data.x_bool;
52585382}
52595383
5384bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
5385 if (a->data.x_ptr.special != b->data.x_ptr.special)
5386 return false;
5387 if (a->data.x_ptr.mut != b->data.x_ptr.mut)
5388 return false;
5389 switch (a->data.x_ptr.special) {
5390 case ConstPtrSpecialInvalid:
5391 zig_unreachable();
5392 case ConstPtrSpecialRef:
5393 if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee)
5394 return false;
5395 return true;
5396 case ConstPtrSpecialBaseArray:
5397 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
5398 a->data.x_ptr.data.base_array.array_val->global_refs !=
5399 b->data.x_ptr.data.base_array.array_val->global_refs)
5400 {
5401 return false;
5402 }
5403 if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
5404 return false;
5405 if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
5406 return false;
5407 return true;
5408 case ConstPtrSpecialBaseStruct:
5409 if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
5410 a->data.x_ptr.data.base_struct.struct_val->global_refs !=
5411 b->data.x_ptr.data.base_struct.struct_val->global_refs)
5412 {
5413 return false;
5414 }
5415 if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
5416 return false;
5417 return true;
5418 case ConstPtrSpecialHardCodedAddr:
5419 if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
5420 return false;
5421 return true;
5422 case ConstPtrSpecialDiscard:
5423 return true;
5424 case ConstPtrSpecialFunction:
5425 return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
5426 }
5427 zig_unreachable();
5428}
5429
52605430bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
52615431 assert(a->type->id == b->type->id);
52625432 assert(a->special == ConstValSpecialStatic);
......@@ -5292,6 +5462,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
52925462 case TypeTableEntryIdFloat:
52935463 assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count);
52945464 switch (a->type->data.floating.bit_count) {
5465 case 16:
5466 return f16_eq(a->data.x_f16, b->data.x_f16);
52955467 case 32:
52965468 return a->data.x_f32 == b->data.x_f32;
52975469 case 64:
......@@ -5301,58 +5473,30 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
53015473 default:
53025474 zig_unreachable();
53035475 }
5304 case TypeTableEntryIdNumLitFloat:
5476 case TypeTableEntryIdComptimeFloat:
53055477 return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ;
53065478 case TypeTableEntryIdInt:
5307 case TypeTableEntryIdNumLitInt:
5479 case TypeTableEntryIdComptimeInt:
53085480 return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
53095481 case TypeTableEntryIdPointer:
53105482 case TypeTableEntryIdFn:
5311 if (a->data.x_ptr.special != b->data.x_ptr.special)
5312 return false;
5313 if (a->data.x_ptr.mut != b->data.x_ptr.mut)
5314 return false;
5315 switch (a->data.x_ptr.special) {
5316 case ConstPtrSpecialInvalid:
5317 zig_unreachable();
5318 case ConstPtrSpecialRef:
5319 if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee)
5320 return false;
5321 return true;
5322 case ConstPtrSpecialBaseArray:
5323 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
5324 a->data.x_ptr.data.base_array.array_val->global_refs !=
5325 b->data.x_ptr.data.base_array.array_val->global_refs)
5326 {
5327 return false;
5328 }
5329 if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
5330 return false;
5331 if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
5332 return false;
5333 return true;
5334 case ConstPtrSpecialBaseStruct:
5335 if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
5336 a->data.x_ptr.data.base_struct.struct_val->global_refs !=
5337 b->data.x_ptr.data.base_struct.struct_val->global_refs)
5338 {
5339 return false;
5340 }
5341 if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
5342 return false;
5343 return true;
5344 case ConstPtrSpecialHardCodedAddr:
5345 if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
5346 return false;
5347 return true;
5348 case ConstPtrSpecialDiscard:
5349 return true;
5350 case ConstPtrSpecialFunction:
5351 return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
5483 return const_values_equal_ptr(a, b);
5484 case TypeTableEntryIdArray: {
5485 assert(a->type->data.array.len == b->type->data.array.len);
5486 assert(a->data.x_array.special != ConstArraySpecialUndef);
5487 assert(b->data.x_array.special != ConstArraySpecialUndef);
5488
5489 size_t len = a->type->data.array.len;
5490 ConstExprValue *a_elems = a->data.x_array.s_none.elements;
5491 ConstExprValue *b_elems = b->data.x_array.s_none.elements;
5492
5493 for (size_t i = 0; i < len; ++i) {
5494 if (!const_values_equal(&a_elems[i], &b_elems[i]))
5495 return false;
53525496 }
5353 zig_unreachable();
5354 case TypeTableEntryIdArray:
5355 zig_panic("TODO");
5497
5498 return true;
5499 }
53565500 case TypeTableEntryIdStruct:
53575501 for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) {
53585502 ConstExprValue *field_a = &a->data.x_struct.fields[i];
......@@ -5361,15 +5505,17 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
53615505 return false;
53625506 }
53635507 return true;
5364 case TypeTableEntryIdUndefLit:
5508 case TypeTableEntryIdUndefined:
53655509 zig_panic("TODO");
5366 case TypeTableEntryIdNullLit:
5510 case TypeTableEntryIdNull:
53675511 zig_panic("TODO");
5368 case TypeTableEntryIdMaybe:
5369 if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) {
5370 return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr);
5512 case TypeTableEntryIdOptional:
5513 if (get_codegen_ptr_type(a->type) != nullptr)
5514 return const_values_equal_ptr(a, b);
5515 if (a->data.x_optional == nullptr || b->data.x_optional == nullptr) {
5516 return (a->data.x_optional == nullptr && b->data.x_optional == nullptr);
53715517 } else {
5372 return const_values_equal(a->data.x_maybe, b->data.x_maybe);
5518 return const_values_equal(a->data.x_optional, b->data.x_optional);
53735519 }
53745520 case TypeTableEntryIdErrorUnion:
53755521 zig_panic("TODO");
......@@ -5442,6 +5588,41 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
54425588 }
54435589}
54445590
5591void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeTableEntry *type_entry) {
5592 switch (const_val->data.x_ptr.special) {
5593 case ConstPtrSpecialInvalid:
5594 zig_unreachable();
5595 case ConstPtrSpecialRef:
5596 case ConstPtrSpecialBaseStruct:
5597 buf_appendf(buf, "*");
5598 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5599 return;
5600 case ConstPtrSpecialBaseArray:
5601 if (const_val->data.x_ptr.data.base_array.is_cstr) {
5602 buf_appendf(buf, "*(c str lit)");
5603 return;
5604 } else {
5605 buf_appendf(buf, "*");
5606 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5607 return;
5608 }
5609 case ConstPtrSpecialHardCodedAddr:
5610 buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name),
5611 const_val->data.x_ptr.data.hard_coded_addr.addr);
5612 return;
5613 case ConstPtrSpecialDiscard:
5614 buf_append_str(buf, "*_");
5615 return;
5616 case ConstPtrSpecialFunction:
5617 {
5618 FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
5619 buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
5620 return;
5621 }
5622 }
5623 zig_unreachable();
5624}
5625
54455626void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
54465627 switch (const_val->special) {
54475628 case ConstValSpecialRuntime:
......@@ -5465,11 +5646,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
54655646 case TypeTableEntryIdVoid:
54665647 buf_appendf(buf, "{}");
54675648 return;
5468 case TypeTableEntryIdNumLitFloat:
5649 case TypeTableEntryIdComptimeFloat:
54695650 bigfloat_append_buf(buf, &const_val->data.x_bigfloat);
54705651 return;
54715652 case TypeTableEntryIdFloat:
54725653 switch (type_entry->data.floating.bit_count) {
5654 case 16:
5655 buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16));
5656 return;
54735657 case 32:
54745658 buf_appendf(buf, "%f", const_val->data.x_f32);
54755659 return;
......@@ -5493,7 +5677,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
54935677 default:
54945678 zig_unreachable();
54955679 }
5496 case TypeTableEntryIdNumLitInt:
5680 case TypeTableEntryIdComptimeInt:
54975681 case TypeTableEntryIdInt:
54985682 bigint_append_buf(buf, &const_val->data.x_bigint, 10);
54995683 return;
......@@ -5518,38 +5702,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
55185702 return;
55195703 }
55205704 case TypeTableEntryIdPointer:
5521 switch (const_val->data.x_ptr.special) {
5522 case ConstPtrSpecialInvalid:
5523 zig_unreachable();
5524 case ConstPtrSpecialRef:
5525 case ConstPtrSpecialBaseStruct:
5526 buf_appendf(buf, "&");
5527 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5528 return;
5529 case ConstPtrSpecialBaseArray:
5530 if (const_val->data.x_ptr.data.base_array.is_cstr) {
5531 buf_appendf(buf, "&(c str lit)");
5532 return;
5533 } else {
5534 buf_appendf(buf, "&");
5535 render_const_value(g, buf, const_ptr_pointee(g, const_val));
5536 return;
5537 }
5538 case ConstPtrSpecialHardCodedAddr:
5539 buf_appendf(buf, "(&%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
5540 const_val->data.x_ptr.data.hard_coded_addr.addr);
5541 return;
5542 case ConstPtrSpecialDiscard:
5543 buf_append_str(buf, "&_");
5544 return;
5545 case ConstPtrSpecialFunction:
5546 {
5547 FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
5548 buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
5549 return;
5550 }
5551 }
5552 zig_unreachable();
5705 return render_const_val_ptr(g, buf, const_val, type_entry);
55535706 case TypeTableEntryIdBlock:
55545707 {
55555708 AstNode *node = const_val->data.x_block->source_node;
......@@ -5597,20 +5750,22 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
55975750 buf_appendf(buf, "}");
55985751 return;
55995752 }
5600 case TypeTableEntryIdNullLit:
5753 case TypeTableEntryIdNull:
56015754 {
56025755 buf_appendf(buf, "null");
56035756 return;
56045757 }
5605 case TypeTableEntryIdUndefLit:
5758 case TypeTableEntryIdUndefined:
56065759 {
56075760 buf_appendf(buf, "undefined");
56085761 return;
56095762 }
5610 case TypeTableEntryIdMaybe:
5763 case TypeTableEntryIdOptional:
56115764 {
5612 if (const_val->data.x_maybe) {
5613 render_const_value(g, buf, const_val->data.x_maybe);
5765 if (get_codegen_ptr_type(const_val->type) != nullptr)
5766 return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type);
5767 if (const_val->data.x_optional) {
5768 render_const_value(g, buf, const_val->data.x_optional);
56145769 } else {
56155770 buf_appendf(buf, "null");
56165771 }
......@@ -5712,11 +5867,11 @@ uint32_t type_id_hash(TypeId x) {
57125867 case TypeTableEntryIdUnreachable:
57135868 case TypeTableEntryIdFloat:
57145869 case TypeTableEntryIdStruct:
5715 case TypeTableEntryIdNumLitFloat:
5716 case TypeTableEntryIdNumLitInt:
5717 case TypeTableEntryIdUndefLit:
5718 case TypeTableEntryIdNullLit:
5719 case TypeTableEntryIdMaybe:
5870 case TypeTableEntryIdComptimeFloat:
5871 case TypeTableEntryIdComptimeInt:
5872 case TypeTableEntryIdUndefined:
5873 case TypeTableEntryIdNull:
5874 case TypeTableEntryIdOptional:
57205875 case TypeTableEntryIdErrorSet:
57215876 case TypeTableEntryIdEnum:
57225877 case TypeTableEntryIdUnion:
......@@ -5731,6 +5886,7 @@ uint32_t type_id_hash(TypeId x) {
57315886 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
57325887 case TypeTableEntryIdPointer:
57335888 return hash_ptr(x.data.pointer.child_type) +
5889 ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) +
57345890 (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
57355891 (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) +
57365892 (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
......@@ -5757,11 +5913,11 @@ bool type_id_eql(TypeId a, TypeId b) {
57575913 case TypeTableEntryIdUnreachable:
57585914 case TypeTableEntryIdFloat:
57595915 case TypeTableEntryIdStruct:
5760 case TypeTableEntryIdNumLitFloat:
5761 case TypeTableEntryIdNumLitInt:
5762 case TypeTableEntryIdUndefLit:
5763 case TypeTableEntryIdNullLit:
5764 case TypeTableEntryIdMaybe:
5916 case TypeTableEntryIdComptimeFloat:
5917 case TypeTableEntryIdComptimeInt:
5918 case TypeTableEntryIdUndefined:
5919 case TypeTableEntryIdNull:
5920 case TypeTableEntryIdOptional:
57655921 case TypeTableEntryIdPromise:
57665922 case TypeTableEntryIdErrorSet:
57675923 case TypeTableEntryIdEnum:
......@@ -5779,6 +5935,7 @@ bool type_id_eql(TypeId a, TypeId b) {
57795935
57805936 case TypeTableEntryIdPointer:
57815937 return a.data.pointer.child_type == b.data.pointer.child_type &&
5938 a.data.pointer.ptr_len == b.data.pointer.ptr_len &&
57825939 a.data.pointer.is_const == b.data.pointer.is_const &&
57835940 a.data.pointer.is_volatile == b.data.pointer.is_volatile &&
57845941 a.data.pointer.alignment == b.data.pointer.alignment &&
......@@ -5800,10 +5957,14 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
58005957 return (uint32_t)(x.data.ctz.bit_count) * (uint32_t)810453934;
58015958 case ZigLLVMFnIdClz:
58025959 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;
5960 case ZigLLVMFnIdPopCount:
5961 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049;
58035962 case ZigLLVMFnIdFloor:
5804 return (uint32_t)(x.data.floor_ceil.bit_count) * (uint32_t)1899859168;
5963 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;
58055964 case ZigLLVMFnIdCeil:
5806 return (uint32_t)(x.data.floor_ceil.bit_count) * (uint32_t)1953839089;
5965 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089;
5966 case ZigLLVMFnIdSqrt:
5967 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
58075968 case ZigLLVMFnIdOverflowArithmetic:
58085969 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
58095970 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
......@@ -5820,9 +5981,12 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
58205981 return a.data.ctz.bit_count == b.data.ctz.bit_count;
58215982 case ZigLLVMFnIdClz:
58225983 return a.data.clz.bit_count == b.data.clz.bit_count;
5984 case ZigLLVMFnIdPopCount:
5985 return a.data.pop_count.bit_count == b.data.pop_count.bit_count;
58235986 case ZigLLVMFnIdFloor:
58245987 case ZigLLVMFnIdCeil:
5825 return a.data.floor_ceil.bit_count == b.data.floor_ceil.bit_count;
5988 case ZigLLVMFnIdSqrt:
5989 return a.data.floating.bit_count == b.data.floating.bit_count;
58265990 case ZigLLVMFnIdOverflowArithmetic:
58275991 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
58285992 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
......@@ -5875,11 +6039,11 @@ static const TypeTableEntryId all_type_ids[] = {
58756039 TypeTableEntryIdPointer,
58766040 TypeTableEntryIdArray,
58776041 TypeTableEntryIdStruct,
5878 TypeTableEntryIdNumLitFloat,
5879 TypeTableEntryIdNumLitInt,
5880 TypeTableEntryIdUndefLit,
5881 TypeTableEntryIdNullLit,
5882 TypeTableEntryIdMaybe,
6042 TypeTableEntryIdComptimeFloat,
6043 TypeTableEntryIdComptimeInt,
6044 TypeTableEntryIdUndefined,
6045 TypeTableEntryIdNull,
6046 TypeTableEntryIdOptional,
58836047 TypeTableEntryIdErrorUnion,
58846048 TypeTableEntryIdErrorSet,
58856049 TypeTableEntryIdEnum,
......@@ -5902,8 +6066,8 @@ size_t type_id_len() {
59026066 return array_length(all_type_ids);
59036067}
59046068
5905size_t type_id_index(TypeTableEntryId id) {
5906 switch (id) {
6069size_t type_id_index(TypeTableEntry *entry) {
6070 switch (entry->id) {
59076071 case TypeTableEntryIdInvalid:
59086072 zig_unreachable();
59096073 case TypeTableEntryIdMetaType:
......@@ -5923,16 +6087,18 @@ size_t type_id_index(TypeTableEntryId id) {
59236087 case TypeTableEntryIdArray:
59246088 return 7;
59256089 case TypeTableEntryIdStruct:
6090 if (entry->data.structure.is_slice)
6091 return 6;
59266092 return 8;
5927 case TypeTableEntryIdNumLitFloat:
6093 case TypeTableEntryIdComptimeFloat:
59286094 return 9;
5929 case TypeTableEntryIdNumLitInt:
6095 case TypeTableEntryIdComptimeInt:
59306096 return 10;
5931 case TypeTableEntryIdUndefLit:
6097 case TypeTableEntryIdUndefined:
59326098 return 11;
5933 case TypeTableEntryIdNullLit:
6099 case TypeTableEntryIdNull:
59346100 return 12;
5935 case TypeTableEntryIdMaybe:
6101 case TypeTableEntryIdOptional:
59366102 return 13;
59376103 case TypeTableEntryIdErrorUnion:
59386104 return 14;
......@@ -5982,16 +6148,16 @@ const char *type_id_name(TypeTableEntryId id) {
59826148 return "Array";
59836149 case TypeTableEntryIdStruct:
59846150 return "Struct";
5985 case TypeTableEntryIdNumLitFloat:
5986 return "FloatLiteral";
5987 case TypeTableEntryIdNumLitInt:
5988 return "IntLiteral";
5989 case TypeTableEntryIdUndefLit:
5990 return "UndefinedLiteral";
5991 case TypeTableEntryIdNullLit:
5992 return "NullLiteral";
5993 case TypeTableEntryIdMaybe:
5994 return "Nullable";
6151 case TypeTableEntryIdComptimeFloat:
6152 return "ComptimeFloat";
6153 case TypeTableEntryIdComptimeInt:
6154 return "ComptimeInt";
6155 case TypeTableEntryIdUndefined:
6156 return "Undefined";
6157 case TypeTableEntryIdNull:
6158 return "Null";
6159 case TypeTableEntryIdOptional:
6160 return "Optional";
59956161 case TypeTableEntryIdErrorUnion:
59966162 return "ErrorUnion";
59976163 case TypeTableEntryIdErrorSet:
......@@ -6061,7 +6227,12 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
60616227 } else if (type_entry->id == TypeTableEntryIdOpaque) {
60626228 return 1;
60636229 } else {
6064 return LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
6230 uint32_t llvm_alignment = LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
6231 // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
6232 if (type_entry->id == TypeTableEntryIdPromise && llvm_alignment < 8) {
6233 return 8;
6234 }
6235 return llvm_alignment;
60656236 }
60666237}
60676238
......@@ -6109,3 +6280,27 @@ bool fn_type_can_fail(FnTypeId *fn_type_id) {
61096280 return type_can_fail(fn_type_id->return_type) || fn_type_id->cc == CallingConventionAsync;
61106281}
61116282
6283TypeTableEntry *get_primitive_type(CodeGen *g, Buf *name) {
6284 if (buf_len(name) >= 2) {
6285 uint8_t first_c = buf_ptr(name)[0];
6286 if (first_c == 'i' || first_c == 'u') {
6287 for (size_t i = 1; i < buf_len(name); i += 1) {
6288 uint8_t c = buf_ptr(name)[i];
6289 if (c < '0' || c > '9') {
6290 goto not_integer;
6291 }
6292 }
6293 bool is_signed = (first_c == 'i');
6294 uint32_t bit_count = atoi(buf_ptr(name) + 1);
6295 return get_int_type(g, is_signed, bit_count);
6296 }
6297 }
6298
6299not_integer:
6300
6301 auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
6302 if (primitive_table_entry != nullptr) {
6303 return primitive_table_entry->value;
6304 }
6305 return nullptr;
6306}
src/analyze.hpp+13-7
......@@ -16,15 +16,14 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
1616TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
1717TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
1818TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
19 bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count);
19 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count);
2020uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
2121uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry);
22TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_bits);
2322TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
2423TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
2524TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
2625TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
27TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
26TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type);
2827TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
2928TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);
3029TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
......@@ -70,6 +69,8 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
7069TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
7170TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
7271
72bool is_ref(TypeTableEntry *type_entry);
73bool is_array_ref(TypeTableEntry *type_entry);
7374bool is_container_ref(TypeTableEntry *type_entry);
7475void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
7576void scan_import(CodeGen *g, ImportTableEntry *import);
......@@ -104,6 +105,7 @@ ScopeDeferExpr *create_defer_expr_scope(AstNode *node, Scope *parent);
104105Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
105106ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent);
106107ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);
108ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent);
107109ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
108110ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
109111Scope *create_comptime_scope(AstNode *node, Scope *parent);
......@@ -151,8 +153,9 @@ ConstExprValue *create_const_ptr_hard_coded_addr(CodeGen *g, TypeTableEntry *poi
151153 size_t addr, bool is_const);
152154
153155void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
154 size_t elem_index, bool is_const);
155ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const);
156 size_t elem_index, bool is_const, PtrLen ptr_len);
157ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index,
158 bool is_const, PtrLen ptr_len);
156159
157160void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
158161 size_t start, size_t len, bool is_const);
......@@ -173,7 +176,7 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
173176const char *type_id_name(TypeTableEntryId id);
174177TypeTableEntryId type_id_at_index(size_t index);
175178size_t type_id_len();
176size_t type_id_index(TypeTableEntryId id);
179size_t type_id_index(TypeTableEntry *entry);
177180TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
178181bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
179182LinkLib *create_link_lib(Buf *name);
......@@ -190,7 +193,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
190193
191194ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
192195TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
193void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
196bool resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node);
194197
195198TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
196199
......@@ -198,5 +201,8 @@ uint32_t get_coro_frame_align_bytes(CodeGen *g);
198201bool fn_type_can_fail(FnTypeId *fn_type_id);
199202bool type_can_fail(TypeTableEntry *type_entry);
200203bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type);
204AstNode *type_decl_node(TypeTableEntry *type_entry);
205
206TypeTableEntry *get_primitive_type(CodeGen *g, Buf *name);
201207
202208#endif
src/ast_render.cpp+43-23
......@@ -50,7 +50,7 @@ static const char *bin_op_str(BinOpType bin_op) {
5050 case BinOpTypeAssignBitXor: return "^=";
5151 case BinOpTypeAssignBitOr: return "|=";
5252 case BinOpTypeAssignMergeErrorSets: return "||=";
53 case BinOpTypeUnwrapMaybe: return "??";
53 case BinOpTypeUnwrapOptional: return "orelse";
5454 case BinOpTypeArrayCat: return "++";
5555 case BinOpTypeArrayMult: return "**";
5656 case BinOpTypeErrorUnion: return "!";
......@@ -66,9 +66,8 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
6666 case PrefixOpNegationWrap: return "-%";
6767 case PrefixOpBoolNot: return "!";
6868 case PrefixOpBinNot: return "~";
69 case PrefixOpDereference: return "*";
70 case PrefixOpMaybe: return "?";
71 case PrefixOpUnwrapMaybe: return "??";
69 case PrefixOpOptional: return "?";
70 case PrefixOpAddrOf: return "&";
7271 }
7372 zig_unreachable();
7473}
......@@ -186,8 +185,6 @@ static const char *node_type_str(NodeType node_type) {
186185 return "Symbol";
187186 case NodeTypePrefixOpExpr:
188187 return "PrefixOpExpr";
189 case NodeTypeAddrOfExpr:
190 return "AddrOfExpr";
191188 case NodeTypeUse:
192189 return "Use";
193190 case NodeTypeBoolLiteral:
......@@ -222,6 +219,10 @@ static const char *node_type_str(NodeType node_type) {
222219 return "AsmExpr";
223220 case NodeTypeFieldAccessExpr:
224221 return "FieldAccessExpr";
222 case NodeTypePtrDeref:
223 return "PtrDerefExpr";
224 case NodeTypeUnwrapOptional:
225 return "UnwrapOptional";
225226 case NodeTypeContainerDecl:
226227 return "ContainerDecl";
227228 case NodeTypeStructField:
......@@ -250,6 +251,8 @@ static const char *node_type_str(NodeType node_type) {
250251 return "Suspend";
251252 case NodeTypePromiseType:
252253 return "PromiseType";
254 case NodeTypePointerType:
255 return "PointerType";
253256 }
254257 zig_unreachable();
255258}
......@@ -615,41 +618,47 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
615618 fprintf(ar->f, "%s", prefix_op_str(op));
616619
617620 AstNode *child_node = node->data.prefix_op_expr.primary_expr;
618 bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypeAddrOfExpr;
621 bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypePointerType;
619622 render_node_extra(ar, child_node, new_grouped);
620623 if (!grouped) fprintf(ar->f, ")");
621624 break;
622625 }
623 case NodeTypeAddrOfExpr:
626 case NodeTypePointerType:
624627 {
625628 if (!grouped) fprintf(ar->f, "(");
626 fprintf(ar->f, "&");
627 if (node->data.addr_of_expr.align_expr != nullptr) {
629 const char *star = "[*]";
630 if (node->data.pointer_type.star_token != nullptr &&
631 (node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
632 {
633 star = "*";
634 }
635 fprintf(ar->f, "%s", star);
636 if (node->data.pointer_type.align_expr != nullptr) {
628637 fprintf(ar->f, "align(");
629 render_node_grouped(ar, node->data.addr_of_expr.align_expr);
630 if (node->data.addr_of_expr.bit_offset_start != nullptr) {
631 assert(node->data.addr_of_expr.bit_offset_end != nullptr);
638 render_node_grouped(ar, node->data.pointer_type.align_expr);
639 if (node->data.pointer_type.bit_offset_start != nullptr) {
640 assert(node->data.pointer_type.bit_offset_end != nullptr);
632641
633642 Buf offset_start_buf = BUF_INIT;
634643 buf_resize(&offset_start_buf, 0);
635 bigint_append_buf(&offset_start_buf, node->data.addr_of_expr.bit_offset_start, 10);
644 bigint_append_buf(&offset_start_buf, node->data.pointer_type.bit_offset_start, 10);
636645
637646 Buf offset_end_buf = BUF_INIT;
638647 buf_resize(&offset_end_buf, 0);
639 bigint_append_buf(&offset_end_buf, node->data.addr_of_expr.bit_offset_end, 10);
648 bigint_append_buf(&offset_end_buf, node->data.pointer_type.bit_offset_end, 10);
640649
641650 fprintf(ar->f, ":%s:%s ", buf_ptr(&offset_start_buf), buf_ptr(&offset_end_buf));
642651 }
643652 fprintf(ar->f, ") ");
644653 }
645 if (node->data.addr_of_expr.is_const) {
654 if (node->data.pointer_type.is_const) {
646655 fprintf(ar->f, "const ");
647656 }
648 if (node->data.addr_of_expr.is_volatile) {
657 if (node->data.pointer_type.is_volatile) {
649658 fprintf(ar->f, "volatile ");
650659 }
651660
652 render_node_ungrouped(ar, node->data.addr_of_expr.op_expr);
661 render_node_ungrouped(ar, node->data.pointer_type.op_expr);
653662 if (!grouped) fprintf(ar->f, ")");
654663 break;
655664 }
......@@ -668,7 +677,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
668677 fprintf(ar->f, " ");
669678 }
670679 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
671 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr);
680 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);
672681 render_node_extra(ar, fn_ref_node, grouped);
673682 fprintf(ar->f, "(");
674683 for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
......@@ -696,6 +705,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
696705 print_symbol(ar, rhs);
697706 break;
698707 }
708 case NodeTypePtrDeref:
709 {
710 AstNode *lhs = node->data.ptr_deref_expr.target;
711 render_node_ungrouped(ar, lhs);
712 fprintf(ar->f, ".*");
713 break;
714 }
715 case NodeTypeUnwrapOptional:
716 {
717 AstNode *lhs = node->data.unwrap_optional.expr;
718 render_node_ungrouped(ar, lhs);
719 fprintf(ar->f, ".?");
720 break;
721 }
699722 case NodeTypeUndefinedLiteral:
700723 fprintf(ar->f, "undefined");
701724 break;
......@@ -728,7 +751,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
728751 render_node_grouped(ar, field_node->data.struct_field.type);
729752 }
730753 if (field_node->data.struct_field.value != nullptr) {
731 fprintf(ar->f, "= ");
754 fprintf(ar->f, " = ");
732755 render_node_grouped(ar, field_node->data.struct_field.value);
733756 }
734757 fprintf(ar->f, ",\n");
......@@ -1089,9 +1112,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
10891112 {
10901113 fprintf(ar->f, "suspend");
10911114 if (node->data.suspend.block != nullptr) {
1092 fprintf(ar->f, " |");
1093 render_node_grouped(ar, node->data.suspend.promise_symbol);
1094 fprintf(ar->f, "| ");
10951115 render_node_grouped(ar, node->data.suspend.block);
10961116 }
10971117 break;
src/bigfloat.cpp+12
......@@ -18,6 +18,10 @@ void bigfloat_init_128(BigFloat *dest, float128_t x) {
1818 dest->value = x;
1919}
2020
21void bigfloat_init_16(BigFloat *dest, float16_t x) {
22 f16_to_f128M(x, &dest->value);
23}
24
2125void bigfloat_init_32(BigFloat *dest, float x) {
2226 float32_t f32_val;
2327 memcpy(&f32_val, &x, sizeof(float));
......@@ -146,6 +150,10 @@ Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
146150 }
147151}
148152
153float16_t bigfloat_to_f16(const BigFloat *bigfloat) {
154 return f128M_to_f16(&bigfloat->value);
155}
156
149157float bigfloat_to_f32(const BigFloat *bigfloat) {
150158 float32_t f32_value = f128M_to_f32(&bigfloat->value);
151159 float result;
......@@ -181,3 +189,7 @@ bool bigfloat_has_fraction(const BigFloat *bigfloat) {
181189 f128M_roundToInt(&bigfloat->value, softfloat_round_minMag, false, &floored);
182190 return !f128M_eq(&floored, &bigfloat->value);
183191}
192
193void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) {
194 f128M_sqrt(&op->value, &dest->value);
195}
src/bigfloat.hpp+3
......@@ -22,6 +22,7 @@ struct BigFloat {
2222
2323struct Buf;
2424
25void bigfloat_init_16(BigFloat *dest, float16_t x);
2526void bigfloat_init_32(BigFloat *dest, float x);
2627void bigfloat_init_64(BigFloat *dest, double x);
2728void bigfloat_init_128(BigFloat *dest, float128_t x);
......@@ -29,6 +30,7 @@ void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);
2930void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);
3031int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);
3132
33float16_t bigfloat_to_f16(const BigFloat *bigfloat);
3234float bigfloat_to_f32(const BigFloat *bigfloat);
3335double bigfloat_to_f64(const BigFloat *bigfloat);
3436float128_t bigfloat_to_f128(const BigFloat *bigfloat);
......@@ -42,6 +44,7 @@ void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2
4244void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
4345void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
4446void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
47void bigfloat_sqrt(BigFloat *dest, const BigFloat *op);
4548void bigfloat_append_buf(Buf *buf, const BigFloat *op);
4649Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2);
4750
src/bigint.cpp+49-10
......@@ -86,6 +86,11 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
8686 size_t digits_to_copy = bit_count / 64;
8787 size_t leftover_bits = bit_count % 64;
8888 dest->digit_count = digits_to_copy + ((leftover_bits == 0) ? 0 : 1);
89 if (dest->digit_count == 1 && leftover_bits == 0) {
90 dest->data.digit = op_digits[0];
91 if (dest->data.digit == 0) dest->digit_count = 0;
92 return;
93 }
8994 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);
9095 for (size_t i = 0; i < digits_to_copy; i += 1) {
9196 uint64_t digit = (i < op->digit_count) ? op_digits[i] : 0;
......@@ -1254,12 +1259,11 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) {
12541259 bigint_normalize(dest);
12551260 return;
12561261 }
1257 // TODO this code path is untested
1258 uint64_t first_digit = dest->data.digit;
1262
12591263 dest->digit_count = max(op1->digit_count, op2->digit_count);
12601264 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);
1261 dest->data.digits[0] = first_digit;
1262 size_t i = 1;
1265
1266 size_t i = 0;
12631267 for (; i < op1->digit_count && i < op2->digit_count; i += 1) {
12641268 dest->data.digits[i] = op1_digits[i] & op2_digits[i];
12651269 }
......@@ -1407,7 +1411,6 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
14071411 return;
14081412 }
14091413
1410 // TODO this code path is untested
14111414 size_t digit_shift_count = shift_amt / 64;
14121415 size_t leftover_shift_count = shift_amt % 64;
14131416
......@@ -1422,7 +1425,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
14221425 uint64_t digit = op1_digits[op_digit_index];
14231426 size_t dest_digit_index = op_digit_index - digit_shift_count;
14241427 dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count);
1425 carry = (0xffffffffffffffffULL << leftover_shift_count) & digit;
1428 carry = digit << (64 - leftover_shift_count);
14261429
14271430 if (dest_digit_index == 0) { break; }
14281431 op_digit_index -= 1;
......@@ -1590,6 +1593,37 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base) {
15901593 }
15911594}
15921595
1596size_t bigint_popcount_unsigned(const BigInt *bi) {
1597 assert(!bi->is_negative);
1598 if (bi->digit_count == 0)
1599 return 0;
1600
1601 size_t count = 0;
1602 size_t bit_count = bi->digit_count * 64;
1603 for (size_t i = 0; i < bit_count; i += 1) {
1604 if (bit_at_index(bi, i))
1605 count += 1;
1606 }
1607 return count;
1608}
1609
1610size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count) {
1611 if (bit_count == 0)
1612 return 0;
1613 if (bi->digit_count == 0)
1614 return 0;
1615
1616 BigInt twos_comp = {0};
1617 to_twos_complement(&twos_comp, bi, bit_count);
1618
1619 size_t count = 0;
1620 for (size_t i = 0; i < bit_count; i += 1) {
1621 if (bit_at_index(&twos_comp, i))
1622 count += 1;
1623 }
1624 return count;
1625}
1626
15931627size_t bigint_ctz(const BigInt *bi, size_t bit_count) {
15941628 if (bit_count == 0)
15951629 return 0;
......@@ -1680,10 +1714,15 @@ void bigint_incr(BigInt *x) {
16801714 bigint_init_unsigned(x, 1);
16811715 return;
16821716 }
1683
1684 if (x->digit_count == 1 && x->data.digit != UINT64_MAX) {
1685 x->data.digit += 1;
1686 return;
1717
1718 if (x->digit_count == 1) {
1719 if (x->is_negative && x->data.digit != 0) {
1720 x->data.digit -= 1;
1721 return;
1722 } else if (!x->is_negative && x->data.digit != UINT64_MAX) {
1723 x->data.digit += 1;
1724 return;
1725 }
16871726 }
16881727
16891728 BigInt copy;
src/bigint.hpp+2
......@@ -81,6 +81,8 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base);
8181
8282size_t bigint_ctz(const BigInt *bi, size_t bit_count);
8383size_t bigint_clz(const BigInt *bi, size_t bit_count);
84size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count);
85size_t bigint_popcount_unsigned(const BigInt *bi);
8486
8587size_t bigint_bits_needed(const BigInt *op);
8688
src/codegen.cpp+936-399
......@@ -17,6 +17,7 @@
1717#include "os.hpp"
1818#include "translate_c.hpp"
1919#include "target.hpp"
20#include "util.hpp"
2021#include "zig_llvm.h"
2122
2223#include <stdio.h>
......@@ -59,6 +60,33 @@ PackageTableEntry *new_anonymous_package(void) {
5960 return new_package("", "");
6061}
6162
63static const char *symbols_that_llvm_depends_on[] = {
64 "memcpy",
65 "memset",
66 "sqrt",
67 "powi",
68 "sin",
69 "cos",
70 "pow",
71 "exp",
72 "exp2",
73 "log",
74 "log10",
75 "log2",
76 "fma",
77 "fabs",
78 "minnum",
79 "maxnum",
80 "copysign",
81 "floor",
82 "ceil",
83 "trunc",
84 "rint",
85 "nearbyint",
86 "round",
87 // TODO probably all of compiler-rt needs to go here
88};
89
6290CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
6391 Buf *zig_lib_dir)
6492{
......@@ -88,10 +116,15 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
88116 g->exported_symbol_names.init(8);
89117 g->external_prototypes.init(8);
90118 g->string_literals_table.init(16);
119 g->type_info_cache.init(32);
91120 g->is_test_build = false;
92121 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
93122 buf_resize(&g->global_asm, 0);
94123
124 for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
125 g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
126 }
127
95128 if (root_src_path) {
96129 Buf *src_basename = buf_alloc();
97130 Buf *src_dir = buf_alloc();
......@@ -325,13 +358,6 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
325358 return addLLVMAttr(arg_val, param_index + 1, attr_name);
326359}
327360
328static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, const char *attr_name) {
329 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
330 assert(kind_id != 0);
331 LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0);
332 LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
333}
334
335361static bool is_symbol_available(CodeGen *g, Buf *name) {
336362 return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
337363}
......@@ -512,7 +538,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
512538 }
513539
514540 if (fn_table_entry->body_node != nullptr) {
515 bool want_fn_safety = g->build_mode != BuildModeFastRelease && !fn_table_entry->def_scope->safety_off;
541 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
542 g->build_mode != BuildModeSmallRelease &&
543 !fn_table_entry->def_scope->safety_off;
516544 if (want_fn_safety) {
517545 if (g->libc_link_lib != nullptr) {
518546 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
......@@ -578,11 +606,6 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
578606 if (param_type->id == TypeTableEntryIdPointer) {
579607 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
580608 }
581 // Note: byval is disabled on windows due to an LLVM bug:
582 // https://github.com/zig-lang/zig/issues/536
583 if (is_byval && g->zig_target.os != OsWindows) {
584 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
585 }
586609 }
587610
588611 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
......@@ -652,6 +675,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
652675 }
653676 case ScopeIdDeferExpr:
654677 case ScopeIdLoop:
678 case ScopeIdSuspend:
655679 case ScopeIdCompTime:
656680 case ScopeIdCoroPrelude:
657681 return get_di_scope(g, scope->parent);
......@@ -717,12 +741,12 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
717741 return fn_val;
718742}
719743
720static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, ZigLLVMFnId fn_id) {
744static LLVMValueRef get_float_fn(CodeGen *g, TypeTableEntry *type_entry, ZigLLVMFnId fn_id) {
721745 assert(type_entry->id == TypeTableEntryIdFloat);
722746
723747 ZigLLVMFnKey key = {};
724748 key.id = fn_id;
725 key.data.floor_ceil.bit_count = (uint32_t)type_entry->data.floating.bit_count;
749 key.data.floating.bit_count = (uint32_t)type_entry->data.floating.bit_count;
726750
727751 auto existing_entry = g->llvm_fn_table.maybe_get(key);
728752 if (existing_entry)
......@@ -733,6 +757,8 @@ static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, Zi
733757 name = "floor";
734758 } else if (fn_id == ZigLLVMFnIdCeil) {
735759 name = "ceil";
760 } else if (fn_id == ZigLLVMFnIdSqrt) {
761 name = "sqrt";
736762 } else {
737763 zig_unreachable();
738764 }
......@@ -815,7 +841,7 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
815841}
816842
817843static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
818 if (g->build_mode == BuildModeFastRelease)
844 if (g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease)
819845 return false;
820846
821847 // TODO memoize
......@@ -859,7 +885,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
859885 return buf_create_from_str("exact division produced remainder");
860886 case PanicMsgIdSliceWidenRemainder:
861887 return buf_create_from_str("slice widening size mismatch");
862 case PanicMsgIdUnwrapMaybeFail:
888 case PanicMsgIdUnwrapOptionalFail:
863889 return buf_create_from_str("attempt to unwrap null");
864890 case PanicMsgIdUnreachable:
865891 return buf_create_from_str("reached unreachable code");
......@@ -869,6 +895,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
869895 return buf_create_from_str("incorrect alignment");
870896 case PanicMsgIdBadUnionField:
871897 return buf_create_from_str("access of inactive union field");
898 case PanicMsgIdBadEnumValue:
899 return buf_create_from_str("invalid enum value");
900 case PanicMsgIdFloatToInt:
901 return buf_create_from_str("integer part of floating point value out of bounds");
872902 }
873903 zig_unreachable();
874904}
......@@ -887,7 +917,8 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
887917 assert(val->global_refs->llvm_global);
888918 }
889919
890 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
920 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
921 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
891922 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
892923 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
893924}
......@@ -932,6 +963,53 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
932963 return g->memcpy_fn_val;
933964}
934965
966static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
967 if (g->stacksave_fn_val)
968 return g->stacksave_fn_val;
969
970 // declare i8* @llvm.stacksave()
971
972 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false);
973 g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type);
974 assert(LLVMGetIntrinsicID(g->stacksave_fn_val));
975
976 return g->stacksave_fn_val;
977}
978
979static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) {
980 if (g->stackrestore_fn_val)
981 return g->stackrestore_fn_val;
982
983 // declare void @llvm.stackrestore(i8* %ptr)
984
985 LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0);
986 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), &param_type, 1, false);
987 g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type);
988 assert(LLVMGetIntrinsicID(g->stackrestore_fn_val));
989
990 return g->stackrestore_fn_val;
991}
992
993static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
994 if (g->write_register_fn_val)
995 return g->write_register_fn_val;
996
997 // declare void @llvm.write_register.i64(metadata, i64 @value)
998 // !0 = !{!"sp\00"}
999
1000 LLVMTypeRef param_types[] = {
1001 LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
1002 LLVMIntType(g->pointer_size_bytes * 8),
1003 };
1004
1005 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1006 Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8);
1007 g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1008 assert(LLVMGetIntrinsicID(g->write_register_fn_val));
1009
1010 return g->write_register_fn_val;
1011}
1012
9351013static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
9361014 if (g->coro_destroy_fn_val)
9371015 return g->coro_destroy_fn_val;
......@@ -1408,7 +1486,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
14081486 LLVMValueRef full_buf_ptr = LLVMConstInBoundsGEP(global_array, full_buf_ptr_indices, 2);
14091487
14101488
1411 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
1489 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
1490 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
14121491 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
14131492 LLVMValueRef global_slice_fields[] = {
14141493 full_buf_ptr,
......@@ -1626,7 +1705,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, T
16261705 return trunc_val;
16271706 }
16281707 LLVMValueRef orig_val;
1629 if (actual_type->data.integral.is_signed) {
1708 if (wanted_type->data.integral.is_signed) {
16301709 orig_val = LLVMBuildSExt(g->builder, trunc_val, actual_type->type_ref, "");
16311710 } else {
16321711 orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
......@@ -1900,7 +1979,7 @@ static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, TypeTableEntry *type
19001979 if (type_entry->id == TypeTableEntryIdInt)
19011980 return val;
19021981
1903 LLVMValueRef floor_fn = get_floor_ceil_fn(g, type_entry, ZigLLVMFnIdFloor);
1982 LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor);
19041983 return LLVMBuildCall(g->builder, floor_fn, &val, 1, "");
19051984}
19061985
......@@ -1908,7 +1987,7 @@ static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, TypeTableEntry *type_
19081987 if (type_entry->id == TypeTableEntryIdInt)
19091988 return val;
19101989
1911 LLVMValueRef ceil_fn = get_floor_ceil_fn(g, type_entry, ZigLLVMFnIdCeil);
1990 LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil);
19121991 return LLVMBuildCall(g->builder, ceil_fn, &val, 1, "");
19131992}
19141993
......@@ -2159,9 +2238,13 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
21592238 IrInstruction *op2 = bin_op_instruction->op2;
21602239
21612240 assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
2162 op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
2163 op_id == IrBinOpBitShiftRightExact ||
2164 (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet));
2241 op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
2242 op_id == IrBinOpBitShiftRightExact ||
2243 (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet) ||
2244 (op1->value.type->id == TypeTableEntryIdPointer &&
2245 (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
2246 op1->value.type->data.pointer.ptr_len == PtrLenUnknown)
2247 );
21652248 TypeTableEntry *type_entry = op1->value.type;
21662249
21672250 bool want_runtime_safety = bin_op_instruction->safety_check_on &&
......@@ -2169,6 +2252,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
21692252
21702253 LLVMValueRef op1_value = ir_llvm_value(g, op1);
21712254 LLVMValueRef op2_value = ir_llvm_value(g, op2);
2255
2256
21722257 switch (op_id) {
21732258 case IrBinOpInvalid:
21742259 case IrBinOpArrayCat:
......@@ -2193,12 +2278,10 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
21932278 } else if (type_entry->id == TypeTableEntryIdInt) {
21942279 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
21952280 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2196 } else if (type_entry->id == TypeTableEntryIdEnum) {
2197 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2198 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2199 } else if (type_entry->id == TypeTableEntryIdErrorSet ||
2200 type_entry->id == TypeTableEntryIdPointer ||
2201 type_entry->id == TypeTableEntryIdBool)
2281 } else if (type_entry->id == TypeTableEntryIdEnum ||
2282 type_entry->id == TypeTableEntryIdErrorSet ||
2283 type_entry->id == TypeTableEntryIdBool ||
2284 get_codegen_ptr_type(type_entry) != nullptr)
22022285 {
22032286 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
22042287 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
......@@ -2207,7 +2290,11 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
22072290 }
22082291 case IrBinOpAdd:
22092292 case IrBinOpAddWrap:
2210 if (type_entry->id == TypeTableEntryIdFloat) {
2293 if (type_entry->id == TypeTableEntryIdPointer) {
2294 assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
2295 // TODO runtime safety
2296 return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, "");
2297 } else if (type_entry->id == TypeTableEntryIdFloat) {
22112298 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
22122299 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
22132300 } else if (type_entry->id == TypeTableEntryIdInt) {
......@@ -2270,7 +2357,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
22702357 }
22712358 case IrBinOpSub:
22722359 case IrBinOpSubWrap:
2273 if (type_entry->id == TypeTableEntryIdFloat) {
2360 if (type_entry->id == TypeTableEntryIdPointer) {
2361 assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
2362 // TODO runtime safety
2363 LLVMValueRef subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
2364 return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
2365 } else if (type_entry->id == TypeTableEntryIdFloat) {
22742366 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
22752367 return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
22762368 } else if (type_entry->id == TypeTableEntryIdInt) {
......@@ -2460,7 +2552,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
24602552 assert(wanted_type->data.structure.is_slice);
24612553 assert(actual_type->id == TypeTableEntryIdArray);
24622554
2463 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
2555 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
24642556 TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
24652557
24662558
......@@ -2486,15 +2578,41 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
24862578 } else {
24872579 return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
24882580 }
2489 case CastOpFloatToInt:
2581 case CastOpFloatToInt: {
24902582 assert(wanted_type->id == TypeTableEntryIdInt);
24912583 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base));
2584
2585 bool want_safety = ir_want_runtime_safety(g, &cast_instruction->base);
2586
2587 LLVMValueRef result;
24922588 if (wanted_type->data.integral.is_signed) {
2493 return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
2589 result = LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
24942590 } else {
2495 return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
2591 result = LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
24962592 }
24972593
2594 if (want_safety) {
2595 LLVMValueRef back_to_float;
2596 if (wanted_type->data.integral.is_signed) {
2597 back_to_float = LLVMBuildSIToFP(g->builder, result, LLVMTypeOf(expr_val), "");
2598 } else {
2599 back_to_float = LLVMBuildUIToFP(g->builder, result, LLVMTypeOf(expr_val), "");
2600 }
2601 LLVMValueRef difference = LLVMBuildFSub(g->builder, expr_val, back_to_float, "");
2602 LLVMValueRef one_pos = LLVMConstReal(LLVMTypeOf(expr_val), 1.0f);
2603 LLVMValueRef one_neg = LLVMConstReal(LLVMTypeOf(expr_val), -1.0f);
2604 LLVMValueRef ok_bit_pos = LLVMBuildFCmp(g->builder, LLVMRealOLT, difference, one_pos, "");
2605 LLVMValueRef ok_bit_neg = LLVMBuildFCmp(g->builder, LLVMRealOGT, difference, one_neg, "");
2606 LLVMValueRef ok_bit = LLVMBuildAnd(g->builder, ok_bit_pos, ok_bit_neg, "");
2607 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckOk");
2608 LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckFail");
2609 LLVMBuildCondBr(g->builder, ok_bit, ok_block, bad_block);
2610 LLVMPositionBuilderAtEnd(g->builder, bad_block);
2611 gen_safety_crash(g, PanicMsgIdFloatToInt);
2612 LLVMPositionBuilderAtEnd(g->builder, ok_block);
2613 }
2614 return result;
2615 }
24982616 case CastOpBoolToInt:
24992617 assert(wanted_type->id == TypeTableEntryIdInt);
25002618 assert(actual_type->id == TypeTableEntryIdBool);
......@@ -2504,6 +2622,31 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
25042622 add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
25052623 }
25062624 return expr_val;
2625 case CastOpBitCast:
2626 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
2627 case CastOpPtrOfArrayToSlice: {
2628 assert(cast_instruction->tmp_ptr);
2629 assert(actual_type->id == TypeTableEntryIdPointer);
2630 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
2631 assert(array_type->id == TypeTableEntryIdArray);
2632
2633 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
2634 slice_ptr_index, "");
2635 LLVMValueRef indices[] = {
2636 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
2637 LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
2638 };
2639 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
2640 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
2641
2642 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
2643 slice_len_index, "");
2644 LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
2645 array_type->data.array.len, false);
2646 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
2647
2648 return cast_instruction->tmp_ptr;
2649 }
25072650 }
25082651 zig_unreachable();
25092652}
......@@ -2559,8 +2702,25 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
25592702 TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
25602703
25612704 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
2562 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
2705 LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
25632706 instruction->target->value.type, tag_int_type, target_val);
2707
2708 if (ir_want_runtime_safety(g, &instruction->base)) {
2709 LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
2710 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
2711 size_t field_count = wanted_type->data.enumeration.src_field_count;
2712 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
2713 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
2714 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
2715 &wanted_type->data.enumeration.fields[field_i].value);
2716 LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
2717 }
2718 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
2719 gen_safety_crash(g, PanicMsgIdBadEnumValue);
2720
2721 LLVMPositionBuilderAtEnd(g->builder, ok_value_block);
2722 }
2723 return tag_int_value;
25642724}
25652725
25662726static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
......@@ -2639,7 +2799,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
26392799
26402800 switch (op_id) {
26412801 case IrUnOpInvalid:
2642 case IrUnOpMaybe:
2802 case IrUnOpOptional:
26432803 case IrUnOpDereference:
26442804 zig_unreachable();
26452805 case IrUnOpNegation:
......@@ -2717,7 +2877,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
27172877 if (have_init_expr) {
27182878 assert(var->value->type == init_value->value.type);
27192879 TypeTableEntry *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
2720 var->align_bytes, 0, 0);
2880 PtrLenSingle, var->align_bytes, 0, 0);
27212881 gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value));
27222882 } else {
27232883 bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
......@@ -2814,7 +2974,13 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
28142974
28152975 bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on;
28162976
2817 if (array_type->id == TypeTableEntryIdArray) {
2977 if (array_type->id == TypeTableEntryIdArray ||
2978 (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
2979 {
2980 if (array_type->id == TypeTableEntryIdPointer) {
2981 assert(array_type->data.pointer.child_type->id == TypeTableEntryIdArray);
2982 array_type = array_type->data.pointer.child_type;
2983 }
28182984 if (safety_check_on) {
28192985 LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
28202986 array_type->data.array.len, false);
......@@ -2855,18 +3021,26 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
28553021 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
28563022 } else if (array_type->id == TypeTableEntryIdStruct) {
28573023 assert(array_type->data.structure.is_slice);
3024 if (!type_has_bits(instruction->base.value.type)) {
3025 if (safety_check_on) {
3026 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMIntegerTypeKind);
3027 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, array_ptr);
3028 }
3029 return nullptr;
3030 }
3031
28583032 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
28593033 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
28603034
28613035 if (safety_check_on) {
2862 size_t len_index = array_type->data.structure.fields[1].gen_index;
3036 size_t len_index = array_type->data.structure.fields[slice_len_index].gen_index;
28633037 assert(len_index != SIZE_MAX);
28643038 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, "");
28653039 LLVMValueRef len = gen_load_untyped(g, len_ptr, 0, false, "");
28663040 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
28673041 }
28683042
2869 size_t ptr_index = array_type->data.structure.fields[0].gen_index;
3043 size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index;
28703044 assert(ptr_index != SIZE_MAX);
28713045 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, "");
28723046 LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, "");
......@@ -2895,6 +3069,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
28953069 return 1 + get_async_allocator_arg_index(g, fn_type_id);
28963070}
28973071
3072
3073static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
3074 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
3075 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
3076
3077 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
3078 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
3079
3080 LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
3081 LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
3082 LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
3083 LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
3084 return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
3085}
3086
3087static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
3088 LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
3089
3090 if (g->sp_md_node == nullptr) {
3091 Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
3092 LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
3093 g->sp_md_node = LLVMMDNode(&str_node, 1);
3094 }
3095
3096 LLVMValueRef params[] = {
3097 g->sp_md_node,
3098 aligned_end_addr,
3099 };
3100
3101 LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
3102}
3103
28983104static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
28993105 LLVMValueRef fn_val;
29003106 TypeTableEntry *fn_type;
......@@ -2961,18 +3167,24 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
29613167 }
29623168
29633169 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
2964 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
2965 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3170 LLVMValueRef result;
3171
3172 if (instruction->new_stack == nullptr) {
3173 result = ZigLLVMBuildCall(g->builder, fn_val,
3174 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3175 } else {
3176 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
3177 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
29663178
2967 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
2968 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
2969 // Note: byval is disabled on windows due to an LLVM bug:
2970 // https://github.com/zig-lang/zig/issues/536
2971 if (gen_info->is_byval && g->zig_target.os != OsWindows) {
2972 addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
2973 }
3179 LLVMValueRef new_stack_addr = get_new_stack_addr(g, ir_llvm_value(g, instruction->new_stack));
3180 LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
3181 gen_set_stack_pointer(g, new_stack_addr);
3182 result = ZigLLVMBuildCall(g->builder, fn_val,
3183 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3184 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
29743185 }
29753186
3187
29763188 if (instruction->is_async) {
29773189 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
29783190 LLVMBuildStore(g->builder, result, payload_ptr);
......@@ -2985,6 +3197,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
29853197 return nullptr;
29863198 } else if (first_arg_ret) {
29873199 return instruction->tmp_ptr;
3200 } else if (handle_is_ptr(src_return_type)) {
3201 auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr);
3202 LLVMSetAlignment(store_instr, LLVMGetAlignment(instruction->tmp_ptr));
3203 return instruction->tmp_ptr;
29883204 } else {
29893205 return result;
29903206 }
......@@ -3185,7 +3401,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
31853401}
31863402
31873403static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
3188 assert(maybe_type->id == TypeTableEntryIdMaybe);
3404 assert(maybe_type->id == TypeTableEntryIdOptional);
31893405 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
31903406 if (child_type->zero_bits) {
31913407 return maybe_handle;
......@@ -3207,23 +3423,23 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
32073423}
32083424
32093425static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
3210 IrInstructionUnwrapMaybe *instruction)
3426 IrInstructionUnwrapOptional *instruction)
32113427{
32123428 TypeTableEntry *ptr_type = instruction->value->value.type;
32133429 assert(ptr_type->id == TypeTableEntryIdPointer);
32143430 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
3215 assert(maybe_type->id == TypeTableEntryIdMaybe);
3431 assert(maybe_type->id == TypeTableEntryIdOptional);
32163432 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
32173433 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
32183434 LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
32193435 if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
32203436 LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
3221 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
3222 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
3437 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
3438 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
32233439 LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
32243440
32253441 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3226 gen_safety_crash(g, PanicMsgIdUnwrapMaybeFail);
3442 gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
32273443
32283444 LLVMPositionBuilderAtEnd(g->builder, ok_block);
32293445 }
......@@ -3243,14 +3459,24 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
32433459static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {
32443460 ZigLLVMFnKey key = {};
32453461 const char *fn_name;
3462 uint32_t n_args;
32463463 if (fn_id == BuiltinFnIdCtz) {
32473464 fn_name = "cttz";
3465 n_args = 2;
32483466 key.id = ZigLLVMFnIdCtz;
32493467 key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3250 } else {
3468 } else if (fn_id == BuiltinFnIdClz) {
32513469 fn_name = "ctlz";
3470 n_args = 2;
32523471 key.id = ZigLLVMFnIdClz;
32533472 key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3473 } else if (fn_id == BuiltinFnIdPopCount) {
3474 fn_name = "ctpop";
3475 n_args = 1;
3476 key.id = ZigLLVMFnIdPopCount;
3477 key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
3478 } else {
3479 zig_unreachable();
32543480 }
32553481
32563482 auto existing_entry = g->llvm_fn_table.maybe_get(key);
......@@ -3263,7 +3489,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
32633489 int_type->type_ref,
32643490 LLVMInt1Type(),
32653491 };
3266 LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false);
3492 LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, n_args, false);
32673493 LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);
32683494 assert(LLVMGetIntrinsicID(fn_val));
32693495
......@@ -3296,6 +3522,14 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru
32963522 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
32973523}
32983524
3525static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
3526 TypeTableEntry *int_type = instruction->value->value.type;
3527 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
3528 LLVMValueRef operand = ir_llvm_value(g, instruction->value);
3529 LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, &operand, 1, "");
3530 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
3531}
3532
32993533static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {
33003534 LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);
33013535 LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;
......@@ -3366,34 +3600,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
33663600 return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
33673601}
33683602
3603static LLVMValueRef get_enum_tag_name_function(CodeGen *g, TypeTableEntry *enum_type) {
3604 assert(enum_type->id == TypeTableEntryIdEnum);
3605 if (enum_type->data.enumeration.name_function)
3606 return enum_type->data.enumeration.name_function;
3607
3608 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
3609 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
3610 TypeTableEntry *u8_slice_type = get_slice_type(g, u8_ptr_type);
3611 TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
3612
3613 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0),
3614 &tag_int_type->type_ref, 1, false);
3615
3616 Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
3617 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
3618 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
3619 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
3620 addLLVMFnAttr(fn_val, "nounwind");
3621 add_uwtable_attr(g, fn_val);
3622 if (g->build_mode == BuildModeDebug) {
3623 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
3624 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
3625 }
3626
3627 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
3628 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
3629 FnTableEntry *prev_cur_fn = g->cur_fn;
3630 LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
3631
3632 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
3633 LLVMPositionBuilderAtEnd(g->builder, entry_block);
3634 ZigLLVMClearCurrentDebugLocation(g->builder);
3635 g->cur_fn = nullptr;
3636 g->cur_fn_val = fn_val;
3637
3638 size_t field_count = enum_type->data.enumeration.src_field_count;
3639 LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
3640 LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0);
3641 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
3642
3643
3644 TypeTableEntry *usize = g->builtin_types.entry_usize;
3645 LLVMValueRef array_ptr_indices[] = {
3646 LLVMConstNull(usize->type_ref),
3647 LLVMConstNull(usize->type_ref),
3648 };
3649
3650 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
3651 Buf *name = enum_type->data.enumeration.fields[field_i].name;
3652 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
3653 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
3654 LLVMSetInitializer(str_global, str_init);
3655 LLVMSetLinkage(str_global, LLVMPrivateLinkage);
3656 LLVMSetGlobalConstant(str_global, true);
3657 LLVMSetUnnamedAddr(str_global, true);
3658 LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
3659
3660 LLVMValueRef fields[] = {
3661 LLVMConstGEP(str_global, array_ptr_indices, 2),
3662 LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
3663 };
3664 LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2);
3665
3666 LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), "");
3667 LLVMSetInitializer(slice_global, slice_init_value);
3668 LLVMSetLinkage(slice_global, LLVMPrivateLinkage);
3669 LLVMSetGlobalConstant(slice_global, true);
3670 LLVMSetUnnamedAddr(slice_global, true);
3671 LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value)));
3672
3673 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name");
3674 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
3675 &enum_type->data.enumeration.fields[field_i].value);
3676 LLVMAddCase(switch_instr, this_tag_int_value, return_block);
3677
3678 LLVMPositionBuilderAtEnd(g->builder, return_block);
3679 LLVMBuildRet(g->builder, slice_global);
3680 }
3681
3682 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
3683 if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
3684 gen_safety_crash(g, PanicMsgIdBadEnumValue);
3685 } else {
3686 LLVMBuildUnreachable(g->builder);
3687 }
3688
3689 g->cur_fn = prev_cur_fn;
3690 g->cur_fn_val = prev_cur_fn_val;
3691 LLVMPositionBuilderAtEnd(g->builder, prev_block);
3692 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
3693
3694 enum_type->data.enumeration.name_function = fn_val;
3695 return fn_val;
3696}
3697
33693698static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
33703699 IrInstructionTagName *instruction)
33713700{
33723701 TypeTableEntry *enum_type = instruction->target->value.type;
33733702 assert(enum_type->id == TypeTableEntryIdEnum);
3374 assert(enum_type->data.enumeration.generate_name_table);
33753703
3376 TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
3377 LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
3378 if (ir_want_runtime_safety(g, &instruction->base)) {
3379 size_t field_count = enum_type->data.enumeration.src_field_count;
3380
3381 // if the field_count can't fit in the bits of the enum_type, then it can't possibly
3382 // be the wrong value
3383 BigInt field_bi;
3384 bigint_init_unsigned(&field_bi, field_count);
3385 if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
3386 LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
3387 add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
3388 }
3389 }
3704 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
33903705
3391 LLVMValueRef indices[] = {
3392 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
3393 gen_widen_or_shorten(g, false, tag_int_type,
3394 g->builtin_types.entry_usize, enum_tag_value),
3395 };
3396 return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
3706 LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
3707 return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1,
3708 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
33973709}
33983710
33993711static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
......@@ -3443,17 +3755,17 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
34433755 } else if (target_type->id == TypeTableEntryIdFn) {
34443756 align_bytes = target_type->data.fn.fn_type_id.alignment;
34453757 ptr_val = target_val;
3446 } else if (target_type->id == TypeTableEntryIdMaybe &&
3758 } else if (target_type->id == TypeTableEntryIdOptional &&
34473759 target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
34483760 {
34493761 align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
34503762 ptr_val = target_val;
3451 } else if (target_type->id == TypeTableEntryIdMaybe &&
3763 } else if (target_type->id == TypeTableEntryIdOptional &&
34523764 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
34533765 {
34543766 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
34553767 ptr_val = target_val;
3456 } else if (target_type->id == TypeTableEntryIdMaybe &&
3768 } else if (target_type->id == TypeTableEntryIdOptional &&
34573769 target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
34583770 {
34593771 zig_panic("TODO audit this function");
......@@ -3552,9 +3864,30 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
35523864 LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
35533865
35543866 LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
3555 success_order, failure_order);
3867 success_order, failure_order, instruction->is_weak);
3868
3869 TypeTableEntry *maybe_type = instruction->base.value.type;
3870 assert(maybe_type->id == TypeTableEntryIdOptional);
3871 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
35563872
3557 return LLVMBuildExtractValue(g->builder, result_val, 1, "");
3873 if (type_is_codegen_pointer(child_type)) {
3874 LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
3875 LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
3876 return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
3877 }
3878
3879 assert(instruction->tmp_ptr != nullptr);
3880 assert(type_has_bits(instruction->type));
3881
3882 LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
3883 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
3884 gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
3885
3886 LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
3887 LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
3888 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
3889 gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
3890 return instruction->tmp_ptr;
35583891}
35593892
35603893static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
......@@ -3654,7 +3987,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
36543987
36553988 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
36563989
3657 if (array_type->id == TypeTableEntryIdArray) {
3990 if (array_type->id == TypeTableEntryIdArray ||
3991 (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
3992 {
3993 if (array_type->id == TypeTableEntryIdPointer) {
3994 array_type = array_type->data.pointer.child_type;
3995 }
36583996 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
36593997 LLVMValueRef end_val;
36603998 if (instruction->end) {
......@@ -3662,7 +4000,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
36624000 } else {
36634001 end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
36644002 }
3665
36664003 if (want_runtime_safety) {
36674004 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
36684005 if (instruction->end) {
......@@ -3695,6 +4032,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
36954032
36964033 return tmp_struct_ptr;
36974034 } else if (array_type->id == TypeTableEntryIdPointer) {
4035 assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
36984036 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
36994037 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
37004038
......@@ -3702,11 +4040,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
37024040 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
37034041 }
37044042
3705 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
3706 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
3707 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
4043 if (type_has_bits(array_type)) {
4044 size_t gen_ptr_index = instruction->base.value.type->data.structure.fields[slice_ptr_index].gen_index;
4045 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
4046 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
4047 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
4048 }
37084049
3709 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
4050 size_t gen_len_index = instruction->base.value.type->data.structure.fields[slice_len_index].gen_index;
4051 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
37104052 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
37114053 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
37124054
......@@ -3804,6 +4146,26 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
38044146 return LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");
38054147}
38064148
4149static LLVMValueRef get_handle_fn_val(CodeGen *g) {
4150 if (g->coro_frame_fn_val)
4151 return g->coro_frame_fn_val;
4152
4153 LLVMTypeRef fn_type = LLVMFunctionType( LLVMPointerType(LLVMInt8Type(), 0)
4154 , nullptr, 0, false);
4155 Buf *name = buf_sprintf("llvm.coro.frame");
4156 g->coro_frame_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
4157 assert(LLVMGetIntrinsicID(g->coro_frame_fn_val));
4158
4159 return g->coro_frame_fn_val;
4160}
4161
4162static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
4163 IrInstructionHandle *instruction)
4164{
4165 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_promise->type_ref);
4166 return LLVMBuildCall(g->builder, get_handle_fn_val(g), &zero, 0, "");
4167}
4168
38074169static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
38084170 TypeTableEntry *int_type = instruction->result_ptr_type;
38094171 assert(int_type->id == TypeTableEntryIdInt);
......@@ -3939,10 +4301,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
39394301 }
39404302}
39414303
3942static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
4304static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) {
39434305 TypeTableEntry *wanted_type = instruction->base.value.type;
39444306
3945 assert(wanted_type->id == TypeTableEntryIdMaybe);
4307 assert(wanted_type->id == TypeTableEntryIdOptional);
39464308
39474309 TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
39484310
......@@ -4049,7 +4411,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
40494411 uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry);
40504412
40514413 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
4052 false, false, field_align_bytes,
4414 false, false, PtrLenSingle, field_align_bytes,
40534415 (uint32_t)type_struct_field->packed_bits_offset, (uint32_t)type_struct_field->unaligned_bit_count);
40544416
40554417 gen_assign_raw(g, field_ptr, ptr_type, value);
......@@ -4065,7 +4427,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
40654427
40664428 uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
40674429 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
4068 false, false, field_align_bytes,
4430 false, false, PtrLenSingle, field_align_bytes,
40694431 0, 0);
40704432
40714433 LLVMValueRef uncasted_union_ptr;
......@@ -4312,7 +4674,8 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
43124674
43134675 LLVMPositionBuilderAtEnd(g->builder, ok_block);
43144676 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
4315 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
4677 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
4678 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
43164679 TypeTableEntry *slice_type = get_slice_type(g, u8_ptr_type);
43174680 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
43184681 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
......@@ -4381,6 +4744,16 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
43814744 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
43824745}
43834746
4747static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
4748 IrInstructionAtomicLoad *instruction)
4749{
4750 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
4751 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
4752 LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value.type, "");
4753 LLVMSetOrdering(load_inst, ordering);
4754 return load_inst;
4755}
4756
43844757static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
43854758 IrInstructionMergeErrRetTraces *instruction)
43864759{
......@@ -4402,6 +4775,13 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e
44024775 return nullptr;
44034776}
44044777
4778static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {
4779 LLVMValueRef op = ir_llvm_value(g, instruction->op);
4780 assert(instruction->base.value.type->id == TypeTableEntryIdFloat);
4781 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdSqrt);
4782 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
4783}
4784
44054785static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
44064786 AstNode *source_node = instruction->source_node;
44074787 Scope *scope = instruction->scope;
......@@ -4453,13 +4833,13 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
44534833 case IrInstructionIdCheckSwitchProngs:
44544834 case IrInstructionIdCheckStatementIsVoid:
44554835 case IrInstructionIdTypeName:
4456 case IrInstructionIdCanImplicitCast:
44574836 case IrInstructionIdDeclRef:
44584837 case IrInstructionIdSwitchVar:
44594838 case IrInstructionIdOffsetOf:
4839 case IrInstructionIdTypeInfo:
44604840 case IrInstructionIdTypeId:
44614841 case IrInstructionIdSetEvalBranchQuota:
4462 case IrInstructionIdPtrTypeOf:
4842 case IrInstructionIdPtrType:
44634843 case IrInstructionIdOpaqueType:
44644844 case IrInstructionIdSetAlignStack:
44654845 case IrInstructionIdArgType:
......@@ -4469,6 +4849,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
44694849 case IrInstructionIdPromiseResultType:
44704850 case IrInstructionIdAwaitBookkeeping:
44714851 case IrInstructionIdAddImplicitReturnType:
4852 case IrInstructionIdIntCast:
4853 case IrInstructionIdFloatCast:
4854 case IrInstructionIdIntToFloat:
4855 case IrInstructionIdFloatToInt:
4856 case IrInstructionIdBoolToInt:
4857 case IrInstructionIdErrSetCast:
4858 case IrInstructionIdFromBytes:
4859 case IrInstructionIdToBytes:
4860 case IrInstructionIdEnumToInt:
44724861 zig_unreachable();
44734862
44744863 case IrInstructionIdReturn:
......@@ -4505,12 +4894,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
45054894 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
45064895 case IrInstructionIdTestNonNull:
45074896 return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
4508 case IrInstructionIdUnwrapMaybe:
4509 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
4897 case IrInstructionIdUnwrapOptional:
4898 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
45104899 case IrInstructionIdClz:
45114900 return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
45124901 case IrInstructionIdCtz:
45134902 return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
4903 case IrInstructionIdPopCount:
4904 return ir_render_pop_count(g, executable, (IrInstructionPopCount *)instruction);
45144905 case IrInstructionIdSwitchBr:
45154906 return ir_render_switch_br(g, executable, (IrInstructionSwitchBr *)instruction);
45164907 case IrInstructionIdPhi:
......@@ -4539,6 +4930,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
45394930 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
45404931 case IrInstructionIdFrameAddress:
45414932 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
4933 case IrInstructionIdHandle:
4934 return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);
45424935 case IrInstructionIdOverflowOp:
45434936 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
45444937 case IrInstructionIdTestErr:
......@@ -4547,8 +4940,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
45474940 return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
45484941 case IrInstructionIdUnwrapErrPayload:
45494942 return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction);
4550 case IrInstructionIdMaybeWrap:
4551 return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction);
4943 case IrInstructionIdOptionalWrap:
4944 return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction);
45524945 case IrInstructionIdErrWrapCode:
45534946 return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
45544947 case IrInstructionIdErrWrapPayload:
......@@ -4617,12 +5010,16 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
46175010 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
46185011 case IrInstructionIdAtomicRmw:
46195012 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
5013 case IrInstructionIdAtomicLoad:
5014 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
46205015 case IrInstructionIdSaveErrRetAddr:
46215016 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
46225017 case IrInstructionIdMergeErrRetTraces:
46235018 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
46245019 case IrInstructionIdMarkErrRetTracePtr:
46255020 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
5021 case IrInstructionIdSqrt:
5022 return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
46265023 }
46275024 zig_unreachable();
46285025}
......@@ -4649,7 +5046,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
46495046
46505047static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
46515048static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
4652static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
5049static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
46535050
46545051static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
46555052 switch (parent->id) {
......@@ -4665,6 +5062,10 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
46655062 parent->data.p_array.elem_index);
46665063 case ConstParentIdUnion:
46675064 return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);
5065 case ConstParentIdScalar:
5066 render_const_val(g, parent->data.p_scalar.scalar_val, "");
5067 render_const_val_global(g, parent->data.p_scalar.scalar_val, "");
5068 return parent->data.p_scalar.scalar_val->global_refs->llvm_global;
46685069 }
46695070 zig_unreachable();
46705071}
......@@ -4690,7 +5091,8 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
46905091 };
46915092 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
46925093 } else {
4693 zig_unreachable();
5094 assert(parent->id == ConstParentIdScalar);
5095 return base_ptr;
46945096 }
46955097}
46965098
......@@ -4734,10 +5136,10 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
47345136 case TypeTableEntryIdInvalid:
47355137 case TypeTableEntryIdMetaType:
47365138 case TypeTableEntryIdUnreachable:
4737 case TypeTableEntryIdNumLitFloat:
4738 case TypeTableEntryIdNumLitInt:
4739 case TypeTableEntryIdUndefLit:
4740 case TypeTableEntryIdNullLit:
5139 case TypeTableEntryIdComptimeFloat:
5140 case TypeTableEntryIdComptimeInt:
5141 case TypeTableEntryIdUndefined:
5142 case TypeTableEntryIdNull:
47415143 case TypeTableEntryIdErrorUnion:
47425144 case TypeTableEntryIdErrorSet:
47435145 case TypeTableEntryIdNamespace:
......@@ -4769,7 +5171,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
47695171 }
47705172 case TypeTableEntryIdPointer:
47715173 case TypeTableEntryIdFn:
4772 case TypeTableEntryIdMaybe:
5174 case TypeTableEntryIdOptional:
47735175 case TypeTableEntryIdPromise:
47745176 {
47755177 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
......@@ -4817,6 +5219,79 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef
48175219 return LLVMTypeOf(val) != type_entry->type_ref;
48185220}
48195221
5222static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) {
5223 render_const_val_global(g, const_val, name);
5224 switch (const_val->data.x_ptr.special) {
5225 case ConstPtrSpecialInvalid:
5226 case ConstPtrSpecialDiscard:
5227 zig_unreachable();
5228 case ConstPtrSpecialRef:
5229 {
5230 ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
5231 render_const_val(g, pointee, "");
5232 render_const_val_global(g, pointee, "");
5233 ConstExprValue *other_val = pointee;
5234 const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
5235 render_const_val_global(g, const_val, "");
5236 return const_val->global_refs->llvm_value;
5237 }
5238 case ConstPtrSpecialBaseArray:
5239 {
5240 ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
5241 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
5242 assert(array_const_val->type->id == TypeTableEntryIdArray);
5243 if (array_const_val->type->zero_bits) {
5244 // make this a null pointer
5245 TypeTableEntry *usize = g->builtin_types.entry_usize;
5246 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5247 const_val->type->type_ref);
5248 render_const_val_global(g, const_val, "");
5249 return const_val->global_refs->llvm_value;
5250 }
5251 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
5252 elem_index);
5253 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5254 const_val->global_refs->llvm_value = ptr_val;
5255 render_const_val_global(g, const_val, "");
5256 return ptr_val;
5257 }
5258 case ConstPtrSpecialBaseStruct:
5259 {
5260 ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
5261 assert(struct_const_val->type->id == TypeTableEntryIdStruct);
5262 if (struct_const_val->type->zero_bits) {
5263 // make this a null pointer
5264 TypeTableEntry *usize = g->builtin_types.entry_usize;
5265 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5266 const_val->type->type_ref);
5267 render_const_val_global(g, const_val, "");
5268 return const_val->global_refs->llvm_value;
5269 }
5270 size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
5271 size_t gen_field_index =
5272 struct_const_val->type->data.structure.fields[src_field_index].gen_index;
5273 LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
5274 gen_field_index);
5275 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5276 const_val->global_refs->llvm_value = ptr_val;
5277 render_const_val_global(g, const_val, "");
5278 return ptr_val;
5279 }
5280 case ConstPtrSpecialHardCodedAddr:
5281 {
5282 uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
5283 TypeTableEntry *usize = g->builtin_types.entry_usize;
5284 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
5285 const_val->type->type_ref);
5286 render_const_val_global(g, const_val, "");
5287 return const_val->global_refs->llvm_value;
5288 }
5289 case ConstPtrSpecialFunction:
5290 return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
5291 }
5292 zig_unreachable();
5293}
5294
48205295static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
48215296 TypeTableEntry *type_entry = const_val->type;
48225297 assert(!type_entry->zero_bits);
......@@ -4839,6 +5314,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
48395314 const_val->data.x_err_set->value, false);
48405315 case TypeTableEntryIdFloat:
48415316 switch (type_entry->data.floating.bit_count) {
5317 case 16:
5318 return LLVMConstReal(type_entry->type_ref, zig_f16_to_double(const_val->data.x_f16));
48425319 case 32:
48435320 return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);
48445321 case 64:
......@@ -4861,23 +5338,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
48615338 } else {
48625339 return LLVMConstNull(LLVMInt1Type());
48635340 }
4864 case TypeTableEntryIdMaybe:
5341 case TypeTableEntryIdOptional:
48655342 {
48665343 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
48675344 if (child_type->zero_bits) {
4868 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
5345 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
48695346 } else if (type_is_codegen_pointer(child_type)) {
4870 if (const_val->data.x_maybe) {
4871 return gen_const_val(g, const_val->data.x_maybe, "");
4872 } else {
4873 return LLVMConstNull(child_type->type_ref);
4874 }
5347 return gen_const_val_ptr(g, const_val, name);
48755348 } else {
48765349 LLVMValueRef child_val;
48775350 LLVMValueRef maybe_val;
48785351 bool make_unnamed_struct;
4879 if (const_val->data.x_maybe) {
4880 child_val = gen_const_val(g, const_val->data.x_maybe, "");
5352 if (const_val->data.x_optional) {
5353 child_val = gen_const_val(g, const_val->data.x_optional, "");
48815354 maybe_val = LLVMConstAllOnes(LLVMInt1Type());
48825355
48835356 make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
......@@ -5067,78 +5540,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
50675540 assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
50685541 return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
50695542 case TypeTableEntryIdPointer:
5070 {
5071 render_const_val_global(g, const_val, name);
5072 switch (const_val->data.x_ptr.special) {
5073 case ConstPtrSpecialInvalid:
5074 case ConstPtrSpecialDiscard:
5075 zig_unreachable();
5076 case ConstPtrSpecialRef:
5077 {
5078 ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
5079 render_const_val(g, pointee, "");
5080 render_const_val_global(g, pointee, "");
5081 ConstExprValue *other_val = pointee;
5082 const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
5083 render_const_val_global(g, const_val, "");
5084 return const_val->global_refs->llvm_value;
5085 }
5086 case ConstPtrSpecialBaseArray:
5087 {
5088 ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
5089 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
5090 assert(array_const_val->type->id == TypeTableEntryIdArray);
5091 if (array_const_val->type->zero_bits) {
5092 // make this a null pointer
5093 TypeTableEntry *usize = g->builtin_types.entry_usize;
5094 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5095 const_val->type->type_ref);
5096 render_const_val_global(g, const_val, "");
5097 return const_val->global_refs->llvm_value;
5098 }
5099 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
5100 elem_index);
5101 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5102 const_val->global_refs->llvm_value = ptr_val;
5103 render_const_val_global(g, const_val, "");
5104 return ptr_val;
5105 }
5106 case ConstPtrSpecialBaseStruct:
5107 {
5108 ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
5109 assert(struct_const_val->type->id == TypeTableEntryIdStruct);
5110 if (struct_const_val->type->zero_bits) {
5111 // make this a null pointer
5112 TypeTableEntry *usize = g->builtin_types.entry_usize;
5113 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
5114 const_val->type->type_ref);
5115 render_const_val_global(g, const_val, "");
5116 return const_val->global_refs->llvm_value;
5117 }
5118 size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
5119 size_t gen_field_index =
5120 struct_const_val->type->data.structure.fields[src_field_index].gen_index;
5121 LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
5122 gen_field_index);
5123 LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
5124 const_val->global_refs->llvm_value = ptr_val;
5125 render_const_val_global(g, const_val, "");
5126 return ptr_val;
5127 }
5128 case ConstPtrSpecialHardCodedAddr:
5129 {
5130 uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
5131 TypeTableEntry *usize = g->builtin_types.entry_usize;
5132 const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
5133 const_val->type->type_ref);
5134 render_const_val_global(g, const_val, "");
5135 return const_val->global_refs->llvm_value;
5136 }
5137 case ConstPtrSpecialFunction:
5138 return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
5139 }
5140 }
5141 zig_unreachable();
5543 return gen_const_val_ptr(g, const_val, name);
51425544 case TypeTableEntryIdErrorUnion:
51435545 {
51445546 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
......@@ -5180,10 +5582,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
51805582 case TypeTableEntryIdInvalid:
51815583 case TypeTableEntryIdMetaType:
51825584 case TypeTableEntryIdUnreachable:
5183 case TypeTableEntryIdNumLitFloat:
5184 case TypeTableEntryIdNumLitInt:
5185 case TypeTableEntryIdUndefLit:
5186 case TypeTableEntryIdNullLit:
5585 case TypeTableEntryIdComptimeFloat:
5586 case TypeTableEntryIdComptimeInt:
5587 case TypeTableEntryIdUndefined:
5588 case TypeTableEntryIdNull:
51875589 case TypeTableEntryIdNamespace:
51885590 case TypeTableEntryIdBlock:
51895591 case TypeTableEntryIdBoundFn:
......@@ -5232,7 +5634,8 @@ static void generate_error_name_table(CodeGen *g) {
52325634
52335635 assert(g->errors_by_index.length > 0);
52345636
5235 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
5637 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
5638 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
52365639 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
52375640
52385641 LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
......@@ -5269,54 +5672,6 @@ static void generate_error_name_table(CodeGen *g) {
52695672 LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init)));
52705673}
52715674
5272static void generate_enum_name_tables(CodeGen *g) {
5273 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
5274 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
5275
5276 TypeTableEntry *usize = g->builtin_types.entry_usize;
5277 LLVMValueRef array_ptr_indices[] = {
5278 LLVMConstNull(usize->type_ref),
5279 LLVMConstNull(usize->type_ref),
5280 };
5281
5282
5283 for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
5284 TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
5285 assert(enum_type->id == TypeTableEntryIdEnum);
5286
5287 size_t field_count = enum_type->data.enumeration.src_field_count;
5288 LLVMValueRef *values = allocate<LLVMValueRef>(field_count);
5289 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
5290 Buf *name = enum_type->data.enumeration.fields[field_i].name;
5291
5292 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
5293 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
5294 LLVMSetInitializer(str_global, str_init);
5295 LLVMSetLinkage(str_global, LLVMPrivateLinkage);
5296 LLVMSetGlobalConstant(str_global, true);
5297 LLVMSetUnnamedAddr(str_global, true);
5298 LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
5299
5300 LLVMValueRef fields[] = {
5301 LLVMConstGEP(str_global, array_ptr_indices, 2),
5302 LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
5303 };
5304 values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
5305 }
5306
5307 LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)field_count);
5308
5309 Buf *table_name = get_mangled_name(g, buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)), false);
5310 LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name));
5311 LLVMSetInitializer(name_table, name_table_init);
5312 LLVMSetLinkage(name_table, LLVMPrivateLinkage);
5313 LLVMSetGlobalConstant(name_table, true);
5314 LLVMSetUnnamedAddr(name_table, true);
5315 LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
5316 enum_type->data.enumeration.name_table = name_table;
5317 }
5318}
5319
53205675static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
53215676 IrExecutable *executable = &fn->analyzed_executable;
53225677 assert(executable->basic_block_list.length > 0);
......@@ -5413,14 +5768,13 @@ static void do_code_gen(CodeGen *g) {
54135768 }
54145769
54155770 generate_error_name_table(g);
5416 generate_enum_name_tables(g);
54175771
54185772 // Generate module level variables
54195773 for (size_t i = 0; i < g->global_vars.length; i += 1) {
54205774 TldVar *tld_var = g->global_vars.at(i);
54215775 VariableTableEntry *var = tld_var->var;
54225776
5423 if (var->value->type->id == TypeTableEntryIdNumLitFloat) {
5777 if (var->value->type->id == TypeTableEntryIdComptimeFloat) {
54245778 // Generate debug info for it but that's it.
54255779 ConstExprValue *const_val = var->value;
54265780 assert(const_val->special != ConstValSpecialRuntime);
......@@ -5434,7 +5788,7 @@ static void do_code_gen(CodeGen *g) {
54345788 continue;
54355789 }
54365790
5437 if (var->value->type->id == TypeTableEntryIdNumLitInt) {
5791 if (var->value->type->id == TypeTableEntryIdComptimeInt) {
54385792 // Generate debug info for it but that's it.
54395793 ConstExprValue *const_val = var->value;
54405794 assert(const_val->special != ConstValSpecialRuntime);
......@@ -5552,8 +5906,8 @@ static void do_code_gen(CodeGen *g) {
55525906 } else if (instruction->id == IrInstructionIdSlice) {
55535907 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
55545908 slot = &slice_instruction->tmp_ptr;
5555 } else if (instruction->id == IrInstructionIdMaybeWrap) {
5556 IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction;
5909 } else if (instruction->id == IrInstructionIdOptionalWrap) {
5910 IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction;
55575911 slot = &maybe_wrap_instruction->tmp_ptr;
55585912 } else if (instruction->id == IrInstructionIdErrWrapPayload) {
55595913 IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
......@@ -5561,6 +5915,9 @@ static void do_code_gen(CodeGen *g) {
55615915 } else if (instruction->id == IrInstructionIdErrWrapCode) {
55625916 IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
55635917 slot = &err_wrap_code_instruction->tmp_ptr;
5918 } else if (instruction->id == IrInstructionIdCmpxchg) {
5919 IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
5920 slot = &cmpxchg_instruction->tmp_ptr;
55645921 } else {
55655922 zig_unreachable();
55665923 }
......@@ -5670,6 +6027,7 @@ static void do_code_gen(CodeGen *g) {
56706027 ir_render(g, fn_table_entry);
56716028
56726029 }
6030
56736031 assert(!g->errors.length);
56746032
56756033 if (buf_len(&g->global_asm) != 0) {
......@@ -5722,10 +6080,12 @@ static void do_code_gen(CodeGen *g) {
57226080 os_path_join(g->cache_dir, o_basename, output_path);
57236081 ensure_cache_dir(g);
57246082
6083 bool is_small = g->build_mode == BuildModeSmallRelease;
6084
57256085 switch (g->emit_file_type) {
57266086 case EmitFileTypeBinary:
57276087 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
5728 ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug))
6088 ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small))
57296089 {
57306090 zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
57316091 }
......@@ -5735,7 +6095,7 @@ static void do_code_gen(CodeGen *g) {
57356095
57366096 case EmitFileTypeAssembly:
57376097 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
5738 ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug))
6098 ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small))
57396099 {
57406100 zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
57416101 }
......@@ -5744,7 +6104,7 @@ static void do_code_gen(CodeGen *g) {
57446104
57456105 case EmitFileTypeLLVMIr:
57466106 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
5747 ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug))
6107 ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small))
57486108 {
57496109 zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
57506110 }
......@@ -5756,21 +6116,6 @@ static void do_code_gen(CodeGen *g) {
57566116 }
57576117}
57586118
5759static const uint8_t int_sizes_in_bits[] = {
5760 2,
5761 3,
5762 4,
5763 5,
5764 6,
5765 7,
5766 8,
5767 16,
5768 29,
5769 32,
5770 64,
5771 128,
5772};
5773
57746119struct CIntTypeInfo {
57756120 CIntType id;
57766121 const char *name;
......@@ -5823,25 +6168,27 @@ static void define_builtin_types(CodeGen *g) {
58236168 g->builtin_types.entry_block = entry;
58246169 }
58256170 {
5826 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
5827 buf_init_from_str(&entry->name, "(float literal)");
6171 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdComptimeFloat);
6172 buf_init_from_str(&entry->name, "comptime_float");
58286173 entry->zero_bits = true;
58296174 g->builtin_types.entry_num_lit_float = entry;
6175 g->primitive_type_table.put(&entry->name, entry);
58306176 }
58316177 {
5832 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
5833 buf_init_from_str(&entry->name, "(integer literal)");
6178 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdComptimeInt);
6179 buf_init_from_str(&entry->name, "comptime_int");
58346180 entry->zero_bits = true;
58356181 g->builtin_types.entry_num_lit_int = entry;
6182 g->primitive_type_table.put(&entry->name, entry);
58366183 }
58376184 {
5838 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
6185 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefined);
58396186 buf_init_from_str(&entry->name, "(undefined)");
58406187 entry->zero_bits = true;
58416188 g->builtin_types.entry_undef = entry;
58426189 }
58436190 {
5844 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNullLit);
6191 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNull);
58456192 buf_init_from_str(&entry->name, "(null)");
58466193 entry->zero_bits = true;
58476194 g->builtin_types.entry_null = entry;
......@@ -5853,16 +6200,6 @@ static void define_builtin_types(CodeGen *g) {
58536200 g->builtin_types.entry_arg_tuple = entry;
58546201 }
58556202
5856 for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
5857 uint8_t size_in_bits = int_sizes_in_bits[int_size_i];
5858 for (size_t is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) {
5859 bool is_signed = is_signed_list[is_sign_i];
5860 TypeTableEntry *entry = make_int_type(g, is_signed, size_in_bits);
5861 g->primitive_type_table.put(&entry->name, entry);
5862 get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
5863 }
5864 }
5865
58666203 for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) {
58676204 const CIntTypeInfo *info = &c_int_type_infos[i];
58686205 uint32_t size_in_bits = target_c_type_size_in_bits(&g->zig_target, info->id);
......@@ -5921,58 +6258,30 @@ static void define_builtin_types(CodeGen *g) {
59216258 g->builtin_types.entry_usize = entry;
59226259 }
59236260 }
5924 {
5925 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
5926 entry->type_ref = LLVMFloatType();
5927 buf_init_from_str(&entry->name, "f32");
5928 entry->data.floating.bit_count = 32;
59296261
5930 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
5931 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
5932 debug_size_in_bits,
5933 ZigLLVMEncoding_DW_ATE_float());
5934 g->builtin_types.entry_f32 = entry;
5935 g->primitive_type_table.put(&entry->name, entry);
5936 }
5937 {
6262 auto add_fp_entry = [] (CodeGen *g,
6263 const char *name,
6264 uint32_t bit_count,
6265 LLVMTypeRef type_ref,
6266 TypeTableEntry **field) {
59386267 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
5939 entry->type_ref = LLVMDoubleType();
5940 buf_init_from_str(&entry->name, "f64");
5941 entry->data.floating.bit_count = 64;
6268 entry->type_ref = type_ref;
6269 buf_init_from_str(&entry->name, name);
6270 entry->data.floating.bit_count = bit_count;
59426271
59436272 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
59446273 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
59456274 debug_size_in_bits,
59466275 ZigLLVMEncoding_DW_ATE_float());
5947 g->builtin_types.entry_f64 = entry;
6276 *field = entry;
59486277 g->primitive_type_table.put(&entry->name, entry);
5949 }
5950 {
5951 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
5952 entry->type_ref = LLVMFP128Type();
5953 buf_init_from_str(&entry->name, "f128");
5954 entry->data.floating.bit_count = 128;
5955
5956 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
5957 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
5958 debug_size_in_bits,
5959 ZigLLVMEncoding_DW_ATE_float());
5960 g->builtin_types.entry_f128 = entry;
5961 g->primitive_type_table.put(&entry->name, entry);
5962 }
5963 {
5964 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
5965 entry->type_ref = LLVMX86FP80Type();
5966 buf_init_from_str(&entry->name, "c_longdouble");
5967 entry->data.floating.bit_count = 80;
6278 };
6279 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
6280 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
6281 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
6282 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
6283 add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble);
59686284
5969 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
5970 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
5971 debug_size_in_bits,
5972 ZigLLVMEncoding_DW_ATE_float());
5973 g->builtin_types.entry_c_longdouble = entry;
5974 g->primitive_type_table.put(&entry->name, entry);
5975 }
59766285 {
59776286 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
59786287 entry->type_ref = LLVMVoidType();
......@@ -6006,12 +6315,9 @@ static void define_builtin_types(CodeGen *g) {
60066315 g->builtin_types.entry_u29 = get_int_type(g, false, 29);
60076316 g->builtin_types.entry_u32 = get_int_type(g, false, 32);
60086317 g->builtin_types.entry_u64 = get_int_type(g, false, 64);
6009 g->builtin_types.entry_u128 = get_int_type(g, false, 128);
60106318 g->builtin_types.entry_i8 = get_int_type(g, true, 8);
6011 g->builtin_types.entry_i16 = get_int_type(g, true, 16);
60126319 g->builtin_types.entry_i32 = get_int_type(g, true, 32);
60136320 g->builtin_types.entry_i64 = get_int_type(g, true, 64);
6014 g->builtin_types.entry_i128 = get_int_type(g, true, 128);
60156321
60166322 {
60176323 g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");
......@@ -6061,6 +6367,7 @@ static void define_builtin_fns(CodeGen *g) {
60616367 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
60626368 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
60636369 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
6370 create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
60646371 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
60656372 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
60666373 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
......@@ -6070,6 +6377,8 @@ static void define_builtin_fns(CodeGen *g) {
60706377 create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
60716378 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
60726379 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
6380 create_builtin_fn(g, BuiltinFnIdField, "field", 2);
6381 create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
60736382 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
60746383 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
60756384 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
......@@ -6080,15 +6389,25 @@ static void define_builtin_fns(CodeGen *g) {
60806389 create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
60816390 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
60826391 create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
6392 create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1);
60836393 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
60846394 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
60856395 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
60866396 create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
6087 create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
60886397 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
6089 create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
6398 create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
6399 create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
60906400 create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);
60916401 create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
6402 create_builtin_fn(g, BuiltinFnIdIntCast, "intCast", 2);
6403 create_builtin_fn(g, BuiltinFnIdFloatCast, "floatCast", 2);
6404 create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2);
6405 create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2);
6406 create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1);
6407 create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1);
6408 create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1);
6409 create_builtin_fn(g, BuiltinFnIdEnumToInt, "enumToInt", 1);
6410 create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2);
60926411 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
60936412 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
60946413 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
......@@ -6109,8 +6428,10 @@ static void define_builtin_fns(CodeGen *g) {
61096428 create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2);
61106429 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
61116430 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
6431 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
61126432 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
61136433 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
6434 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
61146435 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
61156436 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
61166437 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
......@@ -6122,6 +6443,10 @@ static void define_builtin_fns(CodeGen *g) {
61226443 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
61236444 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
61246445 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
6446 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
6447 create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
6448 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
6449 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
61256450}
61266451
61276452static const char *bool_to_str(bool b) {
......@@ -6133,17 +6458,12 @@ static const char *build_mode_to_str(BuildMode build_mode) {
61336458 case BuildModeDebug: return "Mode.Debug";
61346459 case BuildModeSafeRelease: return "Mode.ReleaseSafe";
61356460 case BuildModeFastRelease: return "Mode.ReleaseFast";
6461 case BuildModeSmallRelease: return "Mode.ReleaseSmall";
61366462 }
61376463 zig_unreachable();
61386464}
61396465
6140static void define_builtin_compile_vars(CodeGen *g) {
6141 if (g->std_package == nullptr)
6142 return;
6143
6144 const char *builtin_zig_basename = "builtin.zig";
6145 Buf *builtin_zig_path = buf_alloc();
6146 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
6466Buf *codegen_generate_builtin_source(CodeGen *g) {
61476467 Buf *contents = buf_alloc();
61486468
61496469 // Modifications to this struct must be coordinated with code that does anything with
......@@ -6273,6 +6593,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
62736593 " Debug,\n"
62746594 " ReleaseSafe,\n"
62756595 " ReleaseFast,\n"
6596 " ReleaseSmall,\n"
62766597 "};\n\n");
62776598 }
62786599 {
......@@ -6284,6 +6605,197 @@ static void define_builtin_compile_vars(CodeGen *g) {
62846605 }
62856606 buf_appendf(contents, "};\n\n");
62866607 }
6608 {
6609 buf_appendf(contents,
6610 "pub const TypeInfo = union(TypeId) {\n"
6611 " Type: void,\n"
6612 " Void: void,\n"
6613 " Bool: void,\n"
6614 " NoReturn: void,\n"
6615 " Int: Int,\n"
6616 " Float: Float,\n"
6617 " Pointer: Pointer,\n"
6618 " Array: Array,\n"
6619 " Struct: Struct,\n"
6620 " ComptimeFloat: void,\n"
6621 " ComptimeInt: void,\n"
6622 " Undefined: void,\n"
6623 " Null: void,\n"
6624 " Optional: Optional,\n"
6625 " ErrorUnion: ErrorUnion,\n"
6626 " ErrorSet: ErrorSet,\n"
6627 " Enum: Enum,\n"
6628 " Union: Union,\n"
6629 " Fn: Fn,\n"
6630 " Namespace: void,\n"
6631 " Block: void,\n"
6632 " BoundFn: Fn,\n"
6633 " ArgTuple: void,\n"
6634 " Opaque: void,\n"
6635 " Promise: Promise,\n"
6636 "\n\n"
6637 " pub const Int = struct {\n"
6638 " is_signed: bool,\n"
6639 " bits: u8,\n"
6640 " };\n"
6641 "\n"
6642 " pub const Float = struct {\n"
6643 " bits: u8,\n"
6644 " };\n"
6645 "\n"
6646 " pub const Pointer = struct {\n"
6647 " size: Size,\n"
6648 " is_const: bool,\n"
6649 " is_volatile: bool,\n"
6650 " alignment: u32,\n"
6651 " child: type,\n"
6652 "\n"
6653 " pub const Size = enum {\n"
6654 " One,\n"
6655 " Many,\n"
6656 " Slice,\n"
6657 " };\n"
6658 " };\n"
6659 "\n"
6660 " pub const Array = struct {\n"
6661 " len: usize,\n"
6662 " child: type,\n"
6663 " };\n"
6664 "\n"
6665 " pub const ContainerLayout = enum {\n"
6666 " Auto,\n"
6667 " Extern,\n"
6668 " Packed,\n"
6669 " };\n"
6670 "\n"
6671 " pub const StructField = struct {\n"
6672 " name: []const u8,\n"
6673 " offset: ?usize,\n"
6674 " field_type: type,\n"
6675 " };\n"
6676 "\n"
6677 " pub const Struct = struct {\n"
6678 " layout: ContainerLayout,\n"
6679 " fields: []StructField,\n"
6680 " defs: []Definition,\n"
6681 " };\n"
6682 "\n"
6683 " pub const Optional = struct {\n"
6684 " child: type,\n"
6685 " };\n"
6686 "\n"
6687 " pub const ErrorUnion = struct {\n"
6688 " error_set: type,\n"
6689 " payload: type,\n"
6690 " };\n"
6691 "\n"
6692 " pub const Error = struct {\n"
6693 " name: []const u8,\n"
6694 " value: usize,\n"
6695 " };\n"
6696 "\n"
6697 " pub const ErrorSet = struct {\n"
6698 " errors: []Error,\n"
6699 " };\n"
6700 "\n"
6701 " pub const EnumField = struct {\n"
6702 " name: []const u8,\n"
6703 " value: usize,\n"
6704 " };\n"
6705 "\n"
6706 " pub const Enum = struct {\n"
6707 " layout: ContainerLayout,\n"
6708 " tag_type: type,\n"
6709 " fields: []EnumField,\n"
6710 " defs: []Definition,\n"
6711 " };\n"
6712 "\n"
6713 " pub const UnionField = struct {\n"
6714 " name: []const u8,\n"
6715 " enum_field: ?EnumField,\n"
6716 " field_type: type,\n"
6717 " };\n"
6718 "\n"
6719 " pub const Union = struct {\n"
6720 " layout: ContainerLayout,\n"
6721 " tag_type: ?type,\n"
6722 " fields: []UnionField,\n"
6723 " defs: []Definition,\n"
6724 " };\n"
6725 "\n"
6726 " pub const CallingConvention = enum {\n"
6727 " Unspecified,\n"
6728 " C,\n"
6729 " Cold,\n"
6730 " Naked,\n"
6731 " Stdcall,\n"
6732 " Async,\n"
6733 " };\n"
6734 "\n"
6735 " pub const FnArg = struct {\n"
6736 " is_generic: bool,\n"
6737 " is_noalias: bool,\n"
6738 " arg_type: ?type,\n"
6739 " };\n"
6740 "\n"
6741 " pub const Fn = struct {\n"
6742 " calling_convention: CallingConvention,\n"
6743 " is_generic: bool,\n"
6744 " is_var_args: bool,\n"
6745 " return_type: ?type,\n"
6746 " async_allocator_type: ?type,\n"
6747 " args: []FnArg,\n"
6748 " };\n"
6749 "\n"
6750 " pub const Promise = struct {\n"
6751 " child: ?type,\n"
6752 " };\n"
6753 "\n"
6754 " pub const Definition = struct {\n"
6755 " name: []const u8,\n"
6756 " is_pub: bool,\n"
6757 " data: Data,\n"
6758 "\n"
6759 " pub const Data = union(enum) {\n"
6760 " Type: type,\n"
6761 " Var: type,\n"
6762 " Fn: FnDef,\n"
6763 "\n"
6764 " pub const FnDef = struct {\n"
6765 " fn_type: type,\n"
6766 " inline_type: Inline,\n"
6767 " calling_convention: CallingConvention,\n"
6768 " is_var_args: bool,\n"
6769 " is_extern: bool,\n"
6770 " is_export: bool,\n"
6771 " lib_name: ?[]const u8,\n"
6772 " return_type: type,\n"
6773 " arg_names: [][] const u8,\n"
6774 "\n"
6775 " pub const Inline = enum {\n"
6776 " Auto,\n"
6777 " Always,\n"
6778 " Never,\n"
6779 " };\n"
6780 " };\n"
6781 " };\n"
6782 " };\n"
6783 "};\n\n");
6784 assert(ContainerLayoutAuto == 0);
6785 assert(ContainerLayoutExtern == 1);
6786 assert(ContainerLayoutPacked == 2);
6787
6788 assert(CallingConventionUnspecified == 0);
6789 assert(CallingConventionC == 1);
6790 assert(CallingConventionCold == 2);
6791 assert(CallingConventionNaked == 3);
6792 assert(CallingConventionStdcall == 4);
6793 assert(CallingConventionAsync == 5);
6794
6795 assert(FnInlineAuto == 0);
6796 assert(FnInlineAlways == 1);
6797 assert(FnInlineNever == 2);
6798 }
62876799 {
62886800 buf_appendf(contents,
62896801 "pub const FloatMode = enum {\n"
......@@ -6317,13 +6829,27 @@ static void define_builtin_compile_vars(CodeGen *g) {
63176829
63186830 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
63196831
6832
6833 return contents;
6834}
6835
6836static void define_builtin_compile_vars(CodeGen *g) {
6837 if (g->std_package == nullptr)
6838 return;
6839
6840 const char *builtin_zig_basename = "builtin.zig";
6841 Buf *builtin_zig_path = buf_alloc();
6842 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
6843
6844 Buf *contents = codegen_generate_builtin_source(g);
63206845 ensure_cache_dir(g);
63216846 os_write_file(builtin_zig_path, contents);
63226847
63236848 int err;
63246849 Buf *abs_full_path = buf_alloc();
63256850 if ((err = os_path_real(builtin_zig_path, abs_full_path))) {
6326 zig_panic("unable to open '%s': %s", buf_ptr(builtin_zig_path), err_str(err));
6851 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err));
6852 exit(1);
63276853 }
63286854
63296855 assert(g->root_package);
......@@ -6383,7 +6909,7 @@ static void init(CodeGen *g) {
63836909 const char *target_specific_features;
63846910 if (g->is_native_target) {
63856911 // LLVM creates invalid binaries on Windows sometimes.
6386 // See https://github.com/zig-lang/zig/issues/508
6912 // See https://github.com/ziglang/zig/issues/508
63876913 // As a workaround we do not use target native features on Windows.
63886914 if (g->zig_target.os == OsWindows) {
63896915 target_specific_cpu_args = "";
......@@ -6443,7 +6969,7 @@ static void init(CodeGen *g) {
64436969 }
64446970 }
64456971
6446 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
6972 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
64476973
64486974 define_builtin_fns(g);
64496975 define_builtin_compile_vars(g);
......@@ -6490,11 +7016,11 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
64907016 Buf *abs_full_path = buf_alloc();
64917017 int err;
64927018 if ((err = os_path_real(&path_to_code_src, abs_full_path))) {
6493 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
7019 zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
64947020 }
64957021 Buf *import_code = buf_alloc();
64967022 if ((err = os_fetch_file_path(abs_full_path, import_code, false))) {
6497 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
7023 zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
64987024 }
64997025
65007026 return add_source_file(g, package, abs_full_path, import_code);
......@@ -6522,7 +7048,8 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
65227048 exit(0);
65237049 }
65247050
6525 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
7051 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
7052 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
65267053 TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
65277054 TypeTableEntry *fn_type = get_test_fn_type(g);
65287055
......@@ -6577,12 +7104,14 @@ static void gen_root_source(CodeGen *g) {
65777104 Buf *abs_full_path = buf_alloc();
65787105 int err;
65797106 if ((err = os_path_real(rel_full_path, abs_full_path))) {
6580 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
7107 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
7108 exit(1);
65817109 }
65827110
65837111 Buf *source_code = buf_alloc();
65847112 if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
6585 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
7113 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
7114 exit(1);
65867115 }
65877116
65887117 g->root_import = add_source_file(g, g->root_package, abs_full_path, source_code);
......@@ -6681,10 +7210,10 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
66817210 switch (type_entry->id) {
66827211 case TypeTableEntryIdInvalid:
66837212 case TypeTableEntryIdMetaType:
6684 case TypeTableEntryIdNumLitFloat:
6685 case TypeTableEntryIdNumLitInt:
6686 case TypeTableEntryIdUndefLit:
6687 case TypeTableEntryIdNullLit:
7213 case TypeTableEntryIdComptimeFloat:
7214 case TypeTableEntryIdComptimeInt:
7215 case TypeTableEntryIdUndefined:
7216 case TypeTableEntryIdNull:
66887217 case TypeTableEntryIdNamespace:
66897218 case TypeTableEntryIdBlock:
66907219 case TypeTableEntryIdBoundFn:
......@@ -6726,7 +7255,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
67267255 case TypeTableEntryIdArray:
67277256 prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
67287257 return;
6729 case TypeTableEntryIdMaybe:
7258 case TypeTableEntryIdOptional:
67307259 prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
67317260 return;
67327261 case TypeTableEntryIdFn:
......@@ -6815,7 +7344,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
68157344 buf_appendf(out_buf, "%s%s *", const_str, buf_ptr(&child_buf));
68167345 break;
68177346 }
6818 case TypeTableEntryIdMaybe:
7347 case TypeTableEntryIdOptional:
68197348 {
68207349 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
68217350 if (child_type->zero_bits) {
......@@ -6866,10 +7395,10 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
68667395 case TypeTableEntryIdBoundFn:
68677396 case TypeTableEntryIdNamespace:
68687397 case TypeTableEntryIdBlock:
6869 case TypeTableEntryIdNumLitFloat:
6870 case TypeTableEntryIdNumLitInt:
6871 case TypeTableEntryIdUndefLit:
6872 case TypeTableEntryIdNullLit:
7398 case TypeTableEntryIdComptimeFloat:
7399 case TypeTableEntryIdComptimeInt:
7400 case TypeTableEntryIdUndefined:
7401 case TypeTableEntryIdNull:
68737402 case TypeTableEntryIdArgTuple:
68747403 case TypeTableEntryIdPromise:
68757404 zig_unreachable();
......@@ -6925,7 +7454,7 @@ static void gen_h_file(CodeGen *g) {
69257454
69267455 FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
69277456 if (!out_h)
6928 zig_panic("unable to open %s: %s", buf_ptr(g->out_h_path), strerror(errno));
7457 zig_panic("unable to open %s: %s\n", buf_ptr(g->out_h_path), strerror(errno));
69297458
69307459 Buf *export_macro = preprocessor_mangle(buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)));
69317460 buf_upcase(export_macro);
......@@ -7018,67 +7547,76 @@ static void gen_h_file(CodeGen *g) {
70187547 case TypeTableEntryIdInt:
70197548 case TypeTableEntryIdFloat:
70207549 case TypeTableEntryIdPointer:
7021 case TypeTableEntryIdNumLitFloat:
7022 case TypeTableEntryIdNumLitInt:
7550 case TypeTableEntryIdComptimeFloat:
7551 case TypeTableEntryIdComptimeInt:
70237552 case TypeTableEntryIdArray:
7024 case TypeTableEntryIdUndefLit:
7025 case TypeTableEntryIdNullLit:
7553 case TypeTableEntryIdUndefined:
7554 case TypeTableEntryIdNull:
70267555 case TypeTableEntryIdErrorUnion:
70277556 case TypeTableEntryIdErrorSet:
70287557 case TypeTableEntryIdNamespace:
70297558 case TypeTableEntryIdBlock:
70307559 case TypeTableEntryIdBoundFn:
70317560 case TypeTableEntryIdArgTuple:
7032 case TypeTableEntryIdMaybe:
7561 case TypeTableEntryIdOptional:
70337562 case TypeTableEntryIdFn:
70347563 case TypeTableEntryIdPromise:
70357564 zig_unreachable();
70367565 case TypeTableEntryIdEnum:
7037 assert(type_entry->data.enumeration.layout == ContainerLayoutExtern);
7038 fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name));
7039 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
7040 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
7041 Buf *value_buf = buf_alloc();
7042 bigint_append_buf(value_buf, &enum_field->value, 10);
7043 fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf));
7044 if (field_i != type_entry->data.enumeration.src_field_count - 1) {
7045 fprintf(out_h, ",");
7566 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
7567 fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name));
7568 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
7569 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
7570 Buf *value_buf = buf_alloc();
7571 bigint_append_buf(value_buf, &enum_field->value, 10);
7572 fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf));
7573 if (field_i != type_entry->data.enumeration.src_field_count - 1) {
7574 fprintf(out_h, ",");
7575 }
7576 fprintf(out_h, "\n");
70467577 }
7047 fprintf(out_h, "\n");
7578 fprintf(out_h, "};\n\n");
7579 } else {
7580 fprintf(out_h, "enum %s;\n", buf_ptr(&type_entry->name));
70487581 }
7049 fprintf(out_h, "};\n\n");
70507582 break;
70517583 case TypeTableEntryIdStruct:
7052 assert(type_entry->data.structure.layout == ContainerLayoutExtern);
7053 fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name));
7054 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
7055 TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
7056
7057 Buf *type_name_buf = buf_alloc();
7058 get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);
7059
7060 if (struct_field->type_entry->id == TypeTableEntryIdArray) {
7061 fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf),
7062 buf_ptr(struct_field->name),
7063 struct_field->type_entry->data.array.len);
7064 } else {
7065 fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name));
7066 }
7584 if (type_entry->data.structure.layout == ContainerLayoutExtern) {
7585 fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name));
7586 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
7587 TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
7588
7589 Buf *type_name_buf = buf_alloc();
7590 get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);
7591
7592 if (struct_field->type_entry->id == TypeTableEntryIdArray) {
7593 fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf),
7594 buf_ptr(struct_field->name),
7595 struct_field->type_entry->data.array.len);
7596 } else {
7597 fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name));
7598 }
70677599
7600 }
7601 fprintf(out_h, "};\n\n");
7602 } else {
7603 fprintf(out_h, "struct %s;\n", buf_ptr(&type_entry->name));
70687604 }
7069 fprintf(out_h, "};\n\n");
70707605 break;
70717606 case TypeTableEntryIdUnion:
7072 assert(type_entry->data.unionation.layout == ContainerLayoutExtern);
7073 fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name));
7074 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
7075 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
7076
7077 Buf *type_name_buf = buf_alloc();
7078 get_c_type(g, gen_h, union_field->type_entry, type_name_buf);
7079 fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name));
7607 if (type_entry->data.unionation.layout == ContainerLayoutExtern) {
7608 fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name));
7609 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
7610 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
7611
7612 Buf *type_name_buf = buf_alloc();
7613 get_c_type(g, gen_h, union_field->type_entry, type_name_buf);
7614 fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name));
7615 }
7616 fprintf(out_h, "};\n\n");
7617 } else {
7618 fprintf(out_h, "union %s;\n", buf_ptr(&type_entry->name));
70807619 }
7081 fprintf(out_h, "};\n\n");
70827620 break;
70837621 case TypeTableEntryIdOpaque:
70847622 fprintf(out_h, "struct %s;\n\n", buf_ptr(&type_entry->name));
......@@ -7135,4 +7673,3 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
71357673 }
71367674 return pkg;
71377675}
7138
src/codegen.hpp+2
......@@ -59,5 +59,7 @@ void codegen_add_object(CodeGen *g, Buf *object_path);
5959
6060void codegen_translate_c(CodeGen *g, Buf *path);
6161
62Buf *codegen_generate_builtin_source(CodeGen *g);
63
6264
6365#endif
src/ir.cpp+4707-1826
......@@ -11,9 +11,10 @@
1111#include "ir.hpp"
1212#include "ir_print.hpp"
1313#include "os.hpp"
14#include "translate_c.hpp"
1514#include "range_set.hpp"
1615#include "softfloat.hpp"
16#include "translate_c.hpp"
17#include "util.hpp"
1718
1819struct IrExecContext {
1920 ConstExprValue *mem_slot_list;
......@@ -38,20 +39,13 @@ struct IrAnalyze {
3839 IrBasicBlock *const_predecessor_bb;
3940};
4041
41static const LVal LVAL_NONE = { false, false, false };
42static const LVal LVAL_PTR = { true, false, false };
43
44static LVal make_lval_addr(bool is_const, bool is_volatile) {
45 return { true, is_const, is_volatile };
46}
47
4842enum ConstCastResultId {
4943 ConstCastResultIdOk,
5044 ConstCastResultIdErrSet,
5145 ConstCastResultIdErrSetGlobal,
5246 ConstCastResultIdPointerChild,
5347 ConstCastResultIdSliceChild,
54 ConstCastResultIdNullableChild,
48 ConstCastResultIdOptionalChild,
5549 ConstCastResultIdErrorUnionPayload,
5650 ConstCastResultIdErrorUnionErrorSet,
5751 ConstCastResultIdFnAlign,
......@@ -66,14 +60,10 @@ enum ConstCastResultId {
6660 ConstCastResultIdType,
6761 ConstCastResultIdUnresolvedInferredErrSet,
6862 ConstCastResultIdAsyncAllocatorType,
69};
70
71struct ConstCastErrSetMismatch {
72 ZigList<ErrorTableEntry *> missing_errors;
63 ConstCastResultIdNullWrapPtr,
7364};
7465
7566struct ConstCastOnly;
76
7767struct ConstCastArg {
7868 size_t arg_index;
7969 ConstCastOnly *child;
......@@ -83,22 +73,70 @@ struct ConstCastArgNoAlias {
8373 size_t arg_index;
8474};
8575
76struct ConstCastOptionalMismatch;
77struct ConstCastPointerMismatch;
78struct ConstCastSliceMismatch;
79struct ConstCastErrUnionErrSetMismatch;
80struct ConstCastErrUnionPayloadMismatch;
81struct ConstCastErrSetMismatch;
82struct ConstCastTypeMismatch;
83
8684struct ConstCastOnly {
8785 ConstCastResultId id;
8886 union {
89 ConstCastErrSetMismatch error_set;
90 ConstCastOnly *pointer_child;
91 ConstCastOnly *slice_child;
92 ConstCastOnly *nullable_child;
93 ConstCastOnly *error_union_payload;
94 ConstCastOnly *error_union_error_set;
87 ConstCastErrSetMismatch *error_set_mismatch;
88 ConstCastPointerMismatch *pointer_mismatch;
89 ConstCastSliceMismatch *slice_mismatch;
90 ConstCastOptionalMismatch *optional;
91 ConstCastErrUnionPayloadMismatch *error_union_payload;
92 ConstCastErrUnionErrSetMismatch *error_union_error_set;
93 ConstCastTypeMismatch *type_mismatch;
9594 ConstCastOnly *return_type;
9695 ConstCastOnly *async_allocator_type;
96 ConstCastOnly *null_wrap_ptr_child;
9797 ConstCastArg fn_arg;
9898 ConstCastArgNoAlias arg_no_alias;
9999 } data;
100100};
101101
102struct ConstCastTypeMismatch {
103 TypeTableEntry *wanted_type;
104 TypeTableEntry *actual_type;
105};
106
107struct ConstCastOptionalMismatch {
108 ConstCastOnly child;
109 TypeTableEntry *wanted_child;
110 TypeTableEntry *actual_child;
111};
112
113struct ConstCastPointerMismatch {
114 ConstCastOnly child;
115 TypeTableEntry *wanted_child;
116 TypeTableEntry *actual_child;
117};
118
119struct ConstCastSliceMismatch {
120 ConstCastOnly child;
121 TypeTableEntry *wanted_child;
122 TypeTableEntry *actual_child;
123};
124
125struct ConstCastErrUnionErrSetMismatch {
126 ConstCastOnly child;
127 TypeTableEntry *wanted_err_set;
128 TypeTableEntry *actual_err_set;
129};
130
131struct ConstCastErrUnionPayloadMismatch {
132 ConstCastOnly child;
133 TypeTableEntry *wanted_payload;
134 TypeTableEntry *actual_payload;
135};
136
137struct ConstCastErrSetMismatch {
138 ZigList<ErrorTableEntry *> missing_errors;
139};
102140
103141static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
104142static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
......@@ -108,11 +146,14 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
108146static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg);
109147static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
110148 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type);
111static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
112 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr);
149static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var);
150static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
151static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
152static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
153static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align);
113154
114155ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
115 assert(const_val->type->id == TypeTableEntryIdPointer);
156 assert(get_codegen_ptr_type(const_val->type) != nullptr);
116157 assert(const_val->special == ConstValSpecialStatic);
117158 switch (const_val->data.x_ptr.special) {
118159 case ConstPtrSpecialInvalid:
......@@ -143,6 +184,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
143184 while (scope != nullptr) {
144185 if (scope->id == ScopeIdCompTime)
145186 return true;
187 if (scope->id == ScopeIdFnDef)
188 break;
146189 scope = scope->parent;
147190 }
148191 return false;
......@@ -369,8 +412,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) {
369412 return IrInstructionIdTestNonNull;
370413}
371414
372static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) {
373 return IrInstructionIdUnwrapMaybe;
415static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) {
416 return IrInstructionIdUnwrapOptional;
374417}
375418
376419static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) {
......@@ -381,6 +424,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {
381424 return IrInstructionIdCtz;
382425}
383426
427static constexpr IrInstructionId ir_instruction_id(IrInstructionPopCount *) {
428 return IrInstructionIdPopCount;
429}
430
384431static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) {
385432 return IrInstructionIdUnionTag;
386433}
......@@ -457,6 +504,38 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTruncate *) {
457504 return IrInstructionIdTruncate;
458505}
459506
507static constexpr IrInstructionId ir_instruction_id(IrInstructionIntCast *) {
508 return IrInstructionIdIntCast;
509}
510
511static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatCast *) {
512 return IrInstructionIdFloatCast;
513}
514
515static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) {
516 return IrInstructionIdErrSetCast;
517}
518
519static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytes *) {
520 return IrInstructionIdToBytes;
521}
522
523static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytes *) {
524 return IrInstructionIdFromBytes;
525}
526
527static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
528 return IrInstructionIdIntToFloat;
529}
530
531static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatToInt *) {
532 return IrInstructionIdFloatToInt;
533}
534
535static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolToInt *) {
536 return IrInstructionIdBoolToInt;
537}
538
460539static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) {
461540 return IrInstructionIdIntType;
462541}
......@@ -501,6 +580,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
501580 return IrInstructionIdFrameAddress;
502581}
503582
583static constexpr IrInstructionId ir_instruction_id(IrInstructionHandle *) {
584 return IrInstructionIdHandle;
585}
586
504587static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
505588 return IrInstructionIdAlignOf;
506589}
......@@ -521,8 +604,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrPayload
521604 return IrInstructionIdUnwrapErrPayload;
522605}
523606
524static constexpr IrInstructionId ir_instruction_id(IrInstructionMaybeWrap *) {
525 return IrInstructionIdMaybeWrap;
607static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalWrap *) {
608 return IrInstructionIdOptionalWrap;
526609}
527610
528611static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapPayload *) {
......@@ -565,6 +648,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {
565648 return IrInstructionIdIntToEnum;
566649}
567650
651static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumToInt *) {
652 return IrInstructionIdEnumToInt;
653}
654
568655static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) {
569656 return IrInstructionIdIntToErr;
570657}
......@@ -585,10 +672,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeName *) {
585672 return IrInstructionIdTypeName;
586673}
587674
588static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast *) {
589 return IrInstructionIdCanImplicitCast;
590}
591
592675static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) {
593676 return IrInstructionIdDeclRef;
594677}
......@@ -613,6 +696,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
613696 return IrInstructionIdOffsetOf;
614697}
615698
699static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) {
700 return IrInstructionIdTypeInfo;
701}
702
616703static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) {
617704 return IrInstructionIdTypeId;
618705}
......@@ -621,8 +708,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetEvalBranchQuo
621708 return IrInstructionIdSetEvalBranchQuota;
622709}
623710
624static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeOf *) {
625 return IrInstructionIdPtrTypeOf;
711static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrType *) {
712 return IrInstructionIdPtrType;
626713}
627714
628715static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) {
......@@ -709,6 +796,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
709796 return IrInstructionIdAtomicRmw;
710797}
711798
799static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
800 return IrInstructionIdAtomicLoad;
801}
802
712803static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
713804 return IrInstructionIdPromiseResultType;
714805}
......@@ -733,6 +824,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP
733824 return IrInstructionIdMarkErrRetTracePtr;
734825}
735826
827static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {
828 return IrInstructionIdSqrt;
829}
830
736831template<typename T>
737832static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
738833 T *special_instruction = allocate<T>(1);
......@@ -988,13 +1083,9 @@ static IrInstruction *ir_build_bin_op_from(IrBuilder *irb, IrInstruction *old_in
9881083 return new_instruction;
9891084}
9901085
991static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
992 VariableTableEntry *var, bool is_const, bool is_volatile)
993{
1086static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, VariableTableEntry *var) {
9941087 IrInstructionVarPtr *instruction = ir_build_instruction<IrInstructionVarPtr>(irb, scope, source_node);
9951088 instruction->var = var;
996 instruction->is_const = is_const;
997 instruction->is_volatile = is_volatile;
9981089
9991090 ir_ref_var(var);
10001091
......@@ -1002,12 +1093,13 @@ static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *so
10021093}
10031094
10041095static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr,
1005 IrInstruction *elem_index, bool safety_check_on)
1096 IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len)
10061097{
10071098 IrInstructionElemPtr *instruction = ir_build_instruction<IrInstructionElemPtr>(irb, scope, source_node);
10081099 instruction->array_ptr = array_ptr;
10091100 instruction->elem_index = elem_index;
10101101 instruction->safety_check_on = safety_check_on;
1102 instruction->ptr_len = ptr_len;
10111103
10121104 ir_ref_instruction(array_ptr, irb->current_basic_block);
10131105 ir_ref_instruction(elem_index, irb->current_basic_block);
......@@ -1015,13 +1107,18 @@ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *s
10151107 return &instruction->base;
10161108}
10171109
1018static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
1019 IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on)
1110static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node,
1111 IrInstruction *container_ptr, IrInstruction *field_name_expr)
10201112{
1021 IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->scope,
1022 old_instruction->source_node, array_ptr, elem_index, safety_check_on);
1023 ir_link_new_instruction(new_instruction, old_instruction);
1024 return new_instruction;
1113 IrInstructionFieldPtr *instruction = ir_build_instruction<IrInstructionFieldPtr>(irb, scope, source_node);
1114 instruction->container_ptr = container_ptr;
1115 instruction->field_name_buffer = nullptr;
1116 instruction->field_name_expr = field_name_expr;
1117
1118 ir_ref_instruction(container_ptr, irb->current_basic_block);
1119 ir_ref_instruction(field_name_expr, irb->current_basic_block);
1120
1121 return &instruction->base;
10251122}
10261123
10271124static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
......@@ -1029,7 +1126,8 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *
10291126{
10301127 IrInstructionFieldPtr *instruction = ir_build_instruction<IrInstructionFieldPtr>(irb, scope, source_node);
10311128 instruction->container_ptr = container_ptr;
1032 instruction->field_name = field_name;
1129 instruction->field_name_buffer = field_name;
1130 instruction->field_name_expr = nullptr;
10331131
10341132 ir_ref_instruction(container_ptr, irb->current_basic_block);
10351133
......@@ -1071,7 +1169,8 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
10711169
10721170static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
10731171 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1074 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
1172 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1173 IrInstruction *new_stack)
10751174{
10761175 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
10771176 call_instruction->fn_entry = fn_entry;
......@@ -1082,6 +1181,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
10821181 call_instruction->arg_count = arg_count;
10831182 call_instruction->is_async = is_async;
10841183 call_instruction->async_allocator = async_allocator;
1184 call_instruction->new_stack = new_stack;
10851185
10861186 if (fn_ref)
10871187 ir_ref_instruction(fn_ref, irb->current_basic_block);
......@@ -1089,16 +1189,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
10891189 ir_ref_instruction(args[i], irb->current_basic_block);
10901190 if (async_allocator)
10911191 ir_ref_instruction(async_allocator, irb->current_basic_block);
1192 if (new_stack != nullptr)
1193 ir_ref_instruction(new_stack, irb->current_basic_block);
10921194
10931195 return &call_instruction->base;
10941196}
10951197
10961198static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
10971199 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1098 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
1200 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1201 IrInstruction *new_stack)
10991202{
11001203 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
1101 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
1204 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator, new_stack);
11021205 ir_link_new_instruction(new_instruction, old_instruction);
11031206 return new_instruction;
11041207}
......@@ -1160,15 +1263,16 @@ static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instru
11601263 return new_instruction;
11611264}
11621265
1163static IrInstruction *ir_build_ptr_type_of(IrBuilder *irb, Scope *scope, AstNode *source_node,
1164 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value,
1165 uint32_t bit_offset_start, uint32_t bit_offset_end)
1266static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1267 IrInstruction *child_type, bool is_const, bool is_volatile, PtrLen ptr_len,
1268 IrInstruction *align_value, uint32_t bit_offset_start, uint32_t bit_offset_end)
11661269{
1167 IrInstructionPtrTypeOf *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrTypeOf>(irb, scope, source_node);
1270 IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrType>(irb, scope, source_node);
11681271 ptr_type_of_instruction->align_value = align_value;
11691272 ptr_type_of_instruction->child_type = child_type;
11701273 ptr_type_of_instruction->is_const = is_const;
11711274 ptr_type_of_instruction->is_volatile = is_volatile;
1275 ptr_type_of_instruction->ptr_len = ptr_len;
11721276 ptr_type_of_instruction->bit_offset_start = bit_offset_start;
11731277 ptr_type_of_instruction->bit_offset_end = bit_offset_end;
11741278
......@@ -1551,7 +1655,7 @@ static IrInstruction *ir_build_test_nonnull_from(IrBuilder *irb, IrInstruction *
15511655static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
15521656 bool safety_check_on)
15531657{
1554 IrInstructionUnwrapMaybe *instruction = ir_build_instruction<IrInstructionUnwrapMaybe>(irb, scope, source_node);
1658 IrInstructionUnwrapOptional *instruction = ir_build_instruction<IrInstructionUnwrapOptional>(irb, scope, source_node);
15551659 instruction->value = value;
15561660 instruction->safety_check_on = safety_check_on;
15571661
......@@ -1570,7 +1674,7 @@ static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *
15701674}
15711675
15721676static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1573 IrInstructionMaybeWrap *instruction = ir_build_instruction<IrInstructionMaybeWrap>(irb, scope, source_node);
1677 IrInstructionOptionalWrap *instruction = ir_build_instruction<IrInstructionOptionalWrap>(irb, scope, source_node);
15741678 instruction->value = value;
15751679
15761680 ir_ref_instruction(value, irb->current_basic_block);
......@@ -1626,8 +1730,18 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr
16261730 return new_instruction;
16271731}
16281732
1733static IrInstruction *ir_build_pop_count(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1734 IrInstructionPopCount *instruction = ir_build_instruction<IrInstructionPopCount>(irb, scope, source_node);
1735 instruction->value = value;
1736
1737 ir_ref_instruction(value, irb->current_basic_block);
1738
1739 return &instruction->base;
1740}
1741
16291742static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
1630 IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime)
1743 IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
1744 IrInstruction *switch_prongs_void)
16311745{
16321746 IrInstructionSwitchBr *instruction = ir_build_instruction<IrInstructionSwitchBr>(irb, scope, source_node);
16331747 instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
......@@ -1637,10 +1751,12 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *
16371751 instruction->case_count = case_count;
16381752 instruction->cases = cases;
16391753 instruction->is_comptime = is_comptime;
1754 instruction->switch_prongs_void = switch_prongs_void;
16401755
16411756 ir_ref_instruction(target_value, irb->current_basic_block);
16421757 if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
16431758 ir_ref_bb(else_block);
1759 if (switch_prongs_void) ir_ref_instruction(switch_prongs_void, irb->current_basic_block);
16441760
16451761 for (size_t i = 0; i < case_count; i += 1) {
16461762 ir_ref_instruction(cases[i].value, irb->current_basic_block);
......@@ -1652,10 +1768,10 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *
16521768
16531769static IrInstruction *ir_build_switch_br_from(IrBuilder *irb, IrInstruction *old_instruction,
16541770 IrInstruction *target_value, IrBasicBlock *else_block, size_t case_count,
1655 IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime)
1771 IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime, IrInstruction *switch_prongs_void)
16561772{
16571773 IrInstruction *new_instruction = ir_build_switch_br(irb, old_instruction->scope, old_instruction->source_node,
1658 target_value, else_block, case_count, cases, is_comptime);
1774 target_value, else_block, case_count, cases, is_comptime, switch_prongs_void);
16591775 ir_link_new_instruction(new_instruction, old_instruction);
16601776 return new_instruction;
16611777}
......@@ -1824,38 +1940,34 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
18241940 return &instruction->base;
18251941}
18261942
1827static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
1828 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1829 AtomicOrder success_order, AtomicOrder failure_order)
1943static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
1944 IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
1945 IrInstruction *success_order_value, IrInstruction *failure_order_value,
1946 bool is_weak,
1947 TypeTableEntry *type, AtomicOrder success_order, AtomicOrder failure_order)
18301948{
18311949 IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node);
1950 instruction->type_value = type_value;
18321951 instruction->ptr = ptr;
18331952 instruction->cmp_value = cmp_value;
18341953 instruction->new_value = new_value;
18351954 instruction->success_order_value = success_order_value;
18361955 instruction->failure_order_value = failure_order_value;
1956 instruction->is_weak = is_weak;
1957 instruction->type = type;
18371958 instruction->success_order = success_order;
18381959 instruction->failure_order = failure_order;
18391960
1961 if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
18401962 ir_ref_instruction(ptr, irb->current_basic_block);
18411963 ir_ref_instruction(cmp_value, irb->current_basic_block);
18421964 ir_ref_instruction(new_value, irb->current_basic_block);
1843 ir_ref_instruction(success_order_value, irb->current_basic_block);
1844 ir_ref_instruction(failure_order_value, irb->current_basic_block);
1965 if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
1966 if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
18451967
18461968 return &instruction->base;
18471969}
18481970
1849static IrInstruction *ir_build_cmpxchg_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr,
1850 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1851 AtomicOrder success_order, AtomicOrder failure_order)
1852{
1853 IrInstruction *new_instruction = ir_build_cmpxchg(irb, old_instruction->scope, old_instruction->source_node,
1854 ptr, cmp_value, new_value, success_order_value, failure_order_value, success_order, failure_order);
1855 ir_link_new_instruction(new_instruction, old_instruction);
1856 return new_instruction;
1857}
1858
18591971static IrInstruction *ir_build_fence(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *order_value, AtomicOrder order) {
18601972 IrInstructionFence *instruction = ir_build_instruction<IrInstructionFence>(irb, scope, source_node);
18611973 instruction->order_value = order_value;
......@@ -1883,10 +1995,88 @@ static IrInstruction *ir_build_truncate(IrBuilder *irb, Scope *scope, AstNode *s
18831995 return &instruction->base;
18841996}
18851997
1886static IrInstruction *ir_build_truncate_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *dest_type, IrInstruction *target) {
1887 IrInstruction *new_instruction = ir_build_truncate(irb, old_instruction->scope, old_instruction->source_node, dest_type, target);
1888 ir_link_new_instruction(new_instruction, old_instruction);
1889 return new_instruction;
1998static IrInstruction *ir_build_int_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
1999 IrInstructionIntCast *instruction = ir_build_instruction<IrInstructionIntCast>(irb, scope, source_node);
2000 instruction->dest_type = dest_type;
2001 instruction->target = target;
2002
2003 ir_ref_instruction(dest_type, irb->current_basic_block);
2004 ir_ref_instruction(target, irb->current_basic_block);
2005
2006 return &instruction->base;
2007}
2008
2009static IrInstruction *ir_build_float_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
2010 IrInstructionFloatCast *instruction = ir_build_instruction<IrInstructionFloatCast>(irb, scope, source_node);
2011 instruction->dest_type = dest_type;
2012 instruction->target = target;
2013
2014 ir_ref_instruction(dest_type, irb->current_basic_block);
2015 ir_ref_instruction(target, irb->current_basic_block);
2016
2017 return &instruction->base;
2018}
2019
2020static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
2021 IrInstructionErrSetCast *instruction = ir_build_instruction<IrInstructionErrSetCast>(irb, scope, source_node);
2022 instruction->dest_type = dest_type;
2023 instruction->target = target;
2024
2025 ir_ref_instruction(dest_type, irb->current_basic_block);
2026 ir_ref_instruction(target, irb->current_basic_block);
2027
2028 return &instruction->base;
2029}
2030
2031static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
2032 IrInstructionToBytes *instruction = ir_build_instruction<IrInstructionToBytes>(irb, scope, source_node);
2033 instruction->target = target;
2034
2035 ir_ref_instruction(target, irb->current_basic_block);
2036
2037 return &instruction->base;
2038}
2039
2040static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) {
2041 IrInstructionFromBytes *instruction = ir_build_instruction<IrInstructionFromBytes>(irb, scope, source_node);
2042 instruction->dest_child_type = dest_child_type;
2043 instruction->target = target;
2044
2045 ir_ref_instruction(dest_child_type, irb->current_basic_block);
2046 ir_ref_instruction(target, irb->current_basic_block);
2047
2048 return &instruction->base;
2049}
2050
2051static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
2052 IrInstructionIntToFloat *instruction = ir_build_instruction<IrInstructionIntToFloat>(irb, scope, source_node);
2053 instruction->dest_type = dest_type;
2054 instruction->target = target;
2055
2056 ir_ref_instruction(dest_type, irb->current_basic_block);
2057 ir_ref_instruction(target, irb->current_basic_block);
2058
2059 return &instruction->base;
2060}
2061
2062static IrInstruction *ir_build_float_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
2063 IrInstructionFloatToInt *instruction = ir_build_instruction<IrInstructionFloatToInt>(irb, scope, source_node);
2064 instruction->dest_type = dest_type;
2065 instruction->target = target;
2066
2067 ir_ref_instruction(dest_type, irb->current_basic_block);
2068 ir_ref_instruction(target, irb->current_basic_block);
2069
2070 return &instruction->base;
2071}
2072
2073static IrInstruction *ir_build_bool_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
2074 IrInstructionBoolToInt *instruction = ir_build_instruction<IrInstructionBoolToInt>(irb, scope, source_node);
2075 instruction->target = target;
2076
2077 ir_ref_instruction(target, irb->current_basic_block);
2078
2079 return &instruction->base;
18902080}
18912081
18922082static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_signed, IrInstruction *bit_count) {
......@@ -2054,6 +2244,17 @@ static IrInstruction *ir_build_frame_address_from(IrBuilder *irb, IrInstruction
20542244 return new_instruction;
20552245}
20562246
2247static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2248 IrInstructionHandle *instruction = ir_build_instruction<IrInstructionHandle>(irb, scope, source_node);
2249 return &instruction->base;
2250}
2251
2252static IrInstruction *ir_build_handle_from(IrBuilder *irb, IrInstruction *old_instruction) {
2253 IrInstruction *new_instruction = ir_build_handle(irb, old_instruction->scope, old_instruction->source_node);
2254 ir_link_new_instruction(new_instruction, old_instruction);
2255 return new_instruction;
2256}
2257
20572258static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode *source_node,
20582259 IrOverflowOp op, IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2,
20592260 IrInstruction *result_ptr, TypeTableEntry *result_ptr_type)
......@@ -2252,10 +2453,26 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode
22522453}
22532454
22542455static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
2255 IrInstruction *target)
2456 IrInstruction *dest_type, IrInstruction *target)
22562457{
22572458 IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>(
22582459 irb, scope, source_node);
2460 instruction->dest_type = dest_type;
2461 instruction->target = target;
2462
2463 if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
2464 ir_ref_instruction(target, irb->current_basic_block);
2465
2466 return &instruction->base;
2467}
2468
2469
2470
2471static IrInstruction *ir_build_enum_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node,
2472 IrInstruction *target)
2473{
2474 IrInstructionEnumToInt *instruction = ir_build_instruction<IrInstructionEnumToInt>(
2475 irb, scope, source_node);
22592476 instruction->target = target;
22602477
22612478 ir_ref_instruction(target, irb->current_basic_block);
......@@ -2331,20 +2548,6 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *
23312548 return &instruction->base;
23322549}
23332550
2334static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
2335 IrInstruction *type_value, IrInstruction *target_value)
2336{
2337 IrInstructionCanImplicitCast *instruction = ir_build_instruction<IrInstructionCanImplicitCast>(
2338 irb, scope, source_node);
2339 instruction->type_value = type_value;
2340 instruction->target_value = target_value;
2341
2342 ir_ref_instruction(type_value, irb->current_basic_block);
2343 ir_ref_instruction(target_value, irb->current_basic_block);
2344
2345 return &instruction->base;
2346}
2347
23482551static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
23492552 Tld *tld, LVal lval)
23502553{
......@@ -2419,6 +2622,16 @@ static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *
24192622 return &instruction->base;
24202623}
24212624
2625static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode *source_node,
2626 IrInstruction *type_value) {
2627 IrInstructionTypeInfo *instruction = ir_build_instruction<IrInstructionTypeInfo>(irb, scope, source_node);
2628 instruction->type_value = type_value;
2629
2630 ir_ref_instruction(type_value, irb->current_basic_block);
2631
2632 return &instruction->base;
2633}
2634
24222635static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node,
24232636 IrInstruction *type_value)
24242637{
......@@ -2484,9 +2697,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
24842697 return &instruction->base;
24852698}
24862699
2487static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
2700static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Optional optional) {
24882701 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2489 instruction->nullable = nullable;
2702 instruction->optional = optional;
24902703
24912704 return &instruction->base;
24922705}
......@@ -2669,6 +2882,23 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode
26692882 return &instruction->base;
26702883}
26712884
2885static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode *source_node,
2886 IrInstruction *operand_type, IrInstruction *ptr,
2887 IrInstruction *ordering, AtomicOrder resolved_ordering)
2888{
2889 IrInstructionAtomicLoad *instruction = ir_build_instruction<IrInstructionAtomicLoad>(irb, scope, source_node);
2890 instruction->operand_type = operand_type;
2891 instruction->ptr = ptr;
2892 instruction->ordering = ordering;
2893 instruction->resolved_ordering = resolved_ordering;
2894
2895 if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block);
2896 ir_ref_instruction(ptr, irb->current_basic_block);
2897 if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block);
2898
2899 return &instruction->base;
2900}
2901
26722902static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
26732903 IrInstruction *promise_type)
26742904{
......@@ -2731,20 +2961,49 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco
27312961 return &instruction->base;
27322962}
27332963
2964static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) {
2965 IrInstructionSqrt *instruction = ir_build_instruction<IrInstructionSqrt>(irb, scope, source_node);
2966 instruction->type = type;
2967 instruction->op = op;
2968
2969 if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block);
2970 ir_ref_instruction(op, irb->current_basic_block);
2971
2972 return &instruction->base;
2973}
2974
27342975static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
27352976 results[ReturnKindUnconditional] = 0;
27362977 results[ReturnKindError] = 0;
27372978
2738 while (inner_scope != outer_scope) {
2739 assert(inner_scope);
2740 if (inner_scope->id == ScopeIdDefer) {
2741 AstNode *defer_node = inner_scope->source_node;
2742 assert(defer_node->type == NodeTypeDefer);
2743 ReturnKind defer_kind = defer_node->data.defer.kind;
2744 results[defer_kind] += 1;
2979 Scope *scope = inner_scope;
27452980
2981 while (scope != outer_scope) {
2982 assert(scope);
2983 switch (scope->id) {
2984 case ScopeIdDefer: {
2985 AstNode *defer_node = scope->source_node;
2986 assert(defer_node->type == NodeTypeDefer);
2987 ReturnKind defer_kind = defer_node->data.defer.kind;
2988 results[defer_kind] += 1;
2989 scope = scope->parent;
2990 continue;
2991 }
2992 case ScopeIdDecls:
2993 case ScopeIdFnDef:
2994 return;
2995 case ScopeIdBlock:
2996 case ScopeIdVarDecl:
2997 case ScopeIdLoop:
2998 case ScopeIdSuspend:
2999 case ScopeIdCompTime:
3000 scope = scope->parent;
3001 continue;
3002 case ScopeIdDeferExpr:
3003 case ScopeIdCImport:
3004 case ScopeIdCoroPrelude:
3005 zig_unreachable();
27463006 }
2747 inner_scope = inner_scope->parent;
27483007 }
27493008}
27503009
......@@ -2760,27 +3019,43 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
27603019 if (!scope)
27613020 return is_noreturn;
27623021
2763 if (scope->id == ScopeIdDefer) {
2764 AstNode *defer_node = scope->source_node;
2765 assert(defer_node->type == NodeTypeDefer);
2766 ReturnKind defer_kind = defer_node->data.defer.kind;
2767 if (defer_kind == ReturnKindUnconditional ||
2768 (gen_error_defers && defer_kind == ReturnKindError))
2769 {
2770 AstNode *defer_expr_node = defer_node->data.defer.expr;
2771 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
2772 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
2773 if (defer_expr_value != irb->codegen->invalid_instruction) {
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));
3022 switch (scope->id) {
3023 case ScopeIdDefer: {
3024 AstNode *defer_node = scope->source_node;
3025 assert(defer_node->type == NodeTypeDefer);
3026 ReturnKind defer_kind = defer_node->data.defer.kind;
3027 if (defer_kind == ReturnKindUnconditional ||
3028 (gen_error_defers && defer_kind == ReturnKindError))
3029 {
3030 AstNode *defer_expr_node = defer_node->data.defer.expr;
3031 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
3032 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
3033 if (defer_expr_value != irb->codegen->invalid_instruction) {
3034 if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
3035 is_noreturn = true;
3036 } else {
3037 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
3038 }
27783039 }
27793040 }
3041 scope = scope->parent;
3042 continue;
27803043 }
2781
3044 case ScopeIdDecls:
3045 case ScopeIdFnDef:
3046 return is_noreturn;
3047 case ScopeIdBlock:
3048 case ScopeIdVarDecl:
3049 case ScopeIdLoop:
3050 case ScopeIdSuspend:
3051 case ScopeIdCompTime:
3052 scope = scope->parent;
3053 continue;
3054 case ScopeIdDeferExpr:
3055 case ScopeIdCImport:
3056 case ScopeIdCoroPrelude:
3057 zig_unreachable();
27823058 }
2783 scope = scope->parent;
27843059 }
27853060 return is_noreturn;
27863061}
......@@ -2796,6 +3071,18 @@ static void ir_set_cursor_at_end_and_append_block(IrBuilder *irb, IrBasicBlock *
27963071 ir_set_cursor_at_end(irb, basic_block);
27973072}
27983073
3074static ScopeSuspend *get_scope_suspend(Scope *scope) {
3075 while (scope) {
3076 if (scope->id == ScopeIdSuspend)
3077 return (ScopeSuspend *)scope;
3078 if (scope->id == ScopeIdFnDef)
3079 return nullptr;
3080
3081 scope = scope->parent;
3082 }
3083 return nullptr;
3084}
3085
27993086static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
28003087 while (scope) {
28013088 if (scope->id == ScopeIdDeferExpr)
......@@ -2825,20 +3112,47 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
28253112 return return_inst;
28263113 }
28273114
2828 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
2829 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
2830 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
2831 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
2832 IrInstruction *replacement_value = irb->exec->coro_handle;
2833 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
2834 promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr,
2835 AtomicRmwOp_xchg, AtomicOrderSeqCst);
2836 ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle);
2837 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle);
3115 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "Suspended");
3116 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "NotSuspended");
3117 IrBasicBlock *store_awaiter_block = ir_create_basic_block(irb, scope, "StoreAwaiter");
3118 IrBasicBlock *check_canceled_block = ir_create_basic_block(irb, scope, "CheckCanceled");
3119
3120 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
3121 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
3122 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
3123 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
3124 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
28383125 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
2839 return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final,
2840 is_comptime);
2841 // the above blocks are rendered by ir_gen after the rest of codegen
3126 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
3127
3128 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
3129 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
3130 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
3131 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, ptr_mask, nullptr,
3132 AtomicRmwOp_or, AtomicOrderSeqCst);
3133
3134 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
3135 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
3136 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
3137
3138 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
3139 ir_build_unreachable(irb, scope, node);
3140
3141 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
3142 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
3143 // if we ever add null checking safety to the ptrtoint instruction, it needs to be disabled here
3144 IrInstruction *have_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
3145 ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime);
3146
3147 ir_set_cursor_at_end_and_append_block(irb, store_awaiter_block);
3148 IrInstruction *await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, await_handle_addr);
3149 ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, await_handle);
3150 ir_build_br(irb, scope, node, irb->exec->coro_normal_final, is_comptime);
3151
3152 ir_set_cursor_at_end_and_append_block(irb, check_canceled_block);
3153 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
3154 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
3155 return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
28423156}
28433157
28443158static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
......@@ -2923,7 +3237,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29233237 case ReturnKindError:
29243238 {
29253239 assert(expr_node);
2926 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
3240 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
29273241 if (err_union_ptr == irb->codegen->invalid_instruction)
29283242 return irb->codegen->invalid_instruction;
29293243 IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
......@@ -2951,7 +3265,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29513265
29523266 ir_set_cursor_at_end_and_append_block(irb, continue_block);
29533267 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
2954 if (lval.is_ptr)
3268 if (lval == LValPtr)
29553269 return unwrapped_ptr;
29563270 else
29573271 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
......@@ -2981,9 +3295,8 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
29813295 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
29823296 variable_entry->value->type = codegen->builtin_types.entry_invalid;
29833297 } else {
2984 auto primitive_table_entry = codegen->primitive_type_table.maybe_get(name);
2985 if (primitive_table_entry) {
2986 TypeTableEntry *type = primitive_table_entry->value;
3298 TypeTableEntry *type = get_primitive_type(codegen, name);
3299 if (type != nullptr) {
29873300 add_node_error(codegen, node,
29883301 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
29893302 variable_entry->value->type = codegen->builtin_types.entry_invalid;
......@@ -3019,7 +3332,15 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
30193332static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *name,
30203333 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
30213334{
3022 VariableTableEntry *var = create_local_var(irb->codegen, node, scope, name, src_is_const, gen_is_const, is_shadowable, is_comptime);
3335 bool is_underscored = name ? buf_eql_str(name, "_") : false;
3336 VariableTableEntry *var = create_local_var( irb->codegen
3337 , node
3338 , scope
3339 , (is_underscored ? nullptr : name)
3340 , src_is_const
3341 , gen_is_const
3342 , (is_underscored ? true : is_shadowable)
3343 , is_comptime );
30233344 if (is_comptime != nullptr || gen_is_const) {
30243345 var->mem_slot_index = exec_next_mem_slot(irb->exec);
30253346 var->owner_exec = irb->exec;
......@@ -3086,6 +3407,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
30863407 if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) {
30873408 return noreturn_return_value;
30883409 }
3410
3411 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
3412 return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
30893413 } else {
30903414 incoming_blocks.append(irb->current_basic_block);
30913415 incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
......@@ -3113,7 +3437,7 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
31133437}
31143438
31153439static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
3116 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LVAL_PTR);
3440 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr);
31173441 IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
31183442
31193443 if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
......@@ -3124,7 +3448,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node)
31243448}
31253449
31263450static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
3127 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LVAL_PTR);
3451 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr);
31283452 if (lvalue == irb->codegen->invalid_instruction)
31293453 return lvalue;
31303454 IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
......@@ -3226,7 +3550,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
32263550 AstNode *op1_node = node->data.bin_op_expr.op1;
32273551 AstNode *op2_node = node->data.bin_op_expr.op2;
32283552
3229 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LVAL_PTR);
3553 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr);
32303554 if (maybe_ptr == irb->codegen->invalid_instruction)
32313555 return irb->codegen->invalid_instruction;
32323556
......@@ -3240,9 +3564,9 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
32403564 is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null);
32413565 }
32423566
3243 IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "MaybeNonNull");
3244 IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "MaybeNull");
3245 IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "MaybeEnd");
3567 IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull");
3568 IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull");
3569 IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd");
32463570 ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime);
32473571
32483572 ir_set_cursor_at_end_and_append_block(irb, null_block);
......@@ -3371,7 +3695,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
33713695 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
33723696 case BinOpTypeMergeErrorSets:
33733697 return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
3374 case BinOpTypeUnwrapMaybe:
3698 case BinOpTypeUnwrapOptional:
33753699 return ir_gen_maybe_ok_or(irb, scope, node);
33763700 case BinOpTypeErrorUnion:
33773701 return ir_gen_error_union(irb, scope, node);
......@@ -3413,7 +3737,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
34133737
34143738 Buf *variable_name = node->data.symbol_expr.symbol;
34153739
3416 if (buf_eql_str(variable_name, "_") && lval.is_ptr) {
3740 if (buf_eql_str(variable_name, "_") && lval == LValPtr) {
34173741 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, node);
34183742 const_instruction->base.value.type = get_pointer_to_type(irb->codegen,
34193743 irb->codegen->builtin_types.entry_void, false);
......@@ -3422,11 +3746,11 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
34223746 return &const_instruction->base;
34233747 }
34243748
3425 auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name);
3426 if (primitive_table_entry) {
3427 IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_table_entry->value);
3428 if (lval.is_ptr) {
3429 return ir_build_ref(irb, scope, node, value, lval.is_const, lval.is_volatile);
3749 TypeTableEntry *primitive_type = get_primitive_type(irb->codegen, variable_name);
3750 if (primitive_type != nullptr) {
3751 IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
3752 if (lval == LValPtr) {
3753 return ir_build_ref(irb, scope, node, value, false, false);
34303754 } else {
34313755 return value;
34323756 }
......@@ -3434,9 +3758,8 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
34343758
34353759 VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);
34363760 if (var) {
3437 IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var,
3438 !lval.is_ptr || lval.is_const, lval.is_ptr && lval.is_volatile);
3439 if (lval.is_ptr)
3761 IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var);
3762 if (lval == LValPtr)
34403763 return var_ptr;
34413764 else
34423765 return ir_build_load_ptr(irb, scope, node, var_ptr);
......@@ -3462,7 +3785,7 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
34623785 assert(node->type == NodeTypeArrayAccessExpr);
34633786
34643787 AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr;
3465 IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LVAL_PTR);
3788 IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr);
34663789 if (array_ref_instruction == irb->codegen->invalid_instruction)
34673790 return array_ref_instruction;
34683791
......@@ -3472,28 +3795,24 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
34723795 return subscript_instruction;
34733796
34743797 IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction,
3475 subscript_instruction, true);
3476 if (lval.is_ptr)
3798 subscript_instruction, true, PtrLenSingle);
3799 if (lval == LValPtr)
34773800 return ptr_instruction;
34783801
34793802 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
34803803}
34813804
3482static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
3805static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) {
34833806 assert(node->type == NodeTypeFieldAccessExpr);
34843807
34853808 AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
34863809 Buf *field_name = node->data.field_access_expr.field_name;
34873810
3488 IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LVAL_PTR);
3811 IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr);
34893812 if (container_ref_instruction == irb->codegen->invalid_instruction)
34903813 return container_ref_instruction;
34913814
3492 IrInstruction *ptr_instruction = ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
3493 if (lval.is_ptr)
3494 return ptr_instruction;
3495
3496 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
3815 return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
34973816}
34983817
34993818static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
......@@ -3524,7 +3843,7 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
35243843 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
35253844}
35263845
3527static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
3846static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
35283847 assert(node->type == NodeTypeFnCallExpr);
35293848
35303849 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
......@@ -3547,6 +3866,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35473866 return irb->codegen->invalid_instruction;
35483867 }
35493868
3869 bool is_async = exec_is_async(irb->exec);
3870
35503871 switch (builtin_fn->id) {
35513872 case BuiltinFnIdInvalid:
35523873 zig_unreachable();
......@@ -3556,7 +3877,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35563877 IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
35573878 if (arg == irb->codegen->invalid_instruction)
35583879 return arg;
3559 return ir_build_typeof(irb, scope, node, arg);
3880
3881 IrInstruction *type_of = ir_build_typeof(irb, scope, node, arg);
3882 return ir_lval_wrap(irb, scope, type_of, lval);
35603883 }
35613884 case BuiltinFnIdSetCold:
35623885 {
......@@ -3565,7 +3888,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35653888 if (arg0_value == irb->codegen->invalid_instruction)
35663889 return arg0_value;
35673890
3568 return ir_build_set_cold(irb, scope, node, arg0_value);
3891 IrInstruction *set_cold = ir_build_set_cold(irb, scope, node, arg0_value);
3892 return ir_lval_wrap(irb, scope, set_cold, lval);
35693893 }
35703894 case BuiltinFnIdSetRuntimeSafety:
35713895 {
......@@ -3574,7 +3898,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35743898 if (arg0_value == irb->codegen->invalid_instruction)
35753899 return arg0_value;
35763900
3577 return ir_build_set_runtime_safety(irb, scope, node, arg0_value);
3901 IrInstruction *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value);
3902 return ir_lval_wrap(irb, scope, set_safety, lval);
35783903 }
35793904 case BuiltinFnIdSetFloatMode:
35803905 {
......@@ -3588,7 +3913,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35883913 if (arg1_value == irb->codegen->invalid_instruction)
35893914 return arg1_value;
35903915
3591 return ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value);
3916 IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value);
3917 return ir_lval_wrap(irb, scope, set_float_mode, lval);
35923918 }
35933919 case BuiltinFnIdSizeof:
35943920 {
......@@ -3597,7 +3923,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35973923 if (arg0_value == irb->codegen->invalid_instruction)
35983924 return arg0_value;
35993925
3600 return ir_build_size_of(irb, scope, node, arg0_value);
3926 IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
3927 return ir_lval_wrap(irb, scope, size_of, lval);
36013928 }
36023929 case BuiltinFnIdCtz:
36033930 {
......@@ -3606,29 +3933,43 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36063933 if (arg0_value == irb->codegen->invalid_instruction)
36073934 return arg0_value;
36083935
3609 return ir_build_ctz(irb, scope, node, arg0_value);
3936 IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);
3937 return ir_lval_wrap(irb, scope, ctz, lval);
36103938 }
3611 case BuiltinFnIdClz:
3939 case BuiltinFnIdPopCount:
36123940 {
36133941 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
36143942 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
36153943 if (arg0_value == irb->codegen->invalid_instruction)
36163944 return arg0_value;
36173945
3618 return ir_build_clz(irb, scope, node, arg0_value);
3946 IrInstruction *instr = ir_build_pop_count(irb, scope, node, arg0_value);
3947 return ir_lval_wrap(irb, scope, instr, lval);
36193948 }
3620 case BuiltinFnIdImport:
3949 case BuiltinFnIdClz:
36213950 {
36223951 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
36233952 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
36243953 if (arg0_value == irb->codegen->invalid_instruction)
36253954 return arg0_value;
36263955
3627 return ir_build_import(irb, scope, node, arg0_value);
3956 IrInstruction *clz = ir_build_clz(irb, scope, node, arg0_value);
3957 return ir_lval_wrap(irb, scope, clz, lval);
36283958 }
3629 case BuiltinFnIdCImport:
3959 case BuiltinFnIdImport:
3960 {
3961 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
3962 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
3963 if (arg0_value == irb->codegen->invalid_instruction)
3964 return arg0_value;
3965
3966 IrInstruction *import = ir_build_import(irb, scope, node, arg0_value);
3967 return ir_lval_wrap(irb, scope, import, lval);
3968 }
3969 case BuiltinFnIdCImport:
36303970 {
3631 return ir_build_c_import(irb, scope, node);
3971 IrInstruction *c_import = ir_build_c_import(irb, scope, node);
3972 return ir_lval_wrap(irb, scope, c_import, lval);
36323973 }
36333974 case BuiltinFnIdCInclude:
36343975 {
......@@ -3642,7 +3983,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36423983 return irb->codegen->invalid_instruction;
36433984 }
36443985
3645 return ir_build_c_include(irb, scope, node, arg0_value);
3986 IrInstruction *c_include = ir_build_c_include(irb, scope, node, arg0_value);
3987 return ir_lval_wrap(irb, scope, c_include, lval);
36463988 }
36473989 case BuiltinFnIdCDefine:
36483990 {
......@@ -3661,7 +4003,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36614003 return irb->codegen->invalid_instruction;
36624004 }
36634005
3664 return ir_build_c_define(irb, scope, node, arg0_value, arg1_value);
4006 IrInstruction *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value);
4007 return ir_lval_wrap(irb, scope, c_define, lval);
36654008 }
36664009 case BuiltinFnIdCUndef:
36674010 {
......@@ -3675,7 +4018,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36754018 return irb->codegen->invalid_instruction;
36764019 }
36774020
3678 return ir_build_c_undef(irb, scope, node, arg0_value);
4021 IrInstruction *c_undef = ir_build_c_undef(irb, scope, node, arg0_value);
4022 return ir_lval_wrap(irb, scope, c_undef, lval);
36794023 }
36804024 case BuiltinFnIdMaxValue:
36814025 {
......@@ -3684,7 +4028,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36844028 if (arg0_value == irb->codegen->invalid_instruction)
36854029 return arg0_value;
36864030
3687 return ir_build_max_value(irb, scope, node, arg0_value);
4031 IrInstruction *max_value = ir_build_max_value(irb, scope, node, arg0_value);
4032 return ir_lval_wrap(irb, scope, max_value, lval);
36884033 }
36894034 case BuiltinFnIdMinValue:
36904035 {
......@@ -3693,7 +4038,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36934038 if (arg0_value == irb->codegen->invalid_instruction)
36944039 return arg0_value;
36954040
3696 return ir_build_min_value(irb, scope, node, arg0_value);
4041 IrInstruction *min_value = ir_build_min_value(irb, scope, node, arg0_value);
4042 return ir_lval_wrap(irb, scope, min_value, lval);
36974043 }
36984044 case BuiltinFnIdCompileErr:
36994045 {
......@@ -3702,7 +4048,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37024048 if (arg0_value == irb->codegen->invalid_instruction)
37034049 return arg0_value;
37044050
3705 return ir_build_compile_err(irb, scope, node, arg0_value);
4051 IrInstruction *compile_err = ir_build_compile_err(irb, scope, node, arg0_value);
4052 return ir_lval_wrap(irb, scope, compile_err, lval);
37064053 }
37074054 case BuiltinFnIdCompileLog:
37084055 {
......@@ -3715,7 +4062,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37154062 return irb->codegen->invalid_instruction;
37164063 }
37174064
3718 return ir_build_compile_log(irb, scope, node, actual_param_count, args);
4065 IrInstruction *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args);
4066 return ir_lval_wrap(irb, scope, compile_log, lval);
37194067 }
37204068 case BuiltinFnIdErrName:
37214069 {
......@@ -3724,7 +4072,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37244072 if (arg0_value == irb->codegen->invalid_instruction)
37254073 return arg0_value;
37264074
3727 return ir_build_err_name(irb, scope, node, arg0_value);
4075 IrInstruction *err_name = ir_build_err_name(irb, scope, node, arg0_value);
4076 return ir_lval_wrap(irb, scope, err_name, lval);
37284077 }
37294078 case BuiltinFnIdEmbedFile:
37304079 {
......@@ -3733,9 +4082,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37334082 if (arg0_value == irb->codegen->invalid_instruction)
37344083 return arg0_value;
37354084
3736 return ir_build_embed_file(irb, scope, node, arg0_value);
4085 IrInstruction *embed_file = ir_build_embed_file(irb, scope, node, arg0_value);
4086 return ir_lval_wrap(irb, scope, embed_file, lval);
37374087 }
3738 case BuiltinFnIdCmpExchange:
4088 case BuiltinFnIdCmpxchgWeak:
4089 case BuiltinFnIdCmpxchgStrong:
37394090 {
37404091 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
37414092 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
......@@ -3762,9 +4113,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37624113 if (arg4_value == irb->codegen->invalid_instruction)
37634114 return arg4_value;
37644115
3765 return ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
3766 arg2_value, arg3_value, arg4_value,
3767 AtomicOrderUnordered, AtomicOrderUnordered);
4116 AstNode *arg5_node = node->data.fn_call_expr.params.at(5);
4117 IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope);
4118 if (arg5_value == irb->codegen->invalid_instruction)
4119 return arg5_value;
4120
4121 IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
4122 arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
4123 nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
4124 return ir_lval_wrap(irb, scope, cmpxchg, lval);
37684125 }
37694126 case BuiltinFnIdFence:
37704127 {
......@@ -3773,7 +4130,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37734130 if (arg0_value == irb->codegen->invalid_instruction)
37744131 return arg0_value;
37754132
3776 return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
4133 IrInstruction *fence = ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
4134 return ir_lval_wrap(irb, scope, fence, lval);
37774135 }
37784136 case BuiltinFnIdDivExact:
37794137 {
......@@ -3787,7 +4145,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37874145 if (arg1_value == irb->codegen->invalid_instruction)
37884146 return arg1_value;
37894147
3790 return ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true);
4148 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true);
4149 return ir_lval_wrap(irb, scope, bin_op, lval);
37914150 }
37924151 case BuiltinFnIdDivTrunc:
37934152 {
......@@ -3801,7 +4160,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38014160 if (arg1_value == irb->codegen->invalid_instruction)
38024161 return arg1_value;
38034162
3804 return ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true);
4163 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true);
4164 return ir_lval_wrap(irb, scope, bin_op, lval);
38054165 }
38064166 case BuiltinFnIdDivFloor:
38074167 {
......@@ -3815,7 +4175,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38154175 if (arg1_value == irb->codegen->invalid_instruction)
38164176 return arg1_value;
38174177
3818 return ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true);
4178 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true);
4179 return ir_lval_wrap(irb, scope, bin_op, lval);
38194180 }
38204181 case BuiltinFnIdRem:
38214182 {
......@@ -3829,7 +4190,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38294190 if (arg1_value == irb->codegen->invalid_instruction)
38304191 return arg1_value;
38314192
3832 return ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true);
4193 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true);
4194 return ir_lval_wrap(irb, scope, bin_op, lval);
38334195 }
38344196 case BuiltinFnIdMod:
38354197 {
......@@ -3843,7 +4205,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38434205 if (arg1_value == irb->codegen->invalid_instruction)
38444206 return arg1_value;
38454207
3846 return ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true);
4208 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true);
4209 return ir_lval_wrap(irb, scope, bin_op, lval);
4210 }
4211 case BuiltinFnIdSqrt:
4212 {
4213 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4214 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4215 if (arg0_value == irb->codegen->invalid_instruction)
4216 return arg0_value;
4217
4218 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4219 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4220 if (arg1_value == irb->codegen->invalid_instruction)
4221 return arg1_value;
4222
4223 IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value);
4224 return ir_lval_wrap(irb, scope, ir_sqrt, lval);
38474225 }
38484226 case BuiltinFnIdTruncate:
38494227 {
......@@ -3857,7 +4235,138 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38574235 if (arg1_value == irb->codegen->invalid_instruction)
38584236 return arg1_value;
38594237
3860 return ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
4238 IrInstruction *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
4239 return ir_lval_wrap(irb, scope, truncate, lval);
4240 }
4241 case BuiltinFnIdIntCast:
4242 {
4243 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4244 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4245 if (arg0_value == irb->codegen->invalid_instruction)
4246 return arg0_value;
4247
4248 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4249 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4250 if (arg1_value == irb->codegen->invalid_instruction)
4251 return arg1_value;
4252
4253 IrInstruction *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value);
4254 return ir_lval_wrap(irb, scope, result, lval);
4255 }
4256 case BuiltinFnIdFloatCast:
4257 {
4258 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4259 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4260 if (arg0_value == irb->codegen->invalid_instruction)
4261 return arg0_value;
4262
4263 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4264 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4265 if (arg1_value == irb->codegen->invalid_instruction)
4266 return arg1_value;
4267
4268 IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value);
4269 return ir_lval_wrap(irb, scope, result, lval);
4270 }
4271 case BuiltinFnIdErrSetCast:
4272 {
4273 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4274 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4275 if (arg0_value == irb->codegen->invalid_instruction)
4276 return arg0_value;
4277
4278 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4279 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4280 if (arg1_value == irb->codegen->invalid_instruction)
4281 return arg1_value;
4282
4283 IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value);
4284 return ir_lval_wrap(irb, scope, result, lval);
4285 }
4286 case BuiltinFnIdFromBytes:
4287 {
4288 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4289 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4290 if (arg0_value == irb->codegen->invalid_instruction)
4291 return arg0_value;
4292
4293 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4294 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4295 if (arg1_value == irb->codegen->invalid_instruction)
4296 return arg1_value;
4297
4298 IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value);
4299 return ir_lval_wrap(irb, scope, result, lval);
4300 }
4301 case BuiltinFnIdToBytes:
4302 {
4303 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4304 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4305 if (arg0_value == irb->codegen->invalid_instruction)
4306 return arg0_value;
4307
4308 IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value);
4309 return ir_lval_wrap(irb, scope, result, lval);
4310 }
4311 case BuiltinFnIdIntToFloat:
4312 {
4313 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4314 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4315 if (arg0_value == irb->codegen->invalid_instruction)
4316 return arg0_value;
4317
4318 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4319 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4320 if (arg1_value == irb->codegen->invalid_instruction)
4321 return arg1_value;
4322
4323 IrInstruction *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value);
4324 return ir_lval_wrap(irb, scope, result, lval);
4325 }
4326 case BuiltinFnIdFloatToInt:
4327 {
4328 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4329 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4330 if (arg0_value == irb->codegen->invalid_instruction)
4331 return arg0_value;
4332
4333 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4334 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4335 if (arg1_value == irb->codegen->invalid_instruction)
4336 return arg1_value;
4337
4338 IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);
4339 return ir_lval_wrap(irb, scope, result, lval);
4340 }
4341 case BuiltinFnIdErrToInt:
4342 {
4343 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4344 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4345 if (arg0_value == irb->codegen->invalid_instruction)
4346 return arg0_value;
4347
4348 IrInstruction *result = ir_build_err_to_int(irb, scope, node, arg0_value);
4349 return ir_lval_wrap(irb, scope, result, lval);
4350 }
4351 case BuiltinFnIdIntToErr:
4352 {
4353 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4354 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4355 if (arg0_value == irb->codegen->invalid_instruction)
4356 return arg0_value;
4357
4358 IrInstruction *result = ir_build_int_to_err(irb, scope, node, arg0_value);
4359 return ir_lval_wrap(irb, scope, result, lval);
4360 }
4361 case BuiltinFnIdBoolToInt:
4362 {
4363 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4364 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4365 if (arg0_value == irb->codegen->invalid_instruction)
4366 return arg0_value;
4367
4368 IrInstruction *result = ir_build_bool_to_int(irb, scope, node, arg0_value);
4369 return ir_lval_wrap(irb, scope, result, lval);
38614370 }
38624371 case BuiltinFnIdIntType:
38634372 {
......@@ -3871,7 +4380,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38714380 if (arg1_value == irb->codegen->invalid_instruction)
38724381 return arg1_value;
38734382
3874 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
4383 IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
4384 return ir_lval_wrap(irb, scope, int_type, lval);
38754385 }
38764386 case BuiltinFnIdMemcpy:
38774387 {
......@@ -3890,7 +4400,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38904400 if (arg2_value == irb->codegen->invalid_instruction)
38914401 return arg2_value;
38924402
3893 return ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
4403 IrInstruction *ir_memcpy = ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
4404 return ir_lval_wrap(irb, scope, ir_memcpy, lval);
38944405 }
38954406 case BuiltinFnIdMemset:
38964407 {
......@@ -3909,7 +4420,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39094420 if (arg2_value == irb->codegen->invalid_instruction)
39104421 return arg2_value;
39114422
3912 return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
4423 IrInstruction *ir_memset = ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
4424 return ir_lval_wrap(irb, scope, ir_memset, lval);
39134425 }
39144426 case BuiltinFnIdMemberCount:
39154427 {
......@@ -3918,7 +4430,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39184430 if (arg0_value == irb->codegen->invalid_instruction)
39194431 return arg0_value;
39204432
3921 return ir_build_member_count(irb, scope, node, arg0_value);
4433 IrInstruction *member_count = ir_build_member_count(irb, scope, node, arg0_value);
4434 return ir_lval_wrap(irb, scope, member_count, lval);
39224435 }
39234436 case BuiltinFnIdMemberType:
39244437 {
......@@ -3933,7 +4446,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39334446 return arg1_value;
39344447
39354448
3936 return ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
4449 IrInstruction *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
4450 return ir_lval_wrap(irb, scope, member_type, lval);
39374451 }
39384452 case BuiltinFnIdMemberName:
39394453 {
......@@ -3948,14 +4462,54 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39484462 return arg1_value;
39494463
39504464
3951 return ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
4465 IrInstruction *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
4466 return ir_lval_wrap(irb, scope, member_name, lval);
4467 }
4468 case BuiltinFnIdField:
4469 {
4470 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4471 IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr);
4472 if (arg0_value == irb->codegen->invalid_instruction)
4473 return arg0_value;
4474
4475 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4476 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4477 if (arg1_value == irb->codegen->invalid_instruction)
4478 return arg1_value;
4479
4480 IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, arg0_value, arg1_value);
4481
4482 if (lval == LValPtr)
4483 return ptr_instruction;
4484
4485 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
4486 }
4487 case BuiltinFnIdTypeInfo:
4488 {
4489 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4490 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4491 if (arg0_value == irb->codegen->invalid_instruction)
4492 return arg0_value;
4493
4494 IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value);
4495 return ir_lval_wrap(irb, scope, type_info, lval);
39524496 }
39534497 case BuiltinFnIdBreakpoint:
3954 return ir_build_breakpoint(irb, scope, node);
4498 return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);
39554499 case BuiltinFnIdReturnAddress:
3956 return ir_build_return_address(irb, scope, node);
4500 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval);
39574501 case BuiltinFnIdFrameAddress:
3958 return ir_build_frame_address(irb, scope, node);
4502 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval);
4503 case BuiltinFnIdHandle:
4504 if (!irb->exec->fn_entry) {
4505 add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));
4506 return irb->codegen->invalid_instruction;
4507 }
4508 if (!is_async) {
4509 add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
4510 return irb->codegen->invalid_instruction;
4511 }
4512 return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval);
39594513 case BuiltinFnIdAlignOf:
39604514 {
39614515 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -3963,16 +4517,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39634517 if (arg0_value == irb->codegen->invalid_instruction)
39644518 return arg0_value;
39654519
3966 return ir_build_align_of(irb, scope, node, arg0_value);
4520 IrInstruction *align_of = ir_build_align_of(irb, scope, node, arg0_value);
4521 return ir_lval_wrap(irb, scope, align_of, lval);
39674522 }
39684523 case BuiltinFnIdAddWithOverflow:
3969 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd);
4524 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval);
39704525 case BuiltinFnIdSubWithOverflow:
3971 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub);
4526 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval);
39724527 case BuiltinFnIdMulWithOverflow:
3973 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul);
4528 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval);
39744529 case BuiltinFnIdShlWithOverflow:
3975 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl);
4530 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval);
39764531 case BuiltinFnIdTypeName:
39774532 {
39784533 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -3980,21 +4535,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39804535 if (arg0_value == irb->codegen->invalid_instruction)
39814536 return arg0_value;
39824537
3983 return ir_build_type_name(irb, scope, node, arg0_value);
3984 }
3985 case BuiltinFnIdCanImplicitCast:
3986 {
3987 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
3988 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
3989 if (arg0_value == irb->codegen->invalid_instruction)
3990 return arg0_value;
3991
3992 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
3993 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
3994 if (arg1_value == irb->codegen->invalid_instruction)
3995 return arg1_value;
3996
3997 return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
4538 IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value);
4539 return ir_lval_wrap(irb, scope, type_name, lval);
39984540 }
39994541 case BuiltinFnIdPanic:
40004542 {
......@@ -4003,7 +4545,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40034545 if (arg0_value == irb->codegen->invalid_instruction)
40044546 return arg0_value;
40054547
4006 return ir_build_panic(irb, scope, node, arg0_value);
4548 IrInstruction *panic = ir_build_panic(irb, scope, node, arg0_value);
4549 return ir_lval_wrap(irb, scope, panic, lval);
40074550 }
40084551 case BuiltinFnIdPtrCast:
40094552 {
......@@ -4017,7 +4560,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40174560 if (arg1_value == irb->codegen->invalid_instruction)
40184561 return arg1_value;
40194562
4020 return ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
4563 IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
4564 return ir_lval_wrap(irb, scope, ptr_cast, lval);
40214565 }
40224566 case BuiltinFnIdBitCast:
40234567 {
......@@ -4031,7 +4575,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40314575 if (arg1_value == irb->codegen->invalid_instruction)
40324576 return arg1_value;
40334577
4034 return ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
4578 IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
4579 return ir_lval_wrap(irb, scope, bit_cast, lval);
40354580 }
40364581 case BuiltinFnIdIntToPtr:
40374582 {
......@@ -4045,7 +4590,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40454590 if (arg1_value == irb->codegen->invalid_instruction)
40464591 return arg1_value;
40474592
4048 return ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
4593 IrInstruction *int_to_ptr = ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
4594 return ir_lval_wrap(irb, scope, int_to_ptr, lval);
40494595 }
40504596 case BuiltinFnIdPtrToInt:
40514597 {
......@@ -4054,7 +4600,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40544600 if (arg0_value == irb->codegen->invalid_instruction)
40554601 return arg0_value;
40564602
4057 return ir_build_ptr_to_int(irb, scope, node, arg0_value);
4603 IrInstruction *ptr_to_int = ir_build_ptr_to_int(irb, scope, node, arg0_value);
4604 return ir_lval_wrap(irb, scope, ptr_to_int, lval);
40584605 }
40594606 case BuiltinFnIdTagName:
40604607 {
......@@ -4064,7 +4611,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40644611 return arg0_value;
40654612
40664613 IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
4067 return ir_build_tag_name(irb, scope, node, actual_tag);
4614 IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
4615 return ir_lval_wrap(irb, scope, tag_name, lval);
40684616 }
40694617 case BuiltinFnIdTagType:
40704618 {
......@@ -4073,7 +4621,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40734621 if (arg0_value == irb->codegen->invalid_instruction)
40744622 return arg0_value;
40754623
4076 return ir_build_tag_type(irb, scope, node, arg0_value);
4624 IrInstruction *tag_type = ir_build_tag_type(irb, scope, node, arg0_value);
4625 return ir_lval_wrap(irb, scope, tag_type, lval);
40774626 }
40784627 case BuiltinFnIdFieldParentPtr:
40794628 {
......@@ -4092,7 +4641,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40924641 if (arg2_value == irb->codegen->invalid_instruction)
40934642 return arg2_value;
40944643
4095 return ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
4644 IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
4645 return ir_lval_wrap(irb, scope, field_parent_ptr, lval);
40964646 }
40974647 case BuiltinFnIdOffsetOf:
40984648 {
......@@ -4106,7 +4656,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41064656 if (arg1_value == irb->codegen->invalid_instruction)
41074657 return arg1_value;
41084658
4109 return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
4659 IrInstruction *offset_of = ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
4660 return ir_lval_wrap(irb, scope, offset_of, lval);
41104661 }
41114662 case BuiltinFnIdInlineCall:
41124663 case BuiltinFnIdNoInlineCall:
......@@ -4132,7 +4683,38 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41324683 }
41334684 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
41344685
4135 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
4686 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
4687 return ir_lval_wrap(irb, scope, call, lval);
4688 }
4689 case BuiltinFnIdNewStackCall:
4690 {
4691 if (node->data.fn_call_expr.params.length == 0) {
4692 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
4693 return irb->codegen->invalid_instruction;
4694 }
4695
4696 AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
4697 IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
4698 if (new_stack == irb->codegen->invalid_instruction)
4699 return new_stack;
4700
4701 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
4702 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
4703 if (fn_ref == irb->codegen->invalid_instruction)
4704 return fn_ref;
4705
4706 size_t arg_count = node->data.fn_call_expr.params.length - 2;
4707
4708 IrInstruction **args = allocate<IrInstruction*>(arg_count);
4709 for (size_t i = 0; i < arg_count; i += 1) {
4710 AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
4711 args[i] = ir_gen_node(irb, arg_node, scope);
4712 if (args[i] == irb->codegen->invalid_instruction)
4713 return args[i];
4714 }
4715
4716 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
4717 return ir_lval_wrap(irb, scope, call, lval);
41364718 }
41374719 case BuiltinFnIdTypeId:
41384720 {
......@@ -4141,7 +4723,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41414723 if (arg0_value == irb->codegen->invalid_instruction)
41424724 return arg0_value;
41434725
4144 return ir_build_type_id(irb, scope, node, arg0_value);
4726 IrInstruction *type_id = ir_build_type_id(irb, scope, node, arg0_value);
4727 return ir_lval_wrap(irb, scope, type_id, lval);
41454728 }
41464729 case BuiltinFnIdShlExact:
41474730 {
......@@ -4155,7 +4738,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41554738 if (arg1_value == irb->codegen->invalid_instruction)
41564739 return arg1_value;
41574740
4158 return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
4741 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
4742 return ir_lval_wrap(irb, scope, bin_op, lval);
41594743 }
41604744 case BuiltinFnIdShrExact:
41614745 {
......@@ -4169,7 +4753,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41694753 if (arg1_value == irb->codegen->invalid_instruction)
41704754 return arg1_value;
41714755
4172 return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
4756 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
4757 return ir_lval_wrap(irb, scope, bin_op, lval);
41734758 }
41744759 case BuiltinFnIdSetEvalBranchQuota:
41754760 {
......@@ -4178,7 +4763,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41784763 if (arg0_value == irb->codegen->invalid_instruction)
41794764 return arg0_value;
41804765
4181 return ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
4766 IrInstruction *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
4767 return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval);
41824768 }
41834769 case BuiltinFnIdAlignCast:
41844770 {
......@@ -4192,10 +4778,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41924778 if (arg1_value == irb->codegen->invalid_instruction)
41934779 return arg1_value;
41944780
4195 return ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
4781 IrInstruction *align_cast = ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
4782 return ir_lval_wrap(irb, scope, align_cast, lval);
41964783 }
41974784 case BuiltinFnIdOpaqueType:
4198 return ir_build_opaque_type(irb, scope, node);
4785 {
4786 IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node);
4787 return ir_lval_wrap(irb, scope, opaque_type, lval);
4788 }
41994789 case BuiltinFnIdSetAlignStack:
42004790 {
42014791 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -4203,7 +4793,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42034793 if (arg0_value == irb->codegen->invalid_instruction)
42044794 return arg0_value;
42054795
4206 return ir_build_set_align_stack(irb, scope, node, arg0_value);
4796 IrInstruction *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value);
4797 return ir_lval_wrap(irb, scope, set_align_stack, lval);
42074798 }
42084799 case BuiltinFnIdArgType:
42094800 {
......@@ -4217,7 +4808,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42174808 if (arg1_value == irb->codegen->invalid_instruction)
42184809 return arg1_value;
42194810
4220 return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
4811 IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
4812 return ir_lval_wrap(irb, scope, arg_type, lval);
42214813 }
42224814 case BuiltinFnIdExport:
42234815 {
......@@ -4236,11 +4828,13 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42364828 if (arg2_value == irb->codegen->invalid_instruction)
42374829 return arg2_value;
42384830
4239 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
4831 IrInstruction *ir_export = ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
4832 return ir_lval_wrap(irb, scope, ir_export, lval);
42404833 }
42414834 case BuiltinFnIdErrorReturnTrace:
42424835 {
4243 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4836 IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4837 return ir_lval_wrap(irb, scope, error_return_trace, lval);
42444838 }
42454839 case BuiltinFnIdAtomicRmw:
42464840 {
......@@ -4274,15 +4868,61 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42744868 // these 2 values don't mean anything since we passed non-null values for other args
42754869 AtomicRmwOp_xchg, AtomicOrderMonotonic);
42764870 }
4871 case BuiltinFnIdAtomicLoad:
4872 {
4873 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4874 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4875 if (arg0_value == irb->codegen->invalid_instruction)
4876 return arg0_value;
4877
4878 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4879 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4880 if (arg1_value == irb->codegen->invalid_instruction)
4881 return arg1_value;
4882
4883 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
4884 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
4885 if (arg2_value == irb->codegen->invalid_instruction)
4886 return arg2_value;
4887
4888 return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value,
4889 // this value does not mean anything since we passed non-null values for other arg
4890 AtomicOrderMonotonic);
4891 }
4892 case BuiltinFnIdIntToEnum:
4893 {
4894 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4895 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4896 if (arg0_value == irb->codegen->invalid_instruction)
4897 return arg0_value;
4898
4899 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4900 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4901 if (arg1_value == irb->codegen->invalid_instruction)
4902 return arg1_value;
4903
4904 IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value);
4905 return ir_lval_wrap(irb, scope, result, lval);
4906 }
4907 case BuiltinFnIdEnumToInt:
4908 {
4909 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4910 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4911 if (arg0_value == irb->codegen->invalid_instruction)
4912 return arg0_value;
4913
4914 IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value);
4915 return ir_lval_wrap(irb, scope, result, lval);
4916 }
42774917 }
42784918 zig_unreachable();
42794919}
42804920
4281static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
4921static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
42824922 assert(node->type == NodeTypeFnCallExpr);
42834923
42844924 if (node->data.fn_call_expr.is_builtin)
4285 return ir_gen_builtin_fn_call(irb, scope, node);
4925 return ir_gen_builtin_fn_call(irb, scope, node, lval);
42864926
42874927 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
42884928 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
......@@ -4308,7 +4948,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
43084948 }
43094949 }
43104950
4311 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
4951 IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
4952 return ir_lval_wrap(irb, scope, fn_call, lval);
43124953}
43134954
43144955static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -4379,30 +5020,28 @@ static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, Ast
43795020}
43805021
43815022static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
4382 return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LVAL_NONE);
5023 return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone);
43835024}
43845025
43855026static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) {
4386 if (!lval.is_ptr)
5027 if (lval != LValPtr)
43875028 return value;
43885029 if (value == irb->codegen->invalid_instruction)
43895030 return value;
43905031
43915032 // We needed a pointer to a value, but we got a value. So we create
43925033 // an instruction which just makes a const pointer of it.
4393 return ir_build_ref(irb, scope, value->source_node, value, lval.is_const, lval.is_volatile);
5034 return ir_build_ref(irb, scope, value->source_node, value, false, false);
43945035}
43955036
4396static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *node) {
4397 assert(node->type == NodeTypeAddrOfExpr);
4398 bool is_const = node->data.addr_of_expr.is_const;
4399 bool is_volatile = node->data.addr_of_expr.is_volatile;
4400 AstNode *expr_node = node->data.addr_of_expr.op_expr;
4401 AstNode *align_expr = node->data.addr_of_expr.align_expr;
4402
4403 if (align_expr == nullptr && !is_const && !is_volatile) {
4404 return ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile));
4405 }
5037static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) {
5038 assert(node->type == NodeTypePointerType);
5039 PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
5040 node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown;
5041 bool is_const = node->data.pointer_type.is_const;
5042 bool is_volatile = node->data.pointer_type.is_volatile;
5043 AstNode *expr_node = node->data.pointer_type.op_expr;
5044 AstNode *align_expr = node->data.pointer_type.align_expr;
44065045
44075046 IrInstruction *align_value;
44085047 if (align_expr != nullptr) {
......@@ -4418,27 +5057,27 @@ static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *n
44185057 return child_type;
44195058
44205059 uint32_t bit_offset_start = 0;
4421 if (node->data.addr_of_expr.bit_offset_start != nullptr) {
4422 if (!bigint_fits_in_bits(node->data.addr_of_expr.bit_offset_start, 32, false)) {
5060 if (node->data.pointer_type.bit_offset_start != nullptr) {
5061 if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_start, 32, false)) {
44235062 Buf *val_buf = buf_alloc();
4424 bigint_append_buf(val_buf, node->data.addr_of_expr.bit_offset_start, 10);
5063 bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_start, 10);
44255064 exec_add_error_node(irb->codegen, irb->exec, node,
44265065 buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
44275066 return irb->codegen->invalid_instruction;
44285067 }
4429 bit_offset_start = bigint_as_unsigned(node->data.addr_of_expr.bit_offset_start);
5068 bit_offset_start = bigint_as_unsigned(node->data.pointer_type.bit_offset_start);
44305069 }
44315070
44325071 uint32_t bit_offset_end = 0;
4433 if (node->data.addr_of_expr.bit_offset_end != nullptr) {
4434 if (!bigint_fits_in_bits(node->data.addr_of_expr.bit_offset_end, 32, false)) {
5072 if (node->data.pointer_type.bit_offset_end != nullptr) {
5073 if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_end, 32, false)) {
44355074 Buf *val_buf = buf_alloc();
4436 bigint_append_buf(val_buf, node->data.addr_of_expr.bit_offset_end, 10);
5075 bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_end, 10);
44375076 exec_add_error_node(irb->codegen, irb->exec, node,
44385077 buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
44395078 return irb->codegen->invalid_instruction;
44405079 }
4441 bit_offset_end = bigint_as_unsigned(node->data.addr_of_expr.bit_offset_end);
5080 bit_offset_end = bigint_as_unsigned(node->data.pointer_type.bit_offset_end);
44425081 }
44435082
44445083 if ((bit_offset_start != 0 || bit_offset_end != 0) && bit_offset_start >= bit_offset_end) {
......@@ -4447,14 +5086,14 @@ static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *n
44475086 return irb->codegen->invalid_instruction;
44485087 }
44495088
4450 return ir_build_ptr_type_of(irb, scope, node, child_type, is_const, is_volatile,
4451 align_value, bit_offset_start, bit_offset_end);
5089 return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile,
5090 ptr_len, align_value, bit_offset_start, bit_offset_end);
44525091}
44535092
44545093static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
44555094 LVal lval)
44565095{
4457 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
5096 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
44585097 if (err_union_ptr == irb->codegen->invalid_instruction)
44595098 return irb->codegen->invalid_instruction;
44605099
......@@ -4462,27 +5101,12 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode
44625101 if (payload_ptr == irb->codegen->invalid_instruction)
44635102 return irb->codegen->invalid_instruction;
44645103
4465 if (lval.is_ptr)
5104 if (lval == LValPtr)
44665105 return payload_ptr;
44675106
44685107 return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
44695108}
44705109
4471static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
4472 assert(node->type == NodeTypePrefixOpExpr);
4473 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
4474
4475 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
4476 if (maybe_ptr == irb->codegen->invalid_instruction)
4477 return irb->codegen->invalid_instruction;
4478
4479 IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
4480 if (lval.is_ptr)
4481 return unwrapped_ptr;
4482
4483 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
4484}
4485
44865110static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
44875111 assert(node->type == NodeTypePrefixOpExpr);
44885112 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
......@@ -4510,12 +5134,12 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
45105134 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
45115135 case PrefixOpNegationWrap:
45125136 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
4513 case PrefixOpDereference:
4514 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
4515 case PrefixOpMaybe:
4516 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
4517 case PrefixOpUnwrapMaybe:
4518 return ir_gen_maybe_assert_ok(irb, scope, node, lval);
5137 case PrefixOpOptional:
5138 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
5139 case PrefixOpAddrOf: {
5140 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
5141 return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr), lval);
5142 }
45195143 }
45205144 zig_unreachable();
45215145}
......@@ -4570,6 +5194,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
45705194
45715195 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
45725196
5197 if (buf_eql_str(variable_declaration->symbol, "_")) {
5198 add_node_error(irb->codegen, node, buf_sprintf("`_` is not a declarable symbol"));
5199 return irb->codegen->invalid_instruction;
5200 }
5201
45735202 IrInstruction *type_instruction;
45745203 if (variable_declaration->type != nullptr) {
45755204 type_instruction = ir_gen_node(irb, variable_declaration->type, scope);
......@@ -4582,6 +5211,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
45825211 bool is_shadowable = false;
45835212 bool is_const = variable_declaration->is_const;
45845213 bool is_extern = variable_declaration->is_extern;
5214
45855215 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node,
45865216 ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime);
45875217 VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
......@@ -4654,7 +5284,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
46545284 } else {
46555285 payload_scope = scope;
46565286 }
4657 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR);
5287 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LValPtr);
46585288 if (err_val_ptr == irb->codegen->invalid_instruction)
46595289 return err_val_ptr;
46605290 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
......@@ -4689,8 +5319,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
46895319 if (body_result == irb->codegen->invalid_instruction)
46905320 return body_result;
46915321
4692 if (!instr_is_unreachable(body_result))
5322 if (!instr_is_unreachable(body_result)) {
5323 ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result));
46935324 ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime));
5325 }
46945326
46955327 if (continue_expr_node) {
46965328 ir_set_cursor_at_end_and_append_block(irb, continue_block);
......@@ -4737,7 +5369,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47375369 VariableTableEntry *payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,
47385370 true, false, false, is_comptime);
47395371 Scope *child_scope = payload_var->child_scope;
4740 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR);
5372 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LValPtr);
47415373 if (maybe_val_ptr == irb->codegen->invalid_instruction)
47425374 return maybe_val_ptr;
47435375 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
......@@ -4769,8 +5401,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47695401 if (body_result == irb->codegen->invalid_instruction)
47705402 return body_result;
47715403
4772 if (!instr_is_unreachable(body_result))
5404 if (!instr_is_unreachable(body_result)) {
5405 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result));
47735406 ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
5407 }
47745408
47755409 if (continue_expr_node) {
47765410 ir_set_cursor_at_end_and_append_block(irb, continue_block);
......@@ -4830,8 +5464,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
48305464 if (body_result == irb->codegen->invalid_instruction)
48315465 return body_result;
48325466
4833 if (!instr_is_unreachable(body_result))
5467 if (!instr_is_unreachable(body_result)) {
5468 ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result));
48345469 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
5470 }
48355471
48365472 if (continue_expr_node) {
48375473 ir_set_cursor_at_end_and_append_block(irb, continue_block);
......@@ -4881,7 +5517,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
48815517 }
48825518 assert(elem_node->type == NodeTypeSymbol);
48835519
4884 IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LVAL_PTR);
5520 IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr);
48855521 if (array_val_ptr == irb->codegen->invalid_instruction)
48865522 return array_val_ptr;
48875523
......@@ -4905,7 +5541,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49055541
49065542 IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
49075543 ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
4908 IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var, false, false);
5544 IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var);
49095545
49105546 AstNode *index_var_source_node;
49115547 VariableTableEntry *index_var;
......@@ -4923,7 +5559,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49235559 IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
49245560 IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
49255561 ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
4926 IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var, false, false);
5562 IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var);
49275563
49285564
49295565 IrBasicBlock *cond_block = ir_create_basic_block(irb, child_scope, "ForCond");
......@@ -4943,7 +5579,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49435579 ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime));
49445580
49455581 ir_set_cursor_at_end_and_append_block(irb, body_block);
4946 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false);
5582 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle);
49475583 IrInstruction *elem_val;
49485584 if (node->data.for_expr.elem_is_ptr) {
49495585 elem_val = elem_ptr;
......@@ -5168,16 +5804,16 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
51685804 AstNode *else_node = node->data.test_expr.else_node;
51695805 bool var_is_ptr = node->data.test_expr.var_is_ptr;
51705806
5171 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
5807 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
51725808 if (maybe_val_ptr == irb->codegen->invalid_instruction)
51735809 return maybe_val_ptr;
51745810
51755811 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
51765812 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
51775813
5178 IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "MaybeThen");
5179 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "MaybeElse");
5180 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "MaybeEndIf");
5814 IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen");
5815 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "OptionalElse");
5816 IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "OptionalEndIf");
51815817
51825818 IrInstruction *is_comptime;
51835819 if (ir_should_inline(irb->exec, scope)) {
......@@ -5246,7 +5882,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
52465882 Buf *var_symbol = node->data.if_err_expr.var_symbol;
52475883 Buf *err_symbol = node->data.if_err_expr.err_symbol;
52485884
5249 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LVAL_PTR);
5885 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr);
52505886 if (err_val_ptr == irb->codegen->invalid_instruction)
52515887 return err_val_ptr;
52525888
......@@ -5372,7 +6008,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
53726008 assert(node->type == NodeTypeSwitchExpr);
53736009
53746010 AstNode *target_node = node->data.switch_expr.expr;
5375 IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LVAL_PTR);
6011 IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr);
53766012 if (target_value_ptr == irb->codegen->invalid_instruction)
53776013 return target_value_ptr;
53786014 IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr);
......@@ -5536,13 +6172,13 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
55366172
55376173 }
55386174
5539 ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length,
6175 IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length,
55406176 else_prong != nullptr);
55416177
55426178 if (cases.length == 0) {
55436179 ir_build_br(irb, scope, node, else_block, is_comptime);
55446180 } else {
5545 ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime);
6181 ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime, switch_prongs_void);
55466182 }
55476183
55486184 if (!else_prong) {
......@@ -5630,6 +6266,9 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
56306266 assert(this_block_scope->end_block != nullptr);
56316267 return ir_gen_return_from_block(irb, break_scope, node, this_block_scope);
56326268 }
6269 } else if (search_scope->id == ScopeIdSuspend) {
6270 add_node_error(irb->codegen, node, buf_sprintf("cannot break out of suspend block"));
6271 return irb->codegen->invalid_instruction;
56336272 }
56346273 search_scope = search_scope->parent;
56356274 }
......@@ -5729,7 +6368,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
57296368 AstNode *start_node = slice_expr->start;
57306369 AstNode *end_node = slice_expr->end;
57316370
5732 IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LVAL_PTR);
6371 IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr);
57336372 if (ptr_value == irb->codegen->invalid_instruction)
57346373 return irb->codegen->invalid_instruction;
57356374
......@@ -5763,11 +6402,11 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
57636402 add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name)));
57646403 return irb->codegen->invalid_instruction;
57656404 }
5766 return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LVAL_NONE);
6405 return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone);
57676406 }
57686407
57696408
5770 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LVAL_PTR);
6409 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr);
57716410 if (err_union_ptr == irb->codegen->invalid_instruction)
57726411 return irb->codegen->invalid_instruction;
57736412
......@@ -5970,16 +6609,10 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
59706609 buf_init_from_buf(&err_set_type->name, type_name);
59716610 err_set_type->is_copyable = true;
59726611 err_set_type->data.error_set.err_count = err_count;
5973
5974 if (err_count == 0) {
5975 err_set_type->zero_bits = true;
5976 err_set_type->di_type = irb->codegen->builtin_types.entry_void->di_type;
5977 } else {
5978 err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref;
5979 err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type;
5980 irb->codegen->error_di_types.append(&err_set_type->di_type);
5981 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
5982 }
6612 err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref;
6613 err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type;
6614 irb->codegen->error_di_types.append(&err_set_type->di_type);
6615 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
59836616
59846617 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
59856618
......@@ -6071,30 +6704,150 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
60716704 async_allocator_type_value, is_var_args);
60726705}
60736706
6074static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
6075 assert(node->type == NodeTypeCancel);
6707static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode *node,
6708 IrInstruction *target_inst, bool cancel_non_suspended, bool cancel_awaited)
6709{
6710 IrBasicBlock *done_block = ir_create_basic_block(irb, scope, "CancelDone");
6711 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
6712 IrBasicBlock *pre_return_block = ir_create_basic_block(irb, scope, "PreReturn");
6713 IrBasicBlock *post_return_block = ir_create_basic_block(irb, scope, "PostReturn");
6714 IrBasicBlock *do_cancel_block = ir_create_basic_block(irb, scope, "DoCancel");
6715
6716 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6717 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
6718 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
6719 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
6720 IrInstruction *promise_T_type_val = ir_build_const_type(irb, scope, node,
6721 get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
6722 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
6723 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
6724 IrInstruction *await_mask = ir_build_const_usize(irb, scope, node, 0x4); // 0b100
6725 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
6726
6727 // TODO relies on Zig not re-ordering fields
6728 IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
6729 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
6730 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
6731 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6732 atomic_state_field_name);
6733
6734 // set the is_canceled bit
6735 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
6736 usize_type_val, atomic_state_ptr, nullptr, is_canceled_mask, nullptr,
6737 AtomicRmwOp_or, AtomicOrderSeqCst);
6738
6739 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
6740 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
6741 ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
6742
6743 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
6744 IrInstruction *awaiter_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
6745 IrInstruction *is_returned_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, awaiter_addr, ptr_mask, false);
6746 ir_build_cond_br(irb, scope, node, is_returned_bool, post_return_block, pre_return_block, is_comptime);
6747
6748 ir_set_cursor_at_end_and_append_block(irb, post_return_block);
6749 if (cancel_awaited) {
6750 ir_build_br(irb, scope, node, do_cancel_block, is_comptime);
6751 } else {
6752 IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
6753 IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
6754 ir_build_cond_br(irb, scope, node, is_awaited_bool, done_block, do_cancel_block, is_comptime);
6755 }
60766756
6077 IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, parent_scope);
6078 if (target_inst == irb->codegen->invalid_instruction)
6079 return irb->codegen->invalid_instruction;
6757 ir_set_cursor_at_end_and_append_block(irb, pre_return_block);
6758 if (cancel_awaited) {
6759 if (cancel_non_suspended) {
6760 ir_build_br(irb, scope, node, do_cancel_block, is_comptime);
6761 } else {
6762 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
6763 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
6764 ir_build_cond_br(irb, scope, node, is_suspended_bool, do_cancel_block, done_block, is_comptime);
6765 }
6766 } else {
6767 ir_build_br(irb, scope, node, done_block, is_comptime);
6768 }
60806769
6081 return ir_build_cancel(irb, parent_scope, node, target_inst);
6770 ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
6771 ir_build_cancel(irb, scope, node, target_inst);
6772 ir_build_br(irb, scope, node, done_block, is_comptime);
6773
6774 ir_set_cursor_at_end_and_append_block(irb, done_block);
6775 return ir_build_const_void(irb, scope, node);
60826776}
60836777
6084static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
6085 assert(node->type == NodeTypeResume);
6778static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) {
6779 assert(node->type == NodeTypeCancel);
60866780
6087 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, parent_scope);
6781 IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope);
60886782 if (target_inst == irb->codegen->invalid_instruction)
60896783 return irb->codegen->invalid_instruction;
60906784
6091 return ir_build_coro_resume(irb, parent_scope, node, target_inst);
6785 return ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
60926786}
60936787
6094static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
6095 assert(node->type == NodeTypeAwaitExpr);
6096
6097 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, parent_scope);
6788static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode *node,
6789 IrInstruction *target_inst)
6790{
6791 IrBasicBlock *done_block = ir_create_basic_block(irb, scope, "ResumeDone");
6792 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
6793 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "IsSuspended");
6794 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "IsNotSuspended");
6795
6796 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6797 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
6798 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
6799 IrInstruction *and_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, is_suspended_mask);
6800 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
6801 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
6802 IrInstruction *promise_T_type_val = ir_build_const_type(irb, scope, node,
6803 get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
6804
6805 // TODO relies on Zig not re-ordering fields
6806 IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
6807 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
6808 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
6809 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6810 atomic_state_field_name);
6811
6812 // clear the is_suspended bit
6813 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
6814 usize_type_val, atomic_state_ptr, nullptr, and_mask, nullptr,
6815 AtomicRmwOp_and, AtomicOrderSeqCst);
6816
6817 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
6818 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
6819 ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
6820
6821 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
6822 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
6823 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
6824 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
6825
6826 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
6827 ir_build_unreachable(irb, scope, node);
6828
6829 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
6830 ir_build_coro_resume(irb, scope, node, target_inst);
6831 ir_build_br(irb, scope, node, done_block, is_comptime);
6832
6833 ir_set_cursor_at_end_and_append_block(irb, done_block);
6834 return ir_build_const_void(irb, scope, node);
6835}
6836
6837static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
6838 assert(node->type == NodeTypeResume);
6839
6840 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope);
6841 if (target_inst == irb->codegen->invalid_instruction)
6842 return irb->codegen->invalid_instruction;
6843
6844 return ir_gen_resume_target(irb, scope, node, target_inst);
6845}
6846
6847static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
6848 assert(node->type == NodeTypeAwaitExpr);
6849
6850 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);
60986851 if (target_inst == irb->codegen->invalid_instruction)
60996852 return irb->codegen->invalid_instruction;
61006853
......@@ -6108,7 +6861,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
61086861 return irb->codegen->invalid_instruction;
61096862 }
61106863
6111 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
6864 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope);
61126865 if (scope_defer_expr) {
61136866 if (!scope_defer_expr->reported_err) {
61146867 add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression"));
......@@ -6119,85 +6872,157 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
61196872
61206873 Scope *outer_scope = irb->exec->begin_scope;
61216874
6122 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, parent_scope, node, target_inst);
6875 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst);
61236876 Buf *result_ptr_field_name = buf_create_from_str(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);
6877 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
61256878
61266879 if (irb->codegen->have_err_ret_tracing) {
6127 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6880 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
61286881 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
6133 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6134 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
6135 awaiter_handle_field_name);
6136
6137 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
6138 VariableTableEntry *result_var = ir_create_var(irb, node, parent_scope, nullptr,
6882 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6883 ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
6884 }
6885
6886 IrBasicBlock *already_awaited_block = ir_create_basic_block(irb, scope, "AlreadyAwaited");
6887 IrBasicBlock *not_awaited_block = ir_create_basic_block(irb, scope, "NotAwaited");
6888 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
6889 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, scope, "YesSuspend");
6890 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, scope, "NoSuspend");
6891 IrBasicBlock *merge_block = ir_create_basic_block(irb, scope, "MergeSuspend");
6892 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, scope, "SuspendCleanup");
6893 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "SuspendResume");
6894 IrBasicBlock *cancel_target_block = ir_create_basic_block(irb, scope, "CancelTarget");
6895 IrBasicBlock *do_cancel_block = ir_create_basic_block(irb, scope, "DoCancel");
6896 IrBasicBlock *do_defers_block = ir_create_basic_block(irb, scope, "DoDefers");
6897 IrBasicBlock *destroy_block = ir_create_basic_block(irb, scope, "DestroyBlock");
6898 IrBasicBlock *my_suspended_block = ir_create_basic_block(irb, scope, "AlreadySuspended");
6899 IrBasicBlock *my_not_suspended_block = ir_create_basic_block(irb, scope, "NotAlreadySuspended");
6900 IrBasicBlock *do_suspend_block = ir_create_basic_block(irb, scope, "DoSuspend");
6901
6902 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
6903 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6904 atomic_state_field_name);
6905
6906 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
6907 IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
6908 IrInstruction *undefined_value = ir_build_const_undefined(irb, scope, node);
6909 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
6910 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6911 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
6912 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
6913 IrInstruction *await_mask = ir_build_const_usize(irb, scope, node, 0x4); // 0b100
6914 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
6915 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
6916
6917 VariableTableEntry *result_var = ir_create_var(irb, node, scope, nullptr,
61396918 false, false, true, const_bool_false);
6140 IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node);
6141 IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst);
6142 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type);
6143 ir_build_await_bookkeeping(irb, parent_scope, node, promise_result_type);
6144 ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value);
6145 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var, false, false);
6146 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);
6147 IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle);
6148 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node,
6149 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6150 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node,
6151 promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr,
6152 AtomicRmwOp_xchg, AtomicOrderSeqCst);
6153 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6154 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6155 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6156 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend");
6157 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
6919 IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
6920 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
6921 ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
6922 ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
6923 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
6924 ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
6925 IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
6926
6927 IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
6928 IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false);
6929 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
6930 usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr,
6931 AtomicRmwOp_or, AtomicOrderSeqCst);
6932
6933 IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
6934 IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
6935 ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false);
6936
6937 ir_set_cursor_at_end_and_append_block(irb, already_awaited_block);
6938 ir_build_unreachable(irb, scope, node);
6939
6940 ir_set_cursor_at_end_and_append_block(irb, not_awaited_block);
6941 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
6942 IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
6943 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
6944 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
6945 ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false);
6946
6947 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
6948 ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
6949
6950 ir_set_cursor_at_end_and_append_block(irb, cancel_target_block);
6951 ir_build_cancel(irb, scope, node, target_inst);
6952 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
61586953
61596954 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
61606955 if (irb->codegen->have_err_ret_tracing) {
61616956 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);
6957 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
6958 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
6959 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
61656960 }
61666961 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6167 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6168 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
6169 ir_build_cancel(irb, parent_scope, node, target_inst);
6170 ir_build_br(irb, parent_scope, node, merge_block, const_bool_false);
6962 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6963 // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
6964 // because we're about to destroy the memory. So we store it into our result variable.
6965 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
6966 ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result);
6967 ir_build_cancel(irb, scope, node, target_inst);
6968 ir_build_br(irb, scope, node, merge_block, const_bool_false);
6969
61716970
61726971 ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
6173 IrInstruction *suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false);
6174 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6175 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
6972 IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
6973 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
6974 AtomicRmwOp_or, AtomicOrderSeqCst);
6975 IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
6976 IrInstruction *my_is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_suspended_value, zero, false);
6977 ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false);
6978
6979 ir_set_cursor_at_end_and_append_block(irb, my_suspended_block);
6980 ir_build_unreachable(irb, scope, node);
6981
6982 ir_set_cursor_at_end_and_append_block(irb, my_not_suspended_block);
6983 IrInstruction *my_is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_canceled_mask, false);
6984 IrInstruction *my_is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_canceled_value, zero, false);
6985 ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false);
6986
6987 ir_set_cursor_at_end_and_append_block(irb, do_suspend_block);
6988 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false);
61766989
61776990 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6178 cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0);
6991 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
61796992 cases[0].block = resume_block;
6180 cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1);
6181 cases[1].block = cleanup_block;
6182 ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6183 2, cases, const_bool_false);
6993 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
6994 cases[1].block = destroy_block;
6995 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block,
6996 2, cases, const_bool_false, nullptr);
6997
6998 ir_set_cursor_at_end_and_append_block(irb, destroy_block);
6999 ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
7000 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
61847001
61857002 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6186 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6187 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
7003 IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false);
7004 IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
7005 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr,
7006 AtomicRmwOp_or, AtomicOrderSeqCst);
7007 IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
7008 IrInstruction *dont_have_my_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, my_await_handle_addr, zero, false);
7009 IrInstruction *dont_destroy_ourselves = ir_build_bin_op(irb, scope, node, IrBinOpBoolAnd, dont_have_my_await_handle, is_canceled_bool, false);
7010 ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false);
7011
7012 ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
7013 IrInstruction *my_await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, my_await_handle_addr);
7014 ir_gen_cancel_target(irb, scope, node, my_await_handle, true, false);
7015 ir_mark_gen(ir_build_br(irb, scope, node, do_defers_block, const_bool_false));
7016
7017 ir_set_cursor_at_end_and_append_block(irb, do_defers_block);
7018 ir_gen_defers_for_block(irb, scope, outer_scope, true);
7019 ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false));
61887020
61897021 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6190 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
6191 ir_build_br(irb, parent_scope, node, merge_block, const_bool_false);
7022 ir_build_br(irb, scope, node, merge_block, const_bool_false);
61927023
61937024 ir_set_cursor_at_end_and_append_block(irb, merge_block);
6194 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
6195 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
6196 incoming_blocks[0] = resume_block;
6197 incoming_values[0] = yes_suspend_result;
6198 incoming_blocks[1] = no_suspend_block;
6199 incoming_values[1] = no_suspend_result;
6200 return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
7025 return ir_build_load_ptr(irb, scope, node, my_result_var_ptr);
62017026}
62027027
62037028static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
......@@ -6216,54 +7041,105 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
62167041 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
62177042 if (scope_defer_expr) {
62187043 if (!scope_defer_expr->reported_err) {
6219 add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
7044 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
7045 add_error_note(irb->codegen, msg, scope_defer_expr->base.source_node, buf_sprintf("defer here"));
62207046 scope_defer_expr->reported_err = true;
62217047 }
62227048 return irb->codegen->invalid_instruction;
62237049 }
7050 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
7051 if (existing_suspend_scope) {
7052 if (!existing_suspend_scope->reported_err) {
7053 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside suspend block"));
7054 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("other suspend block here"));
7055 existing_suspend_scope->reported_err = true;
7056 }
7057 return irb->codegen->invalid_instruction;
7058 }
62247059
62257060 Scope *outer_scope = irb->exec->begin_scope;
62267061
6227
6228 IrInstruction *suspend_code;
7062 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
7063 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
7064 IrBasicBlock *suspended_block = ir_create_basic_block(irb, parent_scope, "AlreadySuspended");
7065 IrBasicBlock *canceled_block = ir_create_basic_block(irb, parent_scope, "IsCanceled");
7066 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, parent_scope, "NotCanceled");
7067 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, parent_scope, "NotAlreadySuspended");
7068 IrBasicBlock *cancel_awaiter_block = ir_create_basic_block(irb, parent_scope, "CancelAwaiter");
7069
7070 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_promise);
7071 IrInstruction *const_bool_true = ir_build_const_bool(irb, parent_scope, node, true);
62297072 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
7073 IrInstruction *usize_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_usize);
7074 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, parent_scope, node, 0x1); // 0b001
7075 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, parent_scope, node, 0x2); // 0b010
7076 IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0);
7077 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, parent_scope, node, 0x7); // 0b111
7078 IrInstruction *ptr_mask = ir_build_un_op(irb, parent_scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
7079
7080 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, parent_scope, node,
7081 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
7082 AtomicRmwOp_or, AtomicOrderSeqCst);
7083
7084 IrInstruction *is_canceled_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
7085 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
7086 ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false);
7087
7088 ir_set_cursor_at_end_and_append_block(irb, canceled_block);
7089 IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
7090 IrInstruction *have_await_handle = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
7091 IrBasicBlock *post_canceled_block = irb->current_basic_block;
7092 ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false);
7093
7094 ir_set_cursor_at_end_and_append_block(irb, cancel_awaiter_block);
7095 IrInstruction *await_handle = ir_build_int_to_ptr(irb, parent_scope, node, promise_type_val, await_handle_addr);
7096 ir_gen_cancel_target(irb, parent_scope, node, await_handle, true, false);
7097 IrBasicBlock *post_cancel_awaiter_block = irb->current_basic_block;
7098 ir_build_br(irb, parent_scope, node, cleanup_block, const_bool_false);
7099
7100 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
7101 IrInstruction *is_suspended_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
7102 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
7103 ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false);
7104
7105 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
7106 ir_build_unreachable(irb, parent_scope, node);
7107
7108 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
7109 IrInstruction *suspend_code;
62307110 if (node->data.suspend.block == nullptr) {
62317111 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, nullptr, const_bool_false);
62327112 } else {
6233 assert(node->data.suspend.promise_symbol != nullptr);
6234 assert(node->data.suspend.promise_symbol->type == NodeTypeSymbol);
6235 Buf *promise_symbol_name = node->data.suspend.promise_symbol->data.symbol_expr.symbol;
62367113 Scope *child_scope;
6237 if (!buf_eql_str(promise_symbol_name, "_")) {
6238 VariableTableEntry *promise_var = ir_create_var(irb, node, parent_scope, promise_symbol_name,
6239 true, true, false, const_bool_false);
6240 ir_build_var_decl(irb, parent_scope, node, promise_var, nullptr, nullptr, irb->exec->coro_handle);
6241 child_scope = promise_var->child_scope;
6242 } else {
6243 child_scope = parent_scope;
6244 }
7114 ScopeSuspend *suspend_scope = create_suspend_scope(node, parent_scope);
7115 suspend_scope->resume_block = resume_block;
7116 child_scope = &suspend_scope->base;
62457117 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
62467118 ir_gen_node(irb, node->data.suspend.block, child_scope);
6247 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false);
7119 suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
62487120 }
62497121
6250 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6251 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
6252
62537122 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6254 cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0);
7123 cases[0].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 0));
62557124 cases[0].block = resume_block;
6256 cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1);
6257 cases[1].block = cleanup_block;
6258 ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6259 2, cases, const_bool_false);
7125 cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
7126 cases[1].block = canceled_block;
7127 ir_mark_gen(ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
7128 2, cases, const_bool_false, nullptr));
62607129
62617130 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
7131 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
7132 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
7133 incoming_blocks[0] = post_canceled_block;
7134 incoming_values[0] = const_bool_true;
7135 incoming_blocks[1] = post_cancel_awaiter_block;
7136 incoming_values[1] = const_bool_false;
7137 IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
62627138 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6263 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
7139 ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false));
62647140
62657141 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6266 return ir_build_const_void(irb, parent_scope, node);
7142 return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
62677143}
62687144
62697145static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
......@@ -6296,13 +7172,11 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
62967172 case NodeTypeSymbol:
62977173 return ir_gen_symbol(irb, scope, node, lval);
62987174 case NodeTypeFnCallExpr:
6299 return ir_lval_wrap(irb, scope, ir_gen_fn_call(irb, scope, node), lval);
7175 return ir_gen_fn_call(irb, scope, node, lval);
63007176 case NodeTypeIfBoolExpr:
63017177 return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval);
63027178 case NodeTypePrefixOpExpr:
63037179 return ir_gen_prefix_op_expr(irb, scope, node, lval);
6304 case NodeTypeAddrOfExpr:
6305 return ir_lval_wrap(irb, scope, ir_gen_address_of(irb, scope, node), lval);
63067180 case NodeTypeContainerInitExpr:
63077181 return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval);
63087182 case NodeTypeVariableDeclaration:
......@@ -6316,13 +7190,44 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
63167190 case NodeTypeReturnExpr:
63177191 return ir_gen_return(irb, scope, node, lval);
63187192 case NodeTypeFieldAccessExpr:
6319 return ir_gen_field_access(irb, scope, node, lval);
7193 {
7194 IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
7195 if (ptr_instruction == irb->codegen->invalid_instruction)
7196 return ptr_instruction;
7197 if (lval == LValPtr)
7198 return ptr_instruction;
7199
7200 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
7201 }
7202 case NodeTypePtrDeref: {
7203 AstNode *expr_node = node->data.ptr_deref_expr.target;
7204 IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
7205 if (value == irb->codegen->invalid_instruction)
7206 return value;
7207
7208 return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
7209 }
7210 case NodeTypeUnwrapOptional: {
7211 AstNode *expr_node = node->data.unwrap_optional.expr;
7212
7213 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
7214 if (maybe_ptr == irb->codegen->invalid_instruction)
7215 return irb->codegen->invalid_instruction;
7216
7217 IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
7218 if (lval == LValPtr)
7219 return unwrapped_ptr;
7220
7221 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
7222 }
63207223 case NodeTypeThisLiteral:
63217224 return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
63227225 case NodeTypeBoolLiteral:
63237226 return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
63247227 case NodeTypeArrayType:
63257228 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);
7229 case NodeTypePointerType:
7230 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval);
63267231 case NodeTypePromiseType:
63277232 return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval);
63287233 case NodeTypeStringLiteral:
......@@ -6380,7 +7285,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc
63807285}
63817286
63827287static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) {
6383 return ir_gen_node_extra(irb, node, scope, LVAL_NONE);
7288 return ir_gen_node_extra(irb, node, scope, LValNone);
63847289}
63857290
63867291static void invalidate_exec(IrExecutable *exec) {
......@@ -6434,15 +7339,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
64347339 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
64357340 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
64367341 ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
6437 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
7342 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
64387343
64397344 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
64407345 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
64417346 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
6442 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
7347 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
64437348 ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
6444 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node,
6445 await_handle_var, false, false);
7349 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
64467350
64477351 u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
64487352 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
......@@ -6473,10 +7377,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
64737377 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
64747378 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
64757379
6476 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6477 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6478 awaiter_handle_field_name);
6479 ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value);
7380 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
7381 irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
7382 atomic_state_field_name);
7383 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
7384 ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero);
64807385 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
64817386 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
64827387 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
......@@ -6494,7 +7399,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
64947399 // coordinate with builtin.zig
64957400 Buf *index_name = buf_create_from_str("index");
64967401 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);
64987402 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
64997403
65007404 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
......@@ -6511,7 +7415,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65117415 irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
65127416 }
65137417
6514 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE);
7418 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone);
65157419 assert(result);
65167420 if (irb->exec->invalid)
65177421 return false;
......@@ -6533,7 +7437,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65337437 cases[0].block = invalid_resume_block;
65347438 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
65357439 cases[1].block = irb->exec->coro_final_cleanup_block;
6536 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false);
7440 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
65377441
65387442 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
65397443 ir_build_coro_end(irb, scope, node);
......@@ -6544,9 +7448,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65447448
65457449 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);
65467450 if (type_has_bits(return_type)) {
7451 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
7452 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
7453 false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8),
7454 0, 0));
65477455 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
6548 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr);
6549 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type,
7456 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
7457 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
65507458 irb->exec->coro_result_field_ptr);
65517459 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
65527460 fn_entry->type_entry->data.fn.fn_type_id.return_type);
......@@ -6559,6 +7467,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65597467 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
65607468 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
65617469 }
7470 // Before we destroy the coroutine frame, we need to load the target promise into
7471 // a register or local variable which does not get spilled into the frame,
7472 // otherwise llvm tries to access memory inside the destroyed frame.
7473 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
7474 irb->exec->await_handle_var_ptr, false);
7475 IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
65627476 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
65637477
65647478 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
......@@ -6573,6 +7487,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65737487 incoming_values[1] = const_bool_true;
65747488 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
65757489
7490 IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2);
7491 IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2);
7492 merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
7493 merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node);
7494 merge_incoming_blocks[1] = irb->exec->coro_normal_final;
7495 merge_incoming_values[1] = await_handle_in_block;
7496 IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values);
7497
65767498 Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
65777499 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
65787500 ImplicitAllocatorIdLocalVar);
......@@ -6580,25 +7502,26 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65807502 IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
65817503 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
65827504 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
6583 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_mem_ptr_maybe);
7505 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
7506 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
7507 false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8),
7508 0, 0));
7509 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
65847510 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
6585 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var, true, false);
7511 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
65867512 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
65877513 IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false);
65887514 size_t arg_count = 2;
65897515 IrInstruction **args = allocate<IrInstruction *>(arg_count);
65907516 args[0] = implicit_allocator_ptr; // self
65917517 args[1] = mem_slice; // old_mem
6592 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr);
7518 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
65937519
65947520 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
65957521 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
65967522
65977523 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6598 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
6599 irb->exec->await_handle_var_ptr, false);
6600 IrInstruction *awaiter_handle = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
6601 ir_build_coro_resume(irb, scope, node, awaiter_handle);
7524 ir_gen_resume_target(irb, scope, node, awaiter_handle);
66027525 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
66037526 }
66047527
......@@ -6671,17 +7594,22 @@ static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *so
66717594}
66727595
66737596static bool const_val_fits_in_num_lit(ConstExprValue *const_val, TypeTableEntry *num_lit_type) {
6674 return ((num_lit_type->id == TypeTableEntryIdNumLitFloat &&
6675 (const_val->type->id == TypeTableEntryIdFloat || const_val->type->id == TypeTableEntryIdNumLitFloat)) ||
6676 (num_lit_type->id == TypeTableEntryIdNumLitInt &&
6677 (const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdNumLitInt)));
7597 return ((num_lit_type->id == TypeTableEntryIdComptimeFloat &&
7598 (const_val->type->id == TypeTableEntryIdFloat || const_val->type->id == TypeTableEntryIdComptimeFloat)) ||
7599 (num_lit_type->id == TypeTableEntryIdComptimeInt &&
7600 (const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdComptimeInt)));
66787601}
66797602
66807603static bool float_has_fraction(ConstExprValue *const_val) {
6681 if (const_val->type->id == TypeTableEntryIdNumLitFloat) {
7604 if (const_val->type->id == TypeTableEntryIdComptimeFloat) {
66827605 return bigfloat_has_fraction(&const_val->data.x_bigfloat);
66837606 } else if (const_val->type->id == TypeTableEntryIdFloat) {
66847607 switch (const_val->type->data.floating.bit_count) {
7608 case 16:
7609 {
7610 float16_t floored = f16_roundToInt(const_val->data.x_f16, softfloat_round_minMag, false);
7611 return !f16_eq(floored, const_val->data.x_f16);
7612 }
66857613 case 32:
66867614 return floorf(const_val->data.x_f32) != const_val->data.x_f32;
66877615 case 64:
......@@ -6701,10 +7629,13 @@ static bool float_has_fraction(ConstExprValue *const_val) {
67017629}
67027630
67037631static void float_append_buf(Buf *buf, ConstExprValue *const_val) {
6704 if (const_val->type->id == TypeTableEntryIdNumLitFloat) {
7632 if (const_val->type->id == TypeTableEntryIdComptimeFloat) {
67057633 bigfloat_append_buf(buf, &const_val->data.x_bigfloat);
67067634 } else if (const_val->type->id == TypeTableEntryIdFloat) {
67077635 switch (const_val->type->data.floating.bit_count) {
7636 case 16:
7637 buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16));
7638 break;
67087639 case 32:
67097640 buf_appendf(buf, "%f", const_val->data.x_f32);
67107641 break;
......@@ -6736,10 +7667,21 @@ static void float_append_buf(Buf *buf, ConstExprValue *const_val) {
67367667}
67377668
67387669static void float_init_bigint(BigInt *bigint, ConstExprValue *const_val) {
6739 if (const_val->type->id == TypeTableEntryIdNumLitFloat) {
7670 if (const_val->type->id == TypeTableEntryIdComptimeFloat) {
67407671 bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat);
67417672 } else if (const_val->type->id == TypeTableEntryIdFloat) {
67427673 switch (const_val->type->data.floating.bit_count) {
7674 case 16:
7675 {
7676 double x = zig_f16_to_double(const_val->data.x_f16);
7677 if (x >= 0) {
7678 bigint_init_unsigned(bigint, (uint64_t)x);
7679 } else {
7680 bigint_init_unsigned(bigint, (uint64_t)-x);
7681 bigint->is_negative = true;
7682 }
7683 break;
7684 }
67437685 case 32:
67447686 if (const_val->data.x_f32 >= 0) {
67457687 bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f32));
......@@ -6772,10 +7714,13 @@ static void float_init_bigint(BigInt *bigint, ConstExprValue *const_val) {
67727714}
67737715
67747716static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
6775 if (dest_val->type->id == TypeTableEntryIdNumLitFloat) {
7717 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
67767718 bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat);
67777719 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
67787720 switch (dest_val->type->data.floating.bit_count) {
7721 case 16:
7722 dest_val->data.x_f16 = bigfloat_to_f16(bigfloat);
7723 break;
67797724 case 32:
67807725 dest_val->data.x_f32 = bigfloat_to_f32(bigfloat);
67817726 break;
......@@ -6793,11 +7738,39 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
67937738 }
67947739}
67957740
7741static void float_init_f16(ConstExprValue *dest_val, float16_t x) {
7742 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
7743 bigfloat_init_16(&dest_val->data.x_bigfloat, x);
7744 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7745 switch (dest_val->type->data.floating.bit_count) {
7746 case 16:
7747 dest_val->data.x_f16 = x;
7748 break;
7749 case 32:
7750 dest_val->data.x_f32 = zig_f16_to_double(x);
7751 break;
7752 case 64:
7753 dest_val->data.x_f64 = zig_f16_to_double(x);
7754 break;
7755 case 128:
7756 f16_to_f128M(x, &dest_val->data.x_f128);
7757 break;
7758 default:
7759 zig_unreachable();
7760 }
7761 } else {
7762 zig_unreachable();
7763 }
7764}
7765
67967766static void float_init_f32(ConstExprValue *dest_val, float x) {
6797 if (dest_val->type->id == TypeTableEntryIdNumLitFloat) {
7767 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
67987768 bigfloat_init_32(&dest_val->data.x_bigfloat, x);
67997769 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
68007770 switch (dest_val->type->data.floating.bit_count) {
7771 case 16:
7772 dest_val->data.x_f16 = zig_double_to_f16(x);
7773 break;
68017774 case 32:
68027775 dest_val->data.x_f32 = x;
68037776 break;
......@@ -6820,10 +7793,13 @@ static void float_init_f32(ConstExprValue *dest_val, float x) {
68207793}
68217794
68227795static void float_init_f64(ConstExprValue *dest_val, double x) {
6823 if (dest_val->type->id == TypeTableEntryIdNumLitFloat) {
7796 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
68247797 bigfloat_init_64(&dest_val->data.x_bigfloat, x);
68257798 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
68267799 switch (dest_val->type->data.floating.bit_count) {
7800 case 16:
7801 dest_val->data.x_f16 = zig_double_to_f16(x);
7802 break;
68277803 case 32:
68287804 dest_val->data.x_f32 = x;
68297805 break;
......@@ -6846,10 +7822,13 @@ static void float_init_f64(ConstExprValue *dest_val, double x) {
68467822}
68477823
68487824static void float_init_f128(ConstExprValue *dest_val, float128_t x) {
6849 if (dest_val->type->id == TypeTableEntryIdNumLitFloat) {
7825 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
68507826 bigfloat_init_128(&dest_val->data.x_bigfloat, x);
68517827 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
68527828 switch (dest_val->type->data.floating.bit_count) {
7829 case 16:
7830 dest_val->data.x_f16 = f128M_to_f16(&x);
7831 break;
68537832 case 32:
68547833 {
68557834 float32_t f32_val = f128M_to_f32(&x);
......@@ -6876,10 +7855,13 @@ static void float_init_f128(ConstExprValue *dest_val, float128_t x) {
68767855}
68777856
68787857static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val) {
6879 if (src_val->type->id == TypeTableEntryIdNumLitFloat) {
7858 if (src_val->type->id == TypeTableEntryIdComptimeFloat) {
68807859 float_init_bigfloat(dest_val, &src_val->data.x_bigfloat);
68817860 } else if (src_val->type->id == TypeTableEntryIdFloat) {
68827861 switch (src_val->type->data.floating.bit_count) {
7862 case 16:
7863 float_init_f16(dest_val, src_val->data.x_f16);
7864 break;
68837865 case 32:
68847866 float_init_f32(dest_val, src_val->data.x_f32);
68857867 break;
......@@ -6899,10 +7881,18 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val)
68997881
69007882static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {
69017883 assert(op1->type == op2->type);
6902 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
7884 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
69037885 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);
69047886 } else if (op1->type->id == TypeTableEntryIdFloat) {
69057887 switch (op1->type->data.floating.bit_count) {
7888 case 16:
7889 if (f16_lt(op1->data.x_f16, op2->data.x_f16)) {
7890 return CmpLT;
7891 } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) {
7892 return CmpGT;
7893 } else {
7894 return CmpEQ;
7895 }
69067896 case 32:
69077897 if (op1->data.x_f32 > op2->data.x_f32) {
69087898 return CmpGT;
......@@ -6936,10 +7926,21 @@ static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {
69367926}
69377927
69387928static Cmp float_cmp_zero(ConstExprValue *op) {
6939 if (op->type->id == TypeTableEntryIdNumLitFloat) {
7929 if (op->type->id == TypeTableEntryIdComptimeFloat) {
69407930 return bigfloat_cmp_zero(&op->data.x_bigfloat);
69417931 } else if (op->type->id == TypeTableEntryIdFloat) {
69427932 switch (op->type->data.floating.bit_count) {
7933 case 16:
7934 {
7935 const float16_t zero = zig_double_to_f16(0);
7936 if (f16_lt(op->data.x_f16, zero)) {
7937 return CmpLT;
7938 } else if (f16_lt(zero, op->data.x_f16)) {
7939 return CmpGT;
7940 } else {
7941 return CmpEQ;
7942 }
7943 }
69437944 case 32:
69447945 if (op->data.x_f32 < 0.0) {
69457946 return CmpLT;
......@@ -6977,10 +7978,13 @@ static Cmp float_cmp_zero(ConstExprValue *op) {
69777978static void float_add(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
69787979 assert(op1->type == op2->type);
69797980 out_val->type = op1->type;
6980 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
7981 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
69817982 bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
69827983 } else if (op1->type->id == TypeTableEntryIdFloat) {
69837984 switch (op1->type->data.floating.bit_count) {
7985 case 16:
7986 out_val->data.x_f16 = f16_add(op1->data.x_f16, op2->data.x_f16);
7987 return;
69847988 case 32:
69857989 out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32;
69867990 return;
......@@ -7001,10 +8005,13 @@ static void float_add(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
70018005static void float_sub(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
70028006 assert(op1->type == op2->type);
70038007 out_val->type = op1->type;
7004 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8008 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
70058009 bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
70068010 } else if (op1->type->id == TypeTableEntryIdFloat) {
70078011 switch (op1->type->data.floating.bit_count) {
8012 case 16:
8013 out_val->data.x_f16 = f16_sub(op1->data.x_f16, op2->data.x_f16);
8014 return;
70088015 case 32:
70098016 out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32;
70108017 return;
......@@ -7025,10 +8032,13 @@ static void float_sub(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
70258032static void float_mul(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
70268033 assert(op1->type == op2->type);
70278034 out_val->type = op1->type;
7028 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8035 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
70298036 bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
70308037 } else if (op1->type->id == TypeTableEntryIdFloat) {
70318038 switch (op1->type->data.floating.bit_count) {
8039 case 16:
8040 out_val->data.x_f16 = f16_mul(op1->data.x_f16, op2->data.x_f16);
8041 return;
70328042 case 32:
70338043 out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32;
70348044 return;
......@@ -7049,10 +8059,13 @@ static void float_mul(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
70498059static void float_div(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
70508060 assert(op1->type == op2->type);
70518061 out_val->type = op1->type;
7052 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8062 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
70538063 bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
70548064 } else if (op1->type->id == TypeTableEntryIdFloat) {
70558065 switch (op1->type->data.floating.bit_count) {
8066 case 16:
8067 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
8068 return;
70568069 case 32:
70578070 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
70588071 return;
......@@ -7073,25 +8086,19 @@ static void float_div(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
70738086static void float_div_trunc(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
70748087 assert(op1->type == op2->type);
70758088 out_val->type = op1->type;
7076 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8089 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
70778090 bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
70788091 } else if (op1->type->id == TypeTableEntryIdFloat) {
70798092 switch (op1->type->data.floating.bit_count) {
8093 case 16:
8094 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
8095 out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_minMag, false);
8096 return;
70808097 case 32:
7081 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
7082 if (out_val->data.x_f32 >= 0.0) {
7083 out_val->data.x_f32 = floorf(out_val->data.x_f32);
7084 } else {
7085 out_val->data.x_f32 = ceilf(out_val->data.x_f32);
7086 }
8098 out_val->data.x_f32 = truncf(op1->data.x_f32 / op2->data.x_f32);
70878099 return;
70888100 case 64:
7089 out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64;
7090 if (out_val->data.x_f64 >= 0.0) {
7091 out_val->data.x_f64 = floor(out_val->data.x_f64);
7092 } else {
7093 out_val->data.x_f64 = ceil(out_val->data.x_f64);
7094 }
8101 out_val->data.x_f64 = trunc(op1->data.x_f64 / op2->data.x_f64);
70958102 return;
70968103 case 128:
70978104 f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
......@@ -7108,10 +8115,14 @@ static void float_div_trunc(ConstExprValue *out_val, ConstExprValue *op1, ConstE
71088115static void float_div_floor(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
71098116 assert(op1->type == op2->type);
71108117 out_val->type = op1->type;
7111 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8118 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
71128119 bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
71138120 } else if (op1->type->id == TypeTableEntryIdFloat) {
71148121 switch (op1->type->data.floating.bit_count) {
8122 case 16:
8123 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
8124 out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_min, false);
8125 return;
71158126 case 32:
71168127 out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32);
71178128 return;
......@@ -7133,10 +8144,13 @@ static void float_div_floor(ConstExprValue *out_val, ConstExprValue *op1, ConstE
71338144static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
71348145 assert(op1->type == op2->type);
71358146 out_val->type = op1->type;
7136 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8147 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
71378148 bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
71388149 } else if (op1->type->id == TypeTableEntryIdFloat) {
71398150 switch (op1->type->data.floating.bit_count) {
8151 case 16:
8152 out_val->data.x_f16 = f16_rem(op1->data.x_f16, op2->data.x_f16);
8153 return;
71408154 case 32:
71418155 out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32);
71428156 return;
......@@ -7154,13 +8168,34 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
71548168 }
71558169}
71568170
8171// c = a - b * trunc(a / b)
8172static float16_t zig_f16_mod(float16_t a, float16_t b) {
8173 float16_t c;
8174 c = f16_div(a, b);
8175 c = f16_roundToInt(c, softfloat_round_min, true);
8176 c = f16_mul(b, c);
8177 c = f16_sub(a, c);
8178 return c;
8179}
8180
8181// c = a - b * trunc(a / b)
8182static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t* c) {
8183 f128M_div(a, b, c);
8184 f128M_roundToInt(c, softfloat_round_min, true, c);
8185 f128M_mul(b, c, c);
8186 f128M_sub(a, c, c);
8187}
8188
71578189static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
71588190 assert(op1->type == op2->type);
71598191 out_val->type = op1->type;
7160 if (op1->type->id == TypeTableEntryIdNumLitFloat) {
8192 if (op1->type->id == TypeTableEntryIdComptimeFloat) {
71618193 bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
71628194 } else if (op1->type->id == TypeTableEntryIdFloat) {
71638195 switch (op1->type->data.floating.bit_count) {
8196 case 16:
8197 out_val->data.x_f16 = zig_f16_mod(op1->data.x_f16, op2->data.x_f16);
8198 return;
71648199 case 32:
71658200 out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32);
71668201 return;
......@@ -7168,9 +8203,7 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
71688203 out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64);
71698204 return;
71708205 case 128:
7171 f128M_rem(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
7172 f128M_add(&out_val->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
7173 f128M_rem(&out_val->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
8206 zig_f128M_mod(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
71748207 return;
71758208 default:
71768209 zig_unreachable();
......@@ -7182,10 +8215,16 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
71828215
71838216static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
71848217 out_val->type = op->type;
7185 if (op->type->id == TypeTableEntryIdNumLitFloat) {
8218 if (op->type->id == TypeTableEntryIdComptimeFloat) {
71868219 bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat);
71878220 } else if (op->type->id == TypeTableEntryIdFloat) {
71888221 switch (op->type->data.floating.bit_count) {
8222 case 16:
8223 {
8224 const float16_t zero = zig_double_to_f16(0);
8225 out_val->data.x_f16 = f16_sub(zero, op->data.x_f16);
8226 return;
8227 }
71898228 case 32:
71908229 out_val->data.x_f32 = -op->data.x_f32;
71918230 return;
......@@ -7208,6 +8247,9 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
72088247void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
72098248 if (op->type->id == TypeTableEntryIdFloat) {
72108249 switch (op->type->data.floating.bit_count) {
8250 case 16:
8251 memcpy(buf, &op->data.x_f16, 2); // TODO wrong when compiler is big endian
8252 return;
72118253 case 32:
72128254 memcpy(buf, &op->data.x_f32, 4); // TODO wrong when compiler is big endian
72138255 return;
......@@ -7228,6 +8270,9 @@ void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
72288270void float_read_ieee597(ConstExprValue *val, uint8_t *buf, bool is_big_endian) {
72298271 if (val->type->id == TypeTableEntryIdFloat) {
72308272 switch (val->type->data.floating.bit_count) {
8273 case 16:
8274 memcpy(&val->data.x_f16, buf, 2); // TODO wrong when compiler is big endian
8275 return;
72318276 case 32:
72328277 memcpy(&val->data.x_f32, buf, 4); // TODO wrong when compiler is big endian
72338278 return;
......@@ -7256,9 +8301,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
72568301 assert(const_val->special != ConstValSpecialRuntime);
72578302
72588303 bool const_val_is_int = (const_val->type->id == TypeTableEntryIdInt ||
7259 const_val->type->id == TypeTableEntryIdNumLitInt);
8304 const_val->type->id == TypeTableEntryIdComptimeInt);
72608305 bool const_val_is_float = (const_val->type->id == TypeTableEntryIdFloat ||
7261 const_val->type->id == TypeTableEntryIdNumLitFloat);
8306 const_val->type->id == TypeTableEntryIdComptimeFloat);
72628307 if (other_type->id == TypeTableEntryIdFloat) {
72638308 return true;
72648309 } else if (other_type->id == TypeTableEntryIdInt && const_val_is_int) {
......@@ -7278,7 +8323,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
72788323 }
72798324 } else if (const_val_fits_in_num_lit(const_val, other_type)) {
72808325 return true;
7281 } else if (other_type->id == TypeTableEntryIdMaybe) {
8326 } else if (other_type->id == TypeTableEntryIdOptional) {
72828327 TypeTableEntry *child_type = other_type->data.maybe.child_type;
72838328 if (const_val_fits_in_num_lit(const_val, child_type)) {
72848329 return true;
......@@ -7302,7 +8347,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
73028347 return true;
73038348 }
73048349 }
7305 if (explicit_cast && (other_type->id == TypeTableEntryIdInt || other_type->id == TypeTableEntryIdNumLitInt) &&
8350 if (explicit_cast && (other_type->id == TypeTableEntryIdInt || other_type->id == TypeTableEntryIdComptimeInt) &&
73068351 const_val_is_float)
73078352 {
73088353 if (float_has_fraction(const_val)) {
......@@ -7315,7 +8360,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
73158360 buf_ptr(&other_type->name)));
73168361 return false;
73178362 } else {
7318 if (other_type->id == TypeTableEntryIdNumLitInt) {
8363 if (other_type->id == TypeTableEntryIdComptimeInt) {
73198364 return true;
73208365 } else {
73218366 BigInt bigint;
......@@ -7356,38 +8401,16 @@ static bool slice_is_const(TypeTableEntry *type) {
73568401 return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
73578402}
73588403
7359static bool resolve_inferred_error_set(IrAnalyze *ira, TypeTableEntry *err_set_type, AstNode *source_node) {
7360 assert(err_set_type->id == TypeTableEntryIdErrorSet);
7361 FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
7362 if (infer_fn != nullptr) {
7363 if (infer_fn->anal_state == FnAnalStateInvalid) {
7364 return false;
7365 } else if (infer_fn->anal_state == FnAnalStateReady) {
7366 analyze_fn_body(ira->codegen, infer_fn);
7367 if (err_set_type->data.error_set.infer_fn != nullptr) {
7368 assert(ira->codegen->errors.length != 0);
7369 return false;
7370 }
7371 } else {
7372 ir_add_error_node(ira, source_node,
7373 buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
7374 buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
7375 return false;
7376 }
7377 }
7378 return true;
7379}
7380
73818404static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry *set1, TypeTableEntry *set2,
73828405 AstNode *source_node)
73838406{
73848407 assert(set1->id == TypeTableEntryIdErrorSet);
73858408 assert(set2->id == TypeTableEntryIdErrorSet);
73868409
7387 if (!resolve_inferred_error_set(ira, set1, source_node)) {
8410 if (!resolve_inferred_error_set(ira->codegen, set1, source_node)) {
73888411 return ira->codegen->builtin_types.entry_invalid;
73898412 }
7390 if (!resolve_inferred_error_set(ira, set2, source_node)) {
8413 if (!resolve_inferred_error_set(ira->codegen, set2, source_node)) {
73918414 return ira->codegen->builtin_types.entry_invalid;
73928415 }
73938416 if (type_is_global_error_set(set1)) {
......@@ -7433,89 +8456,122 @@ static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry
74338456}
74348457
74358458
7436static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry *expected_type,
7437 TypeTableEntry *actual_type, AstNode *source_node)
8459static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry *wanted_type,
8460 TypeTableEntry *actual_type, AstNode *source_node, bool wanted_is_mutable)
74388461{
74398462 CodeGen *g = ira->codegen;
74408463 ConstCastOnly result = {};
74418464 result.id = ConstCastResultIdOk;
74428465
7443 if (expected_type == actual_type)
8466 if (wanted_type == actual_type)
74448467 return result;
74458468
7446 // pointer const
7447 if (expected_type->id == TypeTableEntryIdPointer &&
7448 actual_type->id == TypeTableEntryIdPointer &&
7449 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
7450 (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
7451 actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
7452 actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count &&
7453 actual_type->data.pointer.alignment >= expected_type->data.pointer.alignment)
8469 // * and [*] can do a const-cast-only to ?* and ?[*], respectively
8470 // but not if there is a mutable parent pointer
8471 // and not if the pointer is zero bits
8472 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
8473 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
8474 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))
74548475 {
7455 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.pointer.child_type, actual_type->data.pointer.child_type, source_node);
8476 ConstCastOnly child = types_match_const_cast_only(ira,
8477 wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);
74568478 if (child.id != ConstCastResultIdOk) {
7457 result.id = ConstCastResultIdPointerChild;
7458 result.data.pointer_child = allocate_nonzero<ConstCastOnly>(1);
7459 *result.data.pointer_child = child;
8479 result.id = ConstCastResultIdNullWrapPtr;
8480 result.data.null_wrap_ptr_child = allocate_nonzero<ConstCastOnly>(1);
8481 *result.data.null_wrap_ptr_child = child;
74608482 }
74618483 return result;
74628484 }
74638485
8486 // pointer const
8487 if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {
8488 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
8489 actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
8490 if (child.id != ConstCastResultIdOk) {
8491 result.id = ConstCastResultIdPointerChild;
8492 result.data.pointer_mismatch = allocate_nonzero<ConstCastPointerMismatch>(1);
8493 result.data.pointer_mismatch->child = child;
8494 result.data.pointer_mismatch->wanted_child = wanted_type->data.pointer.child_type;
8495 result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type;
8496 return result;
8497 }
8498 if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
8499 (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
8500 (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
8501 actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset &&
8502 actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count &&
8503 actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment)
8504 {
8505 return result;
8506 }
8507 }
8508
74648509 // slice const
7465 if (is_slice(expected_type) && is_slice(actual_type)) {
8510 if (is_slice(wanted_type) && is_slice(actual_type)) {
74668511 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
7467 TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
7468 if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
7469 (!actual_ptr_type->data.pointer.is_volatile || expected_ptr_type->data.pointer.is_volatile) &&
7470 actual_ptr_type->data.pointer.bit_offset == expected_ptr_type->data.pointer.bit_offset &&
7471 actual_ptr_type->data.pointer.unaligned_bit_count == expected_ptr_type->data.pointer.unaligned_bit_count &&
7472 actual_ptr_type->data.pointer.alignment >= expected_ptr_type->data.pointer.alignment)
8512 TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
8513 if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) &&
8514 (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) &&
8515 actual_ptr_type->data.pointer.bit_offset == wanted_ptr_type->data.pointer.bit_offset &&
8516 actual_ptr_type->data.pointer.unaligned_bit_count == wanted_ptr_type->data.pointer.unaligned_bit_count &&
8517 actual_ptr_type->data.pointer.alignment >= wanted_ptr_type->data.pointer.alignment)
74738518 {
7474 ConstCastOnly child = types_match_const_cast_only(ira, expected_ptr_type->data.pointer.child_type,
7475 actual_ptr_type->data.pointer.child_type, source_node);
8519 ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type,
8520 actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
74768521 if (child.id != ConstCastResultIdOk) {
74778522 result.id = ConstCastResultIdSliceChild;
7478 result.data.slice_child = allocate_nonzero<ConstCastOnly>(1);
7479 *result.data.slice_child = child;
8523 result.data.slice_mismatch = allocate_nonzero<ConstCastSliceMismatch>(1);
8524 result.data.slice_mismatch->child = child;
8525 result.data.slice_mismatch->actual_child = actual_ptr_type->data.pointer.child_type;
8526 result.data.slice_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type;
74808527 }
74818528 return result;
74828529 }
74838530 }
74848531
74858532 // maybe
7486 if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) {
7487 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type, source_node);
8533 if (wanted_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdOptional) {
8534 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type,
8535 actual_type->data.maybe.child_type, source_node, wanted_is_mutable);
74888536 if (child.id != ConstCastResultIdOk) {
7489 result.id = ConstCastResultIdNullableChild;
7490 result.data.nullable_child = allocate_nonzero<ConstCastOnly>(1);
7491 *result.data.nullable_child = child;
8537 result.id = ConstCastResultIdOptionalChild;
8538 result.data.optional = allocate_nonzero<ConstCastOptionalMismatch>(1);
8539 result.data.optional->child = child;
8540 result.data.optional->wanted_child = wanted_type->data.maybe.child_type;
8541 result.data.optional->actual_child = actual_type->data.maybe.child_type;
74928542 }
74938543 return result;
74948544 }
74958545
74968546 // error union
7497 if (expected_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
7498 ConstCastOnly payload_child = types_match_const_cast_only(ira, expected_type->data.error_union.payload_type, actual_type->data.error_union.payload_type, source_node);
8547 if (wanted_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
8548 ConstCastOnly payload_child = types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type,
8549 actual_type->data.error_union.payload_type, source_node, wanted_is_mutable);
74998550 if (payload_child.id != ConstCastResultIdOk) {
75008551 result.id = ConstCastResultIdErrorUnionPayload;
7501 result.data.error_union_payload = allocate_nonzero<ConstCastOnly>(1);
7502 *result.data.error_union_payload = payload_child;
8552 result.data.error_union_payload = allocate_nonzero<ConstCastErrUnionPayloadMismatch>(1);
8553 result.data.error_union_payload->child = payload_child;
8554 result.data.error_union_payload->wanted_payload = wanted_type->data.error_union.payload_type;
8555 result.data.error_union_payload->actual_payload = actual_type->data.error_union.payload_type;
75038556 return result;
75048557 }
7505 ConstCastOnly error_set_child = types_match_const_cast_only(ira, expected_type->data.error_union.err_set_type, actual_type->data.error_union.err_set_type, source_node);
8558 ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type,
8559 actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable);
75068560 if (error_set_child.id != ConstCastResultIdOk) {
75078561 result.id = ConstCastResultIdErrorUnionErrorSet;
7508 result.data.error_union_error_set = allocate_nonzero<ConstCastOnly>(1);
7509 *result.data.error_union_error_set = error_set_child;
8562 result.data.error_union_error_set = allocate_nonzero<ConstCastErrUnionErrSetMismatch>(1);
8563 result.data.error_union_error_set->child = error_set_child;
8564 result.data.error_union_error_set->wanted_err_set = wanted_type->data.error_union.err_set_type;
8565 result.data.error_union_error_set->actual_err_set = actual_type->data.error_union.err_set_type;
75108566 return result;
75118567 }
75128568 return result;
75138569 }
75148570
75158571 // error set
7516 if (expected_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
8572 if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
75178573 TypeTableEntry *contained_set = actual_type;
7518 TypeTableEntry *container_set = expected_type;
8574 TypeTableEntry *container_set = wanted_type;
75198575
75208576 // if the container set is inferred, then this will always work.
75218577 if (container_set->data.error_set.infer_fn != nullptr) {
......@@ -7526,7 +8582,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
75268582 return result;
75278583 }
75288584
7529 if (!resolve_inferred_error_set(ira, contained_set, source_node)) {
8585 if (!resolve_inferred_error_set(ira->codegen, contained_set, source_node)) {
75308586 result.id = ConstCastResultIdUnresolvedInferredErrSet;
75318587 return result;
75328588 }
......@@ -7548,44 +8604,46 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
75488604 if (error_entry == nullptr) {
75498605 if (result.id == ConstCastResultIdOk) {
75508606 result.id = ConstCastResultIdErrSet;
8607 result.data.error_set_mismatch = allocate<ConstCastErrSetMismatch>(1);
75518608 }
7552 result.data.error_set.missing_errors.append(contained_error_entry);
8609 result.data.error_set_mismatch->missing_errors.append(contained_error_entry);
75538610 }
75548611 }
75558612 free(errors);
75568613 return result;
75578614 }
75588615
7559 if (expected_type == ira->codegen->builtin_types.entry_promise &&
8616 if (wanted_type == ira->codegen->builtin_types.entry_promise &&
75608617 actual_type->id == TypeTableEntryIdPromise)
75618618 {
75628619 return result;
75638620 }
75648621
75658622 // fn
7566 if (expected_type->id == TypeTableEntryIdFn &&
8623 if (wanted_type->id == TypeTableEntryIdFn &&
75678624 actual_type->id == TypeTableEntryIdFn)
75688625 {
7569 if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
8626 if (wanted_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
75708627 result.id = ConstCastResultIdFnAlign;
75718628 return result;
75728629 }
7573 if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
8630 if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
75748631 result.id = ConstCastResultIdFnCC;
75758632 return result;
75768633 }
7577 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
8634 if (wanted_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
75788635 result.id = ConstCastResultIdFnVarArgs;
75798636 return result;
75808637 }
7581 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
8638 if (wanted_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
75828639 result.id = ConstCastResultIdFnIsGeneric;
75838640 return result;
75848641 }
7585 if (!expected_type->data.fn.is_generic &&
8642 if (!wanted_type->data.fn.is_generic &&
75868643 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable)
75878644 {
7588 ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.fn.fn_type_id.return_type, actual_type->data.fn.fn_type_id.return_type, source_node);
8645 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.fn.fn_type_id.return_type,
8646 actual_type->data.fn.fn_type_id.return_type, source_node, false);
75898647 if (child.id != ConstCastResultIdOk) {
75908648 result.id = ConstCastResultIdFnReturnType;
75918649 result.data.return_type = allocate_nonzero<ConstCastOnly>(1);
......@@ -7593,9 +8651,11 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
75938651 return result;
75948652 }
75958653 }
7596 if (!expected_type->data.fn.is_generic && expected_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
7597 ConstCastOnly child = types_match_const_cast_only(ira, actual_type->data.fn.fn_type_id.async_allocator_type,
7598 expected_type->data.fn.fn_type_id.async_allocator_type, source_node);
8654 if (!wanted_type->data.fn.is_generic && wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
8655 ConstCastOnly child = types_match_const_cast_only(ira,
8656 actual_type->data.fn.fn_type_id.async_allocator_type,
8657 wanted_type->data.fn.fn_type_id.async_allocator_type,
8658 source_node, false);
75998659 if (child.id != ConstCastResultIdOk) {
76008660 result.id = ConstCastResultIdAsyncAllocatorType;
76018661 result.data.async_allocator_type = allocate_nonzero<ConstCastOnly>(1);
......@@ -7603,22 +8663,23 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
76038663 return result;
76048664 }
76058665 }
7606 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
8666 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
76078667 result.id = ConstCastResultIdFnArgCount;
76088668 return result;
76098669 }
7610 if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
8670 if (wanted_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
76118671 result.id = ConstCastResultIdFnGenericArgCount;
76128672 return result;
76138673 }
7614 assert(expected_type->data.fn.is_generic ||
7615 expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
7616 for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
8674 assert(wanted_type->data.fn.is_generic ||
8675 wanted_type->data.fn.fn_type_id.next_param_index == wanted_type->data.fn.fn_type_id.param_count);
8676 for (size_t i = 0; i < wanted_type->data.fn.fn_type_id.next_param_index; i += 1) {
76178677 // note it's reversed for parameters
76188678 FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
7619 FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
8679 FnTypeParamInfo *expected_param_info = &wanted_type->data.fn.fn_type_id.param_info[i];
76208680
7621 ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, expected_param_info->type, source_node);
8681 ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type,
8682 expected_param_info->type, source_node, false);
76228683 if (arg_child.id != ConstCastResultIdOk) {
76238684 result.id = ConstCastResultIdFnArg;
76248685 result.data.fn_arg.arg_index = i;
......@@ -7637,325 +8698,63 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
76378698 }
76388699
76398700 result.id = ConstCastResultIdType;
8701 result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1);
8702 result.data.type_mismatch->wanted_type = wanted_type;
8703 result.data.type_mismatch->actual_type = actual_type;
76408704 return result;
76418705}
76428706
7643enum ImplicitCastMatchResult {
7644 ImplicitCastMatchResultNo,
7645 ImplicitCastMatchResultYes,
7646 ImplicitCastMatchResultReportedError,
7647};
7648
7649static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type,
7650 TypeTableEntry *actual_type, IrInstruction *value)
7651{
7652 AstNode *source_node = value->source_node;
7653 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, expected_type, actual_type, source_node);
7654 if (const_cast_result.id == ConstCastResultIdOk) {
7655 return ImplicitCastMatchResultYes;
7656 }
7657
7658 // if we got here with error sets, make an error showing the incompatibilities
7659 ZigList<ErrorTableEntry *> *missing_errors = nullptr;
7660 if (const_cast_result.id == ConstCastResultIdErrSet) {
7661 missing_errors = &const_cast_result.data.error_set.missing_errors;
7662 }
7663 if (const_cast_result.id == ConstCastResultIdErrorUnionErrorSet) {
7664 if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSet) {
7665 missing_errors = &const_cast_result.data.error_union_error_set->data.error_set.missing_errors;
7666 } else if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSetGlobal) {
7667 ErrorMsg *msg = ir_add_error(ira, value,
7668 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
7669 add_error_note(ira->codegen, msg, value->source_node,
7670 buf_sprintf("unable to cast global error set into smaller set"));
7671 return ImplicitCastMatchResultReportedError;
7672 }
7673 } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) {
7674 ErrorMsg *msg = ir_add_error(ira, value,
7675 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
7676 add_error_note(ira->codegen, msg, value->source_node,
7677 buf_sprintf("unable to cast global error set into smaller set"));
7678 return ImplicitCastMatchResultReportedError;
7679 }
7680 if (missing_errors != nullptr) {
7681 ErrorMsg *msg = ir_add_error(ira, value,
7682 buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
7683 for (size_t i = 0; i < missing_errors->length; i += 1) {
7684 ErrorTableEntry *error_entry = missing_errors->at(i);
7685 add_error_note(ira->codegen, msg, error_entry->decl_node,
7686 buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name)));
7687 }
7688
7689 return ImplicitCastMatchResultReportedError;
7690 }
7691
7692 // implicit conversion from non maybe type to maybe type
7693 if (expected_type->id == TypeTableEntryIdMaybe &&
7694 ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type, value))
7695 {
7696 return ImplicitCastMatchResultYes;
7697 }
7698
7699 // implicit conversion from null literal to maybe type
7700 if (expected_type->id == TypeTableEntryIdMaybe &&
7701 actual_type->id == TypeTableEntryIdNullLit)
7702 {
7703 return ImplicitCastMatchResultYes;
7704 }
7705
7706 // implicit T to U!T
7707 if (expected_type->id == TypeTableEntryIdErrorUnion &&
7708 ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type, actual_type, value))
7709 {
7710 return ImplicitCastMatchResultYes;
7711 }
7712
7713 // implicit conversion from error set to error union type
7714 if (expected_type->id == TypeTableEntryIdErrorUnion &&
7715 actual_type->id == TypeTableEntryIdErrorSet)
7716 {
7717 return ImplicitCastMatchResultYes;
7718 }
7719
7720 // implicit conversion from T to U!?T
7721 if (expected_type->id == TypeTableEntryIdErrorUnion &&
7722 expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
7723 ir_types_match_with_implicit_cast(ira,
7724 expected_type->data.error_union.payload_type->data.maybe.child_type,
7725 actual_type, value))
7726 {
7727 return ImplicitCastMatchResultYes;
7728 }
7729
7730 // implicit widening conversion
7731 if (expected_type->id == TypeTableEntryIdInt &&
7732 actual_type->id == TypeTableEntryIdInt &&
7733 expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
7734 expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
7735 {
7736 return ImplicitCastMatchResultYes;
7737 }
7738
7739 // small enough unsigned ints can get casted to large enough signed ints
7740 if (expected_type->id == TypeTableEntryIdInt && expected_type->data.integral.is_signed &&
7741 actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
7742 expected_type->data.integral.bit_count > actual_type->data.integral.bit_count)
7743 {
7744 return ImplicitCastMatchResultYes;
7745 }
8707static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
8708 size_t old_errors_count = *errors_count;
8709 *errors_count = g->errors_by_index.length;
8710 *errors = reallocate(*errors, old_errors_count, *errors_count);
8711}
77468712
7747 // implicit float widening conversion
7748 if (expected_type->id == TypeTableEntryIdFloat &&
7749 actual_type->id == TypeTableEntryIdFloat &&
7750 expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
7751 {
7752 return ImplicitCastMatchResultYes;
8713static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, TypeTableEntry *expected_type, IrInstruction **instructions, size_t instruction_count) {
8714 assert(instruction_count >= 1);
8715 IrInstruction *prev_inst = instructions[0];
8716 if (type_is_invalid(prev_inst->value.type)) {
8717 return ira->codegen->builtin_types.entry_invalid;
77538718 }
8719 ErrorTableEntry **errors = nullptr;
8720 size_t errors_count = 0;
8721 TypeTableEntry *err_set_type = nullptr;
8722 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
8723 if (type_is_global_error_set(prev_inst->value.type)) {
8724 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
8725 } else {
8726 err_set_type = prev_inst->value.type;
8727 if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) {
8728 return ira->codegen->builtin_types.entry_invalid;
8729 }
8730 update_errors_helper(ira->codegen, &errors, &errors_count);
77548731
7755 // implicit [N]T to []const T
7756 if (is_slice(expected_type) && actual_type->id == TypeTableEntryIdArray) {
7757 TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
7758 assert(ptr_type->id == TypeTableEntryIdPointer);
7759
7760 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7761 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7762 {
7763 return ImplicitCastMatchResultYes;
8732 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
8733 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
8734 assert(errors[error_entry->value] == nullptr);
8735 errors[error_entry->value] = error_entry;
8736 }
77648737 }
77658738 }
77668739
7767 // implicit &const [N]T to []const T
7768 if (is_slice(expected_type) &&
7769 actual_type->id == TypeTableEntryIdPointer &&
7770 actual_type->data.pointer.is_const &&
7771 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
7772 {
7773 TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
7774 assert(ptr_type->id == TypeTableEntryIdPointer);
7775
7776 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
7777
7778 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
7779 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7780 {
7781 return ImplicitCastMatchResultYes;
7782 }
7783 }
8740 bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNull);
8741 bool convert_to_const_slice = false;
8742 for (size_t i = 1; i < instruction_count; i += 1) {
8743 IrInstruction *cur_inst = instructions[i];
8744 TypeTableEntry *cur_type = cur_inst->value.type;
8745 TypeTableEntry *prev_type = prev_inst->value.type;
77848746
7785 // implicit [N]T to &const []const T
7786 if (expected_type->id == TypeTableEntryIdPointer &&
7787 expected_type->data.pointer.is_const &&
7788 is_slice(expected_type->data.pointer.child_type) &&
7789 actual_type->id == TypeTableEntryIdArray)
7790 {
7791 TypeTableEntry *ptr_type =
7792 expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
7793 assert(ptr_type->id == TypeTableEntryIdPointer);
7794 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7795 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7796 {
7797 return ImplicitCastMatchResultYes;
8747 if (type_is_invalid(cur_type)) {
8748 return cur_type;
77988749 }
7799 }
78008750
7801 // implicit [N]T to ?[]const T
7802 if (expected_type->id == TypeTableEntryIdMaybe &&
7803 is_slice(expected_type->data.maybe.child_type) &&
7804 actual_type->id == TypeTableEntryIdArray)
7805 {
7806 TypeTableEntry *ptr_type =
7807 expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
7808 assert(ptr_type->id == TypeTableEntryIdPointer);
7809 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
7810 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
7811 {
7812 return ImplicitCastMatchResultYes;
8751 if (prev_type->id == TypeTableEntryIdUnreachable) {
8752 prev_inst = cur_inst;
8753 continue;
78138754 }
7814 }
7815
78168755
7817 // implicit number literal to typed number
7818 // implicit number literal to &const integer
7819 if (actual_type->id == TypeTableEntryIdNumLitFloat ||
7820 actual_type->id == TypeTableEntryIdNumLitInt)
7821 {
7822 if (expected_type->id == TypeTableEntryIdPointer &&
7823 expected_type->data.pointer.is_const)
7824 {
7825 if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type, false)) {
7826 return ImplicitCastMatchResultYes;
7827 } else {
7828 return ImplicitCastMatchResultReportedError;
7829 }
7830 } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type, false)) {
7831 return ImplicitCastMatchResultYes;
7832 } else {
7833 return ImplicitCastMatchResultReportedError;
7834 }
7835 }
7836
7837 // implicit typed number to integer or float literal.
7838 // works when the number is known
7839 if (value->value.special == ConstValSpecialStatic) {
7840 if (actual_type->id == TypeTableEntryIdInt && expected_type->id == TypeTableEntryIdNumLitInt) {
7841 return ImplicitCastMatchResultYes;
7842 } else if (actual_type->id == TypeTableEntryIdFloat && expected_type->id == TypeTableEntryIdNumLitFloat) {
7843 return ImplicitCastMatchResultYes;
7844 }
7845 }
7846
7847 // implicit union to its enum tag type
7848 if (expected_type->id == TypeTableEntryIdEnum && actual_type->id == TypeTableEntryIdUnion &&
7849 (actual_type->data.unionation.decl_node->data.container_decl.auto_enum ||
7850 actual_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
7851 {
7852 type_ensure_zero_bits_known(ira->codegen, actual_type);
7853 if (actual_type->data.unionation.tag_type == expected_type) {
7854 return ImplicitCastMatchResultYes;
7855 }
7856 }
7857
7858 // implicit enum to union which has the enum as the tag type
7859 if (expected_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
7860 (expected_type->data.unionation.decl_node->data.container_decl.auto_enum ||
7861 expected_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
7862 {
7863 type_ensure_zero_bits_known(ira->codegen, expected_type);
7864 if (expected_type->data.unionation.tag_type == actual_type) {
7865 return ImplicitCastMatchResultYes;
7866 }
7867 }
7868
7869 // implicit enum to &const union which has the enum as the tag type
7870 if (actual_type->id == TypeTableEntryIdEnum && expected_type->id == TypeTableEntryIdPointer) {
7871 TypeTableEntry *union_type = expected_type->data.pointer.child_type;
7872 if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
7873 union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
7874 {
7875 type_ensure_zero_bits_known(ira->codegen, union_type);
7876 if (union_type->data.unionation.tag_type == actual_type) {
7877 return ImplicitCastMatchResultYes;
7878 }
7879 }
7880 }
7881
7882 // implicit undefined literal to anything
7883 if (actual_type->id == TypeTableEntryIdUndefLit) {
7884 return ImplicitCastMatchResultYes;
7885 }
7886
7887 // implicitly take a const pointer to something
7888 if (!type_requires_comptime(actual_type)) {
7889 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
7890 if (types_match_const_cast_only(ira, expected_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
7891 return ImplicitCastMatchResultYes;
7892 }
7893 }
7894
7895 return ImplicitCastMatchResultNo;
7896}
7897
7898static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
7899 size_t old_errors_count = *errors_count;
7900 *errors_count = g->errors_by_index.length;
7901 *errors = reallocate(*errors, old_errors_count, *errors_count);
7902}
7903
7904static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
7905 assert(instruction_count >= 1);
7906 IrInstruction *prev_inst = instructions[0];
7907 if (type_is_invalid(prev_inst->value.type)) {
7908 return ira->codegen->builtin_types.entry_invalid;
7909 }
7910 ErrorTableEntry **errors = nullptr;
7911 size_t errors_count = 0;
7912 TypeTableEntry *err_set_type = nullptr;
7913 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
7914 if (type_is_global_error_set(prev_inst->value.type)) {
7915 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
7916 } else {
7917 err_set_type = prev_inst->value.type;
7918 if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
7919 return ira->codegen->builtin_types.entry_invalid;
7920 }
7921 update_errors_helper(ira->codegen, &errors, &errors_count);
7922
7923 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
7924 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
7925 assert(errors[error_entry->value] == nullptr);
7926 errors[error_entry->value] = error_entry;
7927 }
7928 }
7929 }
7930
7931 bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit);
7932 bool convert_to_const_slice = false;
7933 for (size_t i = 1; i < instruction_count; i += 1) {
7934 IrInstruction *cur_inst = instructions[i];
7935 TypeTableEntry *cur_type = cur_inst->value.type;
7936 TypeTableEntry *prev_type = prev_inst->value.type;
7937
7938 if (type_is_invalid(cur_type)) {
7939 return cur_type;
7940 }
7941
7942 if (prev_type->id == TypeTableEntryIdUnreachable) {
7943 prev_inst = cur_inst;
7944 continue;
7945 }
7946
7947 if (cur_type->id == TypeTableEntryIdUnreachable) {
7948 continue;
7949 }
7950
7951 if (prev_type->id == TypeTableEntryIdNullLit) {
7952 prev_inst = cur_inst;
7953 continue;
7954 }
7955
7956 if (cur_type->id == TypeTableEntryIdNullLit) {
7957 any_are_null = true;
7958 continue;
8756 if (cur_type->id == TypeTableEntryIdUnreachable) {
8757 continue;
79598758 }
79608759
79618760 if (prev_type->id == TypeTableEntryIdErrorSet) {
......@@ -7964,7 +8763,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
79648763 if (type_is_global_error_set(err_set_type)) {
79658764 continue;
79668765 }
7967 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
8766 if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
79688767 return ira->codegen->builtin_types.entry_invalid;
79698768 }
79708769 if (type_is_global_error_set(cur_type)) {
......@@ -8030,7 +8829,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
80308829 continue;
80318830 }
80328831 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
8033 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
8832 if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
80348833 return ira->codegen->builtin_types.entry_invalid;
80358834 }
80368835 if (type_is_global_error_set(cur_err_set_type)) {
......@@ -8093,7 +8892,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
80938892 if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
80948893 continue;
80958894 }
8096 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
8895 if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
80978896 return ira->codegen->builtin_types.entry_invalid;
80988897 }
80998898
......@@ -8138,9 +8937,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
81388937 TypeTableEntry *cur_payload_type = cur_type->data.error_union.payload_type;
81398938
81408939 bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type,
8141 source_node).id == ConstCastResultIdOk;
8940 source_node, false).id == ConstCastResultIdOk;
81428941 bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type,
8143 source_node).id == ConstCastResultIdOk;
8942 source_node, false).id == ConstCastResultIdOk;
81448943
81458944 if (const_cast_prev || const_cast_cur) {
81468945 if (const_cast_cur) {
......@@ -8150,11 +8949,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
81508949 TypeTableEntry *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
81518950 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
81528951
8153 if (!resolve_inferred_error_set(ira, prev_err_set_type, cur_inst->source_node)) {
8952 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
81548953 return ira->codegen->builtin_types.entry_invalid;
81558954 }
81568955
8157 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
8956 if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
81588957 return ira->codegen->builtin_types.entry_invalid;
81598958 }
81608959
......@@ -8217,11 +9016,21 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
82179016 }
82189017 }
82199018
8220 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node).id == ConstCastResultIdOk) {
9019 if (prev_type->id == TypeTableEntryIdNull) {
9020 prev_inst = cur_inst;
9021 continue;
9022 }
9023
9024 if (cur_type->id == TypeTableEntryIdNull) {
9025 any_are_null = true;
9026 continue;
9027 }
9028
9029 if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) {
82219030 continue;
82229031 }
82239032
8224 if (types_match_const_cast_only(ira, cur_type, prev_type, source_node).id == ConstCastResultIdOk) {
9033 if (types_match_const_cast_only(ira, cur_type, prev_type, source_node, false).id == ConstCastResultIdOk) {
82259034 prev_inst = cur_inst;
82269035 continue;
82279036 }
......@@ -8244,17 +9053,19 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
82449053 }
82459054
82469055 if (prev_type->id == TypeTableEntryIdErrorUnion &&
8247 types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, source_node).id == ConstCastResultIdOk)
9056 types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type,
9057 source_node, false).id == ConstCastResultIdOk)
82489058 {
82499059 continue;
82509060 }
82519061
82529062 if (cur_type->id == TypeTableEntryIdErrorUnion &&
8253 types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, source_node).id == ConstCastResultIdOk)
9063 types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type,
9064 source_node, false).id == ConstCastResultIdOk)
82549065 {
82559066 if (err_set_type != nullptr) {
82569067 TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
8257 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
9068 if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
82589069 return ira->codegen->builtin_types.entry_invalid;
82599070 }
82609071 if (type_is_global_error_set(cur_err_set_type) || type_is_global_error_set(err_set_type)) {
......@@ -8271,30 +9082,32 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
82719082 continue;
82729083 }
82739084
8274 if (prev_type->id == TypeTableEntryIdMaybe &&
8275 types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, source_node).id == ConstCastResultIdOk)
9085 if (prev_type->id == TypeTableEntryIdOptional &&
9086 types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type,
9087 source_node, false).id == ConstCastResultIdOk)
82769088 {
82779089 continue;
82789090 }
82799091
8280 if (cur_type->id == TypeTableEntryIdMaybe &&
8281 types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, source_node).id == ConstCastResultIdOk)
9092 if (cur_type->id == TypeTableEntryIdOptional &&
9093 types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type,
9094 source_node, false).id == ConstCastResultIdOk)
82829095 {
82839096 prev_inst = cur_inst;
82849097 continue;
82859098 }
82869099
8287 if (cur_type->id == TypeTableEntryIdUndefLit) {
9100 if (cur_type->id == TypeTableEntryIdUndefined) {
82889101 continue;
82899102 }
82909103
8291 if (prev_type->id == TypeTableEntryIdUndefLit) {
9104 if (prev_type->id == TypeTableEntryIdUndefined) {
82929105 prev_inst = cur_inst;
82939106 continue;
82949107 }
82959108
8296 if (prev_type->id == TypeTableEntryIdNumLitInt ||
8297 prev_type->id == TypeTableEntryIdNumLitFloat)
9109 if (prev_type->id == TypeTableEntryIdComptimeInt ||
9110 prev_type->id == TypeTableEntryIdComptimeFloat)
82989111 {
82999112 if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) {
83009113 prev_inst = cur_inst;
......@@ -8304,8 +9117,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83049117 }
83059118 }
83069119
8307 if (cur_type->id == TypeTableEntryIdNumLitInt ||
8308 cur_type->id == TypeTableEntryIdNumLitFloat)
9120 if (cur_type->id == TypeTableEntryIdComptimeInt ||
9121 cur_type->id == TypeTableEntryIdComptimeFloat)
83099122 {
83109123 if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) {
83119124 continue;
......@@ -8315,8 +9128,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83159128 }
83169129
83179130 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
8318 cur_type->data.array.len != prev_type->data.array.len &&
8319 types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
9131 cur_type->data.array.len != prev_type->data.array.len &&
9132 types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type,
9133 source_node, false).id == ConstCastResultIdOk)
83209134 {
83219135 convert_to_const_slice = true;
83229136 prev_inst = cur_inst;
......@@ -8324,8 +9138,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83249138 }
83259139
83269140 if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
8327 cur_type->data.array.len != prev_type->data.array.len &&
8328 types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
9141 cur_type->data.array.len != prev_type->data.array.len &&
9142 types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type,
9143 source_node, false).id == ConstCastResultIdOk)
83299144 {
83309145 convert_to_const_slice = true;
83319146 continue;
......@@ -8334,8 +9149,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83349149 if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
83359150 (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
83369151 cur_type->data.array.len == 0) &&
8337 types_match_const_cast_only(ira, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8338 cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
9152 types_match_const_cast_only(ira,
9153 prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
9154 cur_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
83399155 {
83409156 convert_to_const_slice = false;
83419157 continue;
......@@ -8344,8 +9160,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83449160 if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
83459161 (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
83469162 prev_type->data.array.len == 0) &&
8347 types_match_const_cast_only(ira, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
8348 prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
9163 types_match_const_cast_only(ira,
9164 cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
9165 prev_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
83499166 {
83509167 prev_inst = cur_inst;
83519168 convert_to_const_slice = false;
......@@ -8390,7 +9207,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
83909207
83919208 if (convert_to_const_slice) {
83929209 assert(prev_inst->value.type->id == TypeTableEntryIdArray);
8393 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);
9210 TypeTableEntry *ptr_type = get_pointer_to_type_extra(
9211 ira->codegen, prev_inst->value.type->data.array.child_type,
9212 true, false, PtrLenUnknown,
9213 get_abi_alignment(ira->codegen, prev_inst->value.type->data.array.child_type),
9214 0, 0);
83949215 TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type);
83959216 if (err_set_type != nullptr) {
83969217 return get_error_union_type(ira->codegen, err_set_type, slice_type);
......@@ -8400,34 +9221,36 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
84009221 } else if (err_set_type != nullptr) {
84019222 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
84029223 return err_set_type;
9224 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
9225 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type->data.error_union.payload_type);
9226 } else if (expected_type != nullptr && expected_type->id == TypeTableEntryIdErrorUnion) {
9227 return get_error_union_type(ira->codegen, err_set_type, expected_type->data.error_union.payload_type);
84039228 } else {
8404 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
8405 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
9229 if (prev_inst->value.type->id == TypeTableEntryIdComptimeInt ||
9230 prev_inst->value.type->id == TypeTableEntryIdComptimeFloat)
84069231 {
84079232 ir_add_error_node(ira, source_node,
84089233 buf_sprintf("unable to make error union out of number literal"));
84099234 return ira->codegen->builtin_types.entry_invalid;
8410 } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
9235 } else if (prev_inst->value.type->id == TypeTableEntryIdNull) {
84119236 ir_add_error_node(ira, source_node,
84129237 buf_sprintf("unable to make error union out of null literal"));
84139238 return ira->codegen->builtin_types.entry_invalid;
8414 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
8415 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type->data.error_union.payload_type);
84169239 } else {
84179240 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type);
84189241 }
84199242 }
8420 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {
8421 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
8422 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
9243 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNull) {
9244 if (prev_inst->value.type->id == TypeTableEntryIdComptimeInt ||
9245 prev_inst->value.type->id == TypeTableEntryIdComptimeFloat)
84239246 {
84249247 ir_add_error_node(ira, source_node,
84259248 buf_sprintf("unable to make maybe out of number literal"));
84269249 return ira->codegen->builtin_types.entry_invalid;
8427 } else if (prev_inst->value.type->id == TypeTableEntryIdMaybe) {
9250 } else if (prev_inst->value.type->id == TypeTableEntryIdOptional) {
84289251 return prev_inst->value.type;
84299252 } else {
8430 return get_maybe_type(ira->codegen, prev_inst->value.type);
9253 return get_optional_type(ira->codegen, prev_inst->value.type);
84319254 }
84329255 } else {
84339256 return prev_inst->value.type;
......@@ -8448,10 +9271,15 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
84489271 *dest = *src;
84499272 if (!same_global_refs) {
84509273 dest->global_refs = global_refs;
9274 if (dest->type->id == TypeTableEntryIdStruct) {
9275 dest->data.x_struct.fields = allocate_nonzero<ConstExprValue>(dest->type->data.structure.src_field_count);
9276 memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count);
9277 }
84519278 }
84529279}
84539280
8454static void eval_const_expr_implicit_cast(CastOp cast_op,
9281static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_instr,
9282 CastOp cast_op,
84559283 ConstExprValue *other_val, TypeTableEntry *other_type,
84569284 ConstExprValue *const_val, TypeTableEntry *new_type)
84579285{
......@@ -8462,17 +9290,23 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
84629290 case CastOpNoCast:
84639291 zig_unreachable();
84649292 case CastOpErrSet:
9293 case CastOpBitCast:
9294 case CastOpPtrOfArrayToSlice:
84659295 zig_panic("TODO");
84669296 case CastOpNoop:
84679297 {
8468 copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic);
9298 bool same_global_refs = other_val->special == ConstValSpecialStatic;
9299 copy_const_val(const_val, other_val, same_global_refs);
84699300 const_val->type = new_type;
84709301 break;
84719302 }
84729303 case CastOpNumLitToConcrete:
8473 if (other_val->type->id == TypeTableEntryIdNumLitFloat) {
9304 if (other_val->type->id == TypeTableEntryIdComptimeFloat) {
84749305 assert(new_type->id == TypeTableEntryIdFloat);
84759306 switch (new_type->data.floating.bit_count) {
9307 case 16:
9308 const_val->data.x_f16 = bigfloat_to_f16(&other_val->data.x_bigfloat);
9309 break;
84769310 case 32:
84779311 const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat);
84789312 break;
......@@ -8485,7 +9319,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
84859319 default:
84869320 zig_unreachable();
84879321 }
8488 } else if (other_val->type->id == TypeTableEntryIdNumLitInt) {
9322 } else if (other_val->type->id == TypeTableEntryIdComptimeInt) {
84899323 bigint_init_bigint(&const_val->data.x_bigint, &other_val->data.x_bigint);
84909324 } else {
84919325 zig_unreachable();
......@@ -8503,6 +9337,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
85039337 BigFloat bigfloat;
85049338 bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint);
85059339 switch (new_type->data.floating.bit_count) {
9340 case 16:
9341 const_val->data.x_f16 = bigfloat_to_f16(&bigfloat);
9342 break;
85069343 case 32:
85079344 const_val->data.x_f32 = bigfloat_to_f32(&bigfloat);
85089345 break;
......@@ -8520,6 +9357,20 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
85209357 }
85219358 case CastOpFloatToInt:
85229359 float_init_bigint(&const_val->data.x_bigint, other_val);
9360 if (new_type->id == TypeTableEntryIdInt) {
9361 if (!bigint_fits_in_bits(&const_val->data.x_bigint, new_type->data.integral.bit_count,
9362 new_type->data.integral.is_signed))
9363 {
9364 Buf *int_buf = buf_alloc();
9365 bigint_append_buf(int_buf, &const_val->data.x_bigint, 10);
9366
9367 ir_add_error(ira, source_instr,
9368 buf_sprintf("integer value '%s' cannot be stored in type '%s'",
9369 buf_ptr(int_buf), buf_ptr(&new_type->name)));
9370 return false;
9371 }
9372 }
9373
85239374 const_val->special = ConstValSpecialStatic;
85249375 break;
85259376 case CastOpBoolToInt:
......@@ -8527,17 +9378,21 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
85279378 const_val->special = ConstValSpecialStatic;
85289379 break;
85299380 }
9381 return true;
85309382}
85319383static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
85329384 TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
85339385{
8534 if (value->value.special != ConstValSpecialRuntime &&
9386 if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
85359387 cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice)
85369388 {
85379389 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
85389390 source_instr->source_node, wanted_type);
8539 eval_const_expr_implicit_cast(cast_op, &value->value, value->value.type,
8540 &result->value, wanted_type);
9391 if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
9392 &result->value, wanted_type))
9393 {
9394 return ira->codegen->invalid_instruction;
9395 }
85419396 return result;
85429397 } else {
85439398 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
......@@ -8549,17 +9404,69 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
85499404 }
85509405}
85519406
9407static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, IrInstruction *source_instr,
9408 IrInstruction *value, TypeTableEntry *wanted_type)
9409{
9410 assert(value->value.type->id == TypeTableEntryIdPointer);
9411 wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
9412
9413 if (instr_is_comptime(value)) {
9414 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
9415 if (pointee->special != ConstValSpecialRuntime) {
9416 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
9417 source_instr->source_node, wanted_type);
9418 result->value.type = wanted_type;
9419 result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
9420 result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
9421 result->value.data.x_ptr.data.base_array.array_val = pointee;
9422 result->value.data.x_ptr.data.base_array.elem_index = 0;
9423 result->value.data.x_ptr.data.base_array.is_cstr = false;
9424 return result;
9425 }
9426 }
9427
9428 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
9429 wanted_type, value, CastOpBitCast);
9430 result->value.type = wanted_type;
9431 return result;
9432}
9433
9434static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
9435 IrInstruction *value, TypeTableEntry *wanted_type)
9436{
9437 wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
9438
9439 if (instr_is_comptime(value)) {
9440 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
9441 if (pointee->special != ConstValSpecialRuntime) {
9442 assert(value->value.type->id == TypeTableEntryIdPointer);
9443 TypeTableEntry *array_type = value->value.type->data.pointer.child_type;
9444 assert(is_slice(wanted_type));
9445 bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
9446
9447 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
9448 source_instr->source_node, wanted_type);
9449 init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
9450 result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
9451 value->value.data.x_ptr.mut;
9452 result->value.type = wanted_type;
9453 return result;
9454 }
9455 }
9456
9457 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
9458 wanted_type, value, CastOpPtrOfArrayToSlice);
9459 result->value.type = wanted_type;
9460 ir_add_alloca(ira, result, wanted_type);
9461 return result;
9462}
9463
85529464static bool is_container(TypeTableEntry *type) {
85539465 return type->id == TypeTableEntryIdStruct ||
85549466 type->id == TypeTableEntryIdEnum ||
85559467 type->id == TypeTableEntryIdUnion;
85569468}
85579469
8558static bool is_u8(TypeTableEntry *type) {
8559 return type->id == TypeTableEntryIdInt &&
8560 !type->data.integral.is_signed && type->data.integral.bit_count == 8;
8561}
8562
85639470static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {
85649471 assert(old_bb);
85659472
......@@ -8661,26 +9568,9 @@ static TypeTableEntry *ir_finish_anal(IrAnalyze *ira, TypeTableEntry *result_typ
86619568}
86629569
86639570static IrInstruction *ir_get_const(IrAnalyze *ira, IrInstruction *old_instruction) {
8664 IrInstruction *new_instruction;
8665 if (old_instruction->id == IrInstructionIdVarPtr) {
8666 IrInstructionVarPtr *old_var_ptr_instruction = (IrInstructionVarPtr *)old_instruction;
8667 IrInstructionVarPtr *var_ptr_instruction = ir_create_instruction<IrInstructionVarPtr>(&ira->new_irb,
8668 old_instruction->scope, old_instruction->source_node);
8669 var_ptr_instruction->var = old_var_ptr_instruction->var;
8670 new_instruction = &var_ptr_instruction->base;
8671 } else if (old_instruction->id == IrInstructionIdFieldPtr) {
8672 IrInstructionFieldPtr *field_ptr_instruction = ir_create_instruction<IrInstructionFieldPtr>(&ira->new_irb,
8673 old_instruction->scope, old_instruction->source_node);
8674 new_instruction = &field_ptr_instruction->base;
8675 } else if (old_instruction->id == IrInstructionIdElemPtr) {
8676 IrInstructionElemPtr *elem_ptr_instruction = ir_create_instruction<IrInstructionElemPtr>(&ira->new_irb,
8677 old_instruction->scope, old_instruction->source_node);
8678 new_instruction = &elem_ptr_instruction->base;
8679 } else {
8680 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
8681 old_instruction->scope, old_instruction->source_node);
8682 new_instruction = &const_instruction->base;
8683 }
9571 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
9572 old_instruction->scope, old_instruction->source_node);
9573 IrInstruction *new_instruction = &const_instruction->base;
86849574 new_instruction->value.special = ConstValSpecialStatic;
86859575 return new_instruction;
86869576}
......@@ -8700,34 +9590,15 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
87009590 ConstExprValue *pointee, TypeTableEntry *pointee_type,
87019591 ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align)
87029592{
8703 if (pointee_type->id == TypeTableEntryIdMetaType) {
8704 TypeTableEntry *type_entry = pointee->data.x_type;
8705 if (type_entry->id == TypeTableEntryIdUnreachable) {
8706 ir_add_error(ira, instruction, buf_sprintf("pointer to noreturn not allowed"));
8707 return ira->codegen->invalid_instruction;
8708 }
8709
8710 IrInstruction *const_instr = ir_get_const(ira, instruction);
8711 ConstExprValue *const_val = &const_instr->value;
8712 const_val->type = pointee_type;
8713 type_ensure_zero_bits_known(ira->codegen, type_entry);
8714 if (type_is_invalid(type_entry)) {
8715 return ira->codegen->invalid_instruction;
8716 }
8717 const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry,
8718 ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0);
8719 return const_instr;
8720 } else {
8721 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type,
8722 ptr_is_const, ptr_is_volatile, ptr_align, 0, 0);
8723 IrInstruction *const_instr = ir_get_const(ira, instruction);
8724 ConstExprValue *const_val = &const_instr->value;
8725 const_val->type = ptr_type;
8726 const_val->data.x_ptr.special = ConstPtrSpecialRef;
8727 const_val->data.x_ptr.mut = ptr_mut;
8728 const_val->data.x_ptr.data.ref.pointee = pointee;
8729 return const_instr;
8730 }
9593 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type,
9594 ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0);
9595 IrInstruction *const_instr = ir_get_const(ira, instruction);
9596 ConstExprValue *const_val = &const_instr->value;
9597 const_val->type = ptr_type;
9598 const_val->data.x_ptr.special = ConstPtrSpecialRef;
9599 const_val->data.x_ptr.mut = ptr_mut;
9600 const_val->data.x_ptr.data.ref.pointee = pointee;
9601 return const_instr;
87319602}
87329603
87339604static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
......@@ -8757,6 +9628,9 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
87579628 case ConstValSpecialStatic:
87589629 return &value->value;
87599630 case ConstValSpecialRuntime:
9631 if (!type_has_bits(value->value.type)) {
9632 return &value->value;
9633 }
87609634 ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression"));
87619635 return nullptr;
87629636 case ConstValSpecialUndef:
......@@ -8861,7 +9735,7 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
88619735}
88629736
88639737static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
8864 assert(wanted_type->id == TypeTableEntryIdMaybe);
9738 assert(wanted_type->id == TypeTableEntryIdOptional);
88659739
88669740 if (instr_is_comptime(value)) {
88679741 TypeTableEntry *payload_type = wanted_type->data.maybe.child_type;
......@@ -8869,21 +9743,25 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
88699743 if (type_is_invalid(casted_payload->value.type))
88709744 return ira->codegen->invalid_instruction;
88719745
8872 ConstExprValue *val = ir_resolve_const(ira, casted_payload, UndefBad);
9746 ConstExprValue *val = ir_resolve_const(ira, casted_payload, UndefOk);
88739747 if (!val)
88749748 return ira->codegen->invalid_instruction;
88759749
88769750 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
88779751 source_instr->scope, source_instr->source_node);
8878 const_instruction->base.value.type = wanted_type;
88799752 const_instruction->base.value.special = ConstValSpecialStatic;
8880 const_instruction->base.value.data.x_maybe = val;
9753 if (get_codegen_ptr_type(wanted_type) != nullptr) {
9754 copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst);
9755 } else {
9756 const_instruction->base.value.data.x_optional = val;
9757 }
9758 const_instruction->base.value.type = wanted_type;
88819759 return &const_instruction->base;
88829760 }
88839761
88849762 IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
88859763 result->value.type = wanted_type;
8886 result->value.data.rh_maybe = RuntimeHintMaybeNonNull;
9764 result->value.data.rh_maybe = RuntimeHintOptionalNonNull;
88879765 ir_add_alloca(ira, result, wanted_type);
88889766 return result;
88899767}
......@@ -8930,7 +9808,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
89309808 if (!val)
89319809 return ira->codegen->invalid_instruction;
89329810
8933 if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
9811 if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
89349812 return ira->codegen->invalid_instruction;
89359813 }
89369814 if (!type_is_global_error_set(wanted_type)) {
......@@ -9025,16 +9903,21 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_
90259903}
90269904
90279905static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
9028 assert(wanted_type->id == TypeTableEntryIdMaybe);
9906 assert(wanted_type->id == TypeTableEntryIdOptional);
90299907 assert(instr_is_comptime(value));
90309908
90319909 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
90329910 assert(val);
90339911
90349912 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node);
9035 const_instruction->base.value.type = wanted_type;
90369913 const_instruction->base.value.special = ConstValSpecialStatic;
9037 const_instruction->base.value.data.x_maybe = nullptr;
9914 if (get_codegen_ptr_type(wanted_type) != nullptr) {
9915 const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
9916 const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0;
9917 } else {
9918 const_instruction->base.value.data.x_optional = nullptr;
9919 }
9920 const_instruction->base.value.type = wanted_type;
90389921 return &const_instruction->base;
90399922}
90409923
......@@ -9044,25 +9927,17 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
90449927 if (type_is_invalid(value->value.type))
90459928 return ira->codegen->invalid_instruction;
90469929
9047 if (value->id == IrInstructionIdLoadPtr) {
9048 IrInstructionLoadPtr *load_ptr_inst = (IrInstructionLoadPtr *) value;
9049 if (load_ptr_inst->ptr->value.type->data.pointer.is_const) {
9050 return load_ptr_inst->ptr;
9051 }
9052 }
9053
90549930 if (instr_is_comptime(value)) {
90559931 ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);
90569932 if (!val)
90579933 return ira->codegen->invalid_instruction;
9058 bool final_is_const = (value->value.type->id == TypeTableEntryIdMetaType) ? is_const : true;
90599934 return ir_get_const_ptr(ira, source_instruction, val, value->value.type,
9060 ConstPtrMutComptimeConst, final_is_const, is_volatile,
9935 ConstPtrMutComptimeConst, is_const, is_volatile,
90619936 get_abi_alignment(ira->codegen, value->value.type));
90629937 }
90639938
90649939 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
9065 is_const, is_volatile, get_abi_alignment(ira->codegen, value->value.type), 0, 0);
9940 is_const, is_volatile, PtrLenSingle, get_abi_alignment(ira->codegen, value->value.type), 0, 0);
90669941 IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
90679942 source_instruction->source_node, value, is_const, is_volatile);
90689943 new_instruction->value.type = ptr_type;
......@@ -9114,6 +9989,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
91149989 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
91159990 source_instr->source_node, array_ptr, start, end, false);
91169991 result->value.type = wanted_type;
9992 result->value.data.rh_slice.id = RuntimeHintSliceIdLen;
9993 result->value.data.rh_slice.len = array_type->data.array.len;
91179994 ir_add_alloca(ira, result, result->value.type);
91189995
91199996 return result;
......@@ -9202,6 +10079,8 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so
920210079 TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag);
920310080 assert(union_field != nullptr);
920410081 type_ensure_zero_bits_known(ira->codegen, union_field->type_entry);
10082 if (type_is_invalid(union_field->type_entry))
10083 return ira->codegen->invalid_instruction;
920510084 if (!union_field->type_entry->zero_bits) {
920610085 AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(
920710086 union_field->enum_field->decl_index);
......@@ -9332,7 +10211,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
933210211 }
933310212
933410213 IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope,
9335 source_instr->source_node, target);
10214 source_instr->source_node, nullptr, target);
933610215 result->value.type = wanted_type;
933710216 return result;
933810217}
......@@ -9346,9 +10225,9 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
934610225
934710226 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
934810227 source_instr->source_node, wanted_type);
9349 if (wanted_type->id == TypeTableEntryIdNumLitFloat) {
10228 if (wanted_type->id == TypeTableEntryIdComptimeFloat) {
935010229 float_init_float(&result->value, val);
9351 } else if (wanted_type->id == TypeTableEntryIdNumLitInt) {
10230 } else if (wanted_type->id == TypeTableEntryIdComptimeInt) {
935210231 bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint);
935310232 } else {
935410233 zig_unreachable();
......@@ -9371,7 +10250,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
937110250 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
937210251 source_instr->source_node, wanted_type);
937310252
9374 if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
10253 if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
937510254 return ira->codegen->invalid_instruction;
937610255 }
937710256
......@@ -9469,7 +10348,7 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
946910348 zig_unreachable();
947010349 }
947110350 if (!type_is_global_error_set(err_set_type)) {
9472 if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) {
10351 if (!resolve_inferred_error_set(ira->codegen, err_set_type, source_instr->source_node)) {
947310352 return ira->codegen->invalid_instruction;
947410353 }
947510354 if (err_set_type->data.error_set.err_count == 0) {
......@@ -9501,6 +10380,140 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
950110380 return result;
950210381}
950310382
10383static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
10384 TypeTableEntry *wanted_type)
10385{
10386 assert(wanted_type->id == TypeTableEntryIdPointer);
10387 wanted_type = adjust_ptr_align(ira->codegen, wanted_type, target->value.type->data.pointer.alignment);
10388 TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
10389 assert(array_type->id == TypeTableEntryIdArray);
10390 assert(array_type->data.array.len == 1);
10391
10392 if (instr_is_comptime(target)) {
10393 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
10394 if (!val)
10395 return ira->codegen->invalid_instruction;
10396
10397 assert(val->type->id == TypeTableEntryIdPointer);
10398 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, val);
10399 if (pointee->special != ConstValSpecialRuntime) {
10400 ConstExprValue *array_val = create_const_vals(1);
10401 array_val->special = ConstValSpecialStatic;
10402 array_val->type = array_type;
10403 array_val->data.x_array.special = ConstArraySpecialNone;
10404 array_val->data.x_array.s_none.elements = pointee;
10405 array_val->data.x_array.s_none.parent.id = ConstParentIdScalar;
10406 array_val->data.x_array.s_none.parent.data.p_scalar.scalar_val = pointee;
10407
10408 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
10409 source_instr->scope, source_instr->source_node);
10410 const_instruction->base.value.type = wanted_type;
10411 const_instruction->base.value.special = ConstValSpecialStatic;
10412 const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialRef;
10413 const_instruction->base.value.data.x_ptr.data.ref.pointee = array_val;
10414 const_instruction->base.value.data.x_ptr.mut = val->data.x_ptr.mut;
10415 return &const_instruction->base;
10416 }
10417 }
10418
10419 // pointer to array and pointer to single item are represented the same way at runtime
10420 IrInstruction *result = ir_build_cast(&ira->new_irb, target->scope, target->source_node,
10421 wanted_type, target, CastOpBitCast);
10422 result->value.type = wanted_type;
10423 return result;
10424}
10425
10426static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCastOnly *cast_result,
10427 ErrorMsg *parent_msg)
10428{
10429 switch (cast_result->id) {
10430 case ConstCastResultIdOk:
10431 zig_unreachable();
10432 case ConstCastResultIdOptionalChild: {
10433 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10434 buf_sprintf("optional type child '%s' cannot cast into optional type child '%s'",
10435 buf_ptr(&cast_result->data.optional->actual_child->name),
10436 buf_ptr(&cast_result->data.optional->wanted_child->name)));
10437 report_recursive_error(ira, source_node, &cast_result->data.optional->child, msg);
10438 break;
10439 }
10440 case ConstCastResultIdErrorUnionErrorSet: {
10441 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10442 buf_sprintf("error set '%s' cannot cast into error set '%s'",
10443 buf_ptr(&cast_result->data.error_union_error_set->actual_err_set->name),
10444 buf_ptr(&cast_result->data.error_union_error_set->wanted_err_set->name)));
10445 report_recursive_error(ira, source_node, &cast_result->data.error_union_error_set->child, msg);
10446 break;
10447 }
10448 case ConstCastResultIdErrSet: {
10449 ZigList<ErrorTableEntry *> *missing_errors = &cast_result->data.error_set_mismatch->missing_errors;
10450 for (size_t i = 0; i < missing_errors->length; i += 1) {
10451 ErrorTableEntry *error_entry = missing_errors->at(i);
10452 add_error_note(ira->codegen, parent_msg, error_entry->decl_node,
10453 buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name)));
10454 }
10455 break;
10456 }
10457 case ConstCastResultIdErrSetGlobal: {
10458 add_error_note(ira->codegen, parent_msg, source_node,
10459 buf_sprintf("cannot cast global error set into smaller set"));
10460 break;
10461 }
10462 case ConstCastResultIdPointerChild: {
10463 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10464 buf_sprintf("pointer type child '%s' cannot cast into pointer type child '%s'",
10465 buf_ptr(&cast_result->data.pointer_mismatch->actual_child->name),
10466 buf_ptr(&cast_result->data.pointer_mismatch->wanted_child->name)));
10467 report_recursive_error(ira, source_node, &cast_result->data.pointer_mismatch->child, msg);
10468 break;
10469 }
10470 case ConstCastResultIdSliceChild: {
10471 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10472 buf_sprintf("slice type child '%s' cannot cast into slice type child '%s'",
10473 buf_ptr(&cast_result->data.slice_mismatch->actual_child->name),
10474 buf_ptr(&cast_result->data.slice_mismatch->wanted_child->name)));
10475 report_recursive_error(ira, source_node, &cast_result->data.slice_mismatch->child, msg);
10476 break;
10477 }
10478 case ConstCastResultIdErrorUnionPayload: {
10479 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10480 buf_sprintf("error union payload '%s' cannot cast into error union payload '%s'",
10481 buf_ptr(&cast_result->data.error_union_payload->actual_payload->name),
10482 buf_ptr(&cast_result->data.error_union_payload->wanted_payload->name)));
10483 report_recursive_error(ira, source_node, &cast_result->data.error_union_payload->child, msg);
10484 break;
10485 }
10486 case ConstCastResultIdType: {
10487 AstNode *wanted_decl_node = type_decl_node(cast_result->data.type_mismatch->wanted_type);
10488 AstNode *actual_decl_node = type_decl_node(cast_result->data.type_mismatch->actual_type);
10489 if (wanted_decl_node != nullptr) {
10490 add_error_note(ira->codegen, parent_msg, wanted_decl_node,
10491 buf_sprintf("%s declared here",
10492 buf_ptr(&cast_result->data.type_mismatch->wanted_type->name)));
10493 }
10494 if (actual_decl_node != nullptr) {
10495 add_error_note(ira->codegen, parent_msg, actual_decl_node,
10496 buf_sprintf("%s declared here",
10497 buf_ptr(&cast_result->data.type_mismatch->actual_type->name)));
10498 }
10499 break;
10500 }
10501 case ConstCastResultIdFnAlign: // TODO
10502 case ConstCastResultIdFnCC: // TODO
10503 case ConstCastResultIdFnVarArgs: // TODO
10504 case ConstCastResultIdFnIsGeneric: // TODO
10505 case ConstCastResultIdFnReturnType: // TODO
10506 case ConstCastResultIdFnArgCount: // TODO
10507 case ConstCastResultIdFnGenericArgCount: // TODO
10508 case ConstCastResultIdFnArg: // TODO
10509 case ConstCastResultIdFnArgNoAlias: // TODO
10510 case ConstCastResultIdUnresolvedInferredErrSet: // TODO
10511 case ConstCastResultIdAsyncAllocatorType: // TODO
10512 case ConstCastResultIdNullWrapPtr: // TODO
10513 break;
10514 }
10515}
10516
950410517static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
950510518 TypeTableEntry *wanted_type, IrInstruction *value)
950610519{
......@@ -9511,60 +10524,52 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
951110524 return ira->codegen->invalid_instruction;
951210525 }
951310526
9514 // explicit match or non-const to const
9515 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node).id == ConstCastResultIdOk) {
10527 // perfect match or non-const to const
10528 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
10529 source_node, false);
10530 if (const_cast_result.id == ConstCastResultIdOk) {
951610531 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
951710532 }
951810533
9519 // explicit cast from bool to int
10534 // widening conversion
952010535 if (wanted_type->id == TypeTableEntryIdInt &&
9521 actual_type->id == TypeTableEntryIdBool)
9522 {
9523 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false);
9524 }
9525
9526 // explicit widening or shortening cast
9527 if ((wanted_type->id == TypeTableEntryIdInt &&
9528 actual_type->id == TypeTableEntryIdInt) ||
9529 (wanted_type->id == TypeTableEntryIdFloat &&
9530 actual_type->id == TypeTableEntryIdFloat))
10536 actual_type->id == TypeTableEntryIdInt &&
10537 wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
10538 wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
953110539 {
953210540 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
953310541 }
953410542
9535 // explicit error set cast
9536 if (wanted_type->id == TypeTableEntryIdErrorSet &&
9537 actual_type->id == TypeTableEntryIdErrorSet)
10543 // small enough unsigned ints can get casted to large enough signed ints
10544 if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed &&
10545 actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
10546 wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count)
953810547 {
9539 return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type);
10548 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
954010549 }
954110550
9542 // explicit cast from int to float
10551 // float widening conversion
954310552 if (wanted_type->id == TypeTableEntryIdFloat &&
9544 actual_type->id == TypeTableEntryIdInt)
10553 actual_type->id == TypeTableEntryIdFloat &&
10554 wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
954510555 {
9546 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToFloat, false);
10556 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
954710557 }
954810558
9549 // explicit cast from float to int
9550 if (wanted_type->id == TypeTableEntryIdInt &&
9551 actual_type->id == TypeTableEntryIdFloat)
9552 {
9553 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpFloatToInt, false);
9554 }
955510559
9556 // explicit cast from [N]T to []const T
10560 // cast from [N]T to []const T
955710561 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
955810562 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
955910563 assert(ptr_type->id == TypeTableEntryIdPointer);
956010564 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9561 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10565 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10566 source_node, false).id == ConstCastResultIdOk)
956210567 {
956310568 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
956410569 }
956510570 }
956610571
9567 // explicit cast from &const [N]T to []const T
10572 // cast from *const [N]T to []const T
956810573 if (is_slice(wanted_type) &&
956910574 actual_type->id == TypeTableEntryIdPointer &&
957010575 actual_type->data.pointer.is_const &&
......@@ -9576,13 +10581,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
957610581 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
957710582
957810583 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
9579 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10584 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
10585 source_node, false).id == ConstCastResultIdOk)
958010586 {
958110587 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
958210588 }
958310589 }
958410590
9585 // explicit cast from [N]T to &const []const N
10591 // cast from [N]T to *const []const T
958610592 if (wanted_type->id == TypeTableEntryIdPointer &&
958710593 wanted_type->data.pointer.is_const &&
958810594 is_slice(wanted_type->data.pointer.child_type) &&
......@@ -9592,7 +10598,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
959210598 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
959310599 assert(ptr_type->id == TypeTableEntryIdPointer);
959410600 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9595 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10601 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10602 source_node, false).id == ConstCastResultIdOk)
959610603 {
959710604 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
959810605 if (type_is_invalid(cast1->value.type))
......@@ -9606,8 +10613,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
960610613 }
960710614 }
960810615
9609 // explicit cast from [N]T to ?[]const N
9610 if (wanted_type->id == TypeTableEntryIdMaybe &&
10616 // cast from [N]T to ?[]const T
10617 if (wanted_type->id == TypeTableEntryIdOptional &&
961110618 is_slice(wanted_type->data.maybe.child_type) &&
961210619 actual_type->id == TypeTableEntryIdArray)
961310620 {
......@@ -9615,7 +10622,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
961510622 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
961610623 assert(ptr_type->id == TypeTableEntryIdPointer);
961710624 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9618 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10625 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10626 source_node, false).id == ConstCastResultIdOk)
961910627 {
962010628 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
962110629 if (type_is_invalid(cast1->value.type))
......@@ -9629,59 +10637,47 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
962910637 }
963010638 }
963110639
9632 // explicit cast from []T to []u8 or []u8 to []T
9633 if (is_slice(wanted_type) && is_slice(actual_type)) {
9634 TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
9635 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
9636 if ((is_u8(wanted_ptr_type->data.pointer.child_type) || is_u8(actual_ptr_type->data.pointer.child_type)) &&
9637 (wanted_ptr_type->data.pointer.is_const || !actual_ptr_type->data.pointer.is_const))
9638 {
9639 uint32_t src_align_bytes = get_ptr_align(actual_ptr_type);
9640 uint32_t dest_align_bytes = get_ptr_align(wanted_ptr_type);
9641
9642 if (dest_align_bytes > src_align_bytes) {
9643 ErrorMsg *msg = ir_add_error(ira, source_instr,
9644 buf_sprintf("cast increases pointer alignment"));
9645 add_error_note(ira->codegen, msg, source_instr->source_node,
9646 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), src_align_bytes));
9647 add_error_note(ira->codegen, msg, source_instr->source_node,
9648 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), dest_align_bytes));
9649 return ira->codegen->invalid_instruction;
9650 }
9651
9652 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
9653 return ira->codegen->invalid_instruction;
9654 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
9655 }
10640 // *[N]T to [*]T
10641 if (wanted_type->id == TypeTableEntryIdPointer &&
10642 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
10643 actual_type->id == TypeTableEntryIdPointer &&
10644 actual_type->data.pointer.ptr_len == PtrLenSingle &&
10645 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
10646 actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
10647 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
10648 actual_type->data.pointer.child_type->data.array.child_type, source_node,
10649 !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
10650 {
10651 return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
965610652 }
965710653
9658 // explicit cast from [N]u8 to []const T
10654 // *[N]T to []T
965910655 if (is_slice(wanted_type) &&
9660 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const &&
9661 actual_type->id == TypeTableEntryIdArray &&
9662 is_u8(actual_type->data.array.child_type))
10656 actual_type->id == TypeTableEntryIdPointer &&
10657 actual_type->data.pointer.ptr_len == PtrLenSingle &&
10658 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
966310659 {
9664 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
9665 return ira->codegen->invalid_instruction;
9666 uint64_t child_type_size = type_size(ira->codegen,
9667 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type);
9668 if (actual_type->data.array.len % child_type_size == 0) {
9669 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true);
9670 } else {
9671 ir_add_error_node(ira, source_instr->source_node,
9672 buf_sprintf("unable to convert %s to %s: size mismatch",
9673 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
9674 return ira->codegen->invalid_instruction;
10660 TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
10661 assert(slice_ptr_type->id == TypeTableEntryIdPointer);
10662 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
10663 actual_type->data.pointer.child_type->data.array.child_type, source_node,
10664 !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
10665 {
10666 return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
967510667 }
967610668 }
967710669
9678 // explicit cast from child type of maybe type to maybe type
9679 if (wanted_type->id == TypeTableEntryIdMaybe) {
10670
10671 // cast from T to ?T
10672 // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
10673 if (wanted_type->id == TypeTableEntryIdOptional) {
968010674 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
9681 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) {
10675 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
10676 false).id == ConstCastResultIdOk)
10677 {
968210678 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
9683 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
9684 actual_type->id == TypeTableEntryIdNumLitFloat)
10679 } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
10680 actual_type->id == TypeTableEntryIdComptimeFloat)
968510681 {
968610682 if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
968710683 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
......@@ -9704,19 +10700,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
970410700 }
970510701 }
970610702
9707 // explicit cast from null literal to maybe type
9708 if (wanted_type->id == TypeTableEntryIdMaybe &&
9709 actual_type->id == TypeTableEntryIdNullLit)
10703 // cast from null literal to maybe type
10704 if (wanted_type->id == TypeTableEntryIdOptional &&
10705 actual_type->id == TypeTableEntryIdNull)
971010706 {
971110707 return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
971210708 }
971310709
9714 // explicit cast from child type of error type to error type
10710 // cast from child type of error type to error type
971510711 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
9716 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node).id == ConstCastResultIdOk) {
10712 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
10713 source_node, false).id == ConstCastResultIdOk)
10714 {
971710715 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
9718 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
9719 actual_type->id == TypeTableEntryIdNumLitFloat)
10716 } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
10717 actual_type->id == TypeTableEntryIdComptimeFloat)
972010718 {
972110719 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) {
972210720 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
......@@ -9726,7 +10724,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
972610724 }
972710725 }
972810726
9729 // explicit cast from [N]T to %[]const T
10727 // cast from [N]T to E![]const T
973010728 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
973110729 is_slice(wanted_type->data.error_union.payload_type) &&
973210730 actual_type->id == TypeTableEntryIdArray)
......@@ -9735,7 +10733,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
973510733 wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
973610734 assert(ptr_type->id == TypeTableEntryIdPointer);
973710735 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
9738 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10736 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
10737 source_node, false).id == ConstCastResultIdOk)
973910738 {
974010739 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
974110740 if (type_is_invalid(cast1->value.type))
......@@ -9749,23 +10748,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
974910748 }
975010749 }
975110750
9752 // explicit cast from error set to error union type
10751 // cast from error set to error union type
975310752 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
975410753 actual_type->id == TypeTableEntryIdErrorSet)
975510754 {
975610755 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
975710756 }
975810757
9759 // explicit cast from T to %?T
10758 // cast from T to E!?T
976010759 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
9761 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
9762 actual_type->id != TypeTableEntryIdMaybe)
10760 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
10761 actual_type->id != TypeTableEntryIdOptional)
976310762 {
976410763 TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
9765 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk ||
9766 actual_type->id == TypeTableEntryIdNullLit ||
9767 actual_type->id == TypeTableEntryIdNumLitInt ||
9768 actual_type->id == TypeTableEntryIdNumLitFloat)
10764 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
10765 actual_type->id == TypeTableEntryIdNull ||
10766 actual_type->id == TypeTableEntryIdComptimeInt ||
10767 actual_type->id == TypeTableEntryIdComptimeFloat)
976910768 {
977010769 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
977110770 if (type_is_invalid(cast1->value.type))
......@@ -9779,11 +10778,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
977910778 }
978010779 }
978110780
9782 // explicit cast from number literal to another type
9783 // explicit cast from number literal to &const integer
9784 if (actual_type->id == TypeTableEntryIdNumLitFloat ||
9785 actual_type->id == TypeTableEntryIdNumLitInt)
10781 // cast from number literal to another type
10782 // cast from number literal to *const integer
10783 if (actual_type->id == TypeTableEntryIdComptimeFloat ||
10784 actual_type->id == TypeTableEntryIdComptimeInt)
978610785 {
10786 ensure_complete_type(ira->codegen, wanted_type);
10787 if (type_is_invalid(wanted_type))
10788 return ira->codegen->invalid_instruction;
978710789 if (wanted_type->id == TypeTableEntryIdEnum) {
978810790 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
978910791 if (type_is_invalid(cast1->value.type))
......@@ -9808,9 +10810,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
980810810 return cast2;
980910811 } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
981010812 CastOp op;
9811 if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
10813 if ((actual_type->id == TypeTableEntryIdComptimeFloat &&
981210814 wanted_type->id == TypeTableEntryIdFloat) ||
9813 (actual_type->id == TypeTableEntryIdNumLitInt &&
10815 (actual_type->id == TypeTableEntryIdComptimeInt &&
981410816 wanted_type->id == TypeTableEntryIdInt))
981510817 {
981610818 op = CastOpNumLitToConcrete;
......@@ -9827,52 +10829,27 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
982710829 }
982810830 }
982910831
9830 // explicit cast from typed number to integer or float literal.
10832 // cast from typed number to integer or float literal.
983110833 // works when the number is known at compile time
983210834 if (instr_is_comptime(value) &&
9833 ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdNumLitInt) ||
9834 (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdNumLitFloat)))
10835 ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||
10836 (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat)))
983510837 {
983610838 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
983710839 }
983810840
9839 // explicit cast from T!void to integer type which can fit it
9840 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
9841 !type_has_bits(actual_type->data.error_union.payload_type);
9842 bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet;
9843 if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) {
9844 return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
9845 }
9846
9847 // explicit cast from integer to error set
9848 if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt &&
9849 !actual_type->data.integral.is_signed)
9850 {
9851 return ir_analyze_int_to_err(ira, source_instr, value, wanted_type);
9852 }
9853
9854 // explicit cast from integer to enum type with no payload
9855 if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdEnum) {
9856 return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
9857 }
9858
9859 // explicit cast from enum type with no payload to integer
9860 if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdEnum) {
9861 return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
9862 }
9863
9864 // explicit cast from union to the enum type of the union
9865 if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
9866 type_ensure_zero_bits_known(ira->codegen, actual_type);
9867 if (type_is_invalid(actual_type))
9868 return ira->codegen->invalid_instruction;
10841 // cast from union to the enum type of the union
10842 if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
10843 type_ensure_zero_bits_known(ira->codegen, actual_type);
10844 if (type_is_invalid(actual_type))
10845 return ira->codegen->invalid_instruction;
986910846
987010847 if (actual_type->data.unionation.tag_type == wanted_type) {
987110848 return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type);
987210849 }
987310850 }
987410851
9875 // explicit enum to union which has the enum as the tag type
10852 // enum to union which has the enum as the tag type
987610853 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
987710854 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
987810855 wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
......@@ -9883,7 +10860,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
988310860 }
988410861 }
988510862
9886 // explicit enum to &const union which has the enum as the tag type
10863 // enum to &const union which has the enum as the tag type
988710864 if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {
988810865 TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
988910866 if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
......@@ -9904,23 +10881,63 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
990410881 }
990510882 }
990610883
9907 // explicit cast from undefined to anything
9908 if (actual_type->id == TypeTableEntryIdUndefLit) {
10884 // cast from *T to *[1]T
10885 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
10886 actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
10887 {
10888 TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
10889 if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 &&
10890 types_match_const_cast_only(ira, array_type->data.array.child_type,
10891 actual_type->data.pointer.child_type, source_node,
10892 !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
10893 {
10894 if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
10895 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
10896 add_error_note(ira->codegen, msg, value->source_node,
10897 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name),
10898 actual_type->data.pointer.alignment));
10899 add_error_note(ira->codegen, msg, source_instr->source_node,
10900 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name),
10901 wanted_type->data.pointer.alignment));
10902 return ira->codegen->invalid_instruction;
10903 }
10904 return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type);
10905 }
10906 }
10907
10908 // cast from T to *T where T is zero bits
10909 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
10910 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
10911 actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
10912 {
10913 type_ensure_zero_bits_known(ira->codegen, actual_type);
10914 if (type_is_invalid(actual_type)) {
10915 return ira->codegen->invalid_instruction;
10916 }
10917 if (!type_has_bits(actual_type)) {
10918 return ir_get_ref(ira, source_instr, value, false, false);
10919 }
10920 }
10921
10922
10923 // cast from undefined to anything
10924 if (actual_type->id == TypeTableEntryIdUndefined) {
990910925 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
991010926 }
991110927
9912 // explicit cast from something to const pointer of it
10928 // cast from something to const pointer of it
991310929 if (!type_requires_comptime(actual_type)) {
991410930 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
9915 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
10931 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {
991610932 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
991710933 }
991810934 }
991910935
9920 ir_add_error_node(ira, source_instr->source_node,
9921 buf_sprintf("invalid cast from type '%s' to '%s'",
9922 buf_ptr(&actual_type->name),
9923 buf_ptr(&wanted_type->name)));
10936 ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
10937 buf_sprintf("expected type '%s', found '%s'",
10938 buf_ptr(&wanted_type->name),
10939 buf_ptr(&actual_type->name)));
10940 report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
992410941 return ira->codegen->invalid_instruction;
992510942}
992610943
......@@ -9937,29 +10954,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
993710954 if (value->value.type->id == TypeTableEntryIdUnreachable)
993810955 return value;
993910956
9940 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->value.type, value);
9941 switch (result) {
9942 case ImplicitCastMatchResultNo:
9943 ir_add_error(ira, value,
9944 buf_sprintf("expected type '%s', found '%s'",
9945 buf_ptr(&expected_type->name),
9946 buf_ptr(&value->value.type->name)));
9947 return ira->codegen->invalid_instruction;
9948
9949 case ImplicitCastMatchResultYes:
9950 return ir_analyze_cast(ira, value, expected_type, value);
9951 case ImplicitCastMatchResultReportedError:
9952 return ira->codegen->invalid_instruction;
9953 }
9954
9955 zig_unreachable();
9956}
9957
9958static IrInstruction *ir_implicit_byval_const_ref_cast(IrAnalyze *ira, IrInstruction *inst) {
9959 if (type_is_copyable(ira->codegen, inst->value.type))
9960 return inst;
9961 TypeTableEntry *const_ref_type = get_pointer_to_type(ira->codegen, inst->value.type, true);
9962 return ir_implicit_cast(ira, inst, const_ref_type);
10957 return ir_analyze_cast(ira, value, expected_type, value);
996310958}
996410959
996510960static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
......@@ -9977,6 +10972,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
997710972 IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
997810973 source_instruction->source_node, child_type);
997910974 copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
10975 result->value.type = child_type;
998010976 return result;
998110977 }
998210978 }
......@@ -9986,21 +10982,6 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
998610982 source_instruction->source_node, ptr);
998710983 load_ptr_instruction->value.type = child_type;
998810984 return load_ptr_instruction;
9989 } else if (type_entry->id == TypeTableEntryIdMetaType) {
9990 ConstExprValue *ptr_val = ir_resolve_const(ira, ptr, UndefBad);
9991 if (!ptr_val)
9992 return ira->codegen->invalid_instruction;
9993
9994 TypeTableEntry *ptr_type = ptr_val->data.x_type;
9995 if (ptr_type->id == TypeTableEntryIdPointer) {
9996 TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
9997 return ir_create_const_type(&ira->new_irb, source_instruction->scope,
9998 source_instruction->source_node, child_type);
9999 } else {
10000 ir_add_error(ira, source_instruction,
10001 buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr_type->name)));
10002 return ira->codegen->invalid_instruction;
10003 }
1000410985 } else {
1000510986 ir_add_error_node(ira, source_instruction->source_node,
1000610987 buf_sprintf("attempt to dereference non pointer type '%s'",
......@@ -10044,11 +11025,11 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out
1004411025 return true;
1004511026}
1004611027
10047static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
11028static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *int_type, uint64_t *out) {
1004811029 if (type_is_invalid(value->value.type))
1004911030 return false;
1005011031
10051 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_usize);
11032 IrInstruction *casted_value = ir_implicit_cast(ira, value, int_type);
1005211033 if (type_is_invalid(casted_value->value.type))
1005311034 return false;
1005411035
......@@ -10060,6 +11041,10 @@ static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out
1006011041 return true;
1006111042}
1006211043
11044static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
11045 return ir_resolve_unsigned(ira, value, ira->codegen->builtin_types.entry_usize, out);
11046}
11047
1006311048static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
1006411049 if (type_is_invalid(value->value.type))
1006511050 return false;
......@@ -10169,7 +11154,9 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
1016911154 if (type_is_invalid(value->value.type))
1017011155 return nullptr;
1017111156
10172 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
11157 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
11158 true, false, PtrLenUnknown,
11159 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
1017311160 TypeTableEntry *str_type = get_slice_type(ira->codegen, ptr_type);
1017411161 IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type);
1017511162 if (type_is_invalid(casted_value->value.type))
......@@ -10267,10 +11254,15 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
1026711254 if (casted_op2 == ira->codegen->invalid_instruction)
1026811255 return ira->codegen->builtin_types.entry_invalid;
1026911256
10270 ConstExprValue *op1_val = &casted_op1->value;
10271 ConstExprValue *op2_val = &casted_op2->value;
10272 if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) {
11257 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {
1027311258 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
11259 ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad);
11260 if (op1_val == nullptr)
11261 return ira->codegen->builtin_types.entry_invalid;
11262
11263 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
11264 if (op2_val == nullptr)
11265 return ira->codegen->builtin_types.entry_invalid;
1027411266
1027511267 assert(casted_op1->value.type->id == TypeTableEntryIdBool);
1027611268 assert(casted_op2->value.type->id == TypeTableEntryIdBool);
......@@ -10307,6 +11299,16 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
1030711299 }
1030811300}
1030911301
11302static bool optional_value_is_null(ConstExprValue *val) {
11303 assert(val->special == ConstValSpecialStatic);
11304 if (get_codegen_ptr_type(val->type) != nullptr) {
11305 return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
11306 val->data.x_ptr.data.hard_coded_addr.addr == 0;
11307 } else {
11308 return val->data.x_optional == nullptr;
11309 }
11310}
11311
1031011312static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
1031111313 IrInstruction *op1 = bin_op_instruction->op1->other;
1031211314 IrInstruction *op2 = bin_op_instruction->op2->other;
......@@ -10315,19 +11317,19 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1031511317 IrBinOp op_id = bin_op_instruction->op_id;
1031611318 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
1031711319 if (is_equality_cmp &&
10318 ((op1->value.type->id == TypeTableEntryIdNullLit && op2->value.type->id == TypeTableEntryIdMaybe) ||
10319 (op2->value.type->id == TypeTableEntryIdNullLit && op1->value.type->id == TypeTableEntryIdMaybe) ||
10320 (op1->value.type->id == TypeTableEntryIdNullLit && op2->value.type->id == TypeTableEntryIdNullLit)))
11320 ((op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdOptional) ||
11321 (op2->value.type->id == TypeTableEntryIdNull && op1->value.type->id == TypeTableEntryIdOptional) ||
11322 (op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdNull)))
1032111323 {
10322 if (op1->value.type->id == TypeTableEntryIdNullLit && op2->value.type->id == TypeTableEntryIdNullLit) {
11324 if (op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdNull) {
1032311325 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
1032411326 out_val->data.x_bool = (op_id == IrBinOpCmpEq);
1032511327 return ira->codegen->builtin_types.entry_bool;
1032611328 }
1032711329 IrInstruction *maybe_op;
10328 if (op1->value.type->id == TypeTableEntryIdNullLit) {
11330 if (op1->value.type->id == TypeTableEntryIdNull) {
1032911331 maybe_op = op2;
10330 } else if (op2->value.type->id == TypeTableEntryIdNullLit) {
11332 } else if (op2->value.type->id == TypeTableEntryIdNull) {
1033111333 maybe_op = op1;
1033211334 } else {
1033311335 zig_unreachable();
......@@ -10336,7 +11338,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1033611338 ConstExprValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad);
1033711339 if (!maybe_val)
1033811340 return ira->codegen->builtin_types.entry_invalid;
10339 bool is_null = (maybe_val->data.x_maybe == nullptr);
11341 bool is_null = optional_value_is_null(maybe_val);
1034011342 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
1034111343 out_val->data.x_bool = (op_id == IrBinOpCmpEq) ? is_null : !is_null;
1034211344 return ira->codegen->builtin_types.entry_bool;
......@@ -10364,7 +11366,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1036411366 return ira->codegen->builtin_types.entry_invalid;
1036511367 }
1036611368
10367 if (!resolve_inferred_error_set(ira, intersect_type, source_node)) {
11369 if (!resolve_inferred_error_set(ira->codegen, intersect_type, source_node)) {
1036811370 return ira->codegen->builtin_types.entry_invalid;
1036911371 }
1037011372
......@@ -10410,9 +11412,14 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1041011412 }
1041111413 }
1041211414
10413 ConstExprValue *op1_val = &op1->value;
10414 ConstExprValue *op2_val = &op2->value;
10415 if (value_is_comptime(op1_val) && value_is_comptime(op2_val)) {
11415 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
11416 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11417 if (op1_val == nullptr)
11418 return ira->codegen->builtin_types.entry_invalid;
11419 ConstExprValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
11420 if (op2_val == nullptr)
11421 return ira->codegen->builtin_types.entry_invalid;
11422
1041611423 bool answer;
1041711424 bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value;
1041811425 if (op_id == IrBinOpCmpEq) {
......@@ -10435,22 +11442,23 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1043511442 }
1043611443
1043711444 IrInstruction *instructions[] = {op1, op2};
10438 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, instructions, 2);
11445 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2);
1043911446 if (type_is_invalid(resolved_type))
1044011447 return resolved_type;
1044111448 type_ensure_zero_bits_known(ira->codegen, resolved_type);
1044211449 if (type_is_invalid(resolved_type))
1044311450 return resolved_type;
1044411451
10445
11452 bool operator_allowed;
1044611453 switch (resolved_type->id) {
1044711454 case TypeTableEntryIdInvalid:
1044811455 zig_unreachable(); // handled above
1044911456
10450 case TypeTableEntryIdNumLitFloat:
10451 case TypeTableEntryIdNumLitInt:
11457 case TypeTableEntryIdComptimeFloat:
11458 case TypeTableEntryIdComptimeInt:
1045211459 case TypeTableEntryIdInt:
1045311460 case TypeTableEntryIdFloat:
11461 operator_allowed = true;
1045411462 break;
1045511463
1045611464 case TypeTableEntryIdBool:
......@@ -10465,32 +11473,27 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1046511473 case TypeTableEntryIdBoundFn:
1046611474 case TypeTableEntryIdArgTuple:
1046711475 case TypeTableEntryIdPromise:
10468 if (!is_equality_cmp) {
10469 ir_add_error_node(ira, source_node,
10470 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
10471 return ira->codegen->builtin_types.entry_invalid;
10472 }
10473 break;
10474
1047511476 case TypeTableEntryIdEnum:
10476 if (!is_equality_cmp) {
10477 ir_add_error_node(ira, source_node,
10478 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
10479 return ira->codegen->builtin_types.entry_invalid;
10480 }
11477 operator_allowed = is_equality_cmp;
1048111478 break;
1048211479
1048311480 case TypeTableEntryIdUnreachable:
1048411481 case TypeTableEntryIdArray:
1048511482 case TypeTableEntryIdStruct:
10486 case TypeTableEntryIdUndefLit:
10487 case TypeTableEntryIdNullLit:
10488 case TypeTableEntryIdMaybe:
11483 case TypeTableEntryIdUndefined:
11484 case TypeTableEntryIdNull:
1048911485 case TypeTableEntryIdErrorUnion:
1049011486 case TypeTableEntryIdUnion:
10491 ir_add_error_node(ira, source_node,
10492 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
10493 return ira->codegen->builtin_types.entry_invalid;
11487 operator_allowed = false;
11488 break;
11489 case TypeTableEntryIdOptional:
11490 operator_allowed = is_equality_cmp && get_codegen_ptr_type(resolved_type) != nullptr;
11491 break;
11492 }
11493 if (!operator_allowed) {
11494 ir_add_error_node(ira, source_node,
11495 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
11496 return ira->codegen->builtin_types.entry_invalid;
1049411497 }
1049511498
1049611499 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, resolved_type);
......@@ -10501,15 +11504,20 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1050111504 if (casted_op2 == ira->codegen->invalid_instruction)
1050211505 return ira->codegen->builtin_types.entry_invalid;
1050311506
10504 ConstExprValue *op1_val = &casted_op1->value;
10505 ConstExprValue *op2_val = &casted_op2->value;
1050611507 bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type);
10507 if (one_possible_value || (value_is_comptime(op1_val) && value_is_comptime(op2_val))) {
11508 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
11509 ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
11510 if (op1_val == nullptr)
11511 return ira->codegen->builtin_types.entry_invalid;
11512 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);
11513 if (op2_val == nullptr)
11514 return ira->codegen->builtin_types.entry_invalid;
11515
1050811516 bool answer;
10509 if (resolved_type->id == TypeTableEntryIdNumLitFloat || resolved_type->id == TypeTableEntryIdFloat) {
11517 if (resolved_type->id == TypeTableEntryIdComptimeFloat || resolved_type->id == TypeTableEntryIdFloat) {
1051011518 Cmp cmp_result = float_cmp(op1_val, op2_val);
1051111519 answer = resolve_cmp_op_id(op_id, cmp_result);
10512 } else if (resolved_type->id == TypeTableEntryIdNumLitInt || resolved_type->id == TypeTableEntryIdInt) {
11520 } else if (resolved_type->id == TypeTableEntryIdComptimeInt || resolved_type->id == TypeTableEntryIdInt) {
1051311521 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
1051411522 answer = resolve_cmp_op_id(op_id, cmp_result);
1051511523 } else {
......@@ -10532,11 +11540,17 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1053211540 if (resolved_type->id == TypeTableEntryIdInt && !resolved_type->data.integral.is_signed) {
1053311541 ConstExprValue *known_left_val;
1053411542 IrBinOp flipped_op_id;
10535 if (value_is_comptime(op1_val)) {
10536 known_left_val = op1_val;
11543 if (instr_is_comptime(casted_op1)) {
11544 known_left_val = ir_resolve_const(ira, casted_op1, UndefBad);
11545 if (known_left_val == nullptr)
11546 return ira->codegen->builtin_types.entry_invalid;
11547
1053711548 flipped_op_id = op_id;
10538 } else if (value_is_comptime(op2_val)) {
10539 known_left_val = op2_val;
11549 } else if (instr_is_comptime(casted_op2)) {
11550 known_left_val = ir_resolve_const(ira, casted_op2, UndefBad);
11551 if (known_left_val == nullptr)
11552 return ira->codegen->builtin_types.entry_invalid;
11553
1054011554 if (op_id == IrBinOpCmpLessThan) {
1054111555 flipped_op_id = IrBinOpCmpGreaterThan;
1054211556 } else if (op_id == IrBinOpCmpGreaterThan) {
......@@ -10573,12 +11587,12 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
1057311587 bool is_int;
1057411588 bool is_float;
1057511589 Cmp op2_zcmp;
10576 if (type_entry->id == TypeTableEntryIdInt || type_entry->id == TypeTableEntryIdNumLitInt) {
11590 if (type_entry->id == TypeTableEntryIdInt || type_entry->id == TypeTableEntryIdComptimeInt) {
1057711591 is_int = true;
1057811592 is_float = false;
1057911593 op2_zcmp = bigint_cmp_zero(&op2_val->data.x_bigint);
1058011594 } else if (type_entry->id == TypeTableEntryIdFloat ||
10581 type_entry->id == TypeTableEntryIdNumLitFloat)
11595 type_entry->id == TypeTableEntryIdComptimeFloat)
1058211596 {
1058311597 is_int = false;
1058411598 is_float = true;
......@@ -10752,7 +11766,7 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1075211766 if (type_is_invalid(op1->value.type))
1075311767 return ira->codegen->builtin_types.entry_invalid;
1075411768
10755 if (op1->value.type->id != TypeTableEntryIdInt && op1->value.type->id != TypeTableEntryIdNumLitInt) {
11769 if (op1->value.type->id != TypeTableEntryIdInt && op1->value.type->id != TypeTableEntryIdComptimeInt) {
1075611770 ir_add_error(ira, &bin_op_instruction->base,
1075711771 buf_sprintf("bit shifting operation expected integer type, found '%s'",
1075811772 buf_ptr(&op1->value.type->name)));
......@@ -10765,7 +11779,7 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1076511779
1076611780 IrInstruction *casted_op2;
1076711781 IrBinOp op_id = bin_op_instruction->op_id;
10768 if (op1->value.type->id == TypeTableEntryIdNumLitInt) {
11782 if (op1->value.type->id == TypeTableEntryIdComptimeInt) {
1076911783 casted_op2 = op2;
1077011784
1077111785 if (op_id == IrBinOpBitShiftLeftLossy) {
......@@ -10781,6 +11795,26 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1078111795 } else {
1078211796 TypeTableEntry *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
1078311797 op1->value.type->data.integral.bit_count - 1);
11798 if (bin_op_instruction->op_id == IrBinOpBitShiftLeftLossy &&
11799 op2->value.type->id == TypeTableEntryIdComptimeInt) {
11800 if (!bigint_fits_in_bits(&op2->value.data.x_bigint,
11801 shift_amt_type->data.integral.bit_count,
11802 op2->value.data.x_bigint.is_negative)) {
11803 Buf *val_buf = buf_alloc();
11804 bigint_append_buf(val_buf, &op2->value.data.x_bigint, 10);
11805 ErrorMsg* msg = ir_add_error(ira,
11806 &bin_op_instruction->base,
11807 buf_sprintf("RHS of shift is too large for LHS type"));
11808 add_error_note(
11809 ira->codegen,
11810 msg,
11811 op2->source_node,
11812 buf_sprintf("value %s cannot fit into type %s",
11813 buf_ptr(val_buf),
11814 buf_ptr(&shift_amt_type->name)));
11815 return ira->codegen->builtin_types.entry_invalid;
11816 }
11817 }
1078411818
1078511819 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
1078611820 if (casted_op2 == ira->codegen->invalid_instruction)
......@@ -10788,8 +11822,14 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1078811822 }
1078911823
1079011824 if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {
10791 ConstExprValue *op1_val = &op1->value;
10792 ConstExprValue *op2_val = &casted_op2->value;
11825 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11826 if (op1_val == nullptr)
11827 return ira->codegen->builtin_types.entry_invalid;
11828
11829 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
11830 if (op2_val == nullptr)
11831 return ira->codegen->builtin_types.entry_invalid;
11832
1079311833 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);
1079411834 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);
1079511835 ConstExprValue *out_val = &result_instruction->value;
......@@ -10810,7 +11850,7 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1081011850
1081111851 ir_num_lit_fits_in_other_type(ira, result_instruction, op1->value.type, false);
1081211852 return op1->value.type;
10813 } else if (op1->value.type->id == TypeTableEntryIdNumLitInt) {
11853 } else if (op1->value.type->id == TypeTableEntryIdComptimeInt) {
1081411854 ir_add_error(ira, &bin_op_instruction->base,
1081511855 buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known"));
1081611856 return ira->codegen->builtin_types.entry_invalid;
......@@ -10823,22 +11863,44 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1082311863
1082411864static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
1082511865 IrInstruction *op1 = bin_op_instruction->op1->other;
11866 if (type_is_invalid(op1->value.type))
11867 return ira->codegen->builtin_types.entry_invalid;
11868
1082611869 IrInstruction *op2 = bin_op_instruction->op2->other;
11870 if (type_is_invalid(op2->value.type))
11871 return ira->codegen->builtin_types.entry_invalid;
11872
11873 IrBinOp op_id = bin_op_instruction->op_id;
11874
11875 // look for pointer math
11876 if (op1->value.type->id == TypeTableEntryIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown &&
11877 (op_id == IrBinOpAdd || op_id == IrBinOpSub))
11878 {
11879 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);
11880 if (casted_op2 == ira->codegen->invalid_instruction)
11881 return ira->codegen->builtin_types.entry_invalid;
11882
11883 IrInstruction *result = ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.scope,
11884 bin_op_instruction->base.source_node, op_id, op1, casted_op2, true);
11885 result->value.type = op1->value.type;
11886 ir_link_new_instruction(result, &bin_op_instruction->base);
11887 return result->value.type;
11888 }
11889
1082711890 IrInstruction *instructions[] = {op1, op2};
10828 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
11891 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, nullptr, instructions, 2);
1082911892 if (type_is_invalid(resolved_type))
1083011893 return resolved_type;
10831 IrBinOp op_id = bin_op_instruction->op_id;
1083211894
10833 bool is_int = resolved_type->id == TypeTableEntryIdInt || resolved_type->id == TypeTableEntryIdNumLitInt;
10834 bool is_float = resolved_type->id == TypeTableEntryIdFloat || resolved_type->id == TypeTableEntryIdNumLitFloat;
11895 bool is_int = resolved_type->id == TypeTableEntryIdInt || resolved_type->id == TypeTableEntryIdComptimeInt;
11896 bool is_float = resolved_type->id == TypeTableEntryIdFloat || resolved_type->id == TypeTableEntryIdComptimeFloat;
1083511897 bool is_signed_div = (
1083611898 (resolved_type->id == TypeTableEntryIdInt && resolved_type->data.integral.is_signed) ||
1083711899 resolved_type->id == TypeTableEntryIdFloat ||
10838 (resolved_type->id == TypeTableEntryIdNumLitFloat &&
11900 (resolved_type->id == TypeTableEntryIdComptimeFloat &&
1083911901 ((bigfloat_cmp_zero(&op1->value.data.x_bigfloat) != CmpGT) !=
1084011902 (bigfloat_cmp_zero(&op2->value.data.x_bigfloat) != CmpGT))) ||
10841 (resolved_type->id == TypeTableEntryIdNumLitInt &&
11903 (resolved_type->id == TypeTableEntryIdComptimeInt &&
1084211904 ((bigint_cmp_zero(&op1->value.data.x_bigint) != CmpGT) !=
1084311905 (bigint_cmp_zero(&op2->value.data.x_bigint) != CmpGT)))
1084411906 );
......@@ -10846,7 +11908,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1084611908 if (is_signed_div) {
1084711909 bool ok = false;
1084811910 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
10849 if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) {
11911 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11912 if (op1_val == nullptr)
11913 return ira->codegen->builtin_types.entry_invalid;
11914
11915 ConstExprValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
11916 if (op2_val == nullptr)
11917 return ira->codegen->builtin_types.entry_invalid;
11918
11919 if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ) {
1085011920 // the division by zero error will be caught later, but we don't have a
1085111921 // division function ambiguity problem.
1085211922 op_id = IrBinOpDivTrunc;
......@@ -10854,8 +11924,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1085411924 } else {
1085511925 BigInt trunc_result;
1085611926 BigInt floor_result;
10857 bigint_div_trunc(&trunc_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
10858 bigint_div_floor(&floor_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
11927 bigint_div_trunc(&trunc_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
11928 bigint_div_floor(&floor_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
1085911929 if (bigint_cmp(&trunc_result, &floor_result) == CmpEQ) {
1086011930 ok = true;
1086111931 op_id = IrBinOpDivTrunc;
......@@ -10876,7 +11946,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1087611946 if (is_signed_div && (is_int || is_float)) {
1087711947 bool ok = false;
1087811948 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
11949 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11950 if (op1_val == nullptr)
11951 return ira->codegen->builtin_types.entry_invalid;
11952
1087911953 if (is_int) {
11954 ConstExprValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
11955 if (op2_val == nullptr)
11956 return ira->codegen->builtin_types.entry_invalid;
11957
1088011958 if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) {
1088111959 // the division by zero error will be caught later, but we don't
1088211960 // have a remainder function ambiguity problem
......@@ -10884,14 +11962,19 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1088411962 } else {
1088511963 BigInt rem_result;
1088611964 BigInt mod_result;
10887 bigint_rem(&rem_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
10888 bigint_mod(&mod_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
11965 bigint_rem(&rem_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
11966 bigint_mod(&mod_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
1088911967 ok = bigint_cmp(&rem_result, &mod_result) == CmpEQ;
1089011968 }
1089111969 } else {
1089211970 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, resolved_type);
1089311971 if (casted_op2 == ira->codegen->invalid_instruction)
1089411972 return ira->codegen->builtin_types.entry_invalid;
11973
11974 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
11975 if (op2_val == nullptr)
11976 return ira->codegen->builtin_types.entry_invalid;
11977
1089511978 if (float_cmp_zero(&casted_op2->value) == CmpEQ) {
1089611979 // the division by zero error will be caught later, but we don't
1089711980 // have a remainder function ambiguity problem
......@@ -10899,8 +11982,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1089911982 } else {
1090011983 ConstExprValue rem_result;
1090111984 ConstExprValue mod_result;
10902 float_rem(&rem_result, &op1->value, &casted_op2->value);
10903 float_mod(&mod_result, &op1->value, &casted_op2->value);
11985 float_rem(&rem_result, op1_val, op2_val);
11986 float_mod(&mod_result, op1_val, op2_val);
1090411987 ok = float_cmp(&rem_result, &mod_result) == CmpEQ;
1090511988 }
1090611989 }
......@@ -10939,7 +12022,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1093912022 return ira->codegen->builtin_types.entry_invalid;
1094012023 }
1094112024
10942 if (resolved_type->id == TypeTableEntryIdNumLitInt) {
12025 if (resolved_type->id == TypeTableEntryIdComptimeInt) {
1094312026 if (op_id == IrBinOpAddWrap) {
1094412027 op_id = IrBinOpAdd;
1094512028 } else if (op_id == IrBinOpSubWrap) {
......@@ -10958,8 +12041,13 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1095812041 return ira->codegen->builtin_types.entry_invalid;
1095912042
1096012043 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {
10961 ConstExprValue *op1_val = &casted_op1->value;
10962 ConstExprValue *op2_val = &casted_op2->value;
12044 ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad);
12045 if (op1_val == nullptr)
12046 return ira->codegen->builtin_types.entry_invalid;
12047 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
12048 if (op2_val == nullptr)
12049 return ira->codegen->builtin_types.entry_invalid;
12050
1096312051 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);
1096412052 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);
1096512053 ConstExprValue *out_val = &result_instruction->value;
......@@ -11101,7 +12189,8 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
1110112189
1110212190 out_array_val = out_val;
1110312191 } else if (is_slice(op1_type) || is_slice(op2_type)) {
11104 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, child_type, true);
12192 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
12193 true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, child_type), 0, 0);
1110512194 result_type = get_slice_type(ira->codegen, ptr_type);
1110612195 out_array_val = create_const_vals(1);
1110712196 out_array_val->special = ConstValSpecialStatic;
......@@ -11121,7 +12210,9 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
1112112210 } else {
1112212211 new_len += 1; // null byte
1112312212
11124 result_type = get_pointer_to_type(ira->codegen, child_type, true);
12213 // TODO make this `[*]null T` instead of `[*]T`
12214 result_type = get_pointer_to_type_extra(ira->codegen, child_type, true, false,
12215 PtrLenUnknown, get_abi_alignment(ira->codegen, child_type), 0, 0);
1112512216
1112612217 out_array_val = create_const_vals(1);
1112712218 out_array_val->special = ConstValSpecialStatic;
......@@ -11131,9 +12222,16 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
1113112222 out_val->data.x_ptr.data.base_array.array_val = out_array_val;
1113212223 out_val->data.x_ptr.data.base_array.elem_index = 0;
1113312224 }
11134 out_array_val->data.x_array.s_none.elements = create_const_vals(new_len);
1113512225
12226 if (op1_array_val->data.x_array.special == ConstArraySpecialUndef &&
12227 op2_array_val->data.x_array.special == ConstArraySpecialUndef) {
12228 out_array_val->data.x_array.special = ConstArraySpecialUndef;
12229 return result_type;
12230 }
12231
12232 out_array_val->data.x_array.s_none.elements = create_const_vals(new_len);
1113612233 expand_undef_array(ira->codegen, op1_array_val);
12234 expand_undef_array(ira->codegen, op2_array_val);
1113712235
1113812236 size_t next_index = 0;
1113912237 for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) {
......@@ -11185,10 +12283,14 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
1118512283 }
1118612284
1118712285 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
12286 if (array_val->data.x_array.special == ConstArraySpecialUndef) {
12287 out_val->data.x_array.special = ConstArraySpecialUndef;
1118812288
11189 out_val->data.x_array.s_none.elements = create_const_vals(new_array_len);
12289 TypeTableEntry *child_type = array_type->data.array.child_type;
12290 return get_array_type(ira->codegen, child_type, new_array_len);
12291 }
1119012292
11191 expand_undef_array(ira->codegen, array_val);
12293 out_val->data.x_array.s_none.elements = create_const_vals(new_array_len);
1119212294
1119312295 uint64_t i = 0;
1119412296 for (uint64_t x = 0; x < mult_amt; x += 1) {
......@@ -11220,11 +12322,11 @@ static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstruction
1122012322 return ira->codegen->builtin_types.entry_type;
1122112323 }
1122212324
11223 if (!resolve_inferred_error_set(ira, op1_type, instruction->op1->other->source_node)) {
12325 if (!resolve_inferred_error_set(ira->codegen, op1_type, instruction->op1->other->source_node)) {
1122412326 return ira->codegen->builtin_types.entry_invalid;
1122512327 }
1122612328
11227 if (!resolve_inferred_error_set(ira, op2_type, instruction->op2->other->source_node)) {
12329 if (!resolve_inferred_error_set(ira->codegen, op2_type, instruction->op2->other->source_node)) {
1122812330 return ira->codegen->builtin_types.entry_invalid;
1122912331 }
1123012332
......@@ -11290,61 +12392,6 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
1129012392 zig_unreachable();
1129112393}
1129212394
11293enum VarClassRequired {
11294 VarClassRequiredAny,
11295 VarClassRequiredConst,
11296 VarClassRequiredIllegal,
11297};
11298
11299static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
11300 switch (type_entry->id) {
11301 case TypeTableEntryIdInvalid:
11302 zig_unreachable();
11303 case TypeTableEntryIdUnreachable:
11304 return VarClassRequiredIllegal;
11305 case TypeTableEntryIdBool:
11306 case TypeTableEntryIdInt:
11307 case TypeTableEntryIdFloat:
11308 case TypeTableEntryIdVoid:
11309 case TypeTableEntryIdErrorSet:
11310 case TypeTableEntryIdFn:
11311 case TypeTableEntryIdPromise:
11312 return VarClassRequiredAny;
11313 case TypeTableEntryIdNumLitFloat:
11314 case TypeTableEntryIdNumLitInt:
11315 case TypeTableEntryIdUndefLit:
11316 case TypeTableEntryIdBlock:
11317 case TypeTableEntryIdNullLit:
11318 case TypeTableEntryIdOpaque:
11319 case TypeTableEntryIdMetaType:
11320 case TypeTableEntryIdNamespace:
11321 case TypeTableEntryIdBoundFn:
11322 case TypeTableEntryIdArgTuple:
11323 return VarClassRequiredConst;
11324
11325 case TypeTableEntryIdPointer:
11326 if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
11327 return VarClassRequiredAny;
11328 } else {
11329 return get_var_class_required(type_entry->data.pointer.child_type);
11330 }
11331 case TypeTableEntryIdArray:
11332 return get_var_class_required(type_entry->data.array.child_type);
11333 case TypeTableEntryIdMaybe:
11334 return get_var_class_required(type_entry->data.maybe.child_type);
11335 case TypeTableEntryIdErrorUnion:
11336 return get_var_class_required(type_entry->data.error_union.payload_type);
11337
11338 case TypeTableEntryIdStruct:
11339 case TypeTableEntryIdEnum:
11340 case TypeTableEntryIdUnion:
11341 // TODO check the fields of these things and make sure that they don't recursively
11342 // contain any of the other variable classes
11343 return VarClassRequiredAny;
11344 }
11345 zig_unreachable();
11346}
11347
1134812395static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
1134912396 VariableTableEntry *var = decl_var_instruction->var;
1135012397
......@@ -11379,36 +12426,41 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1137912426 if (type_is_invalid(result_type)) {
1138012427 result_type = ira->codegen->builtin_types.entry_invalid;
1138112428 } else {
11382 switch (get_var_class_required(result_type)) {
11383 case VarClassRequiredIllegal:
12429 type_ensure_zero_bits_known(ira->codegen, result_type);
12430 if (type_is_invalid(result_type)) {
12431 result_type = ira->codegen->builtin_types.entry_invalid;
12432 }
12433 }
12434
12435 if (!type_is_invalid(result_type)) {
12436 if (result_type->id == TypeTableEntryIdUnreachable ||
12437 result_type->id == TypeTableEntryIdOpaque)
12438 {
12439 ir_add_error_node(ira, source_node,
12440 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
12441 result_type = ira->codegen->builtin_types.entry_invalid;
12442 } else if (type_requires_comptime(result_type)) {
12443 var_class_requires_const = true;
12444 if (!var->gen_is_const && !is_comptime_var) {
1138412445 ir_add_error_node(ira, source_node,
11385 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
12446 buf_sprintf("variable of type '%s' must be const or comptime",
12447 buf_ptr(&result_type->name)));
1138612448 result_type = ira->codegen->builtin_types.entry_invalid;
11387 break;
11388 case VarClassRequiredConst:
12449 }
12450 } else {
12451 if (casted_init_value->value.special == ConstValSpecialStatic &&
12452 casted_init_value->value.type->id == TypeTableEntryIdFn &&
12453 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
12454 {
1138912455 var_class_requires_const = true;
1139012456 if (!var->src_is_const && !is_comptime_var) {
11391 ir_add_error_node(ira, source_node,
11392 buf_sprintf("variable of type '%s' must be const or comptime",
11393 buf_ptr(&result_type->name)));
12457 ErrorMsg *msg = ir_add_error_node(ira, source_node,
12458 buf_sprintf("functions marked inline must be stored in const or comptime var"));
12459 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
12460 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
1139412461 result_type = ira->codegen->builtin_types.entry_invalid;
1139512462 }
11396 break;
11397 case VarClassRequiredAny:
11398 if (casted_init_value->value.special == ConstValSpecialStatic &&
11399 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11400 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11401 {
11402 var_class_requires_const = true;
11403 if (!var->src_is_const && !is_comptime_var) {
11404 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11405 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11406 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11407 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
11408 result_type = ira->codegen->builtin_types.entry_invalid;
11409 }
11410 }
11411 break;
12463 }
1141212464 }
1141312465 }
1141412466
......@@ -11432,7 +12484,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1143212484 if (var->mem_slot_index != SIZE_MAX) {
1143312485 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
1143412486 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
11435 *mem_slot = casted_init_value->value;
12487 copy_const_val(mem_slot, &casted_init_value->value,
12488 !is_comptime_var || var->gen_is_const);
1143612489
1143712490 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
1143812491 ir_build_const_from(ira, &decl_var_instruction->base);
......@@ -11578,11 +12631,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1157812631 case TypeTableEntryIdMetaType:
1157912632 case TypeTableEntryIdVoid:
1158012633 case TypeTableEntryIdUnreachable:
11581 case TypeTableEntryIdNumLitFloat:
11582 case TypeTableEntryIdNumLitInt:
11583 case TypeTableEntryIdUndefLit:
11584 case TypeTableEntryIdNullLit:
11585 case TypeTableEntryIdMaybe:
12634 case TypeTableEntryIdComptimeFloat:
12635 case TypeTableEntryIdComptimeInt:
12636 case TypeTableEntryIdUndefined:
12637 case TypeTableEntryIdNull:
12638 case TypeTableEntryIdOptional:
1158612639 case TypeTableEntryIdErrorUnion:
1158712640 case TypeTableEntryIdErrorSet:
1158812641 case TypeTableEntryIdNamespace:
......@@ -11602,11 +12655,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1160212655 case TypeTableEntryIdFloat:
1160312656 case TypeTableEntryIdPointer:
1160412657 case TypeTableEntryIdArray:
11605 case TypeTableEntryIdNumLitFloat:
11606 case TypeTableEntryIdNumLitInt:
11607 case TypeTableEntryIdUndefLit:
11608 case TypeTableEntryIdNullLit:
11609 case TypeTableEntryIdMaybe:
12658 case TypeTableEntryIdComptimeFloat:
12659 case TypeTableEntryIdComptimeInt:
12660 case TypeTableEntryIdUndefined:
12661 case TypeTableEntryIdNull:
12662 case TypeTableEntryIdOptional:
1161012663 case TypeTableEntryIdErrorUnion:
1161112664 case TypeTableEntryIdErrorSet:
1161212665 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
......@@ -11633,22 +12686,24 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
1163312686static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1163412687 IrInstructionErrorReturnTrace *instruction)
1163512688{
11636 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
12689 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
1163712690 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11638 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
12691 TypeTableEntry *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);
1163912692 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
1164012693 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11641 out_val->data.x_maybe = nullptr;
11642 return nullable_type;
12694 assert(get_codegen_ptr_type(optional_type) != nullptr);
12695 out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
12696 out_val->data.x_ptr.data.hard_coded_addr.addr = 0;
12697 return optional_type;
1164312698 }
1164412699 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11645 instruction->base.source_node, instruction->nullable);
12700 instruction->base.source_node, instruction->optional);
1164612701 ir_link_new_instruction(new_instruction, &instruction->base);
11647 return nullable_type;
12702 return optional_type;
1164812703 } else {
1164912704 assert(ira->codegen->have_err_ret_tracing);
1165012705 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11651 instruction->base.source_node, instruction->nullable);
12706 instruction->base.source_node, instruction->optional);
1165212707 ir_link_new_instruction(new_instruction, &instruction->base);
1165312708 return get_ptr_to_stack_trace_type(ira->codegen);
1165412709 }
......@@ -11706,7 +12761,7 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i
1170612761 {
1170712762 VariableTableEntry *coro_allocator_var = ira->old_irb.exec->coro_allocator_var;
1170812763 assert(coro_allocator_var != nullptr);
11709 IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var, true, false);
12764 IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var);
1171012765 IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst);
1171112766 assert(result->value.type != nullptr);
1171212767 return result;
......@@ -11749,7 +12804,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
1174912804 TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
1175012805
1175112806 IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
11752 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst);
12807 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
1175312808 result->value.type = async_return_type;
1175412809 return result;
1175512810}
......@@ -11799,7 +12854,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1179912854 IrInstruction *casted_arg;
1180012855 if (is_var_args) {
1180112856 arg_part_of_generic_id = true;
11802 casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
12857 casted_arg = arg;
1180312858 } else {
1180412859 if (param_decl_node->data.param_decl.var_token == nullptr) {
1180512860 AstNode *param_type_node = param_decl_node->data.param_decl.type;
......@@ -11812,12 +12867,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1181212867 return false;
1181312868 } else {
1181412869 arg_part_of_generic_id = true;
11815 casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
12870 casted_arg = arg;
1181612871 }
1181712872 }
1181812873
1181912874 bool comptime_arg = param_decl_node->data.param_decl.is_inline ||
11820 casted_arg->value.type->id == TypeTableEntryIdNumLitInt || casted_arg->value.type->id == TypeTableEntryIdNumLitFloat;
12875 casted_arg->value.type->id == TypeTableEntryIdComptimeInt || casted_arg->value.type->id == TypeTableEntryIdComptimeFloat;
1182112876
1182212877 ConstExprValue *arg_val;
1182312878
......@@ -11835,6 +12890,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1183512890 }
1183612891
1183712892 Buf *param_name = param_decl_node->data.param_decl.name;
12893 if (!param_name) return false;
1183812894 if (!is_var_args) {
1183912895 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
1184012896 *child_scope, param_name, true, arg_val, nullptr);
......@@ -11842,11 +12898,11 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1184212898 var->shadowable = !comptime_arg;
1184312899
1184412900 *next_proto_i += 1;
11845 } else if (casted_arg->value.type->id == TypeTableEntryIdNumLitInt ||
11846 casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
12901 } else if (casted_arg->value.type->id == TypeTableEntryIdComptimeInt ||
12902 casted_arg->value.type->id == TypeTableEntryIdComptimeFloat)
1184712903 {
1184812904 ir_add_error(ira, casted_arg,
11849 buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));
12905 buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/ziglang/zig/issues/557"));
1185012906 return false;
1185112907 }
1185212908
......@@ -11887,7 +12943,7 @@ static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t in
1188712943}
1188812944
1188912945static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
11890 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
12946 VariableTableEntry *var)
1189112947{
1189212948 if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) {
1189312949 assert(ira->codegen->errors.length != 0);
......@@ -11913,8 +12969,8 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1191312969 }
1191412970 }
1191512971
11916 bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
11917 bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
12972 bool is_const = var->src_is_const;
12973 bool is_volatile = false;
1191812974 if (mem_slot != nullptr) {
1191912975 switch (mem_slot->special) {
1192012976 case ConstValSpecialRuntime:
......@@ -11940,9 +12996,9 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1194012996no_mem_slot:
1194112997
1194212998 IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
11943 instruction->scope, instruction->source_node, var, is_const, is_volatile);
12999 instruction->scope, instruction->source_node, var);
1194413000 var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
11945 var->src_is_const, is_volatile, var->align_bytes, 0, 0);
13001 var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
1194613002 type_ensure_zero_bits_known(ira->codegen, var->value->type);
1194713003
1194813004 bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
......@@ -11961,14 +13017,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1196113017 // for extern functions, the var args argument is not counted.
1196213018 // for zig functions, it is.
1196313019 size_t var_args_1_or_0;
11964 if (fn_type_id->cc == CallingConventionUnspecified) {
11965 var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
11966 } else {
13020 if (fn_type_id->cc == CallingConventionC) {
1196713021 var_args_1_or_0 = 0;
13022 } else {
13023 var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
1196813024 }
1196913025 size_t src_param_count = fn_type_id->param_count - var_args_1_or_0;
1197013026
1197113027 size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0;
13028 for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
13029 ConstExprValue *arg_tuple_value = &call_instruction->args[i]->other->value;
13030 if (arg_tuple_value->type->id == TypeTableEntryIdArgTuple) {
13031 call_param_count -= 1;
13032 call_param_count += arg_tuple_value->data.x_arg_tuple.end_index -
13033 arg_tuple_value->data.x_arg_tuple.start_index;
13034 }
13035 }
1197213036 AstNode *source_node = call_instruction->base.source_node;
1197313037
1197413038 AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;;
......@@ -12031,9 +13095,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1203113095
1203213096 size_t next_proto_i = 0;
1203313097 if (first_arg_ptr) {
12034 IrInstruction *first_arg;
1203513098 assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
12036 if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
13099
13100 bool first_arg_known_bare = false;
13101 if (fn_type_id->next_param_index >= 1) {
13102 TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
13103 if (type_is_invalid(param_type))
13104 return ira->codegen->builtin_types.entry_invalid;
13105 first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
13106 }
13107
13108 IrInstruction *first_arg;
13109 if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
1203713110 first_arg = first_arg_ptr;
1203813111 } else {
1203913112 first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
......@@ -12047,7 +13120,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1204713120
1204813121 if (fn_proto_node->data.fn_proto.is_var_args) {
1204913122 ir_add_error(ira, &call_instruction->base,
12050 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));
13123 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/ziglang/zig/issues/313"));
1205113124 return ira->codegen->builtin_types.entry_invalid;
1205213125 }
1205313126
......@@ -12119,17 +13192,27 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1211913192 return ir_finish_anal(ira, return_type);
1212013193 }
1212113194
13195 IrInstruction *casted_new_stack = nullptr;
13196 if (call_instruction->new_stack != nullptr) {
13197 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
13198 false, false, PtrLenUnknown,
13199 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
13200 TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
13201 IrInstruction *new_stack = call_instruction->new_stack->other;
13202 if (type_is_invalid(new_stack->value.type))
13203 return ira->codegen->builtin_types.entry_invalid;
13204
13205 casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
13206 if (type_is_invalid(casted_new_stack->value.type))
13207 return ira->codegen->builtin_types.entry_invalid;
13208 }
13209
1212213210 if (fn_type->data.fn.is_generic) {
1212313211 if (!fn_entry) {
1212413212 ir_add_error(ira, call_instruction->fn_ref,
1212513213 buf_sprintf("calling a generic function requires compile-time known function value"));
1212613214 return ira->codegen->builtin_types.entry_invalid;
1212713215 }
12128 if (call_instruction->is_async && fn_type_id->is_var_args) {
12129 ir_add_error(ira, call_instruction->fn_ref,
12130 buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/zig-lang/zig/issues/557"));
12131 return ira->codegen->builtin_types.entry_invalid;
12132 }
1213313216
1213413217 // Count the arguments of the function type id we are creating
1213513218 size_t new_fn_arg_count = first_arg_1_or_0;
......@@ -12168,9 +13251,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1216813251 size_t next_proto_i = 0;
1216913252
1217013253 if (first_arg_ptr) {
12171 IrInstruction *first_arg;
1217213254 assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
12173 if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
13255
13256 bool first_arg_known_bare = false;
13257 if (fn_type_id->next_param_index >= 1) {
13258 TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
13259 if (type_is_invalid(param_type))
13260 return ira->codegen->builtin_types.entry_invalid;
13261 first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
13262 }
13263
13264 IrInstruction *first_arg;
13265 if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
1217413266 first_arg = first_arg_ptr;
1217513267 } else {
1217613268 first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
......@@ -12195,25 +13287,25 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1219513287 if (type_is_invalid(arg->value.type))
1219613288 return ira->codegen->builtin_types.entry_invalid;
1219713289
12198 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
12199 assert(param_decl_node->type == NodeTypeParamDecl);
12200 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
12201 if (is_var_args && !found_first_var_arg) {
12202 first_var_arg = inst_fn_type_id.param_count;
12203 found_first_var_arg = true;
12204 }
12205
1220613290 if (arg->value.type->id == TypeTableEntryIdArgTuple) {
1220713291 for (size_t arg_tuple_i = arg->value.data.x_arg_tuple.start_index;
1220813292 arg_tuple_i < arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
1220913293 {
13294 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
13295 assert(param_decl_node->type == NodeTypeParamDecl);
13296 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
13297 if (is_var_args && !found_first_var_arg) {
13298 first_var_arg = inst_fn_type_id.param_count;
13299 found_first_var_arg = true;
13300 }
13301
1221013302 VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
1221113303 if (arg_var == nullptr) {
1221213304 ir_add_error(ira, arg,
12213 buf_sprintf("compiler bug: var args can't handle void. https://github.com/zig-lang/zig/issues/557"));
13305 buf_sprintf("compiler bug: var args can't handle void. https://github.com/ziglang/zig/issues/557"));
1221413306 return ira->codegen->builtin_types.entry_invalid;
1221513307 }
12216 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);
13308 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var);
1221713309 if (type_is_invalid(arg_var_ptr_inst->value.type))
1221813310 return ira->codegen->builtin_types.entry_invalid;
1221913311
......@@ -12227,10 +13319,20 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1222713319 return ira->codegen->builtin_types.entry_invalid;
1222813320 }
1222913321 }
12230 } else if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
12231 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
12232 {
12233 return ira->codegen->builtin_types.entry_invalid;
13322 } else {
13323 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
13324 assert(param_decl_node->type == NodeTypeParamDecl);
13325 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
13326 if (is_var_args && !found_first_var_arg) {
13327 first_var_arg = inst_fn_type_id.param_count;
13328 found_first_var_arg = true;
13329 }
13330
13331 if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
13332 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
13333 {
13334 return ira->codegen->builtin_types.entry_invalid;
13335 }
1223413336 }
1223513337 }
1223613338
......@@ -12273,6 +13375,10 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1227313375 inst_fn_type_id.return_type = specified_return_type;
1227413376 }
1227513377
13378 type_ensure_zero_bits_known(ira->codegen, specified_return_type);
13379 if (type_is_invalid(specified_return_type))
13380 return ira->codegen->builtin_types.entry_invalid;
13381
1227613382 if (type_requires_comptime(specified_return_type)) {
1227713383 // Throw out our work and call the function as if it were comptime.
1227813384 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
......@@ -12299,10 +13405,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1229913405 return ira->codegen->builtin_types.entry_invalid;
1230013406 }
1230113407 if (inst_fn_type_id.async_allocator_type == nullptr) {
12302 IrInstruction *casted_inst = ir_implicit_byval_const_ref_cast(ira, uncasted_async_allocator_inst);
12303 if (type_is_invalid(casted_inst->value.type))
12304 return ira->codegen->builtin_types.entry_invalid;
12305 inst_fn_type_id.async_allocator_type = casted_inst->value.type;
13408 inst_fn_type_id.async_allocator_type = uncasted_async_allocator_inst->value.type;
1230613409 }
1230713410 async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
1230813411 if (type_is_invalid(async_allocator_inst->value.type))
......@@ -12323,6 +13426,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1232313426 impl_fn->ir_executable.parent_exec = ira->new_irb.exec;
1232413427 impl_fn->analyzed_executable.source_node = call_instruction->base.source_node;
1232513428 impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec;
13429 impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota;
1232613430 impl_fn->analyzed_executable.is_generic_instantiation = true;
1232713431
1232813432 ira->codegen->fn_defs.append(impl_fn);
......@@ -12345,7 +13449,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1234513449 assert(async_allocator_inst == nullptr);
1234613450 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
1234713451 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
12348 call_instruction->is_async, nullptr);
13452 call_instruction->is_async, nullptr, casted_new_stack);
1234913453
1235013454 ir_add_alloca(ira, new_call_instruction, return_type);
1235113455
......@@ -12363,9 +13467,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1236313467 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
1236413468 size_t next_arg_index = 0;
1236513469 if (first_arg_ptr) {
12366 IrInstruction *first_arg;
1236713470 assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
12368 if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
13471
13472 TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
13473 if (type_is_invalid(param_type))
13474 return ira->codegen->builtin_types.entry_invalid;
13475
13476 IrInstruction *first_arg;
13477 if (param_type->id == TypeTableEntryIdPointer &&
13478 handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type))
13479 {
1236913480 first_arg = first_arg_ptr;
1237013481 } else {
1237113482 first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
......@@ -12373,10 +13484,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1237313484 return ira->codegen->builtin_types.entry_invalid;
1237413485 }
1237513486
12376 TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
12377 if (type_is_invalid(param_type))
12378 return ira->codegen->builtin_types.entry_invalid;
12379
1238013487 IrInstruction *casted_arg = ir_implicit_cast(ira, first_arg, param_type);
1238113488 if (type_is_invalid(casted_arg->value.type))
1238213489 return ira->codegen->builtin_types.entry_invalid;
......@@ -12436,7 +13543,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1243613543
1243713544
1243813545 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
12439 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
13546 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
1244013547
1244113548 ir_add_alloca(ira, new_call_instruction, return_type);
1244213549 return ir_finish_anal(ira, return_type);
......@@ -12474,6 +13581,8 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1247413581 return ir_finish_anal(ira, cast_instruction->value.type);
1247513582 } else if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1247613583 FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
13584 if (fn_table_entry == nullptr)
13585 return ira->codegen->builtin_types.entry_invalid;
1247713586 return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
1247813587 fn_ref, nullptr, is_comptime, call_instruction->fn_inline);
1247913588 } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {
......@@ -12481,7 +13590,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1248113590 FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;
1248213591 IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;
1248313592 return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
12484 nullptr, first_arg_ptr, is_comptime, call_instruction->fn_inline);
13593 fn_ref, first_arg_ptr, is_comptime, call_instruction->fn_inline);
1248513594 } else {
1248613595 ir_add_error_node(ira, fn_ref->source_node,
1248713596 buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));
......@@ -12507,6 +13616,12 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
1250713616 if (type_is_invalid(ptr_type)) {
1250813617 return ira->codegen->builtin_types.entry_invalid;
1250913618 } else if (ptr_type->id == TypeTableEntryIdPointer) {
13619 if (ptr_type->data.pointer.ptr_len == PtrLenUnknown) {
13620 ir_add_error_node(ira, un_op_instruction->base.source_node,
13621 buf_sprintf("index syntax required for unknown-length pointer type '%s'",
13622 buf_ptr(&ptr_type->name)));
13623 return ira->codegen->builtin_types.entry_invalid;
13624 }
1251013625 child_type = ptr_type->data.pointer.child_type;
1251113626 } else {
1251213627 ir_add_error_node(ira, un_op_instruction->base.source_node,
......@@ -12519,7 +13634,11 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
1251913634 // one of the ptr instructions
1252013635
1252113636 if (instr_is_comptime(value)) {
12522 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
13637 ConstExprValue *comptime_value = ir_resolve_const(ira, value, UndefBad);
13638 if (comptime_value == nullptr)
13639 return ira->codegen->builtin_types.entry_invalid;
13640
13641 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, comptime_value);
1252313642 if (pointee->type == child_type) {
1252413643 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
1252513644 copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
......@@ -12536,6 +13655,10 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1253613655 TypeTableEntry *type_entry = ir_resolve_type(ira, value);
1253713656 if (type_is_invalid(type_entry))
1253813657 return ira->codegen->builtin_types.entry_invalid;
13658 ensure_complete_type(ira->codegen, type_entry);
13659 if (type_is_invalid(type_entry))
13660 return ira->codegen->builtin_types.entry_invalid;
13661
1253913662 switch (type_entry->id) {
1254013663 case TypeTableEntryIdInvalid:
1254113664 zig_unreachable();
......@@ -12547,11 +13670,11 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1254713670 case TypeTableEntryIdPointer:
1254813671 case TypeTableEntryIdArray:
1254913672 case TypeTableEntryIdStruct:
12550 case TypeTableEntryIdNumLitFloat:
12551 case TypeTableEntryIdNumLitInt:
12552 case TypeTableEntryIdUndefLit:
12553 case TypeTableEntryIdNullLit:
12554 case TypeTableEntryIdMaybe:
13673 case TypeTableEntryIdComptimeFloat:
13674 case TypeTableEntryIdComptimeInt:
13675 case TypeTableEntryIdUndefined:
13676 case TypeTableEntryIdNull:
13677 case TypeTableEntryIdOptional:
1255513678 case TypeTableEntryIdErrorUnion:
1255613679 case TypeTableEntryIdErrorSet:
1255713680 case TypeTableEntryIdEnum:
......@@ -12564,13 +13687,13 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1256413687 case TypeTableEntryIdPromise:
1256513688 {
1256613689 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
12567 out_val->data.x_type = get_maybe_type(ira->codegen, type_entry);
13690 out_val->data.x_type = get_optional_type(ira->codegen, type_entry);
1256813691 return ira->codegen->builtin_types.entry_type;
1256913692 }
1257013693 case TypeTableEntryIdUnreachable:
1257113694 case TypeTableEntryIdOpaque:
1257213695 ir_add_error_node(ira, un_op_instruction->base.source_node,
12573 buf_sprintf("type '%s' not nullable", buf_ptr(&type_entry->name)));
13696 buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name)));
1257413697 return ira->codegen->builtin_types.entry_invalid;
1257513698 }
1257613699 zig_unreachable();
......@@ -12584,10 +13707,10 @@ static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un
1258413707
1258513708 bool is_wrap_op = (un_op_instruction->op_id == IrUnOpNegationWrap);
1258613709
12587 bool is_float = (expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat);
13710 bool is_float = (expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdComptimeFloat);
1258813711
1258913712 if ((expr_type->id == TypeTableEntryIdInt && expr_type->data.integral.is_signed) ||
12590 expr_type->id == TypeTableEntryIdNumLitInt || (is_float && !is_wrap_op))
13713 expr_type->id == TypeTableEntryIdComptimeInt || (is_float && !is_wrap_op))
1259113714 {
1259213715 if (instr_is_comptime(value)) {
1259313716 ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);
......@@ -12603,7 +13726,7 @@ static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un
1260313726 } else {
1260413727 bigint_negate(&out_val->data.x_bigint, &target_const_val->data.x_bigint);
1260513728 }
12606 if (is_wrap_op || is_float || expr_type->id == TypeTableEntryIdNumLitInt) {
13729 if (is_wrap_op || is_float || expr_type->id == TypeTableEntryIdComptimeInt) {
1260713730 return expr_type;
1260813731 }
1260913732
......@@ -12632,7 +13755,7 @@ static TypeTableEntry *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *ins
1263213755 if (expr_type->id == TypeTableEntryIdInt) {
1263313756 if (instr_is_comptime(value)) {
1263413757 ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);
12635 if (!target_const_val)
13758 if (target_const_val == nullptr)
1263613759 return ira->codegen->builtin_types.entry_invalid;
1263713760
1263813761 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
......@@ -12662,7 +13785,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
1266213785 return ir_analyze_negation(ira, un_op_instruction);
1266313786 case IrUnOpDereference:
1266413787 return ir_analyze_dereference(ira, un_op_instruction);
12665 case IrUnOpMaybe:
13788 case IrUnOpOptional:
1266613789 return ir_analyze_maybe(ira, un_op_instruction);
1266713790 }
1266813791 zig_unreachable();
......@@ -12794,15 +13917,15 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
1279413917 return first_value->value.type;
1279513918 }
1279613919
12797 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node,
13920 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, nullptr,
1279813921 new_incoming_values.items, new_incoming_values.length);
1279913922 if (type_is_invalid(resolved_type))
1280013923 return resolved_type;
1280113924
12802 if (resolved_type->id == TypeTableEntryIdNumLitFloat ||
12803 resolved_type->id == TypeTableEntryIdNumLitInt ||
12804 resolved_type->id == TypeTableEntryIdNullLit ||
12805 resolved_type->id == TypeTableEntryIdUndefLit)
13925 if (resolved_type->id == TypeTableEntryIdComptimeFloat ||
13926 resolved_type->id == TypeTableEntryIdComptimeInt ||
13927 resolved_type->id == TypeTableEntryIdNull ||
13928 resolved_type->id == TypeTableEntryIdUndefined)
1280613929 {
1280713930 ir_add_error_node(ira, phi_instruction->base.source_node,
1280813931 buf_sprintf("unable to infer expression type"));
......@@ -12847,17 +13970,16 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
1284713970}
1284813971
1284913972static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
12850 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
13973 VariableTableEntry *var)
1285113974{
12852 IrInstruction *result = ir_get_var_ptr(ira, instruction, var, is_const_ptr, is_volatile_ptr);
13975 IrInstruction *result = ir_get_var_ptr(ira, instruction, var);
1285313976 ir_link_new_instruction(result, instruction);
1285413977 return result->value.type;
1285513978}
1285613979
1285713980static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) {
1285813981 VariableTableEntry *var = var_ptr_instruction->var;
12859 return ir_analyze_var_ptr(ira, &var_ptr_instruction->base, var, var_ptr_instruction->is_const,
12860 var_ptr_instruction->is_volatile);
13982 return ir_analyze_var_ptr(ira, &var_ptr_instruction->base, var);
1286113983}
1286213984
1286313985static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align) {
......@@ -12865,25 +13987,40 @@ static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, ui
1286513987 return get_pointer_to_type_extra(g,
1286613988 ptr_type->data.pointer.child_type,
1286713989 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
13990 ptr_type->data.pointer.ptr_len,
1286813991 new_align,
1286913992 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
1287013993}
1287113994
13995static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align) {
13996 assert(is_slice(slice_type));
13997 TypeTableEntry *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
13998 new_align);
13999 return get_slice_type(g, ptr_type);
14000}
14001
14002static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrLen ptr_len) {
14003 assert(ptr_type->id == TypeTableEntryIdPointer);
14004 return get_pointer_to_type_extra(g,
14005 ptr_type->data.pointer.child_type,
14006 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14007 ptr_len,
14008 ptr_type->data.pointer.alignment,
14009 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
14010}
14011
1287214012static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
1287314013 IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
1287414014 if (type_is_invalid(array_ptr->value.type))
1287514015 return ira->codegen->builtin_types.entry_invalid;
1287614016
14017 ConstExprValue *orig_array_ptr_val = &array_ptr->value;
14018
1287714019 IrInstruction *elem_index = elem_ptr_instruction->elem_index->other;
1287814020 if (type_is_invalid(elem_index->value.type))
1287914021 return ira->codegen->builtin_types.entry_invalid;
1288014022
12881 TypeTableEntry *ptr_type = array_ptr->value.type;
12882 if (ptr_type->id == TypeTableEntryIdMetaType) {
12883 ir_add_error(ira, &elem_ptr_instruction->base,
12884 buf_sprintf("array access of non-array type '%s'", buf_ptr(&ptr_type->name)));
12885 return ira->codegen->builtin_types.entry_invalid;
12886 }
14023 TypeTableEntry *ptr_type = orig_array_ptr_val->type;
1288714024 assert(ptr_type->id == TypeTableEntryIdPointer);
1288814025
1288914026 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
......@@ -12894,7 +14031,18 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1289414031
1289514032 if (type_is_invalid(array_type)) {
1289614033 return array_type;
12897 } else if (array_type->id == TypeTableEntryIdArray) {
14034 } else if (array_type->id == TypeTableEntryIdArray ||
14035 (array_type->id == TypeTableEntryIdPointer &&
14036 array_type->data.pointer.ptr_len == PtrLenSingle &&
14037 array_type->data.pointer.child_type->id == TypeTableEntryIdArray))
14038 {
14039 if (array_type->id == TypeTableEntryIdPointer) {
14040 array_type = array_type->data.pointer.child_type;
14041 ptr_type = ptr_type->data.pointer.child_type;
14042 if (orig_array_ptr_val->special != ConstValSpecialRuntime) {
14043 orig_array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val);
14044 }
14045 }
1289814046 if (array_type->data.array.len == 0) {
1289914047 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
1290014048 buf_sprintf("index 0 outside array of size 0"));
......@@ -12904,6 +14052,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1290414052 if (ptr_type->data.pointer.unaligned_bit_count == 0) {
1290514053 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
1290614054 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14055 elem_ptr_instruction->ptr_len,
1290714056 ptr_type->data.pointer.alignment, 0, 0);
1290814057 } else {
1290914058 uint64_t elem_val_scalar;
......@@ -12915,12 +14064,19 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1291514064
1291614065 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
1291714066 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14067 elem_ptr_instruction->ptr_len,
1291814068 1, (uint32_t)bit_offset, (uint32_t)bit_width);
1291914069 }
1292014070 } else if (array_type->id == TypeTableEntryIdPointer) {
12921 return_type = array_type;
14071 if (array_type->data.pointer.ptr_len == PtrLenSingle) {
14072 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
14073 buf_sprintf("index of single-item pointer"));
14074 return ira->codegen->builtin_types.entry_invalid;
14075 }
14076 return_type = adjust_ptr_len(ira->codegen, array_type, elem_ptr_instruction->ptr_len);
1292214077 } else if (is_slice(array_type)) {
12923 return_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
14078 return_type = adjust_ptr_len(ira->codegen, array_type->data.structure.fields[slice_ptr_index].type_entry,
14079 elem_ptr_instruction->ptr_len);
1292414080 } else if (array_type->id == TypeTableEntryIdArgTuple) {
1292514081 ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
1292614082 if (!ptr_val)
......@@ -12945,8 +14101,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1294514101 bool is_const = true;
1294614102 bool is_volatile = false;
1294714103 if (var) {
12948 return ir_analyze_var_ptr(ira, &elem_ptr_instruction->base, var,
12949 is_const, is_volatile);
14104 return ir_analyze_var_ptr(ira, &elem_ptr_instruction->base, var);
1295014105 } else {
1295114106 return ir_analyze_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val,
1295214107 ira->codegen->builtin_types.entry_void, ConstPtrMutComptimeConst, is_const, is_volatile);
......@@ -12964,6 +14119,9 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1296414119
1296514120 bool safety_check_on = elem_ptr_instruction->safety_check_on;
1296614121 ensure_complete_type(ira->codegen, return_type->data.pointer.child_type);
14122 if (type_is_invalid(return_type->data.pointer.child_type))
14123 return ira->codegen->builtin_types.entry_invalid;
14124
1296714125 uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
1296814126 uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
1296914127 uint64_t ptr_align = return_type->data.pointer.alignment;
......@@ -13001,9 +14159,9 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1300114159 }
1300214160
1300314161 ConstExprValue *array_ptr_val;
13004 if (array_ptr->value.special != ConstValSpecialRuntime &&
13005 (array_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
13006 (array_ptr_val = const_ptr_pointee(ira->codegen, &array_ptr->value)) &&
14162 if (orig_array_ptr_val->special != ConstValSpecialRuntime &&
14163 (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
14164 (array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val)) &&
1300714165 array_ptr_val->special != ConstValSpecialRuntime &&
1300814166 (array_type->id != TypeTableEntryIdPointer ||
1300914167 array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
......@@ -13060,8 +14218,10 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1306014218 } else if (is_slice(array_type)) {
1306114219 ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index];
1306214220 if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
13063 ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr,
13064 casted_elem_index, false);
14221 IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node,
14222 array_ptr, casted_elem_index, false, elem_ptr_instruction->ptr_len);
14223 result->value.type = return_type;
14224 ir_link_new_instruction(result, &elem_ptr_instruction->base);
1306514225 return return_type;
1306614226 }
1306714227 ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index];
......@@ -13106,7 +14266,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1310614266 } else if (array_type->id == TypeTableEntryIdArray) {
1310714267 ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
1310814268 out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
13109 out_val->data.x_ptr.mut = array_ptr->value.data.x_ptr.mut;
14269 out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
1311014270 out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;
1311114271 out_val->data.x_ptr.data.base_array.elem_index = index;
1311214272 return return_type;
......@@ -13129,8 +14289,10 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1312914289 }
1313014290 }
1313114291
13132 ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr,
13133 casted_elem_index, safety_check_on);
14292 IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node,
14293 array_ptr, casted_elem_index, safety_check_on, elem_ptr_instruction->ptr_len);
14294 result->value.type = return_type;
14295 ir_link_new_instruction(result, &elem_ptr_instruction->base);
1313414296 return return_type;
1313514297}
1313614298
......@@ -13174,7 +14336,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
1317414336 return ira->codegen->invalid_instruction;
1317514337}
1317614338
13177
1317814339static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
1317914340 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type)
1318014341{
......@@ -13206,7 +14367,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1320614367 return ira->codegen->invalid_instruction;
1320714368 ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
1320814369 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type,
13209 is_const, is_volatile, align_bytes,
14370 is_const, is_volatile, PtrLenSingle, align_bytes,
1321014371 (uint32_t)(ptr_bit_offset + field->packed_bits_offset),
1321114372 (uint32_t)unaligned_bit_count_for_result_type);
1321214373 IrInstruction *result = ir_get_const(ira, source_instr);
......@@ -13222,6 +14383,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1322214383 IrInstruction *result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
1322314384 container_ptr, field);
1322414385 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
14386 PtrLenSingle,
1322514387 align_bytes,
1322614388 (uint32_t)(ptr_bit_offset + field->packed_bits_offset),
1322714389 (uint32_t)unaligned_bit_count_for_result_type);
......@@ -13236,9 +14398,56 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1323614398 } else if (bare_type->id == TypeTableEntryIdUnion) {
1323714399 TypeUnionField *field = find_union_type_field(bare_type, field_name);
1323814400 if (field) {
14401 if (instr_is_comptime(container_ptr)) {
14402 ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
14403 if (!ptr_val)
14404 return ira->codegen->invalid_instruction;
14405
14406 if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
14407 ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val);
14408 if (type_is_invalid(union_val->type))
14409 return ira->codegen->invalid_instruction;
14410
14411 TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag);
14412 if (actual_field == nullptr)
14413 zig_unreachable();
14414
14415 if (field != actual_field) {
14416 ir_add_error_node(ira, source_instr->source_node,
14417 buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name),
14418 buf_ptr(actual_field->name)));
14419 return ira->codegen->invalid_instruction;
14420 }
14421
14422 ConstExprValue *payload_val = union_val->data.x_union.payload;
14423
14424 TypeTableEntry *field_type = field->type_entry;
14425 if (field_type->id == TypeTableEntryIdVoid)
14426 {
14427 assert(payload_val == nullptr);
14428 payload_val = create_const_vals(1);
14429 payload_val->special = ConstValSpecialStatic;
14430 payload_val->type = field_type;
14431 }
14432
14433 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
14434 is_const, is_volatile,
14435 PtrLenSingle,
14436 get_abi_alignment(ira->codegen, field_type), 0, 0);
14437
14438 IrInstruction *result = ir_get_const(ira, source_instr);
14439 ConstExprValue *const_val = &result->value;
14440 const_val->data.x_ptr.special = ConstPtrSpecialRef;
14441 const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
14442 const_val->data.x_ptr.data.ref.pointee = payload_val;
14443 const_val->type = ptr_type;
14444 return result;
14445 }
14446 }
14447
1323914448 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
1324014449 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
13241 get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
14450 PtrLenSingle, get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
1324214451 return result;
1324314452 } else {
1324414453 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
......@@ -13286,7 +14495,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
1328614495 add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node);
1328714496 }
1328814497
13289 return ir_analyze_var_ptr(ira, source_instruction, var, false, false);
14498 return ir_analyze_var_ptr(ira, source_instruction, var);
1329014499 }
1329114500 case TldIdFn:
1329214501 {
......@@ -13335,16 +14544,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1333514544 if (type_is_invalid(container_ptr->value.type))
1333614545 return ira->codegen->builtin_types.entry_invalid;
1333714546
13338 TypeTableEntry *container_type;
13339 if (container_ptr->value.type->id == TypeTableEntryIdPointer) {
13340 container_type = container_ptr->value.type->data.pointer.child_type;
13341 } else if (container_ptr->value.type->id == TypeTableEntryIdMetaType) {
13342 container_type = container_ptr->value.type;
13343 } else {
13344 zig_unreachable();
14547 TypeTableEntry *container_type = container_ptr->value.type->data.pointer.child_type;
14548 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
14549
14550 Buf *field_name = field_ptr_instruction->field_name_buffer;
14551 if (!field_name) {
14552 IrInstruction *field_name_expr = field_ptr_instruction->field_name_expr->other;
14553 field_name = ir_resolve_str(ira, field_name_expr);
14554 if (!field_name)
14555 return ira->codegen->builtin_types.entry_invalid;
1334514556 }
1334614557
13347 Buf *field_name = field_ptr_instruction->field_name;
14558
1334814559 AstNode *source_node = field_ptr_instruction->base.source_node;
1334914560
1335014561 if (type_is_invalid(container_type)) {
......@@ -13362,10 +14573,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1336214573 ir_link_new_instruction(result, &field_ptr_instruction->base);
1336314574 return result->value.type;
1336414575 }
13365 } else if (container_type->id == TypeTableEntryIdArray) {
14576 } else if (is_array_ref(container_type)) {
1336614577 if (buf_eql_str(field_name, "len")) {
1336714578 ConstExprValue *len_val = create_const_vals(1);
13368 init_const_usize(ira->codegen, len_val, container_type->data.array.len);
14579 if (container_type->id == TypeTableEntryIdPointer) {
14580 init_const_usize(ira->codegen, len_val, container_type->data.pointer.child_type->data.array.len);
14581 } else {
14582 init_const_usize(ira->codegen, len_val, container_type->data.array.len);
14583 }
1336914584
1337014585 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
1337114586 bool ptr_is_const = true;
......@@ -13407,17 +14622,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1340714622 if (!container_ptr_val)
1340814623 return ira->codegen->builtin_types.entry_invalid;
1340914624
13410 TypeTableEntry *child_type;
13411 if (container_ptr->value.type->id == TypeTableEntryIdMetaType) {
13412 TypeTableEntry *ptr_type = container_ptr_val->data.x_type;
13413 assert(ptr_type->id == TypeTableEntryIdPointer);
13414 child_type = ptr_type->data.pointer.child_type;
13415 } else if (container_ptr->value.type->id == TypeTableEntryIdPointer) {
13416 ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
13417 child_type = child_val->data.x_type;
13418 } else {
13419 zig_unreachable();
13420 }
14625 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
14626 ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
14627 TypeTableEntry *child_type = child_val->data.x_type;
1342114628
1342214629 if (type_is_invalid(child_type)) {
1342314630 return ira->codegen->builtin_types.entry_invalid;
......@@ -13435,7 +14642,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1343514642 }
1343614643 if (child_type->id == TypeTableEntryIdEnum) {
1343714644 ensure_complete_type(ira->codegen, child_type);
13438 if (child_type->data.enumeration.is_invalid)
14645 if (type_is_invalid(child_type))
1343914646 return ira->codegen->builtin_types.entry_invalid;
1344014647
1344114648 TypeEnumField *field = find_enum_type_field(child_type, field_name);
......@@ -13446,7 +14653,16 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1344614653 create_const_enum(child_type, &field->value), child_type,
1344714654 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
1344814655 }
13449 } else if (child_type->id == TypeTableEntryIdUnion &&
14656 }
14657 ScopeDecls *container_scope = get_container_scope(child_type);
14658 if (container_scope != nullptr) {
14659 auto entry = container_scope->decl_table.maybe_get(field_name);
14660 Tld *tld = entry ? entry->value : nullptr;
14661 if (tld) {
14662 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
14663 }
14664 }
14665 if (child_type->id == TypeTableEntryIdUnion &&
1345014666 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
1345114667 child_type->data.unionation.decl_node->data.container_decl.auto_enum))
1345214668 {
......@@ -13463,14 +14679,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1346314679 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
1346414680 }
1346514681 }
13466 ScopeDecls *container_scope = get_container_scope(child_type);
13467 if (container_scope != nullptr) {
13468 auto entry = container_scope->decl_table.maybe_get(field_name);
13469 Tld *tld = entry ? entry->value : nullptr;
13470 if (tld) {
13471 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
13472 }
13473 }
1347414682 ir_add_error(ira, &field_ptr_instruction->base,
1347514683 buf_sprintf("container '%s' has no member called '%s'",
1347614684 buf_ptr(&child_type->name), buf_ptr(field_name)));
......@@ -13501,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1350114709 }
1350214710 err_set_type = err_entry->set_with_only_this_in_it;
1350314711 } else {
13504 if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) {
14712 if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) {
1350514713 return ira->codegen->builtin_types.entry_invalid;
1350614714 }
1350714715 err_entry = find_err_table_entry(child_type, field_name);
......@@ -13623,7 +14831,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1362314831 buf_ptr(&child_type->name), buf_ptr(field_name)));
1362414832 return ira->codegen->builtin_types.entry_invalid;
1362514833 }
13626 } else if (child_type->id == TypeTableEntryIdMaybe) {
14834 } else if (child_type->id == TypeTableEntryIdOptional) {
1362714835 if (buf_eql_str(field_name, "Child")) {
1362814836 bool ptr_is_const = true;
1362914837 bool ptr_is_volatile = false;
......@@ -13639,6 +14847,15 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1363914847 }
1364014848 } else if (child_type->id == TypeTableEntryIdFn) {
1364114849 if (buf_eql_str(field_name, "ReturnType")) {
14850 if (child_type->data.fn.fn_type_id.return_type == nullptr) {
14851 // Return type can only ever be null, if the function is generic
14852 assert(child_type->data.fn.is_generic);
14853
14854 ir_add_error(ira, &field_ptr_instruction->base,
14855 buf_sprintf("ReturnType has not been resolved because '%s' is generic", buf_ptr(&child_type->name)));
14856 return ira->codegen->builtin_types.entry_invalid;
14857 }
14858
1364214859 bool ptr_is_const = true;
1364314860 bool ptr_is_volatile = false;
1364414861 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
......@@ -13707,6 +14924,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1370714924
1370814925static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
1370914926 IrInstruction *ptr = load_ptr_instruction->ptr->other;
14927 if (type_is_invalid(ptr->value.type))
14928 return ira->codegen->builtin_types.entry_invalid;
14929
1371014930 IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr);
1371114931 ir_link_new_instruction(result, &load_ptr_instruction->base);
1371214932 assert(result->value.type);
......@@ -13779,10 +14999,10 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
1377914999 switch (type_entry->id) {
1378015000 case TypeTableEntryIdInvalid:
1378115001 zig_unreachable(); // handled above
13782 case TypeTableEntryIdNumLitFloat:
13783 case TypeTableEntryIdNumLitInt:
13784 case TypeTableEntryIdUndefLit:
13785 case TypeTableEntryIdNullLit:
15002 case TypeTableEntryIdComptimeFloat:
15003 case TypeTableEntryIdComptimeInt:
15004 case TypeTableEntryIdUndefined:
15005 case TypeTableEntryIdNull:
1378615006 case TypeTableEntryIdNamespace:
1378715007 case TypeTableEntryIdBlock:
1378815008 case TypeTableEntryIdBoundFn:
......@@ -13795,7 +15015,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
1379515015 case TypeTableEntryIdPointer:
1379615016 case TypeTableEntryIdArray:
1379715017 case TypeTableEntryIdStruct:
13798 case TypeTableEntryIdMaybe:
15018 case TypeTableEntryIdOptional:
1379915019 case TypeTableEntryIdErrorUnion:
1380015020 case TypeTableEntryIdErrorSet:
1380115021 case TypeTableEntryIdEnum:
......@@ -13827,7 +15047,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
1382715047 if (type_entry->id == TypeTableEntryIdArray) {
1382815048 ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false);
1382915049 } else if (is_slice(type_entry)) {
13830 ptr_type = type_entry->data.structure.fields[0].type_entry;
15050 ptr_type = adjust_ptr_len(ira->codegen, type_entry->data.structure.fields[0].type_entry, PtrLenSingle);
1383115051 } else if (type_entry->id == TypeTableEntryIdArgTuple) {
1383215052 ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad);
1383315053 if (!arg_tuple_val)
......@@ -14045,8 +15265,8 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1404515265 case TypeTableEntryIdInvalid: // handled above
1404615266 zig_unreachable();
1404715267 case TypeTableEntryIdUnreachable:
14048 case TypeTableEntryIdUndefLit:
14049 case TypeTableEntryIdNullLit:
15268 case TypeTableEntryIdUndefined:
15269 case TypeTableEntryIdNull:
1405015270 case TypeTableEntryIdBlock:
1405115271 case TypeTableEntryIdArgTuple:
1405215272 case TypeTableEntryIdOpaque:
......@@ -14061,9 +15281,9 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1406115281 case TypeTableEntryIdPointer:
1406215282 case TypeTableEntryIdArray:
1406315283 case TypeTableEntryIdStruct:
14064 case TypeTableEntryIdNumLitFloat:
14065 case TypeTableEntryIdNumLitInt:
14066 case TypeTableEntryIdMaybe:
15284 case TypeTableEntryIdComptimeFloat:
15285 case TypeTableEntryIdComptimeInt:
15286 case TypeTableEntryIdOptional:
1406715287 case TypeTableEntryIdErrorUnion:
1406815288 case TypeTableEntryIdErrorSet:
1406915289 case TypeTableEntryIdEnum:
......@@ -14075,7 +15295,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1407515295 {
1407615296 type_ensure_zero_bits_known(ira->codegen, child_type);
1407715297 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
14078 is_const, is_volatile, align_bytes, 0, 0);
15298 is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0);
1407915299 TypeTableEntry *result_type = get_slice_type(ira->codegen, slice_ptr_type);
1408015300 ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base);
1408115301 out_val->data.x_type = result_type;
......@@ -14153,8 +15373,8 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
1415315373 case TypeTableEntryIdInvalid: // handled above
1415415374 zig_unreachable();
1415515375 case TypeTableEntryIdUnreachable:
14156 case TypeTableEntryIdUndefLit:
14157 case TypeTableEntryIdNullLit:
15376 case TypeTableEntryIdUndefined:
15377 case TypeTableEntryIdNull:
1415815378 case TypeTableEntryIdBlock:
1415915379 case TypeTableEntryIdArgTuple:
1416015380 case TypeTableEntryIdOpaque:
......@@ -14169,9 +15389,9 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
1416915389 case TypeTableEntryIdPointer:
1417015390 case TypeTableEntryIdArray:
1417115391 case TypeTableEntryIdStruct:
14172 case TypeTableEntryIdNumLitFloat:
14173 case TypeTableEntryIdNumLitInt:
14174 case TypeTableEntryIdMaybe:
15392 case TypeTableEntryIdComptimeFloat:
15393 case TypeTableEntryIdComptimeInt:
15394 case TypeTableEntryIdOptional:
1417515395 case TypeTableEntryIdErrorUnion:
1417615396 case TypeTableEntryIdErrorSet:
1417715397 case TypeTableEntryIdEnum:
......@@ -14222,11 +15442,11 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
1422215442 case TypeTableEntryIdInvalid: // handled above
1422315443 zig_unreachable();
1422415444 case TypeTableEntryIdUnreachable:
14225 case TypeTableEntryIdUndefLit:
14226 case TypeTableEntryIdNullLit:
15445 case TypeTableEntryIdUndefined:
15446 case TypeTableEntryIdNull:
1422715447 case TypeTableEntryIdBlock:
14228 case TypeTableEntryIdNumLitFloat:
14229 case TypeTableEntryIdNumLitInt:
15448 case TypeTableEntryIdComptimeFloat:
15449 case TypeTableEntryIdComptimeInt:
1423015450 case TypeTableEntryIdBoundFn:
1423115451 case TypeTableEntryIdMetaType:
1423215452 case TypeTableEntryIdNamespace:
......@@ -14242,7 +15462,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
1424215462 case TypeTableEntryIdPointer:
1424315463 case TypeTableEntryIdArray:
1424415464 case TypeTableEntryIdStruct:
14245 case TypeTableEntryIdMaybe:
15465 case TypeTableEntryIdOptional:
1424615466 case TypeTableEntryIdErrorUnion:
1424715467 case TypeTableEntryIdErrorSet:
1424815468 case TypeTableEntryIdEnum:
......@@ -14266,20 +15486,20 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn
1426615486
1426715487 TypeTableEntry *type_entry = value->value.type;
1426815488
14269 if (type_entry->id == TypeTableEntryIdMaybe) {
15489 if (type_entry->id == TypeTableEntryIdOptional) {
1427015490 if (instr_is_comptime(value)) {
1427115491 ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefBad);
1427215492 if (!maybe_val)
1427315493 return ira->codegen->builtin_types.entry_invalid;
1427415494
1427515495 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14276 out_val->data.x_bool = (maybe_val->data.x_maybe != nullptr);
15496 out_val->data.x_bool = !optional_value_is_null(maybe_val);
1427715497 return ira->codegen->builtin_types.entry_bool;
1427815498 }
1427915499
1428015500 ir_build_test_nonnull_from(&ira->new_irb, &instruction->base, value);
1428115501 return ira->codegen->builtin_types.entry_bool;
14282 } else if (type_entry->id == TypeTableEntryIdNullLit) {
15502 } else if (type_entry->id == TypeTableEntryIdNull) {
1428315503 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1428415504 out_val->data.x_bool = false;
1428515505 return ira->codegen->builtin_types.entry_bool;
......@@ -14291,42 +15511,27 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn
1429115511}
1429215512
1429315513static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
14294 IrInstructionUnwrapMaybe *unwrap_maybe_instruction)
15514 IrInstructionUnwrapOptional *unwrap_maybe_instruction)
1429515515{
1429615516 IrInstruction *value = unwrap_maybe_instruction->value->other;
1429715517 if (type_is_invalid(value->value.type))
1429815518 return ira->codegen->builtin_types.entry_invalid;
1429915519
1430015520 TypeTableEntry *ptr_type = value->value.type;
14301 if (ptr_type->id == TypeTableEntryIdMetaType) {
14302 // surprise! actually this is just ??T not an unwrap maybe instruction
14303 TypeTableEntry *ptr_type_ptr = ir_resolve_type(ira, value);
14304 assert(ptr_type_ptr->id == TypeTableEntryIdPointer);
14305 TypeTableEntry *child_type = ptr_type_ptr->data.pointer.child_type;
14306 type_ensure_zero_bits_known(ira->codegen, child_type);
14307 TypeTableEntry *layer1 = get_maybe_type(ira->codegen, child_type);
14308 TypeTableEntry *layer2 = get_maybe_type(ira->codegen, layer1);
14309 TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, layer2, true);
14310
14311 IrInstruction *const_instr = ir_build_const_type(&ira->new_irb, unwrap_maybe_instruction->base.scope,
14312 unwrap_maybe_instruction->base.source_node, result_type);
14313 ir_link_new_instruction(const_instr, &unwrap_maybe_instruction->base);
14314 return const_instr->value.type;
14315 }
14316
1431715521 assert(ptr_type->id == TypeTableEntryIdPointer);
1431815522
1431915523 TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
1432015524 if (type_is_invalid(type_entry)) {
1432115525 return ira->codegen->builtin_types.entry_invalid;
14322 } else if (type_entry->id != TypeTableEntryIdMaybe) {
15526 } else if (type_entry->id != TypeTableEntryIdOptional) {
1432315527 ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node,
14324 buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
15528 buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name)));
1432515529 return ira->codegen->builtin_types.entry_invalid;
1432615530 }
1432715531 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1432815532 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
1432915533 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
15534 PtrLenSingle,
1433015535 get_abi_alignment(ira->codegen, child_type), 0, 0);
1433115536
1433215537 if (instr_is_comptime(value)) {
......@@ -14336,13 +15541,18 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
1433615541 ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val);
1433715542
1433815543 if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
14339 if (!maybe_val->data.x_maybe) {
15544 if (optional_value_is_null(maybe_val)) {
1434015545 ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null"));
1434115546 return ira->codegen->builtin_types.entry_invalid;
1434215547 }
1434315548 ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base);
1434415549 out_val->data.x_ptr.special = ConstPtrSpecialRef;
14345 out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_maybe;
15550 out_val->data.x_ptr.mut = val->data.x_ptr.mut;
15551 if (type_is_codegen_pointer(child_type)) {
15552 out_val->data.x_ptr.data.ref.pointee = maybe_val;
15553 } else {
15554 out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional;
15555 }
1434615556 return result_type;
1434715557 }
1434815558 }
......@@ -14400,6 +15610,48 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
1440015610 }
1440115611}
1440215612
15613static TypeTableEntry *ir_analyze_instruction_pop_count(IrAnalyze *ira, IrInstructionPopCount *instruction) {
15614 IrInstruction *value = instruction->value->other;
15615 if (type_is_invalid(value->value.type))
15616 return ira->codegen->builtin_types.entry_invalid;
15617
15618 if (value->value.type->id != TypeTableEntryIdInt && value->value.type->id != TypeTableEntryIdComptimeInt) {
15619 ir_add_error(ira, value,
15620 buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name)));
15621 return ira->codegen->builtin_types.entry_invalid;
15622 }
15623
15624 if (instr_is_comptime(value)) {
15625 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
15626 if (!val)
15627 return ira->codegen->builtin_types.entry_invalid;
15628 if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) {
15629 size_t result = bigint_popcount_unsigned(&val->data.x_bigint);
15630 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15631 bigint_init_unsigned(&out_val->data.x_bigint, result);
15632 return ira->codegen->builtin_types.entry_num_lit_int;
15633 }
15634 if (value->value.type->id == TypeTableEntryIdComptimeInt) {
15635 Buf *val_buf = buf_alloc();
15636 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
15637 ir_add_error(ira, &instruction->base,
15638 buf_sprintf("@popCount on negative %s value %s",
15639 buf_ptr(&value->value.type->name), buf_ptr(val_buf)));
15640 return ira->codegen->builtin_types.entry_invalid;
15641 }
15642 size_t result = bigint_popcount_signed(&val->data.x_bigint, value->value.type->data.integral.bit_count);
15643 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15644 bigint_init_unsigned(&out_val->data.x_bigint, result);
15645 return ira->codegen->builtin_types.entry_num_lit_int;
15646 }
15647
15648 IrInstruction *result = ir_build_pop_count(&ira->new_irb, instruction->base.scope,
15649 instruction->base.source_node, value);
15650 result->value.type = get_smallest_unsigned_int_type(ira->codegen, value->value.type->data.integral.bit_count);
15651 ir_link_new_instruction(result, &instruction->base);
15652 return result->value.type;
15653}
15654
1440315655static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
1440415656 if (type_is_invalid(value->value.type))
1440515657 return ira->codegen->invalid_instruction;
......@@ -14409,7 +15661,7 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
1440915661 }
1441015662
1441115663 if (value->value.type->id != TypeTableEntryIdUnion) {
14412 ir_add_error(ira, source_instr,
15664 ir_add_error(ira, value,
1441315665 buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
1441415666 return ira->codegen->invalid_instruction;
1441515667 }
......@@ -14450,6 +15702,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
1445015702 if (type_is_invalid(target_value->value.type))
1445115703 return ir_unreach_error(ira);
1445215704
15705 if (switch_br_instruction->switch_prongs_void != nullptr) {
15706 if (type_is_invalid(switch_br_instruction->switch_prongs_void->other->value.type)) {
15707 return ir_unreach_error(ira);
15708 }
15709 }
15710
15711
1445315712 size_t case_count = switch_br_instruction->case_count;
1445415713
1445515714 bool is_comptime;
......@@ -14540,7 +15799,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
1454015799
1454115800 IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base);
1454215801 ir_build_switch_br_from(&ira->new_irb, &switch_br_instruction->base,
14543 target_value, new_else_block, case_count, cases, nullptr);
15802 target_value, new_else_block, case_count, cases, nullptr, nullptr);
1454415803 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
1454515804}
1454615805
......@@ -14561,7 +15820,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1456115820 return out_val->type;
1456215821 }
1456315822
14564 assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer);
15823 if (target_value_ptr->value.type->id != TypeTableEntryIdPointer) {
15824 ir_add_error(ira, target_value_ptr, buf_sprintf("invalid deref on switch target"));
15825 return ira->codegen->builtin_types.entry_invalid;
15826 }
1456515827
1456615828 TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
1456715829 ConstExprValue *pointee_val = nullptr;
......@@ -14582,8 +15844,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1458215844 case TypeTableEntryIdBool:
1458315845 case TypeTableEntryIdInt:
1458415846 case TypeTableEntryIdFloat:
14585 case TypeTableEntryIdNumLitFloat:
14586 case TypeTableEntryIdNumLitInt:
15847 case TypeTableEntryIdComptimeFloat:
15848 case TypeTableEntryIdComptimeInt:
1458715849 case TypeTableEntryIdPointer:
1458815850 case TypeTableEntryIdPromise:
1458915851 case TypeTableEntryIdFn:
......@@ -14661,9 +15923,9 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1466115923 case TypeTableEntryIdUnreachable:
1466215924 case TypeTableEntryIdArray:
1466315925 case TypeTableEntryIdStruct:
14664 case TypeTableEntryIdUndefLit:
14665 case TypeTableEntryIdNullLit:
14666 case TypeTableEntryIdMaybe:
15926 case TypeTableEntryIdUndefined:
15927 case TypeTableEntryIdNull:
15928 case TypeTableEntryIdOptional:
1466715929 case TypeTableEntryIdBlock:
1466815930 case TypeTableEntryIdBoundFn:
1466915931 case TypeTableEntryIdArgTuple:
......@@ -14841,6 +16103,8 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir
1484116103 assert(container_type->id == TypeTableEntryIdUnion);
1484216104
1484316105 ensure_complete_type(ira->codegen, container_type);
16106 if (type_is_invalid(container_type))
16107 return ira->codegen->builtin_types.entry_invalid;
1484416108
1484516109 if (instr_field_count != 1) {
1484616110 ir_add_error(ira, instruction,
......@@ -14868,8 +16132,14 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir
1486816132 if (casted_field_value == ira->codegen->invalid_instruction)
1486916133 return ira->codegen->builtin_types.entry_invalid;
1487016134
16135 type_ensure_zero_bits_known(ira->codegen, casted_field_value->value.type);
16136 if (type_is_invalid(casted_field_value->value.type))
16137 return ira->codegen->builtin_types.entry_invalid;
16138
1487116139 bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
14872 if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) {
16140 if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime ||
16141 !type_has_bits(casted_field_value->value.type))
16142 {
1487316143 ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
1487416144 if (!field_val)
1487516145 return ira->codegen->builtin_types.entry_invalid;
......@@ -14908,6 +16178,8 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
1490816178 }
1490916179
1491016180 ensure_complete_type(ira->codegen, container_type);
16181 if (type_is_invalid(container_type))
16182 return ira->codegen->builtin_types.entry_invalid;
1491116183
1491216184 size_t actual_field_count = container_type->data.structure.src_field_count;
1491316185
......@@ -15176,11 +16448,11 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
1517616448 case TypeTableEntryIdPromise:
1517716449 case TypeTableEntryIdArray:
1517816450 case TypeTableEntryIdStruct:
15179 case TypeTableEntryIdNumLitFloat:
15180 case TypeTableEntryIdNumLitInt:
15181 case TypeTableEntryIdUndefLit:
15182 case TypeTableEntryIdNullLit:
15183 case TypeTableEntryIdMaybe:
16451 case TypeTableEntryIdComptimeFloat:
16452 case TypeTableEntryIdComptimeInt:
16453 case TypeTableEntryIdUndefined:
16454 case TypeTableEntryIdNull:
16455 case TypeTableEntryIdOptional:
1518416456 case TypeTableEntryIdErrorUnion:
1518516457 case TypeTableEntryIdErrorSet:
1518616458 case TypeTableEntryIdUnion:
......@@ -15267,7 +16539,8 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
1526716539 if (type_is_invalid(casted_value->value.type))
1526816540 return ira->codegen->builtin_types.entry_invalid;
1526916541
15270 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
16542 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
16543 true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
1527116544 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
1527216545 if (casted_value->value.special == ConstValSpecialStatic) {
1527316546 ErrorTableEntry *err = casted_value->value.data.x_err_set;
......@@ -15293,6 +16566,9 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
1529316566 assert(target->value.type->id == TypeTableEntryIdEnum);
1529416567
1529516568 if (instr_is_comptime(target)) {
16569 type_ensure_zero_bits_known(ira->codegen, target->value.type);
16570 if (type_is_invalid(target->value.type))
16571 return ira->codegen->builtin_types.entry_invalid;
1529616572 TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
1529716573 ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
1529816574 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
......@@ -15300,15 +16576,14 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
1530016576 return out_val->type;
1530116577 }
1530216578
15303 if (!target->value.type->data.enumeration.generate_name_table) {
15304 target->value.type->data.enumeration.generate_name_table = true;
15305 ira->codegen->name_table_enums.append(target->value.type);
15306 }
15307
1530816579 IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope,
1530916580 instruction->base.source_node, target);
1531016581 ir_link_new_instruction(result, &instruction->base);
15311 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
16582 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(
16583 ira->codegen, ira->codegen->builtin_types.entry_u8,
16584 true, false, PtrLenUnknown,
16585 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),
16586 0, 0);
1531216587 result->value.type = get_slice_type(ira->codegen, u8_ptr_type);
1531316588 return result->value.type;
1531416589}
......@@ -15337,6 +16612,8 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1533716612 }
1533816613
1533916614 ensure_complete_type(ira->codegen, container_type);
16615 if (type_is_invalid(container_type))
16616 return ira->codegen->builtin_types.entry_invalid;
1534016617
1534116618 TypeStructField *field = find_struct_type_field(container_type, field_name);
1534216619 if (field == nullptr) {
......@@ -15359,6 +16636,7 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1535916636 TypeTableEntry *field_ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry,
1536016637 field_ptr->value.type->data.pointer.is_const,
1536116638 field_ptr->value.type->data.pointer.is_volatile,
16639 PtrLenSingle,
1536216640 field_ptr_align, 0, 0);
1536316641 IrInstruction *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type);
1536416642 if (type_is_invalid(casted_field_ptr->value.type))
......@@ -15367,6 +16645,7 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1536716645 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, container_type,
1536816646 casted_field_ptr->value.type->data.pointer.is_const,
1536916647 casted_field_ptr->value.type->data.pointer.is_volatile,
16648 PtrLenSingle,
1537016649 parent_ptr_align, 0, 0);
1537116650
1537216651 if (instr_is_comptime(casted_field_ptr)) {
......@@ -15411,6 +16690,8 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
1541116690 return ira->codegen->builtin_types.entry_invalid;
1541216691
1541316692 ensure_complete_type(ira->codegen, container_type);
16693 if (type_is_invalid(container_type))
16694 return ira->codegen->builtin_types.entry_invalid;
1541416695
1541516696 IrInstruction *field_name_value = instruction->field_name->other;
1541616697 Buf *field_name = ir_resolve_str(ira, field_name_value);
......@@ -15443,131 +16724,1099 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
1544316724 return ira->codegen->builtin_types.entry_num_lit_int;
1544416725}
1544516726
15446static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
15447 IrInstructionTypeId *instruction)
16727static void ensure_field_index(TypeTableEntry *type, const char *field_name, size_t index)
1544816728{
15449 IrInstruction *type_value = instruction->type_value->other;
15450 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
15451 if (type_is_invalid(type_entry))
15452 return ira->codegen->builtin_types.entry_invalid;
15453
15454 ConstExprValue *var_value = get_builtin_value(ira->codegen, "TypeId");
15455 assert(var_value->type->id == TypeTableEntryIdMetaType);
15456 TypeTableEntry *result_type = var_value->data.x_type;
16729 Buf *field_name_buf;
1545716730
15458 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15459 bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry->id));
15460 return result_type;
16731 assert(type != nullptr && !type_is_invalid(type));
16732 // Check for our field by creating a buffer in place then using the comma operator to free it so that we don't
16733 // leak memory in debug mode.
16734 assert(find_struct_type_field(type, field_name_buf = buf_create_from_str(field_name))->src_index == index &&
16735 (buf_deinit(field_name_buf), true));
1546116736}
1546216737
15463static TypeTableEntry *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira,
15464 IrInstructionSetEvalBranchQuota *instruction)
16738static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, TypeTableEntry *root = nullptr)
1546516739{
15466 if (ira->new_irb.exec->parent_exec != nullptr && !ira->new_irb.exec->is_generic_instantiation) {
15467 ir_add_error(ira, &instruction->base,
15468 buf_sprintf("@setEvalBranchQuota must be called from the top of the comptime stack"));
15469 return ira->codegen->builtin_types.entry_invalid;
15470 }
16740 static ConstExprValue *type_info_var = nullptr;
16741 static TypeTableEntry *type_info_type = nullptr;
16742 if (type_info_var == nullptr)
16743 {
16744 type_info_var = get_builtin_value(ira->codegen, "TypeInfo");
16745 assert(type_info_var->type->id == TypeTableEntryIdMetaType);
1547116746
15472 uint64_t new_quota;
15473 if (!ir_resolve_usize(ira, instruction->new_quota->other, &new_quota))
15474 return ira->codegen->builtin_types.entry_invalid;
16747 ensure_complete_type(ira->codegen, type_info_var->data.x_type);
16748 if (type_is_invalid(type_info_var->data.x_type))
16749 return ira->codegen->builtin_types.entry_invalid;
1547516750
15476 if (new_quota > ira->new_irb.exec->backward_branch_quota) {
15477 ira->new_irb.exec->backward_branch_quota = new_quota;
16751 type_info_type = type_info_var->data.x_type;
16752 assert(type_info_type->id == TypeTableEntryIdUnion);
1547816753 }
1547916754
15480 ir_build_const_from(ira, &instruction->base);
15481 return ira->codegen->builtin_types.entry_void;
15482}
16755 if (type_name == nullptr && root == nullptr)
16756 return type_info_type;
16757 else if (type_name == nullptr)
16758 return root;
1548316759
15484static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
15485 IrInstruction *type_value = instruction->type_value->other;
15486 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
15487 if (type_is_invalid(type_entry))
15488 return ira->codegen->builtin_types.entry_invalid;
16760 TypeTableEntry *root_type = (root == nullptr) ? type_info_type : root;
1548916761
15490 if (!type_entry->cached_const_name_val) {
15491 type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, &type_entry->name);
15492 }
15493 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15494 copy_const_val(out_val, type_entry->cached_const_name_val, true);
15495 return out_val->type;
15496}
16762 ScopeDecls *type_info_scope = get_container_scope(root_type);
16763 assert(type_info_scope != nullptr);
1549716764
15498static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
15499 AstNode *node = instruction->base.source_node;
15500 assert(node->type == NodeTypeFnCallExpr);
15501 AstNode *block_node = node->data.fn_call_expr.params.at(0);
16765 Buf field_name = BUF_INIT;
16766 buf_init_from_str(&field_name, type_name);
16767 auto entry = type_info_scope->decl_table.get(&field_name);
16768 buf_deinit(&field_name);
1550216769
15503 ScopeCImport *cimport_scope = create_cimport_scope(node, instruction->base.scope);
16770 TldVar *tld = (TldVar *)entry;
16771 assert(tld->base.id == TldIdVar);
1550416772
15505 // Execute the C import block like an inline function
15506 TypeTableEntry *void_type = ira->codegen->builtin_types.entry_void;
15507 IrInstruction *result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
15508 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
15509 &cimport_scope->buf, block_node, nullptr, nullptr);
15510 if (type_is_invalid(result->value.type))
16773 VariableTableEntry *var = tld->var;
16774
16775 ensure_complete_type(ira->codegen, var->value->type);
16776 if (type_is_invalid(var->value->type))
1551116777 return ira->codegen->builtin_types.entry_invalid;
16778 assert(var->value->type->id == TypeTableEntryIdMetaType);
16779 return var->value->data.x_type;
16780}
1551216781
15513 find_libc_include_path(ira->codegen);
16782static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope)
16783{
16784 TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition");
16785 ensure_complete_type(ira->codegen, type_info_definition_type);
16786 if (type_is_invalid(type_info_definition_type))
16787 return false;
1551416788
15515 ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
15516 child_import->decls_scope = create_decls_scope(node, nullptr, nullptr, child_import);
15517 child_import->c_import_node = node;
15518 child_import->package = new_anonymous_package();
15519 child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);
15520 child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
15521 child_import->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,
15522 buf_ptr(buf_create_from_str("cimport.h")), buf_ptr(buf_create_from_str(".")));
16789 ensure_field_index(type_info_definition_type, "name", 0);
16790 ensure_field_index(type_info_definition_type, "is_pub", 1);
16791 ensure_field_index(type_info_definition_type, "data", 2);
1552316792
15524 ZigList<ErrorMsg *> errors = {0};
16793 TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type);
16794 ensure_complete_type(ira->codegen, type_info_definition_data_type);
16795 if (type_is_invalid(type_info_definition_data_type))
16796 return false;
1552516797
15526 int err;
15527 if ((err = parse_h_buf(child_import, &errors, &cimport_scope->buf, ira->codegen, node))) {
15528 if (err != ErrorCCompileErrors) {
15529 ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err)));
15530 return ira->codegen->builtin_types.entry_invalid;
15531 }
15532 }
16798 TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type);
16799 ensure_complete_type(ira->codegen, type_info_fn_def_type);
16800 if (type_is_invalid(type_info_fn_def_type))
16801 return false;
1553316802
15534 if (errors.length > 0) {
15535 ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed"));
15536 for (size_t i = 0; i < errors.length; i += 1) {
15537 ErrorMsg *err_msg = errors.at(i);
15538 err_msg_add_note(parent_err_msg, err_msg);
16803 TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type);
16804 ensure_complete_type(ira->codegen, type_info_fn_def_inline_type);
16805 if (type_is_invalid(type_info_fn_def_inline_type))
16806 return false;
16807
16808 // Loop through our definitions once to figure out how many definitions we will generate info for.
16809 auto decl_it = decls_scope->decl_table.entry_iterator();
16810 decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr;
16811 int definition_count = 0;
16812
16813 while ((curr_entry = decl_it.next()) != nullptr)
16814 {
16815 // If the definition is unresolved, force it to be resolved again.
16816 if (curr_entry->value->resolution == TldResolutionUnresolved)
16817 {
16818 resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node);
16819 if (curr_entry->value->resolution != TldResolutionOk)
16820 {
16821 return false;
16822 }
1553916823 }
1554016824
15541 return ira->codegen->builtin_types.entry_invalid;
15542 }
16825 // Skip comptime blocks and test functions.
16826 if (curr_entry->value->id != TldIdCompTime)
16827 {
16828 if (curr_entry->value->id == TldIdFn)
16829 {
16830 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
16831 if (fn_entry->is_test)
16832 continue;
16833 }
1554316834
15544 if (ira->codegen->verbose_cimport) {
15545 fprintf(stderr, "\nC imports:\n");
15546 fprintf(stderr, "-----------\n");
15547 ast_render(ira->codegen, stderr, child_import->root, 4);
16835 definition_count += 1;
16836 }
1554816837 }
1554916838
15550 scan_decls(ira->codegen, child_import->decls_scope, child_import->root);
15551
15552 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15553 out_val->data.x_import = child_import;
15554 return ira->codegen->builtin_types.entry_namespace;
15555}
16839 ConstExprValue *definition_array = create_const_vals(1);
16840 definition_array->special = ConstValSpecialStatic;
16841 definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count);
16842 definition_array->data.x_array.special = ConstArraySpecialNone;
16843 definition_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16844 definition_array->data.x_array.s_none.elements = create_const_vals(definition_count);
16845 init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false);
1555616846
15557static TypeTableEntry *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {
15558 IrInstruction *name_value = instruction->name->other;
15559 if (type_is_invalid(name_value->value.type))
15560 return ira->codegen->builtin_types.entry_invalid;
16847 // Loop through the definitions and generate info.
16848 decl_it = decls_scope->decl_table.entry_iterator();
16849 curr_entry = nullptr;
16850 int definition_index = 0;
16851 while ((curr_entry = decl_it.next()) != nullptr)
16852 {
16853 // Skip comptime blocks and test functions.
16854 if (curr_entry->value->id == TldIdCompTime)
16855 continue;
16856 else if (curr_entry->value->id == TldIdFn)
16857 {
16858 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
16859 if (fn_entry->is_test)
16860 continue;
16861 }
1556116862
15562 Buf *include_name = ir_resolve_str(ira, name_value);
15563 if (!include_name)
15564 return ira->codegen->builtin_types.entry_invalid;
16863 ConstExprValue *definition_val = &definition_array->data.x_array.s_none.elements[definition_index];
1556516864
15566 Buf *c_import_buf = exec_c_import_buf(ira->new_irb.exec);
15567 // We check for this error in pass1
15568 assert(c_import_buf);
16865 definition_val->special = ConstValSpecialStatic;
16866 definition_val->type = type_info_definition_type;
1556916867
15570 buf_appendf(c_import_buf, "#include <%s>\n", buf_ptr(include_name));
16868 ConstExprValue *inner_fields = create_const_vals(3);
16869 ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key);
16870 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(curr_entry->key), true);
16871 inner_fields[1].special = ConstValSpecialStatic;
16872 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;
16873 inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub;
16874 inner_fields[2].special = ConstValSpecialStatic;
16875 inner_fields[2].type = type_info_definition_data_type;
16876 inner_fields[2].data.x_union.parent.id = ConstParentIdStruct;
16877 inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;
16878 inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;
16879
16880 switch (curr_entry->value->id)
16881 {
16882 case TldIdVar:
16883 {
16884 VariableTableEntry *var = ((TldVar *)curr_entry->value)->var;
16885 ensure_complete_type(ira->codegen, var->value->type);
16886 if (type_is_invalid(var->value->type))
16887 return false;
16888
16889 if (var->value->type->id == TypeTableEntryIdMetaType)
16890 {
16891 // We have a variable of type 'type', so it's actually a type definition.
16892 // 0: Data.Type: type
16893 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
16894 inner_fields[2].data.x_union.payload = var->value;
16895 }
16896 else
16897 {
16898 // We have a variable of another type, so we store the type of the variable.
16899 // 1: Data.Var: type
16900 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1);
16901
16902 ConstExprValue *payload = create_const_vals(1);
16903 payload->type = ira->codegen->builtin_types.entry_type;
16904 payload->data.x_type = var->value->type;
16905
16906 inner_fields[2].data.x_union.payload = payload;
16907 }
16908
16909 break;
16910 }
16911 case TldIdFn:
16912 {
16913 // 2: Data.Fn: Data.FnDef
16914 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 2);
16915
16916 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
16917 assert(!fn_entry->is_test);
16918
16919 AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
16920
16921 ConstExprValue *fn_def_val = create_const_vals(1);
16922 fn_def_val->special = ConstValSpecialStatic;
16923 fn_def_val->type = type_info_fn_def_type;
16924 fn_def_val->data.x_struct.parent.id = ConstParentIdUnion;
16925 fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2];
16926
16927 ConstExprValue *fn_def_fields = create_const_vals(9);
16928 fn_def_val->data.x_struct.fields = fn_def_fields;
16929
16930 // fn_type: type
16931 ensure_field_index(fn_def_val->type, "fn_type", 0);
16932 fn_def_fields[0].special = ConstValSpecialStatic;
16933 fn_def_fields[0].type = ira->codegen->builtin_types.entry_type;
16934 fn_def_fields[0].data.x_type = fn_entry->type_entry;
16935 // inline_type: Data.FnDef.Inline
16936 ensure_field_index(fn_def_val->type, "inline_type", 1);
16937 fn_def_fields[1].special = ConstValSpecialStatic;
16938 fn_def_fields[1].type = type_info_fn_def_inline_type;
16939 bigint_init_unsigned(&fn_def_fields[1].data.x_enum_tag, fn_entry->fn_inline);
16940 // calling_convention: TypeInfo.CallingConvention
16941 ensure_field_index(fn_def_val->type, "calling_convention", 2);
16942 fn_def_fields[2].special = ConstValSpecialStatic;
16943 fn_def_fields[2].type = ir_type_info_get_type(ira, "CallingConvention");
16944 bigint_init_unsigned(&fn_def_fields[2].data.x_enum_tag, fn_node->cc);
16945 // is_var_args: bool
16946 ensure_field_index(fn_def_val->type, "is_var_args", 3);
16947 bool is_varargs = fn_node->is_var_args;
16948 fn_def_fields[3].special = ConstValSpecialStatic;
16949 fn_def_fields[3].type = ira->codegen->builtin_types.entry_bool;
16950 fn_def_fields[3].data.x_bool = is_varargs;
16951 // is_extern: bool
16952 ensure_field_index(fn_def_val->type, "is_extern", 4);
16953 fn_def_fields[4].special = ConstValSpecialStatic;
16954 fn_def_fields[4].type = ira->codegen->builtin_types.entry_bool;
16955 fn_def_fields[4].data.x_bool = fn_node->is_extern;
16956 // is_export: bool
16957 ensure_field_index(fn_def_val->type, "is_export", 5);
16958 fn_def_fields[5].special = ConstValSpecialStatic;
16959 fn_def_fields[5].type = ira->codegen->builtin_types.entry_bool;
16960 fn_def_fields[5].data.x_bool = fn_node->is_export;
16961 // lib_name: ?[]const u8
16962 ensure_field_index(fn_def_val->type, "lib_name", 6);
16963 fn_def_fields[6].special = ConstValSpecialStatic;
16964 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(
16965 ira->codegen, ira->codegen->builtin_types.entry_u8,
16966 true, false, PtrLenUnknown,
16967 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),
16968 0, 0);
16969 fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
16970 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
16971 fn_def_fields[6].data.x_optional = create_const_vals(1);
16972 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);
16973 init_const_slice(ira->codegen, fn_def_fields[6].data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true);
16974 } else {
16975 fn_def_fields[6].data.x_optional = nullptr;
16976 }
16977 // return_type: type
16978 ensure_field_index(fn_def_val->type, "return_type", 7);
16979 fn_def_fields[7].special = ConstValSpecialStatic;
16980 fn_def_fields[7].type = ira->codegen->builtin_types.entry_type;
16981 if (fn_entry->src_implicit_return_type != nullptr)
16982 fn_def_fields[7].data.x_type = fn_entry->src_implicit_return_type;
16983 else if (fn_entry->type_entry->data.fn.gen_return_type != nullptr)
16984 fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.gen_return_type;
16985 else
16986 fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
16987 // arg_names: [][] const u8
16988 ensure_field_index(fn_def_val->type, "arg_names", 8);
16989 size_t fn_arg_count = fn_entry->variable_list.length;
16990 ConstExprValue *fn_arg_name_array = create_const_vals(1);
16991 fn_arg_name_array->special = ConstValSpecialStatic;
16992 fn_arg_name_array->type = get_array_type(ira->codegen,
16993 get_slice_type(ira->codegen, u8_ptr), fn_arg_count);
16994 fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
16995 fn_arg_name_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16996 fn_arg_name_array->data.x_array.s_none.elements = create_const_vals(fn_arg_count);
16997
16998 init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false);
16999
17000 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
17001 {
17002 VariableTableEntry *arg_var = fn_entry->variable_list.at(fn_arg_index);
17003 ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.s_none.elements[fn_arg_index];
17004 ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name);
17005 init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true);
17006 fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray;
17007 fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array;
17008 fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
17009 }
17010
17011 inner_fields[2].data.x_union.payload = fn_def_val;
17012 break;
17013 }
17014 case TldIdContainer:
17015 {
17016 TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry;
17017 ensure_complete_type(ira->codegen, type_entry);
17018 if (type_is_invalid(type_entry))
17019 return false;
17020
17021 // This is a type.
17022 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
17023
17024 ConstExprValue *payload = create_const_vals(1);
17025 payload->type = ira->codegen->builtin_types.entry_type;
17026 payload->data.x_type = type_entry;
17027
17028 inner_fields[2].data.x_union.payload = payload;
17029
17030 break;
17031 }
17032 default:
17033 zig_unreachable();
17034 }
17035
17036 definition_val->data.x_struct.fields = inner_fields;
17037 definition_index++;
17038 }
17039
17040 assert(definition_index == definition_count);
17041 return true;
17042}
17043
17044static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) {
17045 assert(type_entry != nullptr);
17046 assert(!type_is_invalid(type_entry));
17047
17048 ensure_complete_type(ira->codegen, type_entry);
17049 if (type_is_invalid(type_entry))
17050 return nullptr;
17051
17052 const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field,
17053 TypeTableEntry *type_info_enum_field_type) {
17054 enum_field_val->special = ConstValSpecialStatic;
17055 enum_field_val->type = type_info_enum_field_type;
17056
17057 ConstExprValue *inner_fields = create_const_vals(2);
17058 inner_fields[1].special = ConstValSpecialStatic;
17059 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
17060
17061 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
17062 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true);
17063
17064 bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value);
17065
17066 enum_field_val->data.x_struct.fields = inner_fields;
17067 };
17068
17069 const auto create_ptr_like_type_info = [ira](TypeTableEntry *ptr_type_entry) {
17070 TypeTableEntry *attrs_type;
17071 uint32_t size_enum_index;
17072 if (is_slice(ptr_type_entry)) {
17073 attrs_type = ptr_type_entry->data.structure.fields[slice_ptr_index].type_entry;
17074 size_enum_index = 2;
17075 } else if (ptr_type_entry->id == TypeTableEntryIdPointer) {
17076 attrs_type = ptr_type_entry;
17077 size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1;
17078 } else {
17079 zig_unreachable();
17080 }
17081
17082 TypeTableEntry *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer");
17083 ensure_complete_type(ira->codegen, type_info_pointer_type);
17084 assert(!type_is_invalid(type_info_pointer_type));
17085
17086 ConstExprValue *result = create_const_vals(1);
17087 result->special = ConstValSpecialStatic;
17088 result->type = type_info_pointer_type;
17089
17090 ConstExprValue *fields = create_const_vals(5);
17091 result->data.x_struct.fields = fields;
17092
17093 // size: Size
17094 ensure_field_index(result->type, "size", 0);
17095 TypeTableEntry *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type);
17096 ensure_complete_type(ira->codegen, type_info_pointer_size_type);
17097 assert(!type_is_invalid(type_info_pointer_size_type));
17098 fields[0].special = ConstValSpecialStatic;
17099 fields[0].type = type_info_pointer_size_type;
17100 bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index);
17101
17102 // is_const: bool
17103 ensure_field_index(result->type, "is_const", 1);
17104 fields[1].special = ConstValSpecialStatic;
17105 fields[1].type = ira->codegen->builtin_types.entry_bool;
17106 fields[1].data.x_bool = attrs_type->data.pointer.is_const;
17107 // is_volatile: bool
17108 ensure_field_index(result->type, "is_volatile", 2);
17109 fields[2].special = ConstValSpecialStatic;
17110 fields[2].type = ira->codegen->builtin_types.entry_bool;
17111 fields[2].data.x_bool = attrs_type->data.pointer.is_volatile;
17112 // alignment: u32
17113 ensure_field_index(result->type, "alignment", 3);
17114 fields[3].special = ConstValSpecialStatic;
17115 fields[3].type = ira->codegen->builtin_types.entry_u32;
17116 bigint_init_unsigned(&fields[3].data.x_bigint, attrs_type->data.pointer.alignment);
17117 // child: type
17118 ensure_field_index(result->type, "child", 4);
17119 fields[4].special = ConstValSpecialStatic;
17120 fields[4].type = ira->codegen->builtin_types.entry_type;
17121 fields[4].data.x_type = attrs_type->data.pointer.child_type;
17122
17123 return result;
17124 };
17125
17126 if (type_entry == ira->codegen->builtin_types.entry_global_error_set) {
17127 zig_panic("TODO implement @typeInfo for global error set");
17128 }
17129
17130 ConstExprValue *result = nullptr;
17131 switch (type_entry->id)
17132 {
17133 case TypeTableEntryIdInvalid:
17134 zig_unreachable();
17135 case TypeTableEntryIdMetaType:
17136 case TypeTableEntryIdVoid:
17137 case TypeTableEntryIdBool:
17138 case TypeTableEntryIdUnreachable:
17139 case TypeTableEntryIdComptimeFloat:
17140 case TypeTableEntryIdComptimeInt:
17141 case TypeTableEntryIdUndefined:
17142 case TypeTableEntryIdNull:
17143 case TypeTableEntryIdNamespace:
17144 case TypeTableEntryIdBlock:
17145 case TypeTableEntryIdArgTuple:
17146 case TypeTableEntryIdOpaque:
17147 return nullptr;
17148 default:
17149 {
17150 // Lookup an available value in our cache.
17151 auto entry = ira->codegen->type_info_cache.maybe_get(type_entry);
17152 if (entry != nullptr)
17153 return entry->value;
17154
17155 // Fallthrough if we don't find one.
17156 }
17157 case TypeTableEntryIdInt:
17158 {
17159 result = create_const_vals(1);
17160 result->special = ConstValSpecialStatic;
17161 result->type = ir_type_info_get_type(ira, "Int");
17162
17163 ConstExprValue *fields = create_const_vals(2);
17164 result->data.x_struct.fields = fields;
17165
17166 // is_signed: bool
17167 ensure_field_index(result->type, "is_signed", 0);
17168 fields[0].special = ConstValSpecialStatic;
17169 fields[0].type = ira->codegen->builtin_types.entry_bool;
17170 fields[0].data.x_bool = type_entry->data.integral.is_signed;
17171 // bits: u8
17172 ensure_field_index(result->type, "bits", 1);
17173 fields[1].special = ConstValSpecialStatic;
17174 fields[1].type = ira->codegen->builtin_types.entry_u8;
17175 bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count);
17176
17177 break;
17178 }
17179 case TypeTableEntryIdFloat:
17180 {
17181 result = create_const_vals(1);
17182 result->special = ConstValSpecialStatic;
17183 result->type = ir_type_info_get_type(ira, "Float");
17184
17185 ConstExprValue *fields = create_const_vals(1);
17186 result->data.x_struct.fields = fields;
17187
17188 // bits: u8
17189 ensure_field_index(result->type, "bits", 0);
17190 fields[0].special = ConstValSpecialStatic;
17191 fields[0].type = ira->codegen->builtin_types.entry_u8;
17192 bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count);
17193
17194 break;
17195 }
17196 case TypeTableEntryIdPointer:
17197 {
17198 result = create_ptr_like_type_info(type_entry);
17199 break;
17200 }
17201 case TypeTableEntryIdArray:
17202 {
17203 result = create_const_vals(1);
17204 result->special = ConstValSpecialStatic;
17205 result->type = ir_type_info_get_type(ira, "Array");
17206
17207 ConstExprValue *fields = create_const_vals(2);
17208 result->data.x_struct.fields = fields;
17209
17210 // len: usize
17211 ensure_field_index(result->type, "len", 0);
17212 fields[0].special = ConstValSpecialStatic;
17213 fields[0].type = ira->codegen->builtin_types.entry_usize;
17214 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len);
17215 // child: type
17216 ensure_field_index(result->type, "child", 1);
17217 fields[1].special = ConstValSpecialStatic;
17218 fields[1].type = ira->codegen->builtin_types.entry_type;
17219 fields[1].data.x_type = type_entry->data.array.child_type;
17220
17221 break;
17222 }
17223 case TypeTableEntryIdOptional:
17224 {
17225 result = create_const_vals(1);
17226 result->special = ConstValSpecialStatic;
17227 result->type = ir_type_info_get_type(ira, "Optional");
17228
17229 ConstExprValue *fields = create_const_vals(1);
17230 result->data.x_struct.fields = fields;
17231
17232 // child: type
17233 ensure_field_index(result->type, "child", 0);
17234 fields[0].special = ConstValSpecialStatic;
17235 fields[0].type = ira->codegen->builtin_types.entry_type;
17236 fields[0].data.x_type = type_entry->data.maybe.child_type;
17237
17238 break;
17239 }
17240 case TypeTableEntryIdPromise:
17241 {
17242 result = create_const_vals(1);
17243 result->special = ConstValSpecialStatic;
17244 result->type = ir_type_info_get_type(ira, "Promise");
17245
17246 ConstExprValue *fields = create_const_vals(1);
17247 result->data.x_struct.fields = fields;
17248
17249 // child: ?type
17250 ensure_field_index(result->type, "child", 0);
17251 fields[0].special = ConstValSpecialStatic;
17252 fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
17253
17254 if (type_entry->data.promise.result_type == nullptr)
17255 fields[0].data.x_optional = nullptr;
17256 else {
17257 ConstExprValue *child_type = create_const_vals(1);
17258 child_type->special = ConstValSpecialStatic;
17259 child_type->type = ira->codegen->builtin_types.entry_type;
17260 child_type->data.x_type = type_entry->data.promise.result_type;
17261 fields[0].data.x_optional = child_type;
17262 }
17263
17264 break;
17265 }
17266 case TypeTableEntryIdEnum:
17267 {
17268 result = create_const_vals(1);
17269 result->special = ConstValSpecialStatic;
17270 result->type = ir_type_info_get_type(ira, "Enum");
17271
17272 ConstExprValue *fields = create_const_vals(4);
17273 result->data.x_struct.fields = fields;
17274
17275 // layout: ContainerLayout
17276 ensure_field_index(result->type, "layout", 0);
17277 fields[0].special = ConstValSpecialStatic;
17278 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
17279 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.enumeration.layout);
17280 // tag_type: type
17281 ensure_field_index(result->type, "tag_type", 1);
17282 fields[1].special = ConstValSpecialStatic;
17283 fields[1].type = ira->codegen->builtin_types.entry_type;
17284 fields[1].data.x_type = type_entry->data.enumeration.tag_int_type;
17285 // fields: []TypeInfo.EnumField
17286 ensure_field_index(result->type, "fields", 2);
17287
17288 TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField");
17289 uint32_t enum_field_count = type_entry->data.enumeration.src_field_count;
17290
17291 ConstExprValue *enum_field_array = create_const_vals(1);
17292 enum_field_array->special = ConstValSpecialStatic;
17293 enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
17294 enum_field_array->data.x_array.special = ConstArraySpecialNone;
17295 enum_field_array->data.x_array.s_none.parent.id = ConstParentIdNone;
17296 enum_field_array->data.x_array.s_none.elements = create_const_vals(enum_field_count);
17297
17298 init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false);
17299
17300 for (uint32_t enum_field_index = 0; enum_field_index < enum_field_count; enum_field_index++)
17301 {
17302 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];
17303 ConstExprValue *enum_field_val = &enum_field_array->data.x_array.s_none.elements[enum_field_index];
17304 make_enum_field_val(enum_field_val, enum_field, type_info_enum_field_type);
17305 enum_field_val->data.x_struct.parent.id = ConstParentIdArray;
17306 enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;
17307 enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;
17308 }
17309 // defs: []TypeInfo.Definition
17310 ensure_field_index(result->type, "defs", 3);
17311 if (!ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope))
17312 return nullptr;
17313
17314 break;
17315 }
17316 case TypeTableEntryIdErrorSet:
17317 {
17318 result = create_const_vals(1);
17319 result->special = ConstValSpecialStatic;
17320 result->type = ir_type_info_get_type(ira, "ErrorSet");
17321
17322 ConstExprValue *fields = create_const_vals(1);
17323 result->data.x_struct.fields = fields;
17324
17325 // errors: []TypeInfo.Error
17326 ensure_field_index(result->type, "errors", 0);
17327
17328 TypeTableEntry *type_info_error_type = ir_type_info_get_type(ira, "Error");
17329 uint32_t error_count = type_entry->data.error_set.err_count;
17330 ConstExprValue *error_array = create_const_vals(1);
17331 error_array->special = ConstValSpecialStatic;
17332 error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
17333 error_array->data.x_array.special = ConstArraySpecialNone;
17334 error_array->data.x_array.s_none.parent.id = ConstParentIdNone;
17335 error_array->data.x_array.s_none.elements = create_const_vals(error_count);
17336
17337 init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);
17338 for (uint32_t error_index = 0; error_index < error_count; error_index++)
17339 {
17340 ErrorTableEntry *error = type_entry->data.error_set.errors[error_index];
17341 ConstExprValue *error_val = &error_array->data.x_array.s_none.elements[error_index];
17342
17343 error_val->special = ConstValSpecialStatic;
17344 error_val->type = type_info_error_type;
17345
17346 ConstExprValue *inner_fields = create_const_vals(2);
17347 inner_fields[1].special = ConstValSpecialStatic;
17348 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
17349
17350 ConstExprValue *name = nullptr;
17351 if (error->cached_error_name_val != nullptr)
17352 name = error->cached_error_name_val;
17353 if (name == nullptr)
17354 name = create_const_str_lit(ira->codegen, &error->name);
17355 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(&error->name), true);
17356 bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value);
17357
17358 error_val->data.x_struct.fields = inner_fields;
17359 error_val->data.x_struct.parent.id = ConstParentIdArray;
17360 error_val->data.x_struct.parent.data.p_array.array_val = error_array;
17361 error_val->data.x_struct.parent.data.p_array.elem_index = error_index;
17362 }
17363
17364 break;
17365 }
17366 case TypeTableEntryIdErrorUnion:
17367 {
17368 result = create_const_vals(1);
17369 result->special = ConstValSpecialStatic;
17370 result->type = ir_type_info_get_type(ira, "ErrorUnion");
17371
17372 ConstExprValue *fields = create_const_vals(2);
17373 result->data.x_struct.fields = fields;
17374
17375 // error_set: type
17376 ensure_field_index(result->type, "error_set", 0);
17377 fields[0].special = ConstValSpecialStatic;
17378 fields[0].type = ira->codegen->builtin_types.entry_type;
17379 fields[0].data.x_type = type_entry->data.error_union.err_set_type;
17380
17381 // payload: type
17382 ensure_field_index(result->type, "payload", 1);
17383 fields[1].special = ConstValSpecialStatic;
17384 fields[1].type = ira->codegen->builtin_types.entry_type;
17385 fields[1].data.x_type = type_entry->data.error_union.payload_type;
17386
17387 break;
17388 }
17389 case TypeTableEntryIdUnion:
17390 {
17391 result = create_const_vals(1);
17392 result->special = ConstValSpecialStatic;
17393 result->type = ir_type_info_get_type(ira, "Union");
17394
17395 ConstExprValue *fields = create_const_vals(4);
17396 result->data.x_struct.fields = fields;
17397
17398 // layout: ContainerLayout
17399 ensure_field_index(result->type, "layout", 0);
17400 fields[0].special = ConstValSpecialStatic;
17401 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
17402 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout);
17403 // tag_type: ?type
17404 ensure_field_index(result->type, "tag_type", 1);
17405 fields[1].special = ConstValSpecialStatic;
17406 fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
17407
17408 AstNode *union_decl_node = type_entry->data.unionation.decl_node;
17409 if (union_decl_node->data.container_decl.auto_enum ||
17410 union_decl_node->data.container_decl.init_arg_expr != nullptr)
17411 {
17412 ConstExprValue *tag_type = create_const_vals(1);
17413 tag_type->special = ConstValSpecialStatic;
17414 tag_type->type = ira->codegen->builtin_types.entry_type;
17415 tag_type->data.x_type = type_entry->data.unionation.tag_type;
17416 fields[1].data.x_optional = tag_type;
17417 }
17418 else
17419 fields[1].data.x_optional = nullptr;
17420 // fields: []TypeInfo.UnionField
17421 ensure_field_index(result->type, "fields", 2);
17422
17423 TypeTableEntry *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField");
17424 uint32_t union_field_count = type_entry->data.unionation.src_field_count;
17425
17426 ConstExprValue *union_field_array = create_const_vals(1);
17427 union_field_array->special = ConstValSpecialStatic;
17428 union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
17429 union_field_array->data.x_array.special = ConstArraySpecialNone;
17430 union_field_array->data.x_array.s_none.parent.id = ConstParentIdNone;
17431 union_field_array->data.x_array.s_none.elements = create_const_vals(union_field_count);
17432
17433 init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false);
17434
17435 TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField");
17436
17437 for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) {
17438 TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
17439 ConstExprValue *union_field_val = &union_field_array->data.x_array.s_none.elements[union_field_index];
17440
17441 union_field_val->special = ConstValSpecialStatic;
17442 union_field_val->type = type_info_union_field_type;
17443
17444 ConstExprValue *inner_fields = create_const_vals(3);
17445 inner_fields[1].special = ConstValSpecialStatic;
17446 inner_fields[1].type = get_optional_type(ira->codegen, type_info_enum_field_type);
17447
17448 if (fields[1].data.x_optional == nullptr) {
17449 inner_fields[1].data.x_optional = nullptr;
17450 } else {
17451 inner_fields[1].data.x_optional = create_const_vals(1);
17452 make_enum_field_val(inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type);
17453 }
17454
17455 inner_fields[2].special = ConstValSpecialStatic;
17456 inner_fields[2].type = ira->codegen->builtin_types.entry_type;
17457 inner_fields[2].data.x_type = union_field->type_entry;
17458
17459 ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name);
17460 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true);
17461
17462 union_field_val->data.x_struct.fields = inner_fields;
17463 union_field_val->data.x_struct.parent.id = ConstParentIdArray;
17464 union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array;
17465 union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index;
17466 }
17467 // defs: []TypeInfo.Definition
17468 ensure_field_index(result->type, "defs", 3);
17469 if (!ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope))
17470 return nullptr;
17471
17472 break;
17473 }
17474 case TypeTableEntryIdStruct:
17475 {
17476 if (type_entry->data.structure.is_slice) {
17477 result = create_ptr_like_type_info(type_entry);
17478 break;
17479 }
17480
17481 result = create_const_vals(1);
17482 result->special = ConstValSpecialStatic;
17483 result->type = ir_type_info_get_type(ira, "Struct");
17484
17485 ConstExprValue *fields = create_const_vals(3);
17486 result->data.x_struct.fields = fields;
17487
17488 // layout: ContainerLayout
17489 ensure_field_index(result->type, "layout", 0);
17490 fields[0].special = ConstValSpecialStatic;
17491 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
17492 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.structure.layout);
17493 // fields: []TypeInfo.StructField
17494 ensure_field_index(result->type, "fields", 1);
17495
17496 TypeTableEntry *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField");
17497 uint32_t struct_field_count = type_entry->data.structure.src_field_count;
17498
17499 ConstExprValue *struct_field_array = create_const_vals(1);
17500 struct_field_array->special = ConstValSpecialStatic;
17501 struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
17502 struct_field_array->data.x_array.special = ConstArraySpecialNone;
17503 struct_field_array->data.x_array.s_none.parent.id = ConstParentIdNone;
17504 struct_field_array->data.x_array.s_none.elements = create_const_vals(struct_field_count);
17505
17506 init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false);
17507
17508 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {
17509 TypeStructField *struct_field = &type_entry->data.structure.fields[struct_field_index];
17510 ConstExprValue *struct_field_val = &struct_field_array->data.x_array.s_none.elements[struct_field_index];
17511
17512 struct_field_val->special = ConstValSpecialStatic;
17513 struct_field_val->type = type_info_struct_field_type;
17514
17515 ConstExprValue *inner_fields = create_const_vals(3);
17516 inner_fields[1].special = ConstValSpecialStatic;
17517 inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_usize);
17518
17519 if (!type_has_bits(struct_field->type_entry)) {
17520 inner_fields[1].data.x_optional = nullptr;
17521 } else {
17522 size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
17523 inner_fields[1].data.x_optional = create_const_vals(1);
17524 inner_fields[1].data.x_optional->special = ConstValSpecialStatic;
17525 inner_fields[1].data.x_optional->type = ira->codegen->builtin_types.entry_usize;
17526 bigint_init_unsigned(&inner_fields[1].data.x_optional->data.x_bigint, byte_offset);
17527 }
17528
17529 inner_fields[2].special = ConstValSpecialStatic;
17530 inner_fields[2].type = ira->codegen->builtin_types.entry_type;
17531 inner_fields[2].data.x_type = struct_field->type_entry;
17532
17533 ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name);
17534 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true);
17535
17536 struct_field_val->data.x_struct.fields = inner_fields;
17537 struct_field_val->data.x_struct.parent.id = ConstParentIdArray;
17538 struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array;
17539 struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index;
17540 }
17541 // defs: []TypeInfo.Definition
17542 ensure_field_index(result->type, "defs", 2);
17543 if (!ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope))
17544 return nullptr;
17545
17546 break;
17547 }
17548 case TypeTableEntryIdFn:
17549 {
17550 result = create_const_vals(1);
17551 result->special = ConstValSpecialStatic;
17552 result->type = ir_type_info_get_type(ira, "Fn");
17553
17554 ConstExprValue *fields = create_const_vals(6);
17555 result->data.x_struct.fields = fields;
17556
17557 // calling_convention: TypeInfo.CallingConvention
17558 ensure_field_index(result->type, "calling_convention", 0);
17559 fields[0].special = ConstValSpecialStatic;
17560 fields[0].type = ir_type_info_get_type(ira, "CallingConvention");
17561 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.fn.fn_type_id.cc);
17562 // is_generic: bool
17563 ensure_field_index(result->type, "is_generic", 1);
17564 bool is_generic = type_entry->data.fn.is_generic;
17565 fields[1].special = ConstValSpecialStatic;
17566 fields[1].type = ira->codegen->builtin_types.entry_bool;
17567 fields[1].data.x_bool = is_generic;
17568 // is_varargs: bool
17569 ensure_field_index(result->type, "is_var_args", 2);
17570 bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args;
17571 fields[2].special = ConstValSpecialStatic;
17572 fields[2].type = ira->codegen->builtin_types.entry_bool;
17573 fields[2].data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;
17574 // return_type: ?type
17575 ensure_field_index(result->type, "return_type", 3);
17576 fields[3].special = ConstValSpecialStatic;
17577 fields[3].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
17578 if (type_entry->data.fn.fn_type_id.return_type == nullptr)
17579 fields[3].data.x_optional = nullptr;
17580 else {
17581 ConstExprValue *return_type = create_const_vals(1);
17582 return_type->special = ConstValSpecialStatic;
17583 return_type->type = ira->codegen->builtin_types.entry_type;
17584 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
17585 fields[3].data.x_optional = return_type;
17586 }
17587 // async_allocator_type: type
17588 ensure_field_index(result->type, "async_allocator_type", 4);
17589 fields[4].special = ConstValSpecialStatic;
17590 fields[4].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
17591 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)
17592 fields[4].data.x_optional = nullptr;
17593 else {
17594 ConstExprValue *async_alloc_type = create_const_vals(1);
17595 async_alloc_type->special = ConstValSpecialStatic;
17596 async_alloc_type->type = ira->codegen->builtin_types.entry_type;
17597 async_alloc_type->data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;
17598 fields[4].data.x_optional = async_alloc_type;
17599 }
17600 // args: []TypeInfo.FnArg
17601 TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg");
17602 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -
17603 (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC);
17604
17605 ConstExprValue *fn_arg_array = create_const_vals(1);
17606 fn_arg_array->special = ConstValSpecialStatic;
17607 fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
17608 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
17609 fn_arg_array->data.x_array.s_none.parent.id = ConstParentIdNone;
17610 fn_arg_array->data.x_array.s_none.elements = create_const_vals(fn_arg_count);
17611
17612 init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false);
17613
17614 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
17615 {
17616 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
17617 ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.s_none.elements[fn_arg_index];
17618
17619 fn_arg_val->special = ConstValSpecialStatic;
17620 fn_arg_val->type = type_info_fn_arg_type;
17621
17622 bool arg_is_generic = fn_param_info->type == nullptr;
17623 if (arg_is_generic) assert(is_generic);
17624
17625 ConstExprValue *inner_fields = create_const_vals(3);
17626 inner_fields[0].special = ConstValSpecialStatic;
17627 inner_fields[0].type = ira->codegen->builtin_types.entry_bool;
17628 inner_fields[0].data.x_bool = arg_is_generic;
17629 inner_fields[1].special = ConstValSpecialStatic;
17630 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;
17631 inner_fields[1].data.x_bool = fn_param_info->is_noalias;
17632 inner_fields[2].special = ConstValSpecialStatic;
17633 inner_fields[2].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
17634
17635 if (arg_is_generic)
17636 inner_fields[2].data.x_optional = nullptr;
17637 else {
17638 ConstExprValue *arg_type = create_const_vals(1);
17639 arg_type->special = ConstValSpecialStatic;
17640 arg_type->type = ira->codegen->builtin_types.entry_type;
17641 arg_type->data.x_type = fn_param_info->type;
17642 inner_fields[2].data.x_optional = arg_type;
17643 }
17644
17645 fn_arg_val->data.x_struct.fields = inner_fields;
17646 fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
17647 fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array;
17648 fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
17649 }
17650
17651 break;
17652 }
17653 case TypeTableEntryIdBoundFn:
17654 {
17655 TypeTableEntry *fn_type = type_entry->data.bound_fn.fn_type;
17656 assert(fn_type->id == TypeTableEntryIdFn);
17657 result = ir_make_type_info_value(ira, fn_type);
17658
17659 break;
17660 }
17661 }
17662
17663 assert(result != nullptr);
17664 ira->codegen->type_info_cache.put(type_entry, result);
17665 return result;
17666}
17667
17668static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,
17669 IrInstructionTypeInfo *instruction)
17670{
17671 IrInstruction *type_value = instruction->type_value->other;
17672 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
17673 if (type_is_invalid(type_entry))
17674 return ira->codegen->builtin_types.entry_invalid;
17675
17676 TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr);
17677
17678 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17679 out_val->type = result_type;
17680 bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry));
17681
17682 ConstExprValue *payload = ir_make_type_info_value(ira, type_entry);
17683 out_val->data.x_union.payload = payload;
17684
17685 if (payload != nullptr)
17686 {
17687 assert(payload->type->id == TypeTableEntryIdStruct);
17688 payload->data.x_struct.parent.id = ConstParentIdUnion;
17689 payload->data.x_struct.parent.data.p_union.union_val = out_val;
17690 }
17691
17692 return result_type;
17693}
17694
17695static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
17696 IrInstructionTypeId *instruction)
17697{
17698 IrInstruction *type_value = instruction->type_value->other;
17699 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
17700 if (type_is_invalid(type_entry))
17701 return ira->codegen->builtin_types.entry_invalid;
17702
17703 ConstExprValue *var_value = get_builtin_value(ira->codegen, "TypeId");
17704 assert(var_value->type->id == TypeTableEntryIdMetaType);
17705 TypeTableEntry *result_type = var_value->data.x_type;
17706
17707 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17708 bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry));
17709 return result_type;
17710}
17711
17712static TypeTableEntry *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira,
17713 IrInstructionSetEvalBranchQuota *instruction)
17714{
17715 if (ira->new_irb.exec->parent_exec != nullptr && !ira->new_irb.exec->is_generic_instantiation) {
17716 ir_add_error(ira, &instruction->base,
17717 buf_sprintf("@setEvalBranchQuota must be called from the top of the comptime stack"));
17718 return ira->codegen->builtin_types.entry_invalid;
17719 }
17720
17721 uint64_t new_quota;
17722 if (!ir_resolve_usize(ira, instruction->new_quota->other, &new_quota))
17723 return ira->codegen->builtin_types.entry_invalid;
17724
17725 if (new_quota > ira->new_irb.exec->backward_branch_quota) {
17726 ira->new_irb.exec->backward_branch_quota = new_quota;
17727 }
17728
17729 ir_build_const_from(ira, &instruction->base);
17730 return ira->codegen->builtin_types.entry_void;
17731}
17732
17733static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
17734 IrInstruction *type_value = instruction->type_value->other;
17735 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
17736 if (type_is_invalid(type_entry))
17737 return ira->codegen->builtin_types.entry_invalid;
17738
17739 if (!type_entry->cached_const_name_val) {
17740 type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, &type_entry->name);
17741 }
17742 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17743 copy_const_val(out_val, type_entry->cached_const_name_val, true);
17744 return out_val->type;
17745}
17746
17747static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
17748 AstNode *node = instruction->base.source_node;
17749 assert(node->type == NodeTypeFnCallExpr);
17750 AstNode *block_node = node->data.fn_call_expr.params.at(0);
17751
17752 ScopeCImport *cimport_scope = create_cimport_scope(node, instruction->base.scope);
17753
17754 // Execute the C import block like an inline function
17755 TypeTableEntry *void_type = ira->codegen->builtin_types.entry_void;
17756 IrInstruction *result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
17757 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
17758 &cimport_scope->buf, block_node, nullptr, nullptr);
17759 if (type_is_invalid(result->value.type))
17760 return ira->codegen->builtin_types.entry_invalid;
17761
17762 find_libc_include_path(ira->codegen);
17763
17764 ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
17765 child_import->decls_scope = create_decls_scope(node, nullptr, nullptr, child_import);
17766 child_import->c_import_node = node;
17767 child_import->package = new_anonymous_package();
17768 child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);
17769 child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
17770 child_import->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,
17771 buf_ptr(buf_create_from_str("cimport.h")), buf_ptr(buf_create_from_str(".")));
17772
17773 ZigList<ErrorMsg *> errors = {0};
17774
17775 int err;
17776 if ((err = parse_h_buf(child_import, &errors, &cimport_scope->buf, ira->codegen, node))) {
17777 if (err != ErrorCCompileErrors) {
17778 ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err)));
17779 return ira->codegen->builtin_types.entry_invalid;
17780 }
17781 }
17782
17783 if (errors.length > 0) {
17784 ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed"));
17785 for (size_t i = 0; i < errors.length; i += 1) {
17786 ErrorMsg *err_msg = errors.at(i);
17787 err_msg_add_note(parent_err_msg, err_msg);
17788 }
17789
17790 return ira->codegen->builtin_types.entry_invalid;
17791 }
17792
17793 if (ira->codegen->verbose_cimport) {
17794 fprintf(stderr, "\nC imports:\n");
17795 fprintf(stderr, "-----------\n");
17796 ast_render(ira->codegen, stderr, child_import->root, 4);
17797 }
17798
17799 scan_decls(ira->codegen, child_import->decls_scope, child_import->root);
17800
17801 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17802 out_val->data.x_import = child_import;
17803 return ira->codegen->builtin_types.entry_namespace;
17804}
17805
17806static TypeTableEntry *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {
17807 IrInstruction *name_value = instruction->name->other;
17808 if (type_is_invalid(name_value->value.type))
17809 return ira->codegen->builtin_types.entry_invalid;
17810
17811 Buf *include_name = ir_resolve_str(ira, name_value);
17812 if (!include_name)
17813 return ira->codegen->builtin_types.entry_invalid;
17814
17815 Buf *c_import_buf = exec_c_import_buf(ira->new_irb.exec);
17816 // We check for this error in pass1
17817 assert(c_import_buf);
17818
17819 buf_appendf(c_import_buf, "#include <%s>\n", buf_ptr(include_name));
1557117820
1557217821 ir_build_const_from(ira, &instruction->base);
1557317822 return ira->codegen->builtin_types.entry_void;
......@@ -15659,10 +17908,20 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
1565917908}
1566017909
1566117910static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
17911 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->other);
17912 if (type_is_invalid(operand_type))
17913 return ira->codegen->builtin_types.entry_invalid;
17914
1566217915 IrInstruction *ptr = instruction->ptr->other;
1566317916 if (type_is_invalid(ptr->value.type))
1566417917 return ira->codegen->builtin_types.entry_invalid;
1566517918
17919 // TODO let this be volatile
17920 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
17921 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type);
17922 if (type_is_invalid(casted_ptr->value.type))
17923 return ira->codegen->builtin_types.entry_invalid;
17924
1566617925 IrInstruction *cmp_value = instruction->cmp_value->other;
1566717926 if (type_is_invalid(cmp_value->value.type))
1566817927 return ira->codegen->builtin_types.entry_invalid;
......@@ -15687,28 +17946,11 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1568717946 if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order))
1568817947 return ira->codegen->builtin_types.entry_invalid;
1568917948
15690 if (ptr->value.type->id != TypeTableEntryIdPointer) {
15691 ir_add_error(ira, instruction->ptr,
15692 buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->value.type->name)));
15693 return ira->codegen->builtin_types.entry_invalid;
15694 }
15695
15696 TypeTableEntry *child_type = ptr->value.type->data.pointer.child_type;
15697
15698 uint32_t align_bytes = ptr->value.type->data.pointer.alignment;
15699 uint64_t size_bytes = type_size(ira->codegen, child_type);
15700 if (align_bytes < size_bytes) {
15701 ir_add_error(ira, instruction->ptr,
15702 buf_sprintf("expected pointer alignment of at least %" ZIG_PRI_u64 ", found %" PRIu32,
15703 size_bytes, align_bytes));
15704 return ira->codegen->builtin_types.entry_invalid;
15705 }
15706
15707 IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, child_type);
17949 IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, operand_type);
1570817950 if (type_is_invalid(casted_cmp_value->value.type))
1570917951 return ira->codegen->builtin_types.entry_invalid;
1571017952
15711 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, child_type);
17953 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, operand_type);
1571217954 if (type_is_invalid(casted_new_value->value.type))
1571317955 return ira->codegen->builtin_types.entry_invalid;
1571417956
......@@ -15733,9 +17975,17 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1573317975 return ira->codegen->builtin_types.entry_invalid;
1573417976 }
1573517977
15736 ir_build_cmpxchg_from(&ira->new_irb, &instruction->base, ptr, casted_cmp_value, casted_new_value,
15737 success_order_value, failure_order_value, success_order, failure_order);
15738 return ira->codegen->builtin_types.entry_bool;
17978 if (instr_is_comptime(casted_ptr) && instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
17979 zig_panic("TODO compile-time execution of cmpxchg");
17980 }
17981
17982 IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
17983 nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
17984 operand_type, success_order, failure_order);
17985 result->value.type = get_optional_type(ira->codegen, operand_type);
17986 ir_link_new_instruction(result, &instruction->base);
17987 ir_add_alloca(ira, result, result->value.type);
17988 return result->value.type;
1573917989}
1574017990
1574117991static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {
......@@ -15747,54 +17997,370 @@ static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructio
1574717997 if (!ir_resolve_atomic_order(ira, order_value, &order))
1574817998 return ira->codegen->builtin_types.entry_invalid;
1574917999
15750 ir_build_fence_from(&ira->new_irb, &instruction->base, order_value, order);
15751 return ira->codegen->builtin_types.entry_void;
18000 ir_build_fence_from(&ira->new_irb, &instruction->base, order_value, order);
18001 return ira->codegen->builtin_types.entry_void;
18002}
18003
18004static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) {
18005 IrInstruction *dest_type_value = instruction->dest_type->other;
18006 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
18007 if (type_is_invalid(dest_type))
18008 return ira->codegen->builtin_types.entry_invalid;
18009
18010 if (dest_type->id != TypeTableEntryIdInt &&
18011 dest_type->id != TypeTableEntryIdComptimeInt)
18012 {
18013 ir_add_error(ira, dest_type_value, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
18014 return ira->codegen->builtin_types.entry_invalid;
18015 }
18016
18017 IrInstruction *target = instruction->target->other;
18018 TypeTableEntry *src_type = target->value.type;
18019 if (type_is_invalid(src_type))
18020 return ira->codegen->builtin_types.entry_invalid;
18021
18022 if (src_type->id != TypeTableEntryIdInt &&
18023 src_type->id != TypeTableEntryIdComptimeInt)
18024 {
18025 ir_add_error(ira, target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_type->name)));
18026 return ira->codegen->builtin_types.entry_invalid;
18027 }
18028
18029 if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
18030 const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
18031 ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
18032 return ira->codegen->builtin_types.entry_invalid;
18033 } else if (src_type->data.integral.bit_count < dest_type->data.integral.bit_count) {
18034 ir_add_error(ira, target, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
18035 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
18036 return ira->codegen->builtin_types.entry_invalid;
18037 }
18038
18039 if (target->value.special == ConstValSpecialStatic) {
18040 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
18041 bigint_truncate(&out_val->data.x_bigint, &target->value.data.x_bigint, dest_type->data.integral.bit_count,
18042 dest_type->data.integral.is_signed);
18043 return dest_type;
18044 }
18045
18046 IrInstruction *new_instruction = ir_build_truncate(&ira->new_irb, instruction->base.scope,
18047 instruction->base.source_node, dest_type_value, target);
18048 ir_link_new_instruction(new_instruction, &instruction->base);
18049 return dest_type;
18050}
18051
18052static TypeTableEntry *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstructionIntCast *instruction) {
18053 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
18054 if (type_is_invalid(dest_type))
18055 return ira->codegen->builtin_types.entry_invalid;
18056
18057 if (dest_type->id != TypeTableEntryIdInt) {
18058 ir_add_error(ira, instruction->dest_type, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
18059 return ira->codegen->builtin_types.entry_invalid;
18060 }
18061
18062 IrInstruction *target = instruction->target->other;
18063 if (type_is_invalid(target->value.type))
18064 return ira->codegen->builtin_types.entry_invalid;
18065
18066 if (target->value.type->id == TypeTableEntryIdComptimeInt) {
18067 if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) {
18068 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_type,
18069 CastOpNumLitToConcrete, false);
18070 if (type_is_invalid(result->value.type))
18071 return ira->codegen->builtin_types.entry_invalid;
18072 ir_link_new_instruction(result, &instruction->base);
18073 return dest_type;
18074 } else {
18075 return ira->codegen->builtin_types.entry_invalid;
18076 }
18077 }
18078
18079 if (target->value.type->id != TypeTableEntryIdInt) {
18080 ir_add_error(ira, instruction->target, buf_sprintf("expected integer type, found '%s'",
18081 buf_ptr(&target->value.type->name)));
18082 return ira->codegen->builtin_types.entry_invalid;
18083 }
18084
18085 IrInstruction *result = ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type);
18086 if (type_is_invalid(result->value.type))
18087 return ira->codegen->builtin_types.entry_invalid;
18088
18089 ir_link_new_instruction(result, &instruction->base);
18090 return dest_type;
18091}
18092
18093static TypeTableEntry *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstructionFloatCast *instruction) {
18094 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
18095 if (type_is_invalid(dest_type))
18096 return ira->codegen->builtin_types.entry_invalid;
18097
18098 if (dest_type->id != TypeTableEntryIdFloat) {
18099 ir_add_error(ira, instruction->dest_type,
18100 buf_sprintf("expected float type, found '%s'", buf_ptr(&dest_type->name)));
18101 return ira->codegen->builtin_types.entry_invalid;
18102 }
18103
18104 IrInstruction *target = instruction->target->other;
18105 if (type_is_invalid(target->value.type))
18106 return ira->codegen->builtin_types.entry_invalid;
18107
18108 if (target->value.type->id == TypeTableEntryIdComptimeInt ||
18109 target->value.type->id == TypeTableEntryIdComptimeFloat)
18110 {
18111 if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) {
18112 CastOp op;
18113 if (target->value.type->id == TypeTableEntryIdComptimeInt) {
18114 op = CastOpIntToFloat;
18115 } else {
18116 op = CastOpNumLitToConcrete;
18117 }
18118 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_type, op, false);
18119 if (type_is_invalid(result->value.type))
18120 return ira->codegen->builtin_types.entry_invalid;
18121 ir_link_new_instruction(result, &instruction->base);
18122 return dest_type;
18123 } else {
18124 return ira->codegen->builtin_types.entry_invalid;
18125 }
18126 }
18127
18128 if (target->value.type->id != TypeTableEntryIdFloat) {
18129 ir_add_error(ira, instruction->target, buf_sprintf("expected float type, found '%s'",
18130 buf_ptr(&target->value.type->name)));
18131 return ira->codegen->builtin_types.entry_invalid;
18132 }
18133
18134 IrInstruction *result = ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type);
18135 if (type_is_invalid(result->value.type))
18136 return ira->codegen->builtin_types.entry_invalid;
18137 ir_link_new_instruction(result, &instruction->base);
18138 return dest_type;
18139}
18140
18141static TypeTableEntry *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) {
18142 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
18143 if (type_is_invalid(dest_type))
18144 return ira->codegen->builtin_types.entry_invalid;
18145
18146 if (dest_type->id != TypeTableEntryIdErrorSet) {
18147 ir_add_error(ira, instruction->dest_type,
18148 buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name)));
18149 return ira->codegen->builtin_types.entry_invalid;
18150 }
18151
18152 IrInstruction *target = instruction->target->other;
18153 if (type_is_invalid(target->value.type))
18154 return ira->codegen->builtin_types.entry_invalid;
18155
18156 if (target->value.type->id != TypeTableEntryIdErrorSet) {
18157 ir_add_error(ira, instruction->target,
18158 buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value.type->name)));
18159 return ira->codegen->builtin_types.entry_invalid;
18160 }
18161
18162 IrInstruction *result = ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type);
18163 if (type_is_invalid(result->value.type))
18164 return ira->codegen->builtin_types.entry_invalid;
18165 ir_link_new_instruction(result, &instruction->base);
18166 return dest_type;
18167}
18168
18169static TypeTableEntry *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
18170 TypeTableEntry *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->other);
18171 if (type_is_invalid(dest_child_type))
18172 return ira->codegen->builtin_types.entry_invalid;
18173
18174 IrInstruction *target = instruction->target->other;
18175 if (type_is_invalid(target->value.type))
18176 return ira->codegen->builtin_types.entry_invalid;
18177
18178 bool src_ptr_const;
18179 bool src_ptr_volatile;
18180 uint32_t src_ptr_align;
18181 if (target->value.type->id == TypeTableEntryIdPointer) {
18182 src_ptr_const = target->value.type->data.pointer.is_const;
18183 src_ptr_volatile = target->value.type->data.pointer.is_volatile;
18184 src_ptr_align = target->value.type->data.pointer.alignment;
18185 } else if (is_slice(target->value.type)) {
18186 TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
18187 src_ptr_const = src_ptr_type->data.pointer.is_const;
18188 src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
18189 src_ptr_align = src_ptr_type->data.pointer.alignment;
18190 } else {
18191 src_ptr_const = true;
18192 src_ptr_volatile = false;
18193 src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
18194 }
18195
18196 TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
18197 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
18198 src_ptr_align, 0, 0);
18199 TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
18200
18201 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
18202 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
18203 src_ptr_align, 0, 0);
18204 TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
18205
18206 IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
18207 if (type_is_invalid(casted_value->value.type))
18208 return ira->codegen->builtin_types.entry_invalid;
18209
18210 bool have_known_len = false;
18211 uint64_t known_len;
18212
18213 if (instr_is_comptime(casted_value)) {
18214 ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
18215 if (!val)
18216 return ira->codegen->builtin_types.entry_invalid;
18217
18218 ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index];
18219 if (value_is_comptime(len_val)) {
18220 known_len = bigint_as_unsigned(&len_val->data.x_bigint);
18221 have_known_len = true;
18222 }
18223 }
18224
18225 if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) {
18226 known_len = casted_value->value.data.rh_slice.len;
18227 have_known_len = true;
18228 }
18229
18230 if (have_known_len) {
18231 uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
18232 uint64_t remainder = known_len % child_type_size;
18233 if (remainder != 0) {
18234 ErrorMsg *msg = ir_add_error(ira, &instruction->base,
18235 buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch",
18236 known_len, buf_ptr(&dest_slice_type->name)));
18237 add_error_note(ira->codegen, msg, instruction->dest_child_type->source_node,
18238 buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64,
18239 buf_ptr(&dest_child_type->name), child_type_size, remainder));
18240 return ira->codegen->builtin_types.entry_invalid;
18241 }
18242 }
18243
18244 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
18245 ir_link_new_instruction(result, &instruction->base);
18246 return dest_slice_type;
18247}
18248
18249static TypeTableEntry *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
18250 IrInstruction *target = instruction->target->other;
18251 if (type_is_invalid(target->value.type))
18252 return ira->codegen->builtin_types.entry_invalid;
18253
18254 if (!is_slice(target->value.type)) {
18255 ir_add_error(ira, instruction->target,
18256 buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name)));
18257 return ira->codegen->builtin_types.entry_invalid;
18258 }
18259
18260 TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
18261
18262 TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
18263 src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
18264 src_ptr_type->data.pointer.alignment, 0, 0);
18265 TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
18266
18267 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
18268 ir_link_new_instruction(result, &instruction->base);
18269 return dest_slice_type;
18270}
18271
18272static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
18273 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
18274 if (type_is_invalid(dest_type))
18275 return ira->codegen->builtin_types.entry_invalid;
18276
18277 IrInstruction *target = instruction->target->other;
18278 if (type_is_invalid(target->value.type))
18279 return ira->codegen->builtin_types.entry_invalid;
18280
18281 if (target->value.type->id != TypeTableEntryIdInt && target->value.type->id != TypeTableEntryIdComptimeInt) {
18282 ir_add_error(ira, instruction->target, buf_sprintf("expected int type, found '%s'",
18283 buf_ptr(&target->value.type->name)));
18284 return ira->codegen->builtin_types.entry_invalid;
18285 }
18286
18287 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat, false);
18288 ir_link_new_instruction(result, &instruction->base);
18289 return dest_type;
18290}
18291
18292static TypeTableEntry *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) {
18293 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
18294 if (type_is_invalid(dest_type))
18295 return ira->codegen->builtin_types.entry_invalid;
18296
18297 IrInstruction *target = instruction->target->other;
18298 if (type_is_invalid(target->value.type))
18299 return ira->codegen->builtin_types.entry_invalid;
18300
18301 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpFloatToInt, false);
18302 ir_link_new_instruction(result, &instruction->base);
18303 return dest_type;
18304}
18305
18306static TypeTableEntry *ir_analyze_instruction_err_to_int(IrAnalyze *ira, IrInstructionErrToInt *instruction) {
18307 IrInstruction *target = instruction->target->other;
18308 if (type_is_invalid(target->value.type))
18309 return ira->codegen->builtin_types.entry_invalid;
18310
18311 IrInstruction *casted_target;
18312 if (target->value.type->id == TypeTableEntryIdErrorSet) {
18313 casted_target = target;
18314 } else {
18315 casted_target = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_global_error_set);
18316 if (type_is_invalid(casted_target->value.type))
18317 return ira->codegen->builtin_types.entry_invalid;
18318 }
18319
18320 IrInstruction *result = ir_analyze_err_to_int(ira, &instruction->base, casted_target, ira->codegen->err_tag_type);
18321 ir_link_new_instruction(result, &instruction->base);
18322 return result->value.type;
1575218323}
1575318324
15754static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) {
15755 IrInstruction *dest_type_value = instruction->dest_type->other;
15756 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
15757 if (type_is_invalid(dest_type))
18325static TypeTableEntry *ir_analyze_instruction_int_to_err(IrAnalyze *ira, IrInstructionIntToErr *instruction) {
18326 IrInstruction *target = instruction->target->other;
18327 if (type_is_invalid(target->value.type))
1575818328 return ira->codegen->builtin_types.entry_invalid;
1575918329
15760 if (dest_type->id != TypeTableEntryIdInt &&
15761 dest_type->id != TypeTableEntryIdNumLitInt)
15762 {
15763 ir_add_error(ira, dest_type_value, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
18330 IrInstruction *casted_target = ir_implicit_cast(ira, target, ira->codegen->err_tag_type);
18331 if (type_is_invalid(casted_target->value.type))
1576418332 return ira->codegen->builtin_types.entry_invalid;
15765 }
1576618333
18334 IrInstruction *result = ir_analyze_int_to_err(ira, &instruction->base, casted_target, ira->codegen->builtin_types.entry_global_error_set);
18335 ir_link_new_instruction(result, &instruction->base);
18336 return result->value.type;
18337}
18338
18339static TypeTableEntry *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstructionBoolToInt *instruction) {
1576718340 IrInstruction *target = instruction->target->other;
15768 TypeTableEntry *src_type = target->value.type;
15769 if (type_is_invalid(src_type))
18341 if (type_is_invalid(target->value.type))
1577018342 return ira->codegen->builtin_types.entry_invalid;
1577118343
15772 if (src_type->id != TypeTableEntryIdInt &&
15773 src_type->id != TypeTableEntryIdNumLitInt)
15774 {
15775 ir_add_error(ira, target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_type->name)));
18344 if (target->value.type->id != TypeTableEntryIdBool) {
18345 ir_add_error(ira, instruction->target, buf_sprintf("expected bool, found '%s'",
18346 buf_ptr(&target->value.type->name)));
1577618347 return ira->codegen->builtin_types.entry_invalid;
1577718348 }
1577818349
15779 if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
15780 const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
15781 ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
15782 return ira->codegen->builtin_types.entry_invalid;
15783 } else if (src_type->data.integral.bit_count < dest_type->data.integral.bit_count) {
15784 ir_add_error(ira, target, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
15785 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
15786 return ira->codegen->builtin_types.entry_invalid;
15787 }
18350 if (instr_is_comptime(target)) {
18351 bool is_true;
18352 if (!ir_resolve_bool(ira, target, &is_true))
18353 return ira->codegen->builtin_types.entry_invalid;
1578818354
15789 if (target->value.special == ConstValSpecialStatic) {
1579018355 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15791 bigint_truncate(&out_val->data.x_bigint, &target->value.data.x_bigint, dest_type->data.integral.bit_count,
15792 dest_type->data.integral.is_signed);
15793 return dest_type;
18356 bigint_init_unsigned(&out_val->data.x_bigint, is_true ? 1 : 0);
18357 return ira->codegen->builtin_types.entry_num_lit_int;
1579418358 }
1579518359
15796 ir_build_truncate_from(&ira->new_irb, &instruction->base, dest_type_value, target);
15797 return dest_type;
18360 TypeTableEntry *u1_type = get_int_type(ira->codegen, false, 1);
18361 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, u1_type, CastOpBoolToInt, false);
18362 ir_link_new_instruction(result, &instruction->base);
18363 return u1_type;
1579818364}
1579918365
1580018366static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstructionIntType *instruction) {
......@@ -15805,7 +18371,7 @@ static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruc
1580518371
1580618372 IrInstruction *bit_count_value = instruction->bit_count->other;
1580718373 uint64_t bit_count;
15808 if (!ir_resolve_usize(ira, bit_count_value, &bit_count))
18374 if (!ir_resolve_unsigned(ira, bit_count_value, ira->codegen->builtin_types.entry_u32, &bit_count))
1580918375 return ira->codegen->builtin_types.entry_invalid;
1581018376
1581118377 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
......@@ -15824,9 +18390,13 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
1582418390 if (type_is_invalid(casted_value->value.type))
1582518391 return ira->codegen->builtin_types.entry_invalid;
1582618392
15827 if (casted_value->value.special != ConstValSpecialRuntime) {
18393 if (instr_is_comptime(casted_value)) {
18394 ConstExprValue *value = ir_resolve_const(ira, casted_value, UndefBad);
18395 if (value == nullptr)
18396 return ira->codegen->builtin_types.entry_invalid;
18397
1582818398 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15829 out_val->data.x_bool = !casted_value->value.data.x_bool;
18399 out_val->data.x_bool = !value->data.x_bool;
1583018400 return bool_type;
1583118401 }
1583218402
......@@ -15855,7 +18425,8 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
1585518425 TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
1585618426 uint32_t dest_align = (dest_uncasted_type->id == TypeTableEntryIdPointer) ?
1585718427 dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
15858 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, dest_align, 0, 0);
18428 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
18429 PtrLenUnknown, dest_align, 0, 0);
1585918430
1586018431 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
1586118432 if (type_is_invalid(casted_dest_ptr->value.type))
......@@ -15951,8 +18522,10 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
1595118522 src_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
1595218523
1595318524 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
15954 TypeTableEntry *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, dest_align, 0, 0);
15955 TypeTableEntry *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile, src_align, 0, 0);
18525 TypeTableEntry *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
18526 PtrLenUnknown, dest_align, 0, 0);
18527 TypeTableEntry *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile,
18528 PtrLenUnknown, src_align, 0, 0);
1595618529
1595718530 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
1595818531 if (type_is_invalid(casted_dest_ptr->value.type))
......@@ -16095,18 +18668,38 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1609518668 if (array_type->data.array.len == 0 && byte_alignment == 0) {
1609618669 byte_alignment = get_abi_alignment(ira->codegen, array_type->data.array.child_type);
1609718670 }
18671 bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
18672 ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst;
1609818673 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
16099 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
18674 ptr_type->data.pointer.is_const || is_comptime_const,
18675 ptr_type->data.pointer.is_volatile,
18676 PtrLenUnknown,
1610018677 byte_alignment, 0, 0);
1610118678 return_type = get_slice_type(ira->codegen, slice_ptr_type);
1610218679 } else if (array_type->id == TypeTableEntryIdPointer) {
16103 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
16104 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
16105 array_type->data.pointer.alignment, 0, 0);
16106 return_type = get_slice_type(ira->codegen, slice_ptr_type);
16107 if (!end) {
16108 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
16109 return ira->codegen->builtin_types.entry_invalid;
18680 if (array_type->data.pointer.ptr_len == PtrLenSingle) {
18681 TypeTableEntry *main_type = array_type->data.pointer.child_type;
18682 if (main_type->id == TypeTableEntryIdArray) {
18683 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
18684 main_type->data.pointer.child_type,
18685 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
18686 PtrLenUnknown,
18687 array_type->data.pointer.alignment, 0, 0);
18688 return_type = get_slice_type(ira->codegen, slice_ptr_type);
18689 } else {
18690 ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer"));
18691 return ira->codegen->builtin_types.entry_invalid;
18692 }
18693 } else {
18694 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
18695 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
18696 PtrLenUnknown,
18697 array_type->data.pointer.alignment, 0, 0);
18698 return_type = get_slice_type(ira->codegen, slice_ptr_type);
18699 if (!end) {
18700 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
18701 return ira->codegen->builtin_types.entry_invalid;
18702 }
1611018703 }
1611118704 } else if (is_slice(array_type)) {
1611218705 TypeTableEntry *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
......@@ -16126,12 +18719,24 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1612618719 size_t abs_offset;
1612718720 size_t rel_end;
1612818721 bool ptr_is_undef = false;
16129 if (array_type->id == TypeTableEntryIdArray) {
16130 array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
16131 abs_offset = 0;
16132 rel_end = array_type->data.array.len;
16133 parent_ptr = nullptr;
18722 if (array_type->id == TypeTableEntryIdArray ||
18723 (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
18724 {
18725 if (array_type->id == TypeTableEntryIdPointer) {
18726 TypeTableEntry *child_array_type = array_type->data.pointer.child_type;
18727 assert(child_array_type->id == TypeTableEntryIdArray);
18728 parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
18729 array_val = const_ptr_pointee(ira->codegen, parent_ptr);
18730 rel_end = child_array_type->data.array.len;
18731 abs_offset = 0;
18732 } else {
18733 array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
18734 rel_end = array_type->data.array.len;
18735 parent_ptr = nullptr;
18736 abs_offset = 0;
18737 }
1613418738 } else if (array_type->id == TypeTableEntryIdPointer) {
18739 assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
1613518740 parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
1613618741 if (parent_ptr->special == ConstValSpecialUndef) {
1613718742 array_val = nullptr;
......@@ -16230,7 +18835,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1623018835 if (array_val) {
1623118836 size_t index = abs_offset + start_scalar;
1623218837 bool is_const = slice_is_const(return_type);
16233 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const);
18838 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown);
1623418839 if (array_type->id == TypeTableEntryIdArray) {
1623518840 ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
1623618841 } else if (is_slice(array_type)) {
......@@ -16283,6 +18888,10 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
1628318888 return ira->codegen->builtin_types.entry_invalid;
1628418889 TypeTableEntry *container_type = ir_resolve_type(ira, container);
1628518890
18891 ensure_complete_type(ira->codegen, container_type);
18892 if (type_is_invalid(container_type))
18893 return ira->codegen->builtin_types.entry_invalid;
18894
1628618895 uint64_t result;
1628718896 if (type_is_invalid(container_type)) {
1628818897 return ira->codegen->builtin_types.entry_invalid;
......@@ -16293,7 +18902,7 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
1629318902 } else if (container_type->id == TypeTableEntryIdUnion) {
1629418903 result = container_type->data.unionation.src_field_count;
1629518904 } else if (container_type->id == TypeTableEntryIdErrorSet) {
16296 if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) {
18905 if (!resolve_inferred_error_set(ira->codegen, container_type, instruction->base.source_node)) {
1629718906 return ira->codegen->builtin_types.entry_invalid;
1629818907 }
1629918908 if (type_is_global_error_set(container_type)) {
......@@ -16317,6 +18926,11 @@ static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInst
1631718926 if (type_is_invalid(container_type))
1631818927 return ira->codegen->builtin_types.entry_invalid;
1631918928
18929 ensure_complete_type(ira->codegen, container_type);
18930 if (type_is_invalid(container_type))
18931 return ira->codegen->builtin_types.entry_invalid;
18932
18933
1632018934 uint64_t member_index;
1632118935 IrInstruction *index_value = instruction->member_index->other;
1632218936 if (!ir_resolve_usize(ira, index_value, &member_index))
......@@ -16359,6 +18973,10 @@ static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInst
1635918973 if (type_is_invalid(container_type))
1636018974 return ira->codegen->builtin_types.entry_invalid;
1636118975
18976 ensure_complete_type(ira->codegen, container_type);
18977 if (type_is_invalid(container_type))
18978 return ira->codegen->builtin_types.entry_invalid;
18979
1636218980 uint64_t member_index;
1636318981 IrInstruction *index_value = instruction->member_index->other;
1636418982 if (!ir_resolve_usize(ira, index_value, &member_index))
......@@ -16428,6 +19046,14 @@ static TypeTableEntry *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIn
1642819046 return u8_ptr_const;
1642919047}
1643019048
19049static TypeTableEntry *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructionHandle *instruction) {
19050 ir_build_handle_from(&ira->new_irb, &instruction->base);
19051
19052 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
19053 assert(fn_entry != nullptr);
19054 return get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);
19055}
19056
1643119057static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
1643219058 IrInstruction *type_value = instruction->type_value->other;
1643319059 if (type_is_invalid(type_value->value.type))
......@@ -16443,10 +19069,10 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1644319069 zig_unreachable();
1644419070 case TypeTableEntryIdMetaType:
1644519071 case TypeTableEntryIdUnreachable:
16446 case TypeTableEntryIdNumLitFloat:
16447 case TypeTableEntryIdNumLitInt:
16448 case TypeTableEntryIdUndefLit:
16449 case TypeTableEntryIdNullLit:
19072 case TypeTableEntryIdComptimeFloat:
19073 case TypeTableEntryIdComptimeInt:
19074 case TypeTableEntryIdUndefined:
19075 case TypeTableEntryIdNull:
1645019076 case TypeTableEntryIdNamespace:
1645119077 case TypeTableEntryIdBlock:
1645219078 case TypeTableEntryIdBoundFn:
......@@ -16463,7 +19089,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1646319089 case TypeTableEntryIdPromise:
1646419090 case TypeTableEntryIdArray:
1646519091 case TypeTableEntryIdStruct:
16466 case TypeTableEntryIdMaybe:
19092 case TypeTableEntryIdOptional:
1646719093 case TypeTableEntryIdErrorUnion:
1646819094 case TypeTableEntryIdErrorSet:
1646919095 case TypeTableEntryIdEnum:
......@@ -16525,6 +19151,7 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
1652519151 if (result_ptr->value.type->id == TypeTableEntryIdPointer) {
1652619152 expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type,
1652719153 false, result_ptr->value.type->data.pointer.is_volatile,
19154 PtrLenSingle,
1652819155 result_ptr->value.type->data.pointer.alignment, 0, 0);
1652919156 } else {
1653019157 expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false);
......@@ -16597,7 +19224,7 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
1659719224 }
1659819225
1659919226 TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
16600 if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) {
19227 if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) {
1660119228 return ira->codegen->builtin_types.entry_invalid;
1660219229 }
1660319230 if (!type_is_global_error_set(err_set_type) &&
......@@ -16678,8 +19305,12 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
1667819305 return ira->codegen->builtin_types.entry_invalid;
1667919306 } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
1668019307 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
19308 if (type_is_invalid(payload_type)) {
19309 return ira->codegen->builtin_types.entry_invalid;
19310 }
1668119311 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
1668219312 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
19313 PtrLenSingle,
1668319314 get_abi_alignment(ira->codegen, payload_type), 0, 0);
1668419315 if (instr_is_comptime(value)) {
1668519316 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
......@@ -16769,6 +19400,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
1676919400 fn_type_id.return_type = ir_resolve_type(ira, return_type_value);
1677019401 if (type_is_invalid(fn_type_id.return_type))
1677119402 return ira->codegen->builtin_types.entry_invalid;
19403 if (fn_type_id.return_type->id == TypeTableEntryIdOpaque) {
19404 ir_add_error(ira, instruction->return_type,
19405 buf_sprintf("return type cannot be opaque"));
19406 return ira->codegen->builtin_types.entry_invalid;
19407 }
1677219408
1677319409 if (fn_type_id.cc == CallingConventionAsync) {
1677419410 if (instruction->async_allocator_type_value == nullptr) {
......@@ -16820,7 +19456,11 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1682019456 if (type_is_invalid(end_value->value.type))
1682119457 return ira->codegen->builtin_types.entry_invalid;
1682219458
16823 assert(start_value->value.type->id == TypeTableEntryIdEnum);
19459 if (start_value->value.type->id != TypeTableEntryIdEnum) {
19460 ir_add_error(ira, range->start, buf_sprintf("not an enum type"));
19461 return ira->codegen->builtin_types.entry_invalid;
19462 }
19463
1682419464 BigInt start_index;
1682519465 bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
1682619466
......@@ -16861,7 +19501,7 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1686119501 }
1686219502 }
1686319503 } else if (switch_type->id == TypeTableEntryIdErrorSet) {
16864 if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) {
19504 if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->source_node)) {
1686519505 return ira->codegen->builtin_types.entry_invalid;
1686619506 }
1686719507
......@@ -16925,21 +19565,27 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1692519565 IrInstruction *start_value = range->start->other;
1692619566 if (type_is_invalid(start_value->value.type))
1692719567 return ira->codegen->builtin_types.entry_invalid;
19568 IrInstruction *casted_start_value = ir_implicit_cast(ira, start_value, switch_type);
19569 if (type_is_invalid(casted_start_value->value.type))
19570 return ira->codegen->builtin_types.entry_invalid;
1692819571
1692919572 IrInstruction *end_value = range->end->other;
1693019573 if (type_is_invalid(end_value->value.type))
1693119574 return ira->codegen->builtin_types.entry_invalid;
19575 IrInstruction *casted_end_value = ir_implicit_cast(ira, end_value, switch_type);
19576 if (type_is_invalid(casted_end_value->value.type))
19577 return ira->codegen->builtin_types.entry_invalid;
1693219578
16933 ConstExprValue *start_val = ir_resolve_const(ira, start_value, UndefBad);
19579 ConstExprValue *start_val = ir_resolve_const(ira, casted_start_value, UndefBad);
1693419580 if (!start_val)
1693519581 return ira->codegen->builtin_types.entry_invalid;
1693619582
16937 ConstExprValue *end_val = ir_resolve_const(ira, end_value, UndefBad);
19583 ConstExprValue *end_val = ir_resolve_const(ira, casted_end_value, UndefBad);
1693819584 if (!end_val)
1693919585 return ira->codegen->builtin_types.entry_invalid;
1694019586
16941 assert(start_val->type->id == TypeTableEntryIdInt || start_val->type->id == TypeTableEntryIdNumLitInt);
16942 assert(end_val->type->id == TypeTableEntryIdInt || end_val->type->id == TypeTableEntryIdNumLitInt);
19587 assert(start_val->type->id == TypeTableEntryIdInt || start_val->type->id == TypeTableEntryIdComptimeInt);
19588 assert(end_val->type->id == TypeTableEntryIdInt || end_val->type->id == TypeTableEntryIdComptimeInt);
1694319589 AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint,
1694419590 start_value->source_node);
1694519591 if (prev_node != nullptr) {
......@@ -16983,30 +19629,6 @@ static TypeTableEntry *ir_analyze_instruction_check_statement_is_void(IrAnalyze
1698319629 return ira->codegen->builtin_types.entry_void;
1698419630}
1698519631
16986static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
16987 IrInstructionCanImplicitCast *instruction)
16988{
16989 IrInstruction *type_value = instruction->type_value->other;
16990 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
16991 if (type_is_invalid(type_entry))
16992 return ira->codegen->builtin_types.entry_invalid;
16993
16994 IrInstruction *target_value = instruction->target_value->other;
16995 if (type_is_invalid(target_value->value.type))
16996 return ira->codegen->builtin_types.entry_invalid;
16997
16998 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, type_entry, target_value->value.type,
16999 target_value);
17000
17001 if (result == ImplicitCastMatchResultReportedError) {
17002 zig_panic("TODO refactor implicit cast tester to return bool without reporting errors");
17003 }
17004
17005 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17006 out_val->data.x_bool = (result == ImplicitCastMatchResultYes);
17007 return ira->codegen->builtin_types.entry_bool;
17008}
17009
1701019632static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {
1701119633 IrInstruction *msg = instruction->msg->other;
1701219634 if (type_is_invalid(msg->value.type))
......@@ -17017,7 +19639,8 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio
1701719639 return ir_unreach_error(ira);
1701819640 }
1701919641
17020 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
19642 TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
19643 true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
1702119644 TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
1702219645 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
1702319646 if (type_is_invalid(casted_msg->value.type))
......@@ -17044,22 +19667,22 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1704419667 old_align_bytes = fn_type_id.alignment;
1704519668 fn_type_id.alignment = align_bytes;
1704619669 result_type = get_fn_type(ira->codegen, &fn_type_id);
17047 } else if (target_type->id == TypeTableEntryIdMaybe &&
19670 } else if (target_type->id == TypeTableEntryIdOptional &&
1704819671 target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
1704919672 {
1705019673 TypeTableEntry *ptr_type = target_type->data.maybe.child_type;
1705119674 old_align_bytes = ptr_type->data.pointer.alignment;
1705219675 TypeTableEntry *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes);
1705319676
17054 result_type = get_maybe_type(ira->codegen, better_ptr_type);
17055 } else if (target_type->id == TypeTableEntryIdMaybe &&
19677 result_type = get_optional_type(ira->codegen, better_ptr_type);
19678 } else if (target_type->id == TypeTableEntryIdOptional &&
1705619679 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
1705719680 {
1705819681 FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id;
1705919682 old_align_bytes = fn_type_id.alignment;
1706019683 fn_type_id.alignment = align_bytes;
1706119684 TypeTableEntry *fn_type = get_fn_type(ira->codegen, &fn_type_id);
17062 result_type = get_maybe_type(ira->codegen, fn_type);
19685 result_type = get_optional_type(ira->codegen, fn_type);
1706319686 } else if (is_slice(target_type)) {
1706419687 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
1706519688 old_align_bytes = slice_ptr_type->data.pointer.alignment;
......@@ -17076,6 +19699,15 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1707619699 if (!val)
1707719700 return ira->codegen->invalid_instruction;
1707819701
19702 if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
19703 val->data.x_ptr.data.hard_coded_addr.addr % align_bytes != 0)
19704 {
19705 ir_add_error(ira, target,
19706 buf_sprintf("pointer address 0x%" ZIG_PRI_x64 " is not aligned to %" PRIu32 " bytes",
19707 val->data.x_ptr.data.hard_coded_addr.addr, align_bytes));
19708 return ira->codegen->invalid_instruction;
19709 }
19710
1707919711 IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
1708019712 copy_const_val(&result->value, val, false);
1708119713 result->value.type = result_type;
......@@ -17170,10 +19802,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1717019802 case TypeTableEntryIdNamespace:
1717119803 case TypeTableEntryIdBlock:
1717219804 case TypeTableEntryIdUnreachable:
17173 case TypeTableEntryIdNumLitFloat:
17174 case TypeTableEntryIdNumLitInt:
17175 case TypeTableEntryIdUndefLit:
17176 case TypeTableEntryIdNullLit:
19805 case TypeTableEntryIdComptimeFloat:
19806 case TypeTableEntryIdComptimeInt:
19807 case TypeTableEntryIdUndefined:
19808 case TypeTableEntryIdNull:
1717719809 case TypeTableEntryIdPromise:
1717819810 zig_unreachable();
1717919811 case TypeTableEntryIdVoid:
......@@ -17210,7 +19842,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1721019842 return;
1721119843 case TypeTableEntryIdStruct:
1721219844 zig_panic("TODO buf_write_value_bytes struct type");
17213 case TypeTableEntryIdMaybe:
19845 case TypeTableEntryIdOptional:
1721419846 zig_panic("TODO buf_write_value_bytes maybe type");
1721519847 case TypeTableEntryIdErrorUnion:
1721619848 zig_panic("TODO buf_write_value_bytes error union");
......@@ -17237,10 +19869,10 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1723719869 case TypeTableEntryIdNamespace:
1723819870 case TypeTableEntryIdBlock:
1723919871 case TypeTableEntryIdUnreachable:
17240 case TypeTableEntryIdNumLitFloat:
17241 case TypeTableEntryIdNumLitInt:
17242 case TypeTableEntryIdUndefLit:
17243 case TypeTableEntryIdNullLit:
19872 case TypeTableEntryIdComptimeFloat:
19873 case TypeTableEntryIdComptimeInt:
19874 case TypeTableEntryIdUndefined:
19875 case TypeTableEntryIdNull:
1724419876 case TypeTableEntryIdPromise:
1724519877 zig_unreachable();
1724619878 case TypeTableEntryIdVoid:
......@@ -17268,7 +19900,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1726819900 zig_panic("TODO buf_read_value_bytes array type");
1726919901 case TypeTableEntryIdStruct:
1727019902 zig_panic("TODO buf_read_value_bytes struct type");
17271 case TypeTableEntryIdMaybe:
19903 case TypeTableEntryIdOptional:
1727219904 zig_panic("TODO buf_read_value_bytes maybe type");
1727319905 case TypeTableEntryIdErrorUnion:
1727419906 zig_panic("TODO buf_read_value_bytes error union");
......@@ -17296,7 +19928,12 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
1729619928 return ira->codegen->builtin_types.entry_invalid;
1729719929
1729819930 ensure_complete_type(ira->codegen, dest_type);
19931 if (type_is_invalid(dest_type))
19932 return ira->codegen->builtin_types.entry_invalid;
19933
1729919934 ensure_complete_type(ira->codegen, src_type);
19935 if (type_is_invalid(src_type))
19936 return ira->codegen->builtin_types.entry_invalid;
1730019937
1730119938 if (get_codegen_ptr_type(src_type) != nullptr) {
1730219939 ir_add_error(ira, value,
......@@ -17313,10 +19950,10 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
1731319950 case TypeTableEntryIdNamespace:
1731419951 case TypeTableEntryIdBlock:
1731519952 case TypeTableEntryIdUnreachable:
17316 case TypeTableEntryIdNumLitFloat:
17317 case TypeTableEntryIdNumLitInt:
17318 case TypeTableEntryIdUndefLit:
17319 case TypeTableEntryIdNullLit:
19953 case TypeTableEntryIdComptimeFloat:
19954 case TypeTableEntryIdComptimeInt:
19955 case TypeTableEntryIdUndefined:
19956 case TypeTableEntryIdNull:
1732019957 ir_add_error(ira, dest_type_value,
1732119958 buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
1732219959 return ira->codegen->builtin_types.entry_invalid;
......@@ -17339,10 +19976,10 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
1733919976 case TypeTableEntryIdNamespace:
1734019977 case TypeTableEntryIdBlock:
1734119978 case TypeTableEntryIdUnreachable:
17342 case TypeTableEntryIdNumLitFloat:
17343 case TypeTableEntryIdNumLitInt:
17344 case TypeTableEntryIdUndefLit:
17345 case TypeTableEntryIdNullLit:
19979 case TypeTableEntryIdComptimeFloat:
19980 case TypeTableEntryIdComptimeInt:
19981 case TypeTableEntryIdUndefined:
19982 case TypeTableEntryIdNull:
1734619983 ir_add_error(ira, dest_type_value,
1734719984 buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
1734819985 return ira->codegen->builtin_types.entry_invalid;
......@@ -17429,7 +20066,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1742920066 Tld *tld = instruction->tld;
1743020067 LVal lval = instruction->lval;
1743120068
17432 resolve_top_level_decl(ira->codegen, tld, lval.is_ptr, instruction->base.source_node);
20069 resolve_top_level_decl(ira->codegen, tld, lval == LValPtr, instruction->base.source_node);
1743320070 if (tld->resolution == TldResolutionInvalid)
1743420071 return ira->codegen->builtin_types.entry_invalid;
1743520072
......@@ -17442,8 +20079,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1744220079 TldVar *tld_var = (TldVar *)tld;
1744320080 VariableTableEntry *var = tld_var->var;
1744420081
17445 IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var,
17446 !lval.is_ptr || lval.is_const, lval.is_ptr && lval.is_volatile);
20082 IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);
1744720083 if (type_is_invalid(var_ptr->value.type))
1744820084 return ira->codegen->builtin_types.entry_invalid;
1744920085
......@@ -17451,7 +20087,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1745120087 add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node);
1745220088 }
1745320089
17454 if (lval.is_ptr) {
20090 if (lval == LValPtr) {
1745520091 ir_link_new_instruction(var_ptr, &instruction->base);
1745620092 return var_ptr->value.type;
1745720093 } else {
......@@ -17472,7 +20108,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1747220108
1747320109 IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
1747420110 instruction->base.source_node, fn_entry);
17475 if (lval.is_ptr) {
20111 if (lval == LValPtr) {
1747620112 IrInstruction *ptr_instr = ir_get_ref(ira, &instruction->base, ref_instruction, true, false);
1747720113 ir_link_new_instruction(ptr_instr, &instruction->base);
1747820114 return ptr_instr->value.type;
......@@ -17498,13 +20134,16 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr
1749820134 return ira->codegen->builtin_types.entry_invalid;
1749920135 }
1750020136
20137 if (!type_has_bits(target->value.type)) {
20138 ir_add_error(ira, target,
20139 buf_sprintf("pointer to size 0 type has no address"));
20140 return ira->codegen->builtin_types.entry_invalid;
20141 }
20142
1750120143 if (instr_is_comptime(target)) {
1750220144 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
1750320145 if (!val)
1750420146 return ira->codegen->builtin_types.entry_invalid;
17505 if (target->value.type->id == TypeTableEntryIdMaybe) {
17506 val = val->data.x_maybe;
17507 }
1750820147 if (val->type->id == TypeTableEntryIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
1750920148 IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
1751020149 instruction->base.source_node, usize);
......@@ -17521,22 +20160,34 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr
1752120160 return usize;
1752220161}
1752320162
17524static TypeTableEntry *ir_analyze_instruction_ptr_type_of(IrAnalyze *ira, IrInstructionPtrTypeOf *instruction) {
20163static TypeTableEntry *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) {
1752520164 TypeTableEntry *child_type = ir_resolve_type(ira, instruction->child_type->other);
1752620165 if (type_is_invalid(child_type))
1752720166 return ira->codegen->builtin_types.entry_invalid;
1752820167
20168 if (child_type->id == TypeTableEntryIdUnreachable) {
20169 ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
20170 return ira->codegen->builtin_types.entry_invalid;
20171 } else if (child_type->id == TypeTableEntryIdOpaque && instruction->ptr_len == PtrLenUnknown) {
20172 ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
20173 return ira->codegen->builtin_types.entry_invalid;
20174 }
20175
1752920176 uint32_t align_bytes;
1753020177 if (instruction->align_value != nullptr) {
1753120178 if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes))
1753220179 return ira->codegen->builtin_types.entry_invalid;
1753320180 } else {
20181 type_ensure_zero_bits_known(ira->codegen, child_type);
20182 if (type_is_invalid(child_type))
20183 return ira->codegen->builtin_types.entry_invalid;
1753420184 align_bytes = get_abi_alignment(ira->codegen, child_type);
1753520185 }
1753620186
1753720187 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1753820188 out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type,
17539 instruction->is_const, instruction->is_volatile, align_bytes,
20189 instruction->is_const, instruction->is_volatile,
20190 instruction->ptr_len, align_bytes,
1754020191 instruction->bit_offset_start, instruction->bit_offset_end - instruction->bit_offset_start);
1754120192
1754220193 return ira->codegen->builtin_types.entry_type;
......@@ -17634,6 +20285,16 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc
1763420285
1763520286 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1763620287 out_val->data.x_type = fn_type_id->param_info[arg_index].type;
20288 if (out_val->data.x_type == nullptr) {
20289 // Args are only unresolved if our function is generic.
20290 assert(fn_type->data.fn.is_generic);
20291
20292 ir_add_error(ira, arg_index_inst,
20293 buf_sprintf("@ArgType could not resolve the type of arg %" ZIG_PRI_u64 " because '%s' is generic",
20294 arg_index, buf_ptr(&fn_type->name)));
20295 return ira->codegen->builtin_types.entry_invalid;
20296 }
20297
1763720298 return ira->codegen->builtin_types.entry_type;
1763820299}
1763920300
......@@ -17797,7 +20458,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstru
1779720458 instruction->base.source_node, coro_id, coro_handle);
1779820459 ir_link_new_instruction(result, &instruction->base);
1779920460 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
17800 result->value.type = get_maybe_type(ira->codegen, ptr_type);
20461 result->value.type = get_optional_type(ira->codegen, ptr_type);
1780120462 return result->value.type;
1780220463}
1780320464
......@@ -17865,43 +20526,52 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira,
1786520526 instruction->base.source_node, alloc_fn, coro_size);
1786620527 ir_link_new_instruction(result, &instruction->base);
1786720528 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
17868 result->value.type = get_maybe_type(ira->codegen, u8_ptr_type);
20529 result->value.type = get_optional_type(ira->codegen, u8_ptr_type);
1786920530 return result->value.type;
1787020531}
1787120532
17872static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) {
17873 TypeTableEntry *operand_type = ir_resolve_type(ira, instruction->operand_type->other);
17874 if (type_is_invalid(operand_type)) {
20533static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
20534 TypeTableEntry *operand_type = ir_resolve_type(ira, op);
20535 if (type_is_invalid(operand_type))
1787520536 return ira->codegen->builtin_types.entry_invalid;
17876 }
20537
1787720538 if (operand_type->id == TypeTableEntryIdInt) {
1787820539 if (operand_type->data.integral.bit_count < 8) {
17879 ir_add_error(ira, &instruction->base,
20540 ir_add_error(ira, op,
1788020541 buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type",
1788120542 operand_type->data.integral.bit_count));
1788220543 return ira->codegen->builtin_types.entry_invalid;
1788320544 }
1788420545 if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
17885 ir_add_error(ira, &instruction->base,
20546 ir_add_error(ira, op,
1788620547 buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
1788720548 operand_type->data.integral.bit_count));
1788820549 return ira->codegen->builtin_types.entry_invalid;
1788920550 }
1789020551 if (!is_power_of_2(operand_type->data.integral.bit_count)) {
17891 ir_add_error(ira, &instruction->base,
20552 ir_add_error(ira, op,
1789220553 buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count));
1789320554 return ira->codegen->builtin_types.entry_invalid;
1789420555 }
1789520556 } else if (get_codegen_ptr_type(operand_type) == nullptr) {
17896 ir_add_error(ira, &instruction->base,
20557 ir_add_error(ira, op,
1789720558 buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name)));
1789820559 return ira->codegen->builtin_types.entry_invalid;
1789920560 }
1790020561
20562 return operand_type;
20563}
20564
20565static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) {
20566 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other);
20567 if (type_is_invalid(operand_type))
20568 return ira->codegen->builtin_types.entry_invalid;
20569
1790120570 IrInstruction *ptr_inst = instruction->ptr->other;
1790220571 if (type_is_invalid(ptr_inst->value.type))
1790320572 return ira->codegen->builtin_types.entry_invalid;
1790420573
20574 // TODO let this be volatile
1790520575 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
1790620576 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
1790720577 if (type_is_invalid(casted_ptr->value.type))
......@@ -17930,6 +20600,11 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr
1793020600 } else {
1793120601 if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering))
1793220602 return ira->codegen->builtin_types.entry_invalid;
20603 if (ordering == AtomicOrderUnordered) {
20604 ir_add_error(ira, instruction->ordering,
20605 buf_sprintf("@atomicRmw atomic ordering must not be Unordered"));
20606 return ira->codegen->builtin_types.entry_invalid;
20607 }
1793320608 }
1793420609
1793520610 if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
......@@ -17945,6 +20620,49 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr
1794520620 return result->value.type;
1794620621}
1794720622
20623static TypeTableEntry *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstructionAtomicLoad *instruction) {
20624 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other);
20625 if (type_is_invalid(operand_type))
20626 return ira->codegen->builtin_types.entry_invalid;
20627
20628 IrInstruction *ptr_inst = instruction->ptr->other;
20629 if (type_is_invalid(ptr_inst->value.type))
20630 return ira->codegen->builtin_types.entry_invalid;
20631
20632 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true);
20633 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
20634 if (type_is_invalid(casted_ptr->value.type))
20635 return ira->codegen->builtin_types.entry_invalid;
20636
20637 AtomicOrder ordering;
20638 if (instruction->ordering == nullptr) {
20639 ordering = instruction->resolved_ordering;
20640 } else {
20641 if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering))
20642 return ira->codegen->builtin_types.entry_invalid;
20643 }
20644
20645 if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) {
20646 assert(instruction->ordering != nullptr);
20647 ir_add_error(ira, instruction->ordering,
20648 buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel"));
20649 return ira->codegen->builtin_types.entry_invalid;
20650 }
20651
20652 if (instr_is_comptime(casted_ptr)) {
20653 IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr);
20654 ir_link_new_instruction(result, &instruction->base);
20655 assert(result->value.type != nullptr);
20656 return result->value.type;
20657 }
20658
20659 IrInstruction *result = ir_build_atomic_load(&ira->new_irb, instruction->base.scope,
20660 instruction->base.source_node, nullptr, casted_ptr, nullptr, ordering);
20661 ir_link_new_instruction(result, &instruction->base);
20662 result->value.type = operand_type;
20663 return result->value.type;
20664}
20665
1794820666static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) {
1794920667 TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other);
1795020668 if (type_is_invalid(promise_type))
......@@ -18031,18 +20749,135 @@ static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *
1803120749 return result->value.type;
1803220750}
1803320751
20752static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) {
20753 TypeTableEntry *float_type = ir_resolve_type(ira, instruction->type->other);
20754 if (type_is_invalid(float_type))
20755 return ira->codegen->builtin_types.entry_invalid;
20756
20757 IrInstruction *op = instruction->op->other;
20758 if (type_is_invalid(op->value.type))
20759 return ira->codegen->builtin_types.entry_invalid;
20760
20761 bool ok_type = float_type->id == TypeTableEntryIdComptimeFloat || float_type->id == TypeTableEntryIdFloat;
20762 if (!ok_type) {
20763 ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name)));
20764 return ira->codegen->builtin_types.entry_invalid;
20765 }
20766
20767 IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type);
20768 if (type_is_invalid(casted_op->value.type))
20769 return ira->codegen->builtin_types.entry_invalid;
20770
20771 if (instr_is_comptime(casted_op)) {
20772 ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad);
20773 if (!val)
20774 return ira->codegen->builtin_types.entry_invalid;
20775
20776 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
20777
20778 if (float_type->id == TypeTableEntryIdComptimeFloat) {
20779 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);
20780 } else if (float_type->id == TypeTableEntryIdFloat) {
20781 switch (float_type->data.floating.bit_count) {
20782 case 16:
20783 out_val->data.x_f16 = f16_sqrt(val->data.x_f16);
20784 break;
20785 case 32:
20786 out_val->data.x_f32 = sqrtf(val->data.x_f32);
20787 break;
20788 case 64:
20789 out_val->data.x_f64 = sqrt(val->data.x_f64);
20790 break;
20791 case 128:
20792 f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128);
20793 break;
20794 default:
20795 zig_unreachable();
20796 }
20797 } else {
20798 zig_unreachable();
20799 }
20800
20801 return float_type;
20802 }
20803
20804 assert(float_type->id == TypeTableEntryIdFloat);
20805 if (float_type->data.floating.bit_count != 16 &&
20806 float_type->data.floating.bit_count != 32 &&
20807 float_type->data.floating.bit_count != 64) {
20808 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));
20809 return ira->codegen->builtin_types.entry_invalid;
20810 }
20811
20812 IrInstruction *result = ir_build_sqrt(&ira->new_irb, instruction->base.scope,
20813 instruction->base.source_node, nullptr, casted_op);
20814 ir_link_new_instruction(result, &instruction->base);
20815 result->value.type = float_type;
20816 return result->value.type;
20817}
20818
20819static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
20820 IrInstruction *target = instruction->target->other;
20821 if (type_is_invalid(target->value.type))
20822 return ira->codegen->builtin_types.entry_invalid;
20823
20824 if (target->value.type->id != TypeTableEntryIdEnum) {
20825 ir_add_error(ira, instruction->target,
20826 buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
20827 return ira->codegen->builtin_types.entry_invalid;
20828 }
20829
20830 type_ensure_zero_bits_known(ira->codegen, target->value.type);
20831 if (type_is_invalid(target->value.type))
20832 return ira->codegen->builtin_types.entry_invalid;
20833
20834 TypeTableEntry *tag_type = target->value.type->data.enumeration.tag_int_type;
20835
20836 IrInstruction *result = ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type);
20837 ir_link_new_instruction(result, &instruction->base);
20838 return result->value.type;
20839}
20840
20841static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
20842 IrInstruction *dest_type_value = instruction->dest_type->other;
20843 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
20844 if (type_is_invalid(dest_type))
20845 return ira->codegen->builtin_types.entry_invalid;
20846
20847 if (dest_type->id != TypeTableEntryIdEnum) {
20848 ir_add_error(ira, instruction->dest_type,
20849 buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name)));
20850 return ira->codegen->builtin_types.entry_invalid;
20851 }
20852
20853 type_ensure_zero_bits_known(ira->codegen, dest_type);
20854 if (type_is_invalid(dest_type))
20855 return ira->codegen->builtin_types.entry_invalid;
20856
20857 TypeTableEntry *tag_type = dest_type->data.enumeration.tag_int_type;
20858
20859 IrInstruction *target = instruction->target->other;
20860 if (type_is_invalid(target->value.type))
20861 return ira->codegen->builtin_types.entry_invalid;
20862
20863 IrInstruction *casted_target = ir_implicit_cast(ira, target, tag_type);
20864 if (type_is_invalid(casted_target->value.type))
20865 return ira->codegen->builtin_types.entry_invalid;
20866
20867 IrInstruction *result = ir_analyze_int_to_enum(ira, &instruction->base, casted_target, dest_type);
20868 ir_link_new_instruction(result, &instruction->base);
20869 return result->value.type;
20870}
20871
1803420872static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1803520873 switch (instruction->id) {
1803620874 case IrInstructionIdInvalid:
1803720875 case IrInstructionIdWidenOrShorten:
18038 case IrInstructionIdIntToEnum:
18039 case IrInstructionIdIntToErr:
18040 case IrInstructionIdErrToInt:
1804120876 case IrInstructionIdStructInit:
1804220877 case IrInstructionIdUnionInit:
1804320878 case IrInstructionIdStructFieldPtr:
1804420879 case IrInstructionIdUnionFieldPtr:
18045 case IrInstructionIdMaybeWrap:
20880 case IrInstructionIdOptionalWrap:
1804620881 case IrInstructionIdErrWrapCode:
1804720882 case IrInstructionIdErrWrapPayload:
1804820883 case IrInstructionIdCast:
......@@ -18102,12 +20937,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1810220937 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
1810320938 case IrInstructionIdTestNonNull:
1810420939 return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
18105 case IrInstructionIdUnwrapMaybe:
18106 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction);
20940 case IrInstructionIdUnwrapOptional:
20941 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction);
1810720942 case IrInstructionIdClz:
1810820943 return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
1810920944 case IrInstructionIdCtz:
1811020945 return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction);
20946 case IrInstructionIdPopCount:
20947 return ir_analyze_instruction_pop_count(ira, (IrInstructionPopCount *)instruction);
1811120948 case IrInstructionIdSwitchBr:
1811220949 return ir_analyze_instruction_switch_br(ira, (IrInstructionSwitchBr *)instruction);
1811320950 case IrInstructionIdSwitchTarget:
......@@ -18154,6 +20991,22 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1815420991 return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
1815520992 case IrInstructionIdTruncate:
1815620993 return ir_analyze_instruction_truncate(ira, (IrInstructionTruncate *)instruction);
20994 case IrInstructionIdIntCast:
20995 return ir_analyze_instruction_int_cast(ira, (IrInstructionIntCast *)instruction);
20996 case IrInstructionIdFloatCast:
20997 return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);
20998 case IrInstructionIdErrSetCast:
20999 return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction);
21000 case IrInstructionIdFromBytes:
21001 return ir_analyze_instruction_from_bytes(ira, (IrInstructionFromBytes *)instruction);
21002 case IrInstructionIdToBytes:
21003 return ir_analyze_instruction_to_bytes(ira, (IrInstructionToBytes *)instruction);
21004 case IrInstructionIdIntToFloat:
21005 return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
21006 case IrInstructionIdFloatToInt:
21007 return ir_analyze_instruction_float_to_int(ira, (IrInstructionFloatToInt *)instruction);
21008 case IrInstructionIdBoolToInt:
21009 return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction);
1815721010 case IrInstructionIdIntType:
1815821011 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
1815921012 case IrInstructionIdBoolNot:
......@@ -18176,6 +21029,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1817621029 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
1817721030 case IrInstructionIdFrameAddress:
1817821031 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
21032 case IrInstructionIdHandle:
21033 return ir_analyze_instruction_handle(ira, (IrInstructionHandle *)instruction);
1817921034 case IrInstructionIdAlignOf:
1818021035 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
1818121036 case IrInstructionIdOverflowOp:
......@@ -18194,8 +21049,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1819421049 return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);
1819521050 case IrInstructionIdCheckStatementIsVoid:
1819621051 return ir_analyze_instruction_check_statement_is_void(ira, (IrInstructionCheckStatementIsVoid *)instruction);
18197 case IrInstructionIdCanImplicitCast:
18198 return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
1819921052 case IrInstructionIdDeclRef:
1820021053 return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
1820121054 case IrInstructionIdPanic:
......@@ -18214,12 +21067,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1821421067 return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
1821521068 case IrInstructionIdOffsetOf:
1821621069 return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);
21070 case IrInstructionIdTypeInfo:
21071 return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction);
1821721072 case IrInstructionIdTypeId:
1821821073 return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction);
1821921074 case IrInstructionIdSetEvalBranchQuota:
1822021075 return ir_analyze_instruction_set_eval_branch_quota(ira, (IrInstructionSetEvalBranchQuota *)instruction);
18221 case IrInstructionIdPtrTypeOf:
18222 return ir_analyze_instruction_ptr_type_of(ira, (IrInstructionPtrTypeOf *)instruction);
21076 case IrInstructionIdPtrType:
21077 return ir_analyze_instruction_ptr_type(ira, (IrInstructionPtrType *)instruction);
1822321078 case IrInstructionIdAlignCast:
1822421079 return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);
1822521080 case IrInstructionIdOpaqueType:
......@@ -18266,6 +21121,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1826621121 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
1826721122 case IrInstructionIdAtomicRmw:
1826821123 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
21124 case IrInstructionIdAtomicLoad:
21125 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);
1826921126 case IrInstructionIdPromiseResultType:
1827021127 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
1827121128 case IrInstructionIdAwaitBookkeeping:
......@@ -18278,6 +21135,16 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1827821135 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
1827921136 case IrInstructionIdMarkErrRetTracePtr:
1828021137 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
21138 case IrInstructionIdSqrt:
21139 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);
21140 case IrInstructionIdIntToErr:
21141 return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);
21142 case IrInstructionIdErrToInt:
21143 return ir_analyze_instruction_err_to_int(ira, (IrInstructionErrToInt *)instruction);
21144 case IrInstructionIdIntToEnum:
21145 return ir_analyze_instruction_int_to_enum(ira, (IrInstructionIntToEnum *)instruction);
21146 case IrInstructionIdEnumToInt:
21147 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
1828121148 }
1828221149 zig_unreachable();
1828321150}
......@@ -18285,6 +21152,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1828521152static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) {
1828621153 TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
1828721154 instruction->value.type = instruction_type;
21155
1828821156 if (instruction->other) {
1828921157 instruction->other->value.type = instruction_type;
1829021158 } else {
......@@ -18354,7 +21222,7 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1835421222 } else if (ira->src_implicit_return_type_list.length == 0) {
1835521223 return codegen->builtin_types.entry_unreachable;
1835621224 } else {
18357 return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items,
21225 return ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items,
1835821226 ira->src_implicit_return_type_list.length);
1835921227 }
1836021228}
......@@ -18391,7 +21259,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1839121259 case IrInstructionIdCheckStatementIsVoid:
1839221260 case IrInstructionIdPanic:
1839321261 case IrInstructionIdSetEvalBranchQuota:
18394 case IrInstructionIdPtrTypeOf:
21262 case IrInstructionIdPtrType:
1839521263 case IrInstructionIdSetAlignStack:
1839621264 case IrInstructionIdExport:
1839721265 case IrInstructionIdCancel:
......@@ -18407,6 +21275,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1840721275 case IrInstructionIdAddImplicitReturnType:
1840821276 case IrInstructionIdMergeErrRetTraces:
1840921277 case IrInstructionIdMarkErrRetTracePtr:
21278 case IrInstructionIdAtomicRmw:
1841021279 return true;
1841121280
1841221281 case IrInstructionIdPhi:
......@@ -18433,9 +21302,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1843321302 case IrInstructionIdSliceType:
1843421303 case IrInstructionIdSizeOf:
1843521304 case IrInstructionIdTestNonNull:
18436 case IrInstructionIdUnwrapMaybe:
21305 case IrInstructionIdUnwrapOptional:
1843721306 case IrInstructionIdClz:
1843821307 case IrInstructionIdCtz:
21308 case IrInstructionIdPopCount:
1843921309 case IrInstructionIdSwitchVar:
1844021310 case IrInstructionIdSwitchTarget:
1844121311 case IrInstructionIdUnionTag:
......@@ -18453,9 +21323,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1845321323 case IrInstructionIdAlignOf:
1845421324 case IrInstructionIdReturnAddress:
1845521325 case IrInstructionIdFrameAddress:
21326 case IrInstructionIdHandle:
1845621327 case IrInstructionIdTestErr:
1845721328 case IrInstructionIdUnwrapErrCode:
18458 case IrInstructionIdMaybeWrap:
21329 case IrInstructionIdOptionalWrap:
1845921330 case IrInstructionIdErrWrapCode:
1846021331 case IrInstructionIdErrWrapPayload:
1846121332 case IrInstructionIdFnProto:
......@@ -18468,13 +21339,13 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1846821339 case IrInstructionIdIntToEnum:
1846921340 case IrInstructionIdIntToErr:
1847021341 case IrInstructionIdErrToInt:
18471 case IrInstructionIdCanImplicitCast:
1847221342 case IrInstructionIdDeclRef:
1847321343 case IrInstructionIdErrName:
1847421344 case IrInstructionIdTypeName:
1847521345 case IrInstructionIdTagName:
1847621346 case IrInstructionIdFieldParentPtr:
1847721347 case IrInstructionIdOffsetOf:
21348 case IrInstructionIdTypeInfo:
1847821349 case IrInstructionIdTypeId:
1847921350 case IrInstructionIdAlignCast:
1848021351 case IrInstructionIdOpaqueType:
......@@ -18487,9 +21358,19 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1848721358 case IrInstructionIdCoroSize:
1848821359 case IrInstructionIdCoroSuspend:
1848921360 case IrInstructionIdCoroFree:
18490 case IrInstructionIdAtomicRmw:
1849121361 case IrInstructionIdCoroPromise:
1849221362 case IrInstructionIdPromiseResultType:
21363 case IrInstructionIdSqrt:
21364 case IrInstructionIdAtomicLoad:
21365 case IrInstructionIdIntCast:
21366 case IrInstructionIdFloatCast:
21367 case IrInstructionIdErrSetCast:
21368 case IrInstructionIdIntToFloat:
21369 case IrInstructionIdFloatToInt:
21370 case IrInstructionIdBoolToInt:
21371 case IrInstructionIdFromBytes:
21372 case IrInstructionIdToBytes:
21373 case IrInstructionIdEnumToInt:
1849321374 return false;
1849421375
1849521376 case IrInstructionIdAsm:
src/ir_print.cpp+188-29
......@@ -45,6 +45,10 @@ static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) {
4545}
4646
4747static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
48 if (instruction == nullptr) {
49 fprintf(irp->f, "(null)");
50 return;
51 }
4852 if (instruction->value.special != ConstValSpecialRuntime) {
4953 ir_print_const_value(irp, &instruction->value);
5054 } else {
......@@ -148,7 +152,7 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
148152 return "-%";
149153 case IrUnOpDereference:
150154 return "*";
151 case IrUnOpMaybe:
155 case IrUnOpOptional:
152156 return "?";
153157 }
154158 zig_unreachable();
......@@ -358,9 +362,18 @@ static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *ins
358362}
359363
360364static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) {
361 fprintf(irp->f, "fieldptr ");
362 ir_print_other_instruction(irp, instruction->container_ptr);
363 fprintf(irp->f, ".%s", buf_ptr(instruction->field_name));
365 if (instruction->field_name_buffer) {
366 fprintf(irp->f, "fieldptr ");
367 ir_print_other_instruction(irp, instruction->container_ptr);
368 fprintf(irp->f, ".%s", buf_ptr(instruction->field_name_buffer));
369 } else {
370 assert(instruction->field_name_expr);
371 fprintf(irp->f, "@field(");
372 ir_print_other_instruction(irp, instruction->container_ptr);
373 fprintf(irp->f, ", ");
374 ir_print_other_instruction(irp, instruction->field_name_expr);
375 fprintf(irp->f, ")");
376 }
364377}
365378
366379static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr *instruction) {
......@@ -472,7 +485,7 @@ static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instructi
472485 fprintf(irp->f, " != null");
473486}
474487
475static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) {
488static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
476489 fprintf(irp->f, "&??*");
477490 ir_print_other_instruction(irp, instruction->value);
478491 if (!instruction->safety_check_on) {
......@@ -492,6 +505,12 @@ static void ir_print_ctz(IrPrint *irp, IrInstructionCtz *instruction) {
492505 fprintf(irp->f, ")");
493506}
494507
508static void ir_print_pop_count(IrPrint *irp, IrInstructionPopCount *instruction) {
509 fprintf(irp->f, "@popCount(");
510 ir_print_other_instruction(irp, instruction->value);
511 fprintf(irp->f, ")");
512}
513
495514static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction) {
496515 fprintf(irp->f, "switch (");
497516 ir_print_other_instruction(irp, instruction->target_value);
......@@ -639,6 +658,66 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)
639658 fprintf(irp->f, ")");
640659}
641660
661static void ir_print_int_cast(IrPrint *irp, IrInstructionIntCast *instruction) {
662 fprintf(irp->f, "@intCast(");
663 ir_print_other_instruction(irp, instruction->dest_type);
664 fprintf(irp->f, ", ");
665 ir_print_other_instruction(irp, instruction->target);
666 fprintf(irp->f, ")");
667}
668
669static void ir_print_float_cast(IrPrint *irp, IrInstructionFloatCast *instruction) {
670 fprintf(irp->f, "@floatCast(");
671 ir_print_other_instruction(irp, instruction->dest_type);
672 fprintf(irp->f, ", ");
673 ir_print_other_instruction(irp, instruction->target);
674 fprintf(irp->f, ")");
675}
676
677static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruction) {
678 fprintf(irp->f, "@errSetCast(");
679 ir_print_other_instruction(irp, instruction->dest_type);
680 fprintf(irp->f, ", ");
681 ir_print_other_instruction(irp, instruction->target);
682 fprintf(irp->f, ")");
683}
684
685static void ir_print_from_bytes(IrPrint *irp, IrInstructionFromBytes *instruction) {
686 fprintf(irp->f, "@bytesToSlice(");
687 ir_print_other_instruction(irp, instruction->dest_child_type);
688 fprintf(irp->f, ", ");
689 ir_print_other_instruction(irp, instruction->target);
690 fprintf(irp->f, ")");
691}
692
693static void ir_print_to_bytes(IrPrint *irp, IrInstructionToBytes *instruction) {
694 fprintf(irp->f, "@sliceToBytes(");
695 ir_print_other_instruction(irp, instruction->target);
696 fprintf(irp->f, ")");
697}
698
699static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
700 fprintf(irp->f, "@intToFloat(");
701 ir_print_other_instruction(irp, instruction->dest_type);
702 fprintf(irp->f, ", ");
703 ir_print_other_instruction(irp, instruction->target);
704 fprintf(irp->f, ")");
705}
706
707static void ir_print_float_to_int(IrPrint *irp, IrInstructionFloatToInt *instruction) {
708 fprintf(irp->f, "@floatToInt(");
709 ir_print_other_instruction(irp, instruction->dest_type);
710 fprintf(irp->f, ", ");
711 ir_print_other_instruction(irp, instruction->target);
712 fprintf(irp->f, ")");
713}
714
715static void ir_print_bool_to_int(IrPrint *irp, IrInstructionBoolToInt *instruction) {
716 fprintf(irp->f, "@boolToInt(");
717 ir_print_other_instruction(irp, instruction->target);
718 fprintf(irp->f, ")");
719}
720
642721static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
643722 fprintf(irp->f, "@IntType(");
644723 ir_print_other_instruction(irp, instruction->is_signed);
......@@ -712,6 +791,10 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst
712791 fprintf(irp->f, "@frameAddress()");
713792}
714793
794static void ir_print_handle(IrPrint *irp, IrInstructionHandle *instruction) {
795 fprintf(irp->f, "@handle()");
796}
797
715798static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
716799 fprintf(irp->f, "@returnAddress()");
717800}
......@@ -768,7 +851,7 @@ static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayl
768851 }
769852}
770853
771static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionMaybeWrap *instruction) {
854static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) {
772855 fprintf(irp->f, "@maybeWrap(");
773856 ir_print_other_instruction(irp, instruction->value);
774857 fprintf(irp->f, ")");
......@@ -859,6 +942,17 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction
859942
860943static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) {
861944 fprintf(irp->f, "@intToEnum(");
945 if (instruction->dest_type == nullptr) {
946 fprintf(irp->f, "(null)");
947 } else {
948 ir_print_other_instruction(irp, instruction->dest_type);
949 }
950 ir_print_other_instruction(irp, instruction->target);
951 fprintf(irp->f, ")");
952}
953
954static void ir_print_enum_to_int(IrPrint *irp, IrInstructionEnumToInt *instruction) {
955 fprintf(irp->f, "@enumToInt(");
862956 ir_print_other_instruction(irp, instruction->target);
863957 fprintf(irp->f, ")");
864958}
......@@ -904,15 +998,7 @@ static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) {
904998 ir_print_other_instruction(irp, instruction->target);
905999}
9061000
907static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCast *instruction) {
908 fprintf(irp->f, "@canImplicitCast(");
909 ir_print_other_instruction(irp, instruction->type_value);
910 fprintf(irp->f, ",");
911 ir_print_other_instruction(irp, instruction->target_value);
912 fprintf(irp->f, ")");
913}
914
915static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instruction) {
1001static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
9161002 fprintf(irp->f, "&");
9171003 if (instruction->align_value != nullptr) {
9181004 fprintf(irp->f, "align(");
......@@ -927,10 +1013,8 @@ static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instructi
9271013}
9281014
9291015static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
930 const char *ptr_str = instruction->lval.is_ptr ? "ptr " : "";
931 const char *const_str = instruction->lval.is_const ? "const " : "";
932 const char *volatile_str = instruction->lval.is_volatile ? "volatile " : "";
933 fprintf(irp->f, "declref %s%s%s%s", const_str, volatile_str, ptr_str, buf_ptr(instruction->tld->name));
1016 const char *ptr_str = (instruction->lval == LValPtr) ? "ptr " : "";
1017 fprintf(irp->f, "declref %s%s", ptr_str, buf_ptr(instruction->tld->name));
9341018}
9351019
9361020static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) {
......@@ -957,6 +1041,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)
9571041 fprintf(irp->f, ")");
9581042}
9591043
1044static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) {
1045 fprintf(irp->f, "@typeInfo(");
1046 ir_print_other_instruction(irp, instruction->type_value);
1047 fprintf(irp->f, ")");
1048}
1049
9601050static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {
9611051 fprintf(irp->f, "@typeId(");
9621052 ir_print_other_instruction(irp, instruction->type_value);
......@@ -1025,7 +1115,7 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
10251115
10261116static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
10271117 fprintf(irp->f, "@errorReturnTrace(");
1028 switch (instruction->nullable) {
1118 switch (instruction->optional) {
10291119 case IrInstructionErrorReturnTrace::Null:
10301120 fprintf(irp->f, "Null");
10311121 break;
......@@ -1172,6 +1262,24 @@ static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instructio
11721262 fprintf(irp->f, ")");
11731263}
11741264
1265static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruction) {
1266 fprintf(irp->f, "@atomicLoad(");
1267 if (instruction->operand_type != nullptr) {
1268 ir_print_other_instruction(irp, instruction->operand_type);
1269 } else {
1270 fprintf(irp->f, "[TODO print]");
1271 }
1272 fprintf(irp->f, ",");
1273 ir_print_other_instruction(irp, instruction->ptr);
1274 fprintf(irp->f, ",");
1275 if (instruction->ordering != nullptr) {
1276 ir_print_other_instruction(irp, instruction->ordering);
1277 } else {
1278 fprintf(irp->f, "[TODO print]");
1279 }
1280 fprintf(irp->f, ")");
1281}
1282
11751283static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) {
11761284 fprintf(irp->f, "@awaitBookkeeping(");
11771285 ir_print_other_instruction(irp, instruction->promise_result_type);
......@@ -1204,6 +1312,18 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe
12041312 fprintf(irp->f, ")");
12051313}
12061314
1315static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
1316 fprintf(irp->f, "@sqrt(");
1317 if (instruction->type != nullptr) {
1318 ir_print_other_instruction(irp, instruction->type);
1319 } else {
1320 fprintf(irp->f, "null");
1321 }
1322 fprintf(irp->f, ",");
1323 ir_print_other_instruction(irp, instruction->op);
1324 fprintf(irp->f, ")");
1325}
1326
12071327static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
12081328 ir_print_prefix(irp, instruction);
12091329 switch (instruction->id) {
......@@ -1311,12 +1431,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13111431 case IrInstructionIdTestNonNull:
13121432 ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
13131433 break;
1314 case IrInstructionIdUnwrapMaybe:
1315 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);
1434 case IrInstructionIdUnwrapOptional:
1435 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
13161436 break;
13171437 case IrInstructionIdCtz:
13181438 ir_print_ctz(irp, (IrInstructionCtz *)instruction);
13191439 break;
1440 case IrInstructionIdPopCount:
1441 ir_print_pop_count(irp, (IrInstructionPopCount *)instruction);
1442 break;
13201443 case IrInstructionIdClz:
13211444 ir_print_clz(irp, (IrInstructionClz *)instruction);
13221445 break;
......@@ -1380,6 +1503,30 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13801503 case IrInstructionIdTruncate:
13811504 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
13821505 break;
1506 case IrInstructionIdIntCast:
1507 ir_print_int_cast(irp, (IrInstructionIntCast *)instruction);
1508 break;
1509 case IrInstructionIdFloatCast:
1510 ir_print_float_cast(irp, (IrInstructionFloatCast *)instruction);
1511 break;
1512 case IrInstructionIdErrSetCast:
1513 ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction);
1514 break;
1515 case IrInstructionIdFromBytes:
1516 ir_print_from_bytes(irp, (IrInstructionFromBytes *)instruction);
1517 break;
1518 case IrInstructionIdToBytes:
1519 ir_print_to_bytes(irp, (IrInstructionToBytes *)instruction);
1520 break;
1521 case IrInstructionIdIntToFloat:
1522 ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
1523 break;
1524 case IrInstructionIdFloatToInt:
1525 ir_print_float_to_int(irp, (IrInstructionFloatToInt *)instruction);
1526 break;
1527 case IrInstructionIdBoolToInt:
1528 ir_print_bool_to_int(irp, (IrInstructionBoolToInt *)instruction);
1529 break;
13831530 case IrInstructionIdIntType:
13841531 ir_print_int_type(irp, (IrInstructionIntType *)instruction);
13851532 break;
......@@ -1413,6 +1560,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14131560 case IrInstructionIdFrameAddress:
14141561 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
14151562 break;
1563 case IrInstructionIdHandle:
1564 ir_print_handle(irp, (IrInstructionHandle *)instruction);
1565 break;
14161566 case IrInstructionIdAlignOf:
14171567 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
14181568 break;
......@@ -1428,8 +1578,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14281578 case IrInstructionIdUnwrapErrPayload:
14291579 ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction);
14301580 break;
1431 case IrInstructionIdMaybeWrap:
1432 ir_print_maybe_wrap(irp, (IrInstructionMaybeWrap *)instruction);
1581 case IrInstructionIdOptionalWrap:
1582 ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction);
14331583 break;
14341584 case IrInstructionIdErrWrapCode:
14351585 ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction);
......@@ -1479,11 +1629,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14791629 case IrInstructionIdTagName:
14801630 ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
14811631 break;
1482 case IrInstructionIdCanImplicitCast:
1483 ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
1484 break;
1485 case IrInstructionIdPtrTypeOf:
1486 ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction);
1632 case IrInstructionIdPtrType:
1633 ir_print_ptr_type(irp, (IrInstructionPtrType *)instruction);
14871634 break;
14881635 case IrInstructionIdDeclRef:
14891636 ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction);
......@@ -1497,6 +1644,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14971644 case IrInstructionIdOffsetOf:
14981645 ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
14991646 break;
1647 case IrInstructionIdTypeInfo:
1648 ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction);
1649 break;
15001650 case IrInstructionIdTypeId:
15011651 ir_print_type_id(irp, (IrInstructionTypeId *)instruction);
15021652 break;
......@@ -1590,6 +1740,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15901740 case IrInstructionIdMarkErrRetTracePtr:
15911741 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
15921742 break;
1743 case IrInstructionIdSqrt:
1744 ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
1745 break;
1746 case IrInstructionIdAtomicLoad:
1747 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
1748 break;
1749 case IrInstructionIdEnumToInt:
1750 ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction);
1751 break;
15931752 }
15941753 fprintf(irp->f, "\n");
15951754}
src/link.cpp+27-8
......@@ -208,7 +208,7 @@ static Buf *get_dynamic_linker_path(CodeGen *g) {
208208static void construct_linker_job_elf(LinkJob *lj) {
209209 CodeGen *g = lj->codegen;
210210
211 if (lj->link_in_crt) {
211 if (g->libc_link_lib != nullptr) {
212212 find_libc_lib_path(g);
213213 }
214214
......@@ -217,6 +217,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
217217 lj->args.append(g->linker_script);
218218 }
219219
220 if (g->no_rosegment_workaround) {
221 lj->args.append("--no-rosegment");
222 }
220223 lj->args.append("--gc-sections");
221224
222225 lj->args.append("-m");
......@@ -322,10 +325,13 @@ static void construct_linker_job_elf(LinkJob *lj) {
322325 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
323326 }
324327
325 if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
326 Buf *builtin_o_path = build_o(g, "builtin");
327 lj->args.append(buf_ptr(builtin_o_path));
328 if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
329 if (g->libc_link_lib == nullptr) {
330 Buf *builtin_o_path = build_o(g, "builtin");
331 lj->args.append(buf_ptr(builtin_o_path));
332 }
328333
334 // sometimes libgcc is missing stuff, so we still build compiler_rt and rely on weak linkage
329335 Buf *compiler_rt_o_path = build_compiler_rt(g);
330336 lj->args.append(buf_ptr(compiler_rt_o_path));
331337 }
......@@ -388,6 +394,19 @@ static void construct_linker_job_elf(LinkJob *lj) {
388394 }
389395}
390396
397static void construct_linker_job_wasm(LinkJob *lj) {
398 CodeGen *g = lj->codegen;
399
400 lj->args.append("--relocatable"); // So lld doesn't look for _start.
401 lj->args.append("-o");
402 lj->args.append(buf_ptr(&lj->out_file));
403
404 // .o files
405 for (size_t i = 0; i < g->link_objects.length; i += 1) {
406 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
407 }
408}
409
391410//static bool is_target_cyg_mingw(const ZigTarget *target) {
392411// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) ||
393412// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU);
......@@ -416,7 +435,7 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si
416435static void construct_linker_job_coff(LinkJob *lj) {
417436 CodeGen *g = lj->codegen;
418437
419 if (lj->link_in_crt) {
438 if (g->libc_link_lib != nullptr) {
420439 find_libc_lib_path(g);
421440 }
422441
......@@ -538,7 +557,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
538557 lj->args.append(buf_ptr(builtin_o_path));
539558 }
540559
541 // msvc compiler_rt is missing some stuff, so we still build it and rely on LinkOnce
560 // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
542561 Buf *compiler_rt_o_path = build_compiler_rt(g);
543562 lj->args.append(buf_ptr(compiler_rt_o_path));
544563 }
......@@ -882,7 +901,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
882901 if (strchr(buf_ptr(link_lib->name), '/') == nullptr) {
883902 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
884903 lj->args.append(buf_ptr(arg));
885 } else {
904 } else {
886905 lj->args.append(buf_ptr(link_lib->name));
887906 }
888907 }
......@@ -921,7 +940,7 @@ static void construct_linker_job(LinkJob *lj) {
921940 case ZigLLVM_MachO:
922941 return construct_linker_job_macho(lj);
923942 case ZigLLVM_Wasm:
924 zig_panic("TODO link wasm");
943 return construct_linker_job_wasm(lj);
925944 }
926945}
927946
src/main.cpp+33-4
......@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
2323 " build-exe [source] create executable from source or object files\n"
2424 " build-lib [source] create library from source or object files\n"
2525 " build-obj [source] create object from source or assembly\n"
26 " builtin show the source code of that @import(\"builtin\")\n"
2627 " run [source] create executable and run immediately\n"
2728 " translate-c [source] convert c code to zig code\n"
2829 " targets list available compilation targets\n"
......@@ -33,7 +34,7 @@ static int usage(const char *arg0) {
3334 " --assembly [source] add assembly file to build\n"
3435 " --cache-dir [path] override the cache directory\n"
3536 " --color [auto|off|on] enable or disable colored error messages\n"
36 " --emit [filetype] emit a specific file format as compilation output\n"
37 " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
3738 " --enable-timing-info print timing diagnostics\n"
3839 " --libc-include-dir [path] directory where libc stdlib.h resides\n"
3940 " --name [name] override output name\n"
......@@ -43,6 +44,7 @@ static int usage(const char *arg0) {
4344 " --pkg-end pop current pkg\n"
4445 " --release-fast build with optimizations on and safety off\n"
4546 " --release-safe build with optimizations on and safety on\n"
47 " --release-small build with size optimizations on and safety off\n"
4648 " --static output will be statically linked\n"
4749 " --strip exclude debug symbols\n"
4850 " --target-arch [name] specify target architecture\n"
......@@ -73,6 +75,7 @@ static int usage(const char *arg0) {
7375 " -L[dir] alias for --library-path\n"
7476 " -rdynamic add all symbols to the dynamic symbol table\n"
7577 " -rpath [path] add directory to the runtime library search path\n"
78 " --no-rosegment compromise security to workaround valgrind bug\n"
7679 " -mconsole (windows) --subsystem console to the linker\n"
7780 " -mwindows (windows) --subsystem windows to the linker\n"
7881 " -framework [name] (darwin) link against framework\n"
......@@ -212,6 +215,7 @@ static Buf *resolve_zig_lib_dir(void) {
212215enum Cmd {
213216 CmdInvalid,
214217 CmdBuild,
218 CmdBuiltin,
215219 CmdRun,
216220 CmdTest,
217221 CmdVersion,
......@@ -323,6 +327,7 @@ int main(int argc, char **argv) {
323327 ZigList<const char *> test_exec_args = {0};
324328 int comptime_args_end = 0;
325329 int runtime_args_start = argc;
330 bool no_rosegment_workaround = false;
326331
327332 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
328333 const char *zig_exe_path = arg0;
......@@ -482,6 +487,8 @@ int main(int argc, char **argv) {
482487 build_mode = BuildModeFastRelease;
483488 } else if (strcmp(arg, "--release-safe") == 0) {
484489 build_mode = BuildModeSafeRelease;
490 } else if (strcmp(arg, "--release-small") == 0) {
491 build_mode = BuildModeSmallRelease;
485492 } else if (strcmp(arg, "--strip") == 0) {
486493 strip = true;
487494 } else if (strcmp(arg, "--static") == 0) {
......@@ -504,6 +511,8 @@ int main(int argc, char **argv) {
504511 mconsole = true;
505512 } else if (strcmp(arg, "-rdynamic") == 0) {
506513 rdynamic = true;
514 } else if (strcmp(arg, "--no-rosegment") == 0) {
515 no_rosegment_workaround = true;
507516 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
508517 each_lib_rpath = true;
509518 } else if (strcmp(arg, "--enable-timing-info") == 0) {
......@@ -657,6 +666,8 @@ int main(int argc, char **argv) {
657666 out_type = OutTypeExe;
658667 } else if (strcmp(arg, "targets") == 0) {
659668 cmd = CmdTargets;
669 } else if (strcmp(arg, "builtin") == 0) {
670 cmd = CmdBuiltin;
660671 } else {
661672 fprintf(stderr, "Unrecognized command: %s\n", arg);
662673 return usage(arg0);
......@@ -674,6 +685,7 @@ int main(int argc, char **argv) {
674685 return usage(arg0);
675686 }
676687 break;
688 case CmdBuiltin:
677689 case CmdVersion:
678690 case CmdZen:
679691 case CmdTargets:
......@@ -720,6 +732,16 @@ int main(int argc, char **argv) {
720732 }
721733
722734 switch (cmd) {
735 case CmdBuiltin: {
736 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
737 CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf);
738 Buf *builtin_source = codegen_generate_builtin_source(g);
739 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
740 fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
741 return EXIT_FAILURE;
742 }
743 return EXIT_SUCCESS;
744 }
723745 case CmdRun:
724746 case CmdBuild:
725747 case CmdTranslateC:
......@@ -841,6 +863,7 @@ int main(int argc, char **argv) {
841863
842864 codegen_set_windows_subsystem(g, mwindows, mconsole);
843865 codegen_set_rdynamic(g, rdynamic);
866 g->no_rosegment_workaround = no_rosegment_workaround;
844867 if (mmacosx_version_min && mios_version_min) {
845868 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
846869 return EXIT_FAILURE;
......@@ -868,15 +891,19 @@ int main(int argc, char **argv) {
868891
869892 add_package(g, cur_pkg, g->root_package);
870893
871 if (cmd == CmdBuild || cmd == CmdRun) {
872 codegen_set_emit_file_type(g, emit_file_type);
873
894 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
874895 for (size_t i = 0; i < objects.length; i += 1) {
875896 codegen_add_object(g, buf_create_from_str(objects.at(i)));
876897 }
877898 for (size_t i = 0; i < asm_files.length; i += 1) {
878899 codegen_add_assembly(g, buf_create_from_str(asm_files.at(i)));
879900 }
901 }
902
903
904 if (cmd == CmdBuild || cmd == CmdRun) {
905 codegen_set_emit_file_type(g, emit_file_type);
906
880907 codegen_build(g);
881908 codegen_link(g, out_file);
882909 if (timing_info)
......@@ -901,6 +928,8 @@ int main(int argc, char **argv) {
901928 codegen_print_timing_report(g, stdout);
902929 return EXIT_SUCCESS;
903930 } else if (cmd == CmdTest) {
931 codegen_set_emit_file_type(g, emit_file_type);
932
904933 ZigTarget native;
905934 get_native_target(&native);
906935
src/os.cpp+29-246
......@@ -26,7 +26,6 @@
2626#include <windows.h>
2727#include <io.h>
2828#include <fcntl.h>
29#include "windows_com.hpp"
3029
3130typedef SSIZE_T ssize_t;
3231#else
......@@ -225,6 +224,11 @@ void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) {
225224}
226225
227226void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
227 if (buf_len(dirname) == 0) {
228 buf_init_from_buf(out_full_path, basename);
229 return;
230 }
231
228232 buf_init_from_buf(out_full_path, dirname);
229233 uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1);
230234 if (!os_is_sep(c))
......@@ -989,12 +993,29 @@ int os_self_exe_path(Buf *out_path) {
989993 }
990994
991995#elif defined(ZIG_OS_DARWIN)
996 // How long is the executable's path?
992997 uint32_t u32_len = 0;
993998 int ret1 = _NSGetExecutablePath(nullptr, &u32_len);
994999 assert(ret1 != 0);
995 buf_resize(out_path, u32_len);
996 int ret2 = _NSGetExecutablePath(buf_ptr(out_path), &u32_len);
1000
1001 Buf *tmp = buf_alloc_fixed(u32_len);
1002
1003 // Fill the executable path.
1004 int ret2 = _NSGetExecutablePath(buf_ptr(tmp), &u32_len);
9971005 assert(ret2 == 0);
1006
1007 // According to libuv project, PATH_MAX*2 works around a libc bug where
1008 // the resolved path is sometimes bigger than PATH_MAX.
1009 buf_resize(out_path, PATH_MAX*2);
1010 char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path));
1011 if (!real_path) {
1012 buf_init_from_buf(out_path, tmp);
1013 return 0;
1014 }
1015
1016 // Resize out_path for the correct length.
1017 buf_resize(out_path, strlen(buf_ptr(out_path)));
1018
9981019 return 0;
9991020#elif defined(ZIG_OS_LINUX)
10001021 buf_resize(out_path, 256);
......@@ -1007,6 +1028,7 @@ int os_self_exe_path(Buf *out_path) {
10071028 buf_resize(out_path, buf_len(out_path) * 2);
10081029 continue;
10091030 }
1031 buf_resize(out_path, amt);
10101032 return 0;
10111033 }
10121034#endif
......@@ -1092,249 +1114,10 @@ void os_stderr_set_color(TermColor color) {
10921114#endif
10931115}
10941116
1095int os_find_windows_sdk(ZigWindowsSDK **out_sdk) {
1096#if defined(ZIG_OS_WINDOWS)
1097 ZigWindowsSDK *result_sdk = allocate<ZigWindowsSDK>(1);
1098 buf_resize(&result_sdk->path10, 0);
1099 buf_resize(&result_sdk->path81, 0);
1100
1101 HKEY key;
1102 HRESULT rc;
1103 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key);
1104 if (rc != ERROR_SUCCESS) {
1105 return ErrorFileNotFound;
1106 }
1107
1108 {
1109 DWORD tmp_buf_len = MAX_PATH;
1110 buf_resize(&result_sdk->path10, tmp_buf_len);
1111 rc = RegQueryValueEx(key, "KitsRoot10", NULL, NULL, (LPBYTE)buf_ptr(&result_sdk->path10), &tmp_buf_len);
1112 if (rc == ERROR_FILE_NOT_FOUND) {
1113 buf_resize(&result_sdk->path10, 0);
1114 } else {
1115 buf_resize(&result_sdk->path10, tmp_buf_len);
1116 }
1117 }
1118 {
1119 DWORD tmp_buf_len = MAX_PATH;
1120 buf_resize(&result_sdk->path81, tmp_buf_len);
1121 rc = RegQueryValueEx(key, "KitsRoot81", NULL, NULL, (LPBYTE)buf_ptr(&result_sdk->path81), &tmp_buf_len);
1122 if (rc == ERROR_FILE_NOT_FOUND) {
1123 buf_resize(&result_sdk->path81, 0);
1124 } else {
1125 buf_resize(&result_sdk->path81, tmp_buf_len);
1126 }
1127 }
1128
1129 if (buf_len(&result_sdk->path10) != 0) {
1130 Buf *sdk_lib_dir = buf_sprintf("%s\\Lib\\*", buf_ptr(&result_sdk->path10));
1131
1132 // enumerate files in sdk path looking for latest version
1133 WIN32_FIND_DATA ffd;
1134 HANDLE hFind = FindFirstFileA(buf_ptr(sdk_lib_dir), &ffd);
1135 if (hFind == INVALID_HANDLE_VALUE) {
1136 return ErrorFileNotFound;
1137 }
1138 int v0 = 0, v1 = 0, v2 = 0, v3 = 0;
1139 bool found_version_dir = false;
1140 for (;;) {
1141 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1142 int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
1143 sscanf(ffd.cFileName, "%d.%d.%d.%d", &c0, &c1, &c2, &c3);
1144 if (c0 == 10 && c1 == 0 && c2 == 10240 && c3 == 0) {
1145 // Microsoft released 26624 as 10240 accidentally.
1146 // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
1147 c2 = 26624;
1148 }
1149 if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {
1150 v0 = c0, v1 = c1, v2 = c2, v3 = c3;
1151 buf_init_from_str(&result_sdk->version10, ffd.cFileName);
1152 found_version_dir = true;
1153 }
1154 }
1155 if (FindNextFile(hFind, &ffd) == 0) {
1156 FindClose(hFind);
1157 break;
1158 }
1159 }
1160 if (!found_version_dir) {
1161 buf_resize(&result_sdk->path10, 0);
1162 }
1163 }
1164
1165 if (buf_len(&result_sdk->path81) != 0) {
1166 Buf *sdk_lib_dir = buf_sprintf("%s\\Lib\\winv*", buf_ptr(&result_sdk->path81));
1167
1168 // enumerate files in sdk path looking for latest version
1169 WIN32_FIND_DATA ffd;
1170 HANDLE hFind = FindFirstFileA(buf_ptr(sdk_lib_dir), &ffd);
1171 if (hFind == INVALID_HANDLE_VALUE) {
1172 return ErrorFileNotFound;
1173 }
1174 int v0 = 0, v1 = 0;
1175 bool found_version_dir = false;
1176 for (;;) {
1177 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1178 int c0 = 0, c1 = 0;
1179 sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
1180 if ((c0 > v0) || (c1 > v1)) {
1181 v0 = c0, v1 = c1;
1182 buf_init_from_str(&result_sdk->version81, ffd.cFileName);
1183 found_version_dir = true;
1184 }
1185 }
1186 if (FindNextFile(hFind, &ffd) == 0) {
1187 FindClose(hFind);
1188 break;
1189 }
1190 }
1191 if (!found_version_dir) {
1192 buf_resize(&result_sdk->path81, 0);
1193 }
1194 }
1195
1196 *out_sdk = result_sdk;
1197 return 0;
1198#else
1199 return ErrorFileNotFound;
1200#endif
1201}
1202
1203int os_get_win32_vcruntime_path(Buf* output_buf, ZigLLVM_ArchType platform_type) {
1204#if defined(ZIG_OS_WINDOWS)
1205 buf_resize(output_buf, 0);
1206 //COM Smart Pointerse requires explicit scope
1207 {
1208 HRESULT rc;
1209 rc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
1210 if (rc != S_OK) {
1211 goto com_done;
1212 }
1213
1214 //This COM class is installed when a VS2017
1215 ISetupConfigurationPtr setup_config;
1216 rc = setup_config.CreateInstance(__uuidof(SetupConfiguration));
1217 if (rc != S_OK) {
1218 goto com_done;
1219 }
1220
1221 IEnumSetupInstancesPtr all_instances;
1222 rc = setup_config->EnumInstances(&all_instances);
1223 if (rc != S_OK) {
1224 goto com_done;
1225 }
1226
1227 ISetupInstance* curr_instance;
1228 ULONG found_inst;
1229 while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) {
1230 BSTR bstr_inst_path;
1231 rc = curr_instance->GetInstallationPath(&bstr_inst_path);
1232 if (rc != S_OK) {
1233 goto com_done;
1234 }
1235 //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length
1236 UINT bstr_path_len = *((UINT*)bstr_inst_path - 1);
1237 ULONG tmp_path_len = bstr_path_len / 2 + 1;
1238 char* conv_path = (char*)bstr_inst_path;
1239 char *tmp_path = (char*)alloca(tmp_path_len);
1240 memset(tmp_path, 0, tmp_path_len);
1241 uint32_t c = 0;
1242 for (uint32_t i = 0; i < bstr_path_len; i += 2) {
1243 tmp_path[c] = conv_path[i];
1244 ++c;
1245 assert(c != tmp_path_len);
1246 }
1247
1248 buf_append_str(output_buf, tmp_path);
1249 buf_append_char(output_buf, '\\');
1250
1251 Buf* tmp_buf = buf_alloc();
1252 buf_append_buf(tmp_buf, output_buf);
1253 buf_append_str(tmp_buf, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
1254 FILE* tools_file = fopen(buf_ptr(tmp_buf), "r");
1255 if (!tools_file) {
1256 goto com_done;
1257 }
1258 memset(tmp_path, 0, tmp_path_len);
1259 fgets(tmp_path, tmp_path_len, tools_file);
1260 strtok(tmp_path, " \r\n");
1261 fclose(tools_file);
1262 buf_appendf(output_buf, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path);
1263 switch (platform_type) {
1264 case ZigLLVM_x86:
1265 buf_append_str(output_buf, "x86\\");
1266 break;
1267 case ZigLLVM_x86_64:
1268 buf_append_str(output_buf, "x64\\");
1269 break;
1270 case ZigLLVM_arm:
1271 buf_append_str(output_buf, "arm\\");
1272 break;
1273 default:
1274 zig_panic("Attemped to use vcruntime for non-supported platform.");
1275 }
1276 buf_resize(tmp_buf, 0);
1277 buf_append_buf(tmp_buf, output_buf);
1278 buf_append_str(tmp_buf, "vcruntime.lib");
1279
1280 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1281 return 0;
1282 }
1283 }
1284 }
1285
1286com_done:;
1287 HKEY key;
1288 HRESULT rc;
1289 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);
1290 if (rc != ERROR_SUCCESS) {
1291 return ErrorFileNotFound;
1292 }
1293
1294 DWORD dw_type = 0;
1295 DWORD cb_data = 0;
1296 rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data);
1297 if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) {
1298 return ErrorFileNotFound;
1299 }
1300
1301 Buf* tmp_buf = buf_alloc_fixed(cb_data);
1302 RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)buf_ptr(tmp_buf), &cb_data);
1303 //RegQueryValueExA returns the length of the string INCLUDING the null terminator
1304 buf_resize(tmp_buf, cb_data-1);
1305 buf_append_str(tmp_buf, "VC\\Lib\\");
1306 switch (platform_type) {
1307 case ZigLLVM_x86:
1308 //x86 is in the root of the Lib folder
1309 break;
1310 case ZigLLVM_x86_64:
1311 buf_append_str(tmp_buf, "amd64\\");
1312 break;
1313 case ZigLLVM_arm:
1314 buf_append_str(tmp_buf, "arm\\");
1315 break;
1316 default:
1317 zig_panic("Attemped to use vcruntime for non-supported platform.");
1318 }
1319
1320 buf_append_buf(output_buf, tmp_buf);
1321 buf_append_str(tmp_buf, "vcruntime.lib");
1322
1323 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1324 return 0;
1325 } else {
1326 buf_resize(output_buf, 0);
1327 return ErrorFileNotFound;
1328 }
1329#else
1330 return ErrorFileNotFound;
1331#endif
1332}
1333
13341117int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
13351118#if defined(ZIG_OS_WINDOWS)
13361119 buf_resize(output_buf, 0);
1337 buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));
1120 buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
13381121 switch (platform_type) {
13391122 case ZigLLVM_x86:
13401123 buf_append_str(output_buf, "x86\\");
......@@ -1366,7 +1149,7 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
13661149int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
13671150#if defined(ZIG_OS_WINDOWS)
13681151 buf_resize(output_buf, 0);
1369 buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));
1152 buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
13701153 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
13711154 return 0;
13721155 }
......@@ -1383,7 +1166,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
13831166#if defined(ZIG_OS_WINDOWS)
13841167 {
13851168 buf_resize(output_buf, 0);
1386 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));
1169 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);
13871170 switch (platform_type) {
13881171 case ZigLLVM_x86:
13891172 buf_append_str(output_buf, "x86\\");
......@@ -1406,7 +1189,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
14061189 }
14071190 {
14081191 buf_resize(output_buf, 0);
1409 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", buf_ptr(&sdk->path81), buf_ptr(&sdk->version81));
1192 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);
14101193 switch (platform_type) {
14111194 case ZigLLVM_x86:
14121195 buf_append_str(output_buf, "x86\\");
src/os.hpp+1-9
......@@ -12,6 +12,7 @@
1212#include "buffer.hpp"
1313#include "error.hpp"
1414#include "zig_llvm.h"
15#include "windows_sdk.h"
1516
1617#include <stdio.h>
1718#include <inttypes.h>
......@@ -79,15 +80,6 @@ bool os_is_sep(uint8_t c);
7980
8081int os_self_exe_path(Buf *out_path);
8182
82struct ZigWindowsSDK {
83 Buf path10;
84 Buf version10;
85 Buf path81;
86 Buf version81;
87};
88
89int os_find_windows_sdk(ZigWindowsSDK **out_sdk);
90int os_get_win32_vcruntime_path(Buf *output_buf, ZigLLVM_ArchType platform_type);
9183int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
9284int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
9385int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
src/parser.cpp+74-57
......@@ -648,12 +648,11 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
648648}
649649
650650/*
651SuspendExpression(body) = "suspend" "|" Symbol "|" body
651SuspendExpression(body) = "suspend" option( body )
652652*/
653653static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) {
654 size_t orig_token_index = *token_index;
655
656654 Token *suspend_token = &pc->tokens->at(*token_index);
655
657656 if (suspend_token->id == TokenIdKeywordSuspend) {
658657 *token_index += 1;
659658 } else if (mandatory) {
......@@ -663,23 +662,18 @@ static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, b
663662 return nullptr;
664663 }
665664
666 Token *bar_token = &pc->tokens->at(*token_index);
667 if (bar_token->id == TokenIdBinOr) {
668 *token_index += 1;
665 Token *lbrace = &pc->tokens->at(*token_index);
666 if (lbrace->id == TokenIdLBrace) {
667 AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
668 node->data.suspend.block = ast_parse_block(pc, token_index, true);
669 return node;
669670 } else if (mandatory) {
670 ast_expect_token(pc, suspend_token, TokenIdBinOr);
671 ast_expect_token(pc, lbrace, TokenIdLBrace);
671672 zig_unreachable();
672673 } else {
673 *token_index = orig_token_index;
674 *token_index -= 1;
674675 return nullptr;
675676 }
676
677 AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
678 node->data.suspend.promise_symbol = ast_parse_symbol(pc, token_index);
679 ast_eat_token(pc, token_index, TokenIdBinOr);
680 node->data.suspend.block = ast_parse_block(pc, token_index, true);
681
682 return node;
683677}
684678
685679/*
......@@ -1025,7 +1019,7 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
10251019}
10261020
10271021/*
1028SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
1022SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?")
10291023FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
10301024ArrayAccessExpression : token(LBracket) Expression token(RBracket)
10311025SliceExpression = "[" Expression ".." option(Expression) "]"
......@@ -1110,13 +1104,34 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
11101104 } else if (first_token->id == TokenIdDot) {
11111105 *token_index += 1;
11121106
1113 Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
1107 Token *token = &pc->tokens->at(*token_index);
11141108
1115 AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
1116 node->data.field_access_expr.struct_expr = primary_expr;
1117 node->data.field_access_expr.field_name = token_buf(name_token);
1109 if (token->id == TokenIdSymbol) {
1110 *token_index += 1;
1111
1112 AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
1113 node->data.field_access_expr.struct_expr = primary_expr;
1114 node->data.field_access_expr.field_name = token_buf(token);
1115
1116 primary_expr = node;
1117 } else if (token->id == TokenIdStar) {
1118 *token_index += 1;
1119
1120 AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
1121 node->data.ptr_deref_expr.target = primary_expr;
1122
1123 primary_expr = node;
1124 } else if (token->id == TokenIdQuestion) {
1125 *token_index += 1;
1126
1127 AstNode *node = ast_create_node(pc, NodeTypeUnwrapOptional, first_token);
1128 node->data.unwrap_optional.expr = primary_expr;
1129
1130 primary_expr = node;
1131 } else {
1132 ast_invalid_token_error(pc, token);
1133 }
11181134
1119 primary_expr = node;
11201135 } else {
11211136 return primary_expr;
11221137 }
......@@ -1129,24 +1144,21 @@ static PrefixOp tok_to_prefix_op(Token *token) {
11291144 case TokenIdDash: return PrefixOpNegation;
11301145 case TokenIdMinusPercent: return PrefixOpNegationWrap;
11311146 case TokenIdTilde: return PrefixOpBinNot;
1132 case TokenIdStar: return PrefixOpDereference;
1133 case TokenIdMaybe: return PrefixOpMaybe;
1134 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
1135 case TokenIdStarStar: return PrefixOpDereference;
1147 case TokenIdQuestion: return PrefixOpOptional;
1148 case TokenIdAmpersand: return PrefixOpAddrOf;
11361149 default: return PrefixOpInvalid;
11371150 }
11381151}
11391152
1140static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
1141 Token *ampersand_tok = ast_eat_token(pc, token_index, TokenIdAmpersand);
1142
1143 AstNode *node = ast_create_node(pc, NodeTypeAddrOfExpr, ampersand_tok);
1153static AstNode *ast_parse_pointer_type(ParseContext *pc, size_t *token_index, Token *star_tok) {
1154 AstNode *node = ast_create_node(pc, NodeTypePointerType, star_tok);
1155 node->data.pointer_type.star_token = star_tok;
11441156
11451157 Token *token = &pc->tokens->at(*token_index);
11461158 if (token->id == TokenIdKeywordAlign) {
11471159 *token_index += 1;
11481160 ast_eat_token(pc, token_index, TokenIdLParen);
1149 node->data.addr_of_expr.align_expr = ast_parse_expression(pc, token_index, true);
1161 node->data.pointer_type.align_expr = ast_parse_expression(pc, token_index, true);
11501162
11511163 token = &pc->tokens->at(*token_index);
11521164 if (token->id == TokenIdColon) {
......@@ -1155,35 +1167,45 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
11551167 ast_eat_token(pc, token_index, TokenIdColon);
11561168 Token *bit_offset_end_tok = ast_eat_token(pc, token_index, TokenIdIntLiteral);
11571169
1158 node->data.addr_of_expr.bit_offset_start = token_bigint(bit_offset_start_tok);
1159 node->data.addr_of_expr.bit_offset_end = token_bigint(bit_offset_end_tok);
1170 node->data.pointer_type.bit_offset_start = token_bigint(bit_offset_start_tok);
1171 node->data.pointer_type.bit_offset_end = token_bigint(bit_offset_end_tok);
11601172 }
11611173 ast_eat_token(pc, token_index, TokenIdRParen);
11621174 token = &pc->tokens->at(*token_index);
11631175 }
11641176 if (token->id == TokenIdKeywordConst) {
11651177 *token_index += 1;
1166 node->data.addr_of_expr.is_const = true;
1178 node->data.pointer_type.is_const = true;
11671179
11681180 token = &pc->tokens->at(*token_index);
11691181 }
11701182 if (token->id == TokenIdKeywordVolatile) {
11711183 *token_index += 1;
1172 node->data.addr_of_expr.is_volatile = true;
1184 node->data.pointer_type.is_volatile = true;
11731185 }
11741186
1175 node->data.addr_of_expr.op_expr = ast_parse_prefix_op_expr(pc, token_index, true);
1187 node->data.pointer_type.op_expr = ast_parse_prefix_op_expr(pc, token_index, true);
11761188 return node;
11771189}
11781190
11791191/*
11801192PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
1181PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
1193PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
11821194*/
11831195static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
11841196 Token *token = &pc->tokens->at(*token_index);
1185 if (token->id == TokenIdAmpersand) {
1186 return ast_parse_addr_of(pc, token_index);
1197 if (token->id == TokenIdStar || token->id == TokenIdBracketStarBracket) {
1198 *token_index += 1;
1199 return ast_parse_pointer_type(pc, token_index, token);
1200 }
1201 if (token->id == TokenIdStarStar) {
1202 *token_index += 1;
1203 AstNode *child_node = ast_parse_pointer_type(pc, token_index, token);
1204 child_node->column += 1;
1205 AstNode *parent_node = ast_create_node(pc, NodeTypePointerType, token);
1206 parent_node->data.pointer_type.star_token = token;
1207 parent_node->data.pointer_type.op_expr = child_node;
1208 return parent_node;
11871209 }
11881210 if (token->id == TokenIdKeywordTry) {
11891211 return ast_parse_try_expr(pc, token_index);
......@@ -1200,22 +1222,12 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
12001222
12011223
12021224 AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
1203 AstNode *parent_node = node;
1204 if (token->id == TokenIdStarStar) {
1205 // pretend that we got 2 star tokens
1206
1207 parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
1208 parent_node->data.prefix_op_expr.primary_expr = node;
1209 parent_node->data.prefix_op_expr.prefix_op = PrefixOpDereference;
1210
1211 node->column += 1;
1212 }
12131225
12141226 AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
12151227 node->data.prefix_op_expr.primary_expr = prefix_op_expr;
12161228 node->data.prefix_op_expr.prefix_op = prefix_op;
12171229
1218 return parent_node;
1230 return node;
12191231}
12201232
12211233
......@@ -2270,8 +2282,8 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, size_t *token_index, bool ma
22702282}
22712283
22722284/*
2273UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
2274UnwrapMaybe : "??" BoolOrExpression
2285UnwrapExpression : BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
2286UnwrapOptional = "orelse" Expression
22752287UnwrapError = "catch" option("|" Symbol "|") Expression
22762288*/
22772289static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
......@@ -2281,14 +2293,14 @@ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, boo
22812293
22822294 Token *token = &pc->tokens->at(*token_index);
22832295
2284 if (token->id == TokenIdDoubleQuestion) {
2296 if (token->id == TokenIdKeywordOrElse) {
22852297 *token_index += 1;
22862298
22872299 AstNode *rhs = ast_parse_expression(pc, token_index, true);
22882300
22892301 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
22902302 node->data.bin_op_expr.op1 = lhs;
2291 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
2303 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapOptional;
22922304 node->data.bin_op_expr.op2 = rhs;
22932305
22942306 return node;
......@@ -2991,6 +3003,12 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
29913003 case NodeTypeFieldAccessExpr:
29923004 visit_field(&node->data.field_access_expr.struct_expr, visit, context);
29933005 break;
3006 case NodeTypePtrDeref:
3007 visit_field(&node->data.ptr_deref_expr.target, visit, context);
3008 break;
3009 case NodeTypeUnwrapOptional:
3010 visit_field(&node->data.unwrap_optional.expr, visit, context);
3011 break;
29943012 case NodeTypeUse:
29953013 visit_field(&node->data.use.expr, visit, context);
29963014 break;
......@@ -3093,9 +3111,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30933111 case NodeTypeErrorType:
30943112 // none
30953113 break;
3096 case NodeTypeAddrOfExpr:
3097 visit_field(&node->data.addr_of_expr.align_expr, visit, context);
3098 visit_field(&node->data.addr_of_expr.op_expr, visit, context);
3114 case NodeTypePointerType:
3115 visit_field(&node->data.pointer_type.align_expr, visit, context);
3116 visit_field(&node->data.pointer_type.op_expr, visit, context);
30993117 break;
31003118 case NodeTypeErrorSetDecl:
31013119 visit_node_list(&node->data.err_set_decl.decls, visit, context);
......@@ -3110,7 +3128,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
31103128 visit_field(&node->data.await_expr.expr, visit, context);
31113129 break;
31123130 case NodeTypeSuspend:
3113 visit_field(&node->data.suspend.promise_symbol, visit, context);
31143131 visit_field(&node->data.suspend.block, visit, context);
31153132 break;
31163133 }
src/target.cpp+103-18
......@@ -597,12 +597,15 @@ void resolve_target_object_format(ZigTarget *target) {
597597 case ZigLLVM_tce:
598598 case ZigLLVM_tcele:
599599 case ZigLLVM_thumbeb:
600 case ZigLLVM_wasm32:
601 case ZigLLVM_wasm64:
602600 case ZigLLVM_xcore:
603601 target->oformat= ZigLLVM_ELF;
604602 return;
605603
604 case ZigLLVM_wasm32:
605 case ZigLLVM_wasm64:
606 target->oformat = ZigLLVM_Wasm;
607 return;
608
606609 case ZigLLVM_ppc:
607610 case ZigLLVM_ppc64:
608611 if (is_os_darwin(target)) {
......@@ -683,25 +686,46 @@ static int get_arch_pointer_bit_width(ZigLLVM_ArchType arch) {
683686uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
684687 switch (target->os) {
685688 case OsFreestanding:
686 switch (id) {
687 case CIntTypeShort:
688 case CIntTypeUShort:
689 return 16;
690 case CIntTypeInt:
691 case CIntTypeUInt:
692 return 32;
693 case CIntTypeLong:
694 case CIntTypeULong:
695 return get_arch_pointer_bit_width(target->arch.arch);
696 case CIntTypeLongLong:
697 case CIntTypeULongLong:
698 return 64;
699 case CIntTypeCount:
700 zig_unreachable();
689 switch (target->arch.arch) {
690 case ZigLLVM_msp430:
691 switch (id) {
692 case CIntTypeShort:
693 case CIntTypeUShort:
694 return 16;
695 case CIntTypeInt:
696 case CIntTypeUInt:
697 return 16;
698 case CIntTypeLong:
699 case CIntTypeULong:
700 return 32;
701 case CIntTypeLongLong:
702 case CIntTypeULongLong:
703 return 64;
704 case CIntTypeCount:
705 zig_unreachable();
706 }
707 default:
708 switch (id) {
709 case CIntTypeShort:
710 case CIntTypeUShort:
711 return 16;
712 case CIntTypeInt:
713 case CIntTypeUInt:
714 return 32;
715 case CIntTypeLong:
716 case CIntTypeULong:
717 return get_arch_pointer_bit_width(target->arch.arch);
718 case CIntTypeLongLong:
719 case CIntTypeULongLong:
720 return 64;
721 case CIntTypeCount:
722 zig_unreachable();
723 }
701724 }
702725 case OsLinux:
703726 case OsMacOSX:
704727 case OsZen:
728 case OsOpenBSD:
705729 switch (id) {
706730 case CIntTypeShort:
707731 case CIntTypeUShort:
......@@ -742,7 +766,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
742766 case OsKFreeBSD:
743767 case OsLv2:
744768 case OsNetBSD:
745 case OsOpenBSD:
746769 case OsSolaris:
747770 case OsHaiku:
748771 case OsMinix:
......@@ -896,3 +919,65 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
896919
897920 return false;
898921}
922
923const char *arch_stack_pointer_register_name(const ArchType *arch) {
924 switch (arch->arch) {
925 case ZigLLVM_UnknownArch:
926 zig_unreachable();
927 case ZigLLVM_x86:
928 return "sp";
929 case ZigLLVM_x86_64:
930 return "rsp";
931
932 case ZigLLVM_aarch64:
933 case ZigLLVM_arm:
934 case ZigLLVM_thumb:
935 case ZigLLVM_aarch64_be:
936 case ZigLLVM_amdgcn:
937 case ZigLLVM_amdil:
938 case ZigLLVM_amdil64:
939 case ZigLLVM_armeb:
940 case ZigLLVM_arc:
941 case ZigLLVM_avr:
942 case ZigLLVM_bpfeb:
943 case ZigLLVM_bpfel:
944 case ZigLLVM_hexagon:
945 case ZigLLVM_lanai:
946 case ZigLLVM_hsail:
947 case ZigLLVM_hsail64:
948 case ZigLLVM_kalimba:
949 case ZigLLVM_le32:
950 case ZigLLVM_le64:
951 case ZigLLVM_mips:
952 case ZigLLVM_mips64:
953 case ZigLLVM_mips64el:
954 case ZigLLVM_mipsel:
955 case ZigLLVM_msp430:
956 case ZigLLVM_nios2:
957 case ZigLLVM_nvptx:
958 case ZigLLVM_nvptx64:
959 case ZigLLVM_ppc64le:
960 case ZigLLVM_r600:
961 case ZigLLVM_renderscript32:
962 case ZigLLVM_renderscript64:
963 case ZigLLVM_riscv32:
964 case ZigLLVM_riscv64:
965 case ZigLLVM_shave:
966 case ZigLLVM_sparc:
967 case ZigLLVM_sparcel:
968 case ZigLLVM_sparcv9:
969 case ZigLLVM_spir:
970 case ZigLLVM_spir64:
971 case ZigLLVM_systemz:
972 case ZigLLVM_tce:
973 case ZigLLVM_tcele:
974 case ZigLLVM_thumbeb:
975 case ZigLLVM_wasm32:
976 case ZigLLVM_wasm64:
977 case ZigLLVM_xcore:
978 case ZigLLVM_ppc:
979 case ZigLLVM_ppc64:
980 zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
981 }
982 zig_unreachable();
983}
src/target.hpp+2
......@@ -77,6 +77,8 @@ size_t target_arch_count(void);
7777const ArchType *get_target_arch(size_t index);
7878void get_arch_name(char *out_str, const ArchType *arch);
7979
80const char *arch_stack_pointer_register_name(const ArchType *arch);
81
8082size_t target_vendor_count(void);
8183ZigLLVM_VendorType get_target_vendor(size_t index);
8284
src/tokenizer.cpp+59-39
......@@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = {
134134 {"noalias", TokenIdKeywordNoAlias},
135135 {"null", TokenIdKeywordNull},
136136 {"or", TokenIdKeywordOr},
137 {"orelse", TokenIdKeywordOrElse},
137138 {"packed", TokenIdKeywordPacked},
138139 {"promise", TokenIdKeywordPromise},
139140 {"pub", TokenIdKeywordPub},
......@@ -215,10 +216,11 @@ enum TokenizeState {
215216 TokenizeStateSawGreaterThanGreaterThan,
216217 TokenizeStateSawDot,
217218 TokenizeStateSawDotDot,
218 TokenizeStateSawQuestionMark,
219219 TokenizeStateSawAtSign,
220220 TokenizeStateCharCode,
221221 TokenizeStateError,
222 TokenizeStateLBracket,
223 TokenizeStateLBracketStar,
222224};
223225
224226
......@@ -355,12 +357,19 @@ static void end_float_token(Tokenize *t) {
355357 // Mask the sign bit to 0 since always non-negative lex
356358 const uint64_t exp_mask = 0xffffull << exp_shift;
357359
358 if (shift >= 64) {
360 // must be special-cased to avoid undefined behavior on shift == 64
361 if (shift == 128) {
362 f_bits.repr[0] = 0;
363 f_bits.repr[1] = sig_bits[0];
364 } else if (shift == 0) {
365 f_bits.repr[0] = sig_bits[0];
366 f_bits.repr[1] = sig_bits[1];
367 } else if (shift >= 64) {
359368 f_bits.repr[0] = 0;
360369 f_bits.repr[1] = sig_bits[0] << (shift - 64);
361370 } else {
362371 f_bits.repr[0] = sig_bits[0] << shift;
363 f_bits.repr[1] = ((sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift)));
372 f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
364373 }
365374
366375 f_bits.repr[1] &= ~exp_mask;
......@@ -451,16 +460,21 @@ static const char* get_escape_shorthand(uint8_t c) {
451460static void invalid_char_error(Tokenize *t, uint8_t c) {
452461 if (c == '\r') {
453462 tokenize_error(t, "invalid carriage return, only '\\n' line endings are supported");
454 } else if (isprint(c)) {
463 return;
464 }
465
466 const char *sh = get_escape_shorthand(c);
467 if (sh) {
468 tokenize_error(t, "invalid character: '%s'", sh);
469 return;
470 }
471
472 if (isprint(c)) {
455473 tokenize_error(t, "invalid character: '%c'", c);
456 } else {
457 const char *sh = get_escape_shorthand(c);
458 if (sh) {
459 tokenize_error(t, "invalid character: '%s'", sh);
460 } else {
461 tokenize_error(t, "invalid character: '\\x%x'", c);
462 }
474 return;
463475 }
476
477 tokenize_error(t, "invalid character: '\\x%02x'", c);
464478}
465479
466480void tokenize(Buf *buf, Tokenization *out) {
......@@ -530,6 +544,10 @@ void tokenize(Buf *buf, Tokenization *out) {
530544 begin_token(&t, TokenIdComma);
531545 end_token(&t);
532546 break;
547 case '?':
548 begin_token(&t, TokenIdQuestion);
549 end_token(&t);
550 break;
533551 case '{':
534552 begin_token(&t, TokenIdLBrace);
535553 end_token(&t);
......@@ -539,8 +557,8 @@ void tokenize(Buf *buf, Tokenization *out) {
539557 end_token(&t);
540558 break;
541559 case '[':
560 t.state = TokenizeStateLBracket;
542561 begin_token(&t, TokenIdLBracket);
543 end_token(&t);
544562 break;
545563 case ']':
546564 begin_token(&t, TokenIdRBracket);
......@@ -622,33 +640,10 @@ void tokenize(Buf *buf, Tokenization *out) {
622640 begin_token(&t, TokenIdDot);
623641 t.state = TokenizeStateSawDot;
624642 break;
625 case '?':
626 begin_token(&t, TokenIdMaybe);
627 t.state = TokenizeStateSawQuestionMark;
628 break;
629643 default:
630644 invalid_char_error(&t, c);
631645 }
632646 break;
633 case TokenizeStateSawQuestionMark:
634 switch (c) {
635 case '?':
636 set_token_id(&t, t.cur_tok, TokenIdDoubleQuestion);
637 end_token(&t);
638 t.state = TokenizeStateStart;
639 break;
640 case '=':
641 set_token_id(&t, t.cur_tok, TokenIdMaybeAssign);
642 end_token(&t);
643 t.state = TokenizeStateStart;
644 break;
645 default:
646 t.pos -= 1;
647 end_token(&t);
648 t.state = TokenizeStateStart;
649 continue;
650 }
651 break;
652647 case TokenizeStateSawDot:
653648 switch (c) {
654649 case '.':
......@@ -852,6 +847,30 @@ void tokenize(Buf *buf, Tokenization *out) {
852847 continue;
853848 }
854849 break;
850 case TokenizeStateLBracket:
851 switch (c) {
852 case '*':
853 t.state = TokenizeStateLBracketStar;
854 set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
855 break;
856 default:
857 // reinterpret as just an lbracket
858 t.pos -= 1;
859 end_token(&t);
860 t.state = TokenizeStateStart;
861 continue;
862 }
863 break;
864 case TokenizeStateLBracketStar:
865 switch (c) {
866 case ']':
867 end_token(&t);
868 t.state = TokenizeStateStart;
869 break;
870 default:
871 invalid_char_error(&t, c);
872 }
873 break;
855874 case TokenizeStateSawPlusPercent:
856875 switch (c) {
857876 case '=':
......@@ -1459,7 +1478,6 @@ void tokenize(Buf *buf, Tokenization *out) {
14591478 case TokenizeStateSawGreaterThan:
14601479 case TokenizeStateSawGreaterThanGreaterThan:
14611480 case TokenizeStateSawDot:
1462 case TokenizeStateSawQuestionMark:
14631481 case TokenizeStateSawAtSign:
14641482 case TokenizeStateSawStarPercent:
14651483 case TokenizeStateSawPlusPercent:
......@@ -1467,12 +1485,14 @@ void tokenize(Buf *buf, Tokenization *out) {
14671485 case TokenizeStateLineString:
14681486 case TokenizeStateLineStringEnd:
14691487 case TokenizeStateSawBarBar:
1488 case TokenizeStateLBracket:
14701489 end_token(&t);
14711490 break;
14721491 case TokenizeStateSawDotDot:
14731492 case TokenizeStateSawBackslash:
14741493 case TokenizeStateLineStringContinue:
14751494 case TokenizeStateLineStringContinueC:
1495 case TokenizeStateLBracketStar:
14761496 tokenize_error(&t, "unexpected EOF");
14771497 break;
14781498 case TokenizeStateLineComment:
......@@ -1509,6 +1529,7 @@ const char * token_name(TokenId id) {
15091529 case TokenIdBitShiftRight: return ">>";
15101530 case TokenIdBitShiftRightEq: return ">>=";
15111531 case TokenIdBitXorEq: return "^=";
1532 case TokenIdBracketStarBracket: return "[*]";
15121533 case TokenIdCharLiteral: return "CharLiteral";
15131534 case TokenIdCmpEq: return "==";
15141535 case TokenIdCmpGreaterOrEq: return ">=";
......@@ -1521,7 +1542,6 @@ const char * token_name(TokenId id) {
15211542 case TokenIdDash: return "-";
15221543 case TokenIdDivEq: return "/=";
15231544 case TokenIdDot: return ".";
1524 case TokenIdDoubleQuestion: return "??";
15251545 case TokenIdEllipsis2: return "..";
15261546 case TokenIdEllipsis3: return "...";
15271547 case TokenIdEof: return "EOF";
......@@ -1558,6 +1578,7 @@ const char * token_name(TokenId id) {
15581578 case TokenIdKeywordNoAlias: return "noalias";
15591579 case TokenIdKeywordNull: return "null";
15601580 case TokenIdKeywordOr: return "or";
1581 case TokenIdKeywordOrElse: return "orelse";
15611582 case TokenIdKeywordPacked: return "packed";
15621583 case TokenIdKeywordPromise: return "promise";
15631584 case TokenIdKeywordPub: return "pub";
......@@ -1580,8 +1601,7 @@ const char * token_name(TokenId id) {
15801601 case TokenIdLBrace: return "{";
15811602 case TokenIdLBracket: return "[";
15821603 case TokenIdLParen: return "(";
1583 case TokenIdMaybe: return "?";
1584 case TokenIdMaybeAssign: return "?=";
1604 case TokenIdQuestion: return "?";
15851605 case TokenIdMinusEq: return "-=";
15861606 case TokenIdMinusPercent: return "-%";
15871607 case TokenIdMinusPercentEq: return "-%=";
src/tokenizer.hpp+5-3
......@@ -28,6 +28,7 @@ enum TokenId {
2828 TokenIdBitShiftRight,
2929 TokenIdBitShiftRightEq,
3030 TokenIdBitXorEq,
31 TokenIdBracketStarBracket,
3132 TokenIdCharLiteral,
3233 TokenIdCmpEq,
3334 TokenIdCmpGreaterOrEq,
......@@ -40,7 +41,6 @@ enum TokenId {
4041 TokenIdDash,
4142 TokenIdDivEq,
4243 TokenIdDot,
43 TokenIdDoubleQuestion,
4444 TokenIdEllipsis2,
4545 TokenIdEllipsis3,
4646 TokenIdEof,
......@@ -75,6 +75,7 @@ enum TokenId {
7575 TokenIdKeywordNoAlias,
7676 TokenIdKeywordNull,
7777 TokenIdKeywordOr,
78 TokenIdKeywordOrElse,
7879 TokenIdKeywordPacked,
7980 TokenIdKeywordPromise,
8081 TokenIdKeywordPub,
......@@ -99,8 +100,7 @@ enum TokenId {
99100 TokenIdLBrace,
100101 TokenIdLBracket,
101102 TokenIdLParen,
102 TokenIdMaybe,
103 TokenIdMaybeAssign,
103 TokenIdQuestion,
104104 TokenIdMinusEq,
105105 TokenIdMinusPercent,
106106 TokenIdMinusPercentEq,
......@@ -169,6 +169,8 @@ struct Token {
169169 TokenCharLit char_lit;
170170 } data;
171171};
172// work around conflicting name Token which is also found in libclang
173typedef Token ZigToken;
172174
173175struct Tokenization {
174176 ZigList<Token> *tokens;
src/translate_c.cpp+192-138
......@@ -247,6 +247,12 @@ static AstNode *trans_create_node_field_access_str(Context *c, AstNode *containe
247247 return trans_create_node_field_access(c, container, buf_create_from_str(field_name));
248248}
249249
250static AstNode *trans_create_node_ptr_deref(Context *c, AstNode *child_node) {
251 AstNode *node = trans_create_node(c, NodeTypePtrDeref);
252 node->data.ptr_deref_expr.target = child_node;
253 return node;
254}
255
250256static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {
251257 AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
252258 node->data.prefix_op_expr.prefix_op = op;
......@@ -254,6 +260,12 @@ static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *ch
254260 return node;
255261}
256262
263static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child_node) {
264 AstNode *node = trans_create_node(c, NodeTypeUnwrapOptional);
265 node->data.unwrap_optional.expr = child_node;
266 return node;
267}
268
257269static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) {
258270 AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
259271 node->data.bin_op_expr.op1 = lhs_node;
......@@ -270,11 +282,21 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod
270282 node);
271283}
272284
273static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) {
274 AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr);
275 node->data.addr_of_expr.is_const = is_const;
276 node->data.addr_of_expr.is_volatile = is_volatile;
277 node->data.addr_of_expr.op_expr = child_node;
285static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) {
286 AstNode *node = trans_create_node(c, NodeTypePointerType);
287 node->data.pointer_type.star_token = allocate<ZigToken>(1);
288 node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket;
289 node->data.pointer_type.is_const = is_const;
290 node->data.pointer_type.is_const = is_const;
291 node->data.pointer_type.is_volatile = is_volatile;
292 node->data.pointer_type.op_expr = child_node;
293 return node;
294}
295
296static AstNode *trans_create_node_addr_of(Context *c, AstNode *child_node) {
297 AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
298 node->data.prefix_op_expr.prefix_op = PrefixOpAddrOf;
299 node->data.prefix_op_expr.primary_expr = child_node;
278300 return node;
279301}
280302
......@@ -366,7 +388,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
366388 fn_def->data.fn_def.fn_proto = fn_proto;
367389 fn_proto->data.fn_proto.fn_def_node = fn_def;
368390
369 AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
391 AstNode *unwrap_node = trans_create_node_unwrap_null(c, ref_node);
370392 AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
371393 fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
372394
......@@ -393,10 +415,6 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
393415 return fn_def;
394416}
395417
396static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) {
397 return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child);
398}
399
400418static AstNode *get_global(Context *c, Buf *name) {
401419 {
402420 auto entry = c->global_table.maybe_get(name);
......@@ -409,7 +427,7 @@ static AstNode *get_global(Context *c, Buf *name) {
409427 if (entry)
410428 return entry->value;
411429 }
412 if (c->codegen->primitive_type_table.maybe_get(name) != nullptr) {
430 if (get_primitive_type(c->codegen, name) != nullptr) {
413431 return trans_create_node_symbol(c, name);
414432 }
415433 return nullptr;
......@@ -718,6 +736,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) {
718736 }
719737}
720738
739static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) {
740 switch (ty->getTypeClass()) {
741 case Type::Builtin: {
742 const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
743 return builtin_ty->getKind() == BuiltinType::Void;
744 }
745 case Type::Record: {
746 const RecordType *record_ty = static_cast<const RecordType*>(ty);
747 return record_ty->getDecl()->getDefinition() == nullptr;
748 }
749 case Type::Elaborated: {
750 const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
751 return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc);
752 }
753 case Type::Typedef: {
754 const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
755 const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
756 return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc);
757 }
758 default:
759 return false;
760 }
761}
762
721763static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) {
722764 switch (ty->getTypeClass()) {
723765 case Type::Builtin:
......@@ -839,12 +881,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
839881 }
840882
841883 if (qual_type_child_is_fn_proto(child_qt)) {
842 return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node);
884 return trans_create_node_prefix_op(c, PrefixOpOptional, child_node);
843885 }
844886
845 AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(),
846 child_qt.isVolatileQualified(), child_node);
847 return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node);
887 PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown;
888
889 AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
890 child_qt.isVolatileQualified(), child_node, ptr_len);
891 return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
848892 }
849893 case Type::Typedef:
850894 {
......@@ -1027,8 +1071,8 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
10271071 emit_warning(c, source_loc, "unresolved array element type");
10281072 return nullptr;
10291073 }
1030 AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(),
1031 child_qt.isVolatileQualified(), child_type_node);
1074 AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
1075 child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown);
10321076 return pointer_node;
10331077 }
10341078 case Type::BlockPointer:
......@@ -1396,7 +1440,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
13961440 // const _ref = &lhs;
13971441 AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
13981442 if (lhs == nullptr) return nullptr;
1399 AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
1443 AstNode *addr_of_lhs = trans_create_node_addr_of(c, lhs);
14001444 // TODO: avoid name collisions with generated variable names
14011445 Buf* tmp_var_name = buf_create_from_str("_ref");
14021446 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
......@@ -1412,8 +1456,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
14121456 AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
14131457 stmt->getComputationLHSType(),
14141458 stmt->getLHS()->getType(),
1415 trans_create_node_prefix_op(c, PrefixOpDereference,
1416 trans_create_node_symbol(c, tmp_var_name)));
1459 trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name)));
14171460
14181461 // result_type(... >> u5(rhs))
14191462 AstNode *result_type_cast = trans_c_cast(c, rhs_location,
......@@ -1426,7 +1469,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
14261469
14271470 // *_ref = ...
14281471 AstNode *assign_statement = trans_create_node_bin_op(c,
1429 trans_create_node_prefix_op(c, PrefixOpDereference,
1472 trans_create_node_ptr_deref(c,
14301473 trans_create_node_symbol(c, tmp_var_name)),
14311474 BinOpTypeAssign, result_type_cast);
14321475
......@@ -1436,7 +1479,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
14361479 // break :x *_ref
14371480 child_scope->node->data.block.statements.append(
14381481 trans_create_node_break(c, label_name,
1439 trans_create_node_prefix_op(c, PrefixOpDereference,
1482 trans_create_node_ptr_deref(c,
14401483 trans_create_node_symbol(c, tmp_var_name))));
14411484 }
14421485
......@@ -1471,7 +1514,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
14711514 // const _ref = &lhs;
14721515 AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
14731516 if (lhs == nullptr) return nullptr;
1474 AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
1517 AstNode *addr_of_lhs = trans_create_node_addr_of(c, lhs);
14751518 // TODO: avoid name collisions with generated variable names
14761519 Buf* tmp_var_name = buf_create_from_str("_ref");
14771520 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
......@@ -1483,11 +1526,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
14831526 if (rhs == nullptr) return nullptr;
14841527
14851528 AstNode *assign_statement = trans_create_node_bin_op(c,
1486 trans_create_node_prefix_op(c, PrefixOpDereference,
1529 trans_create_node_ptr_deref(c,
14871530 trans_create_node_symbol(c, tmp_var_name)),
14881531 BinOpTypeAssign,
14891532 trans_create_node_bin_op(c,
1490 trans_create_node_prefix_op(c, PrefixOpDereference,
1533 trans_create_node_ptr_deref(c,
14911534 trans_create_node_symbol(c, tmp_var_name)),
14921535 bin_op,
14931536 rhs));
......@@ -1496,7 +1539,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
14961539 // break :x *_ref
14971540 child_scope->node->data.block.statements.append(
14981541 trans_create_node_break(c, label_name,
1499 trans_create_node_prefix_op(c, PrefixOpDereference,
1542 trans_create_node_ptr_deref(c,
15001543 trans_create_node_symbol(c, tmp_var_name))));
15011544
15021545 return child_scope->node;
......@@ -1808,7 +1851,7 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
18081851 // const _ref = &expr;
18091852 AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
18101853 if (expr == nullptr) return nullptr;
1811 AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
1854 AstNode *addr_of_expr = trans_create_node_addr_of(c, expr);
18121855 // TODO: avoid name collisions with generated variable names
18131856 Buf* ref_var_name = buf_create_from_str("_ref");
18141857 AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
......@@ -1817,13 +1860,13 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
18171860 // const _tmp = *_ref;
18181861 Buf* tmp_var_name = buf_create_from_str("_tmp");
18191862 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
1820 trans_create_node_prefix_op(c, PrefixOpDereference,
1863 trans_create_node_ptr_deref(c,
18211864 trans_create_node_symbol(c, ref_var_name)));
18221865 child_scope->node->data.block.statements.append(tmp_var_decl);
18231866
18241867 // *_ref += 1;
18251868 AstNode *assign_statement = trans_create_node_bin_op(c,
1826 trans_create_node_prefix_op(c, PrefixOpDereference,
1869 trans_create_node_ptr_deref(c,
18271870 trans_create_node_symbol(c, ref_var_name)),
18281871 assign_op,
18291872 trans_create_node_unsigned(c, 1));
......@@ -1863,7 +1906,7 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
18631906 // const _ref = &expr;
18641907 AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
18651908 if (expr == nullptr) return nullptr;
1866 AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
1909 AstNode *addr_of_expr = trans_create_node_addr_of(c, expr);
18671910 // TODO: avoid name collisions with generated variable names
18681911 Buf* ref_var_name = buf_create_from_str("_ref");
18691912 AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
......@@ -1871,14 +1914,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
18711914
18721915 // *_ref += 1;
18731916 AstNode *assign_statement = trans_create_node_bin_op(c,
1874 trans_create_node_prefix_op(c, PrefixOpDereference,
1917 trans_create_node_ptr_deref(c,
18751918 trans_create_node_symbol(c, ref_var_name)),
18761919 assign_op,
18771920 trans_create_node_unsigned(c, 1));
18781921 child_scope->node->data.block.statements.append(assign_statement);
18791922
18801923 // break :x *_ref
1881 AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
1924 AstNode *deref_expr = trans_create_node_ptr_deref(c,
18821925 trans_create_node_symbol(c, ref_var_name));
18831926 child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
18841927
......@@ -1912,7 +1955,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
19121955 AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue);
19131956 if (value_node == nullptr)
19141957 return value_node;
1915 return trans_create_node_addr_of(c, false, false, value_node);
1958 return trans_create_node_addr_of(c, value_node);
19161959 }
19171960 case UO_Deref:
19181961 {
......@@ -1922,8 +1965,8 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
19221965 bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType());
19231966 if (is_fn_ptr)
19241967 return value_node;
1925 AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
1926 return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped);
1968 AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node);
1969 return trans_create_node_ptr_deref(c, unwrapped);
19271970 }
19281971 case UO_Plus:
19291972 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
......@@ -2546,7 +2589,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
25462589 }
25472590 }
25482591 if (callee_node == nullptr) {
2549 callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
2592 callee_node = trans_create_node_unwrap_null(c, callee_raw_node);
25502593 }
25512594 } else {
25522595 callee_node = callee_raw_node;
......@@ -2664,7 +2707,9 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt
26642707 AstNode *child_statement;
26652708 child_scope = trans_stmt(c, &child_block_scope->base, stmt->getBody(), &child_statement);
26662709 if (child_scope == nullptr) return nullptr;
2667 body_node->data.block.statements.append(child_statement);
2710 if (child_statement != nullptr) {
2711 body_node->data.block.statements.append(child_statement);
2712 }
26682713 }
26692714
26702715 // if (!cond) break;
......@@ -2674,6 +2719,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt
26742719 terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node);
26752720 terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak);
26762721
2722 assert(terminator_node != nullptr);
26772723 body_node->data.block.statements.append(terminator_node);
26782724
26792725 while_scope->node->data.while_expr.body = body_node;
......@@ -2737,7 +2783,12 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
27372783 TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), &body_statement);
27382784 if (body_scope == nullptr)
27392785 return nullptr;
2740 while_scope->node->data.while_expr.body = body_statement;
2786
2787 if (body_statement == nullptr) {
2788 while_scope->node->data.while_expr.body = trans_create_node(c, NodeTypeBlock);
2789 } else {
2790 while_scope->node->data.while_expr.body = body_statement;
2791 }
27412792
27422793 return loop_block_node;
27432794}
......@@ -2972,9 +3023,14 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
29723023 trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt));
29733024 case Stmt::DeclStmtClass:
29743025 return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope);
2975 case Stmt::WhileStmtClass:
2976 return wrap_stmt(out_node, out_child_scope, scope,
2977 trans_while_loop(c, scope, (const WhileStmt *)stmt));
3026 case Stmt::WhileStmtClass: {
3027 AstNode *while_node = trans_while_loop(c, scope, (const WhileStmt *)stmt);
3028 assert(while_node->type == NodeTypeWhileExpr);
3029 if (while_node->data.while_expr.body == nullptr) {
3030 while_node->data.while_expr.body = trans_create_node(c, NodeTypeBlock);
3031 }
3032 return wrap_stmt(out_node, out_child_scope, scope, while_node);
3033 }
29783034 case Stmt::IfStmtClass:
29793035 return wrap_stmt(out_node, out_child_scope, scope,
29803036 trans_if_statement(c, scope, (const IfStmt *)stmt));
......@@ -2997,12 +3053,18 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
29973053 case Stmt::UnaryExprOrTypeTraitExprClass:
29983054 return wrap_stmt(out_node, out_child_scope, scope,
29993055 trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt));
3000 case Stmt::DoStmtClass:
3001 return wrap_stmt(out_node, out_child_scope, scope,
3002 trans_do_loop(c, scope, (const DoStmt *)stmt));
3003 case Stmt::ForStmtClass:
3004 return wrap_stmt(out_node, out_child_scope, scope,
3005 trans_for_loop(c, scope, (const ForStmt *)stmt));
3056 case Stmt::DoStmtClass: {
3057 AstNode *while_node = trans_do_loop(c, scope, (const DoStmt *)stmt);
3058 assert(while_node->type == NodeTypeWhileExpr);
3059 if (while_node->data.while_expr.body == nullptr) {
3060 while_node->data.while_expr.body = trans_create_node(c, NodeTypeBlock);
3061 }
3062 return wrap_stmt(out_node, out_child_scope, scope, while_node);
3063 }
3064 case Stmt::ForStmtClass: {
3065 AstNode *node = trans_for_loop(c, scope, (const ForStmt *)stmt);
3066 return wrap_stmt(out_node, out_child_scope, scope, node);
3067 }
30063068 case Stmt::StringLiteralClass:
30073069 return wrap_stmt(out_node, out_child_scope, scope,
30083070 trans_string_literal(c, scope, (const StringLiteral *)stmt));
......@@ -3667,6 +3729,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
36673729 if (existing_entry) {
36683730 return existing_entry->value;
36693731 }
3732
36703733 QualType child_qt = typedef_decl->getUnderlyingType();
36713734 Buf *type_name = buf_create_from_str(decl_name(typedef_decl));
36723735
......@@ -3700,16 +3763,19 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
37003763 // use the name of this typedef
37013764 // TODO
37023765
3766 // trans_qual_type here might cause us to look at this typedef again so we put the item in the map first
3767 AstNode *symbol_node = trans_create_node_symbol(c, type_name);
3768 c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node);
3769
37033770 AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation());
37043771 if (type_node == nullptr) {
37053772 emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name));
37063773 c->decl_table.put(typedef_decl, nullptr);
3774 // TODO add global var with type_name equal to @compileError("unable to resolve C type")
37073775 return nullptr;
37083776 }
37093777 add_global_var(c, type_name, type_node);
37103778
3711 AstNode *symbol_node = trans_create_node_symbol(c, type_name);
3712 c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node);
37133779 return symbol_node;
37143780}
37153781
......@@ -3744,6 +3810,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
37443810 return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);
37453811 }
37463812
3813
37473814 bool pure_enum = true;
37483815 uint32_t field_count = 0;
37493816 for (auto it = enum_def->enumerator_begin(),
......@@ -3755,84 +3822,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
37553822 pure_enum = false;
37563823 }
37573824 }
3758
37593825 AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation());
37603826 assert(tag_int_type);
37613827
3762 if (pure_enum) {
3763 AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
3764 enum_node->data.container_decl.kind = ContainerKindEnum;
3765 enum_node->data.container_decl.layout = ContainerLayoutExtern;
3766 // TODO only emit this tag type if the enum tag type is not the default.
3767 // I don't know what the default is, need to figure out how clang is deciding.
3768 // it appears to at least be different across gcc/msvc
3769 if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
3770 !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
3771 {
3772 enum_node->data.container_decl.init_arg_expr = tag_int_type;
3773 }
3774
3775 enum_node->data.container_decl.fields.resize(field_count);
3776 uint32_t i = 0;
3777 for (auto it = enum_def->enumerator_begin(),
3778 it_end = enum_def->enumerator_end();
3779 it != it_end; ++it, i += 1)
3780 {
3781 const EnumConstantDecl *enum_const = *it;
3782
3783 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
3784 Buf *field_name;
3785 if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
3786 field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
3787 } else {
3788 field_name = enum_val_name;
3789 }
3790
3791 AstNode *field_node = trans_create_node(c, NodeTypeStructField);
3792 field_node->data.struct_field.name = field_name;
3793 field_node->data.struct_field.type = nullptr;
3794 enum_node->data.container_decl.fields.items[i] = field_node;
3795
3796 // in C each enum value is in the global namespace. so we put them there too.
3797 // at this point we can rely on the enum emitting successfully
3798 if (is_anonymous) {
3799 AstNode *lit_node = trans_create_node_unsigned(c, i);
3800 add_global_var(c, enum_val_name, lit_node);
3801 } else {
3802 AstNode *field_access_node = trans_create_node_field_access(c,
3803 trans_create_node_symbol(c, full_type_name), field_name);
3804 add_global_var(c, enum_val_name, field_access_node);
3805 }
3806 }
3807
3808 if (is_anonymous) {
3809 c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node);
3810 return enum_node;
3811 } else {
3812 AstNode *symbol_node = trans_create_node_symbol(c, full_type_name);
3813 add_global_weak_alias(c, bare_name, full_type_name);
3814 add_global_var(c, full_type_name, enum_node);
3815 c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
3816 return enum_node;
3817 }
3828 AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
3829 enum_node->data.container_decl.kind = ContainerKindEnum;
3830 enum_node->data.container_decl.layout = ContainerLayoutExtern;
3831 // TODO only emit this tag type if the enum tag type is not the default.
3832 // I don't know what the default is, need to figure out how clang is deciding.
3833 // it appears to at least be different across gcc/msvc
3834 if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
3835 !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
3836 {
3837 enum_node->data.container_decl.init_arg_expr = tag_int_type;
38183838 }
3819
3820 // TODO after issue #305 is solved, make this be an enum with tag_int_type
3821 // as the integer type and set the custom enum values
3822 AstNode *enum_node = tag_int_type;
3823
3824
3825 // add variables for all the values with enum_node
3839 enum_node->data.container_decl.fields.resize(field_count);
3840 uint32_t i = 0;
38263841 for (auto it = enum_def->enumerator_begin(),
38273842 it_end = enum_def->enumerator_end();
3828 it != it_end; ++it)
3843 it != it_end; ++it, i += 1)
38293844 {
38303845 const EnumConstantDecl *enum_const = *it;
38313846
38323847 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
3833 AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal());
3834 AstNode *var_node = add_global_var(c, enum_val_name, int_node);
3835 var_node->data.variable_declaration.type = tag_int_type;
3848 Buf *field_name;
3849 if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
3850 field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
3851 } else {
3852 field_name = enum_val_name;
3853 }
3854
3855 AstNode *int_node = pure_enum && !is_anonymous ? nullptr : trans_create_node_apint(c, enum_const->getInitVal());
3856 AstNode *field_node = trans_create_node(c, NodeTypeStructField);
3857 field_node->data.struct_field.name = field_name;
3858 field_node->data.struct_field.type = nullptr;
3859 field_node->data.struct_field.value = int_node;
3860 enum_node->data.container_decl.fields.items[i] = field_node;
3861
3862 // in C each enum value is in the global namespace. so we put them there too.
3863 // at this point we can rely on the enum emitting successfully
3864 if (is_anonymous) {
3865 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
3866 add_global_var(c, enum_val_name, int_node);
3867 } else {
3868 AstNode *field_access_node = trans_create_node_field_access(c,
3869 trans_create_node_symbol(c, full_type_name), field_name);
3870 add_global_var(c, enum_val_name, field_access_node);
3871 }
38363872 }
38373873
38383874 if (is_anonymous) {
......@@ -3843,7 +3879,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
38433879 add_global_weak_alias(c, bare_name, full_type_name);
38443880 add_global_var(c, full_type_name, enum_node);
38453881 c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
3846 return symbol_node;
3882 return enum_node;
38473883 }
38483884}
38493885
......@@ -4286,7 +4322,7 @@ static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
42864322 return nullptr;
42874323 if (prefix_node->type != NodeTypePrefixOpExpr)
42884324 return nullptr;
4289 if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
4325 if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpOptional)
42904326 return nullptr;
42914327
42924328 AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
......@@ -4462,34 +4498,52 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
44624498 } else if (first_tok->id == CTokIdAsterisk) {
44634499 *tok_i += 1;
44644500
4465 node = trans_create_node_addr_of(c, false, false, node);
4501 node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown);
44664502 } else {
44674503 return node;
44684504 }
44694505 }
44704506}
44714507
4472static PrefixOp ctok_to_prefix_op(CTok *token) {
4473 switch (token->id) {
4474 case CTokIdBang: return PrefixOpBoolNot;
4475 case CTokIdMinus: return PrefixOpNegation;
4476 case CTokIdTilde: return PrefixOpBinNot;
4477 case CTokIdAsterisk: return PrefixOpDereference;
4478 default: return PrefixOpInvalid;
4479 }
4480}
44814508static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {
44824509 CTok *op_tok = &ctok->tokens.at(*tok_i);
4483 PrefixOp prefix_op = ctok_to_prefix_op(op_tok);
4484 if (prefix_op == PrefixOpInvalid) {
4485 return parse_ctok_suffix_op_expr(c, ctok, tok_i);
4486 }
4487 *tok_i += 1;
44884510
4489 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4490 if (prefix_op_expr == nullptr)
4491 return nullptr;
4492 return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr);
4511 switch (op_tok->id) {
4512 case CTokIdBang:
4513 {
4514 *tok_i += 1;
4515 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4516 if (prefix_op_expr == nullptr)
4517 return nullptr;
4518 return trans_create_node_prefix_op(c, PrefixOpBoolNot, prefix_op_expr);
4519 }
4520 case CTokIdMinus:
4521 {
4522 *tok_i += 1;
4523 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4524 if (prefix_op_expr == nullptr)
4525 return nullptr;
4526 return trans_create_node_prefix_op(c, PrefixOpNegation, prefix_op_expr);
4527 }
4528 case CTokIdTilde:
4529 {
4530 *tok_i += 1;
4531 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4532 if (prefix_op_expr == nullptr)
4533 return nullptr;
4534 return trans_create_node_prefix_op(c, PrefixOpBinNot, prefix_op_expr);
4535 }
4536 case CTokIdAsterisk:
4537 {
4538 *tok_i += 1;
4539 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4540 if (prefix_op_expr == nullptr)
4541 return nullptr;
4542 return trans_create_node_ptr_deref(c, prefix_op_expr);
4543 }
4544 default:
4545 return parse_ctok_suffix_op_expr(c, ctok, tok_i);
4546 }
44934547}
44944548
44954549static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {
src/util.hpp+40-8
......@@ -31,6 +31,8 @@
3131
3232#endif
3333
34#include "softfloat.hpp"
35
3436#define BREAKPOINT __asm("int $0x03")
3537
3638ATTRIBUTE_COLD
......@@ -38,11 +40,11 @@ ATTRIBUTE_NORETURN
3840ATTRIBUTE_PRINTF(1, 2)
3941void zig_panic(const char *format, ...);
4042
41ATTRIBUTE_COLD
42ATTRIBUTE_NORETURN
43static inline void zig_unreachable(void) {
44 zig_panic("unreachable");
45}
43#ifdef WIN32
44#define __func__ __FUNCTION__
45#endif
46
47#define zig_unreachable() zig_panic("unreachable: %s:%s:%d", __FILE__, __func__, __LINE__)
4648
4749#if defined(_MSC_VER)
4850static inline int clzll(unsigned long long mask) {
......@@ -65,6 +67,11 @@ static inline int clzll(unsigned long long mask) {
6567
6668template<typename T>
6769ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {
70#ifndef NDEBUG
71 // make behavior when size == 0 portable
72 if (count == 0)
73 return nullptr;
74#endif
6875 T *ptr = reinterpret_cast<T*>(malloc(count * sizeof(T)));
6976 if (!ptr)
7077 zig_panic("allocation failed");
......@@ -73,6 +80,11 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {
7380
7481template<typename T>
7582ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
83#ifndef NDEBUG
84 // make behavior when size == 0 portable
85 if (count == 0)
86 return nullptr;
87#endif
7688 T *ptr = reinterpret_cast<T*>(calloc(count, sizeof(T)));
7789 if (!ptr)
7890 zig_panic("allocation failed");
......@@ -93,9 +105,7 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) {
93105
94106template<typename T>
95107static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
96 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
97 if (!ptr)
98 zig_panic("allocation failed");
108 T *ptr = reallocate_nonzero(old, old_count, new_count);
99109 if (new_count > old_count) {
100110 memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
101111 }
......@@ -104,6 +114,11 @@ static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
104114
105115template<typename T>
106116static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
117#ifndef NDEBUG
118 // make behavior when size == 0 portable
119 if (new_count == 0 && old == nullptr)
120 return nullptr;
121#endif
107122 T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
108123 if (!ptr)
109124 zig_panic("allocation failed");
......@@ -152,4 +167,21 @@ static inline uint8_t log2_u64(uint64_t x) {
152167 return (63 - clzll(x));
153168}
154169
170static inline float16_t zig_double_to_f16(double x) {
171 float64_t y;
172 static_assert(sizeof(x) == sizeof(y), "");
173 memcpy(&y, &x, sizeof(x));
174 return f64_to_f16(y);
175}
176
177
178// Return value is safe to coerce to float even when |x| is NaN or Infinity.
179static inline double zig_f16_to_double(float16_t x) {
180 float64_t y = f16_to_f64(x);
181 double z;
182 static_assert(sizeof(y) == sizeof(z), "");
183 memcpy(&z, &y, sizeof(y));
184 return z;
185}
186
155187#endif
src/windows_sdk.cpp created+352
......@@ -0,0 +1,352 @@
1/*
2 * Copyright (c) 2018 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "windows_sdk.h"
9
10#if defined(_WIN32)
11
12#include "windows_com.hpp"
13#include <inttypes.h>
14#include <assert.h>
15
16struct ZigWindowsSDKPrivate {
17 ZigWindowsSDK base;
18};
19
20enum NativeArch {
21 NativeArchArm,
22 NativeArchi386,
23 NativeArchx86_64,
24};
25
26#if defined(_M_ARM) || defined(__arm_)
27static const NativeArch native_arch = NativeArchArm;
28#endif
29#if defined(_M_IX86) || defined(__i386__)
30static const NativeArch native_arch = NativeArchi386;
31#endif
32#if defined(_M_X64) || defined(__x86_64__)
33static const NativeArch native_arch = NativeArchx86_64;
34#endif
35
36void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {
37 if (sdk == nullptr) {
38 return;
39 }
40 free((void*)sdk->path10_ptr);
41 free((void*)sdk->version10_ptr);
42 free((void*)sdk->path81_ptr);
43 free((void*)sdk->version81_ptr);
44 free((void*)sdk->msvc_lib_dir_ptr);
45}
46
47static ZigFindWindowsSdkError find_msvc_lib_dir(ZigWindowsSDKPrivate *priv) {
48 //COM Smart Pointers requires explicit scope
49 {
50 HRESULT rc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
51 if (rc != S_OK && rc != S_FALSE) {
52 goto com_done;
53 }
54
55 //This COM class is installed when a VS2017
56 ISetupConfigurationPtr setup_config;
57 rc = setup_config.CreateInstance(__uuidof(SetupConfiguration));
58 if (rc != S_OK) {
59 goto com_done;
60 }
61
62 IEnumSetupInstancesPtr all_instances;
63 rc = setup_config->EnumInstances(&all_instances);
64 if (rc != S_OK) {
65 goto com_done;
66 }
67
68 ISetupInstance* curr_instance;
69 ULONG found_inst;
70 while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) {
71 BSTR bstr_inst_path;
72 rc = curr_instance->GetInstallationPath(&bstr_inst_path);
73 if (rc != S_OK) {
74 goto com_done;
75 }
76 //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length
77 //TODO call an actual function to do this
78 UINT bstr_path_len = *((UINT*)bstr_inst_path - 1);
79 ULONG tmp_path_len = bstr_path_len / 2 + 1;
80 char* conv_path = (char*)bstr_inst_path;
81 // TODO don't use alloca
82 char *tmp_path = (char*)alloca(tmp_path_len);
83 memset(tmp_path, 0, tmp_path_len);
84 uint32_t c = 0;
85 for (uint32_t i = 0; i < bstr_path_len; i += 2) {
86 tmp_path[c] = conv_path[i];
87 ++c;
88 assert(c != tmp_path_len);
89 }
90 char output_path[4096];
91 output_path[0] = 0;
92 char *out_append_ptr = output_path;
93
94 out_append_ptr += sprintf(out_append_ptr, "%s\\", tmp_path);
95
96 char tmp_buf[4096];
97 sprintf(tmp_buf, "%s%s", output_path, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
98 FILE* tools_file = fopen(tmp_buf, "rb");
99 if (!tools_file) {
100 goto com_done;
101 }
102 memset(tmp_path, 0, tmp_path_len);
103 fgets(tmp_path, tmp_path_len, tools_file);
104 strtok(tmp_path, " \r\n");
105 fclose(tools_file);
106 out_append_ptr += sprintf(out_append_ptr, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path);
107 switch (native_arch) {
108 case NativeArchi386:
109 out_append_ptr += sprintf(out_append_ptr, "x86\\");
110 break;
111 case NativeArchx86_64:
112 out_append_ptr += sprintf(out_append_ptr, "x64\\");
113 break;
114 case NativeArchArm:
115 out_append_ptr += sprintf(out_append_ptr, "arm\\");
116 break;
117 }
118 sprintf(tmp_buf, "%s%s", output_path, "vcruntime.lib");
119
120 if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) {
121 priv->base.msvc_lib_dir_ptr = strdup(output_path);
122 if (priv->base.msvc_lib_dir_ptr == nullptr) {
123 return ZigFindWindowsSdkErrorOutOfMemory;
124 }
125 priv->base.msvc_lib_dir_len = strlen(priv->base.msvc_lib_dir_ptr);
126 return ZigFindWindowsSdkErrorNone;
127 }
128 }
129 }
130
131com_done:;
132 HKEY key;
133 HRESULT rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0,
134 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);
135 if (rc != ERROR_SUCCESS) {
136 return ZigFindWindowsSdkErrorNotFound;
137 }
138
139 DWORD dw_type = 0;
140 DWORD cb_data = 0;
141 rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data);
142 if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) {
143 return ZigFindWindowsSdkErrorNotFound;
144 }
145
146 char tmp_buf[4096];
147
148 RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)tmp_buf, &cb_data);
149 // RegQueryValueExA returns the length of the string INCLUDING the null terminator
150 char *tmp_buf_append_ptr = tmp_buf + (cb_data - 1);
151 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "VC\\Lib\\");
152 switch (native_arch) {
153 case NativeArchi386:
154 //x86 is in the root of the Lib folder
155 break;
156 case NativeArchx86_64:
157 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "amd64\\");
158 break;
159 case NativeArchArm:
160 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "arm\\");
161 break;
162 }
163
164 char *output_path = strdup(tmp_buf);
165 if (output_path == nullptr) {
166 return ZigFindWindowsSdkErrorOutOfMemory;
167 }
168
169 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "vcruntime.lib");
170
171 if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) {
172 priv->base.msvc_lib_dir_ptr = output_path;
173 priv->base.msvc_lib_dir_len = strlen(output_path);
174 return ZigFindWindowsSdkErrorNone;
175 } else {
176 free(output_path);
177 return ZigFindWindowsSdkErrorNotFound;
178 }
179}
180
181static ZigFindWindowsSdkError find_10_version(ZigWindowsSDKPrivate *priv) {
182 if (priv->base.path10_ptr == nullptr)
183 return ZigFindWindowsSdkErrorNone;
184
185 char sdk_lib_dir[4096];
186 int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\*", priv->base.path10_ptr);
187 if (n < 0 || n >= 4096) {
188 return ZigFindWindowsSdkErrorPathTooLong;
189 }
190
191 // enumerate files in sdk path looking for latest version
192 WIN32_FIND_DATA ffd;
193 HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd);
194 if (hFind == INVALID_HANDLE_VALUE) {
195 return ZigFindWindowsSdkErrorNotFound;
196 }
197 int v0 = 0, v1 = 0, v2 = 0, v3 = 0;
198 for (;;) {
199 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
200 int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
201 sscanf(ffd.cFileName, "%d.%d.%d.%d", &c0, &c1, &c2, &c3);
202 if (c0 == 10 && c1 == 0 && c2 == 10240 && c3 == 0) {
203 // Microsoft released 26624 as 10240 accidentally.
204 // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
205 c2 = 26624;
206 }
207 if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {
208 v0 = c0, v1 = c1, v2 = c2, v3 = c3;
209 free((void*)priv->base.version10_ptr);
210 priv->base.version10_ptr = strdup(ffd.cFileName);
211 if (priv->base.version10_ptr == nullptr) {
212 FindClose(hFind);
213 return ZigFindWindowsSdkErrorOutOfMemory;
214 }
215 }
216 }
217 if (FindNextFile(hFind, &ffd) == 0) {
218 FindClose(hFind);
219 break;
220 }
221 }
222 priv->base.version10_len = strlen(priv->base.version10_ptr);
223 return ZigFindWindowsSdkErrorNone;
224}
225
226static ZigFindWindowsSdkError find_81_version(ZigWindowsSDKPrivate *priv) {
227 if (priv->base.path81_ptr == nullptr)
228 return ZigFindWindowsSdkErrorNone;
229
230 char sdk_lib_dir[4096];
231 int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\winv*", priv->base.path81_ptr);
232 if (n < 0 || n >= 4096) {
233 return ZigFindWindowsSdkErrorPathTooLong;
234 }
235
236 // enumerate files in sdk path looking for latest version
237 WIN32_FIND_DATA ffd;
238 HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd);
239 if (hFind == INVALID_HANDLE_VALUE) {
240 return ZigFindWindowsSdkErrorNotFound;
241 }
242 int v0 = 0, v1 = 0;
243 for (;;) {
244 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
245 int c0 = 0, c1 = 0;
246 sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
247 if ((c0 > v0) || (c1 > v1)) {
248 v0 = c0, v1 = c1;
249 free((void*)priv->base.version81_ptr);
250 priv->base.version81_ptr = strdup(ffd.cFileName);
251 if (priv->base.version81_ptr == nullptr) {
252 FindClose(hFind);
253 return ZigFindWindowsSdkErrorOutOfMemory;
254 }
255 }
256 }
257 if (FindNextFile(hFind, &ffd) == 0) {
258 FindClose(hFind);
259 break;
260 }
261 }
262 priv->base.version81_len = strlen(priv->base.version81_ptr);
263 return ZigFindWindowsSdkErrorNone;
264}
265
266ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) {
267 ZigWindowsSDKPrivate *priv = (ZigWindowsSDKPrivate*)calloc(1, sizeof(ZigWindowsSDKPrivate));
268 if (priv == nullptr) {
269 return ZigFindWindowsSdkErrorOutOfMemory;
270 }
271
272 HKEY key;
273 HRESULT rc;
274 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0,
275 KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key);
276 if (rc != ERROR_SUCCESS) {
277 zig_free_windows_sdk(&priv->base);
278 return ZigFindWindowsSdkErrorNotFound;
279 }
280
281 {
282 DWORD tmp_buf_len = MAX_PATH;
283 priv->base.path10_ptr = (const char *)calloc(tmp_buf_len, 1);
284 if (priv->base.path10_ptr == nullptr) {
285 zig_free_windows_sdk(&priv->base);
286 return ZigFindWindowsSdkErrorOutOfMemory;
287 }
288 rc = RegQueryValueEx(key, "KitsRoot10", NULL, NULL, (LPBYTE)priv->base.path10_ptr, &tmp_buf_len);
289 if (rc == ERROR_SUCCESS) {
290 priv->base.path10_len = tmp_buf_len - 1;
291 if (priv->base.path10_ptr[priv->base.path10_len - 1] == '\\') {
292 priv->base.path10_len -= 1;
293 }
294 } else {
295 free((void*)priv->base.path10_ptr);
296 priv->base.path10_ptr = nullptr;
297 }
298 }
299 {
300 DWORD tmp_buf_len = MAX_PATH;
301 priv->base.path81_ptr = (const char *)calloc(tmp_buf_len, 1);
302 if (priv->base.path81_ptr == nullptr) {
303 zig_free_windows_sdk(&priv->base);
304 return ZigFindWindowsSdkErrorOutOfMemory;
305 }
306 rc = RegQueryValueEx(key, "KitsRoot81", NULL, NULL, (LPBYTE)priv->base.path81_ptr, &tmp_buf_len);
307 if (rc == ERROR_SUCCESS) {
308 priv->base.path81_len = tmp_buf_len - 1;
309 if (priv->base.path81_ptr[priv->base.path81_len - 1] == '\\') {
310 priv->base.path81_len -= 1;
311 }
312 } else {
313 free((void*)priv->base.path81_ptr);
314 priv->base.path81_ptr = nullptr;
315 }
316 }
317
318 {
319 ZigFindWindowsSdkError err = find_10_version(priv);
320 if (err == ZigFindWindowsSdkErrorOutOfMemory) {
321 zig_free_windows_sdk(&priv->base);
322 return err;
323 }
324 }
325 {
326 ZigFindWindowsSdkError err = find_81_version(priv);
327 if (err == ZigFindWindowsSdkErrorOutOfMemory) {
328 zig_free_windows_sdk(&priv->base);
329 return err;
330 }
331 }
332
333 {
334 ZigFindWindowsSdkError err = find_msvc_lib_dir(priv);
335 if (err == ZigFindWindowsSdkErrorOutOfMemory) {
336 zig_free_windows_sdk(&priv->base);
337 return err;
338 }
339 }
340
341 *out_sdk = &priv->base;
342 return ZigFindWindowsSdkErrorNone;
343}
344
345#else
346
347void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {}
348ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) {
349 return ZigFindWindowsSdkErrorNotFound;
350}
351
352#endif
src/windows_sdk.h created+47
......@@ -0,0 +1,47 @@
1/*
2 * Copyright (c) 2018 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_WINDOWS_SDK_H
9#define ZIG_WINDOWS_SDK_H
10
11#ifdef __cplusplus
12#define ZIG_EXTERN_C extern "C"
13#else
14#define ZIG_EXTERN_C
15#endif
16
17#include <stddef.h>
18
19struct ZigWindowsSDK {
20 const char *path10_ptr;
21 size_t path10_len;
22
23 const char *version10_ptr;
24 size_t version10_len;
25
26 const char *path81_ptr;
27 size_t path81_len;
28
29 const char *version81_ptr;
30 size_t version81_len;
31
32 const char *msvc_lib_dir_ptr;
33 size_t msvc_lib_dir_len;
34};
35
36enum ZigFindWindowsSdkError {
37 ZigFindWindowsSdkErrorNone,
38 ZigFindWindowsSdkErrorOutOfMemory,
39 ZigFindWindowsSdkErrorNotFound,
40 ZigFindWindowsSdkErrorPathTooLong,
41};
42
43ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);
44
45ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);
46
47#endif
src/zig_llvm.cpp+13-6
......@@ -81,7 +81,7 @@ static const bool assertions_on = false;
8181#endif
8282
8383bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
84 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug)
84 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small)
8585{
8686 std::error_code EC;
8787 raw_fd_ostream dest(filename, EC, sys::fs::F_None);
......@@ -100,7 +100,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
100100 return true;
101101 }
102102 PMBuilder->OptLevel = target_machine->getOptLevel();
103 PMBuilder->SizeLevel = 0;
103 PMBuilder->SizeLevel = is_small ? 2 : 0;
104104
105105 PMBuilder->DisableTailCalls = is_debug;
106106 PMBuilder->DisableUnitAtATime = is_debug;
......@@ -440,6 +440,11 @@ ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unreso
440440 return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder);
441441}
442442
443void ZigLLVMDisposeDIBuilder(ZigLLVMDIBuilder *dbuilder) {
444 DIBuilder *di_builder = reinterpret_cast<DIBuilder *>(dbuilder);
445 delete di_builder;
446}
447
443448void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope) {
444449 unwrap(builder)->SetCurrentDebugLocation(DebugLoc::get(
445450 line, column, reinterpret_cast<DIScope*>(scope)));
......@@ -765,10 +770,12 @@ static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
765770
766771LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
767772 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
768 LLVMAtomicOrdering failure_ordering)
773 LLVMAtomicOrdering failure_ordering, bool is_weak)
769774{
770 return wrap(unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp), unwrap(new_val),
771 mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering)));
775 AtomicCmpXchgInst *inst = unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp),
776 unwrap(new_val), mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering));
777 inst->setWeak(is_weak);
778 return wrap(inst);
772779}
773780
774781LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
......@@ -836,7 +843,7 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
836843 return lld::mach_o::link(array_ref_args, diag);
837844
838845 case ZigLLVM_Wasm:
839 assert(false); // TODO ZigLLDLink for Wasm
846 return lld::wasm::link(array_ref_args, false, diag);
840847 }
841848 assert(false); // unreachable
842849 abort();
src/zig_llvm.h+7-3
......@@ -22,6 +22,9 @@
2222#define ZIG_EXTERN_C
2323#endif
2424
25// ATTENTION: If you modify this file, be sure to update the corresponding
26// extern function declarations in the self-hosted compiler.
27
2528struct ZigLLVMDIType;
2629struct ZigLLVMDIBuilder;
2730struct ZigLLVMDICompileUnit;
......@@ -39,7 +42,7 @@ struct ZigLLVMInsertionPoint;
3942ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
4043ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
4144
42/// Caller must free memory.
45/// Caller must free memory with LLVMDisposeMessage
4346ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void);
4447ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
4548
......@@ -52,7 +55,7 @@ enum ZigLLVM_EmitOutputType {
5255};
5356
5457ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
55 const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
58 const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small);
5659
5760ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
5861
......@@ -66,7 +69,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LL
6669
6770ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
6871 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
69 LLVMAtomicOrdering failure_ordering);
72 LLVMAtomicOrdering failure_ordering, bool is_weak);
7073
7174ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
7275 const char *name);
......@@ -139,6 +142,7 @@ ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void);
139142ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
140143
141144ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
145ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);
142146ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
143147ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
144148
std/array_list.zig+264-66
......@@ -1,6 +1,7 @@
11const std = @import("index.zig");
22const debug = std.debug;
33const assert = debug.assert;
4const assertError = debug.assertError;
45const mem = std.mem;
56const Allocator = mem.Allocator;
67
......@@ -8,7 +9,7 @@ pub fn ArrayList(comptime T: type) type {
89 return AlignedArrayList(T, @alignOf(T));
910}
1011
11pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
12pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
1213 return struct {
1314 const Self = this;
1415
......@@ -17,38 +18,55 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
1718 /// you uninitialized memory.
1819 items: []align(A) T,
1920 len: usize,
20 allocator: &Allocator,
21 allocator: *Allocator,
2122
2223 /// Deinitialize with `deinit` or use `toOwnedSlice`.
23 pub fn init(allocator: &Allocator) Self {
24 return Self {
24 pub fn init(allocator: *Allocator) Self {
25 return Self{
2526 .items = []align(A) T{},
2627 .len = 0,
2728 .allocator = allocator,
2829 };
2930 }
3031
31 pub fn deinit(l: &Self) void {
32 l.allocator.free(l.items);
32 pub fn deinit(self: Self) void {
33 self.allocator.free(self.items);
3334 }
3435
35 pub fn toSlice(l: &Self) []align(A) T {
36 return l.items[0..l.len];
36 pub fn toSlice(self: Self) []align(A) T {
37 return self.items[0..self.len];
3738 }
3839
39 pub fn toSliceConst(l: &const Self) []align(A) const T {
40 return l.items[0..l.len];
40 pub fn toSliceConst(self: Self) []align(A) const T {
41 return self.items[0..self.len];
4142 }
4243
43 pub fn at(l: &const Self, n: usize) T {
44 return l.toSliceConst()[n];
44 pub fn at(self: Self, i: usize) T {
45 return self.toSliceConst()[i];
46 }
47
48 /// Sets the value at index `i`, or returns `error.OutOfBounds` if
49 /// the index is not in range.
50 pub fn setOrError(self: Self, i: usize, item: T) !void {
51 if (i >= self.len) return error.OutOfBounds;
52 self.items[i] = item;
53 }
54
55 /// Sets the value at index `i`, asserting that the value is in range.
56 pub fn set(self: *Self, i: usize, item: T) void {
57 assert(i < self.len);
58 self.items[i] = item;
59 }
60
61 pub fn count(self: Self) usize {
62 return self.len;
4563 }
4664
4765 /// ArrayList takes ownership of the passed in slice. The slice must have been
4866 /// allocated with `allocator`.
4967 /// Deinitialize with `deinit` or use `toOwnedSlice`.
50 pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) Self {
51 return Self {
68 pub fn fromOwnedSlice(allocator: *Allocator, slice: []align(A) T) Self {
69 return Self{
5270 .items = slice,
5371 .len = slice.len,
5472 .allocator = allocator,
......@@ -56,122 +74,302 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
5674 }
5775
5876 /// The caller owns the returned memory. ArrayList becomes empty.
59 pub fn toOwnedSlice(self: &Self) []align(A) T {
77 pub fn toOwnedSlice(self: *Self) []align(A) T {
6078 const allocator = self.allocator;
6179 const result = allocator.alignedShrink(T, A, self.items, self.len);
62 *self = init(allocator);
80 self.* = init(allocator);
6381 return result;
6482 }
6583
66 pub fn insert(l: &Self, n: usize, item: &const T) !void {
67 try l.ensureCapacity(l.len + 1);
68 l.len += 1;
84 pub fn insert(self: *Self, n: usize, item: T) !void {
85 try self.ensureCapacity(self.len + 1);
86 self.len += 1;
6987
70 mem.copy(T, l.items[n+1..l.len], l.items[n..l.len-1]);
71 l.items[n] = *item;
88 mem.copyBackwards(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
89 self.items[n] = item;
7290 }
7391
74 pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {
75 try l.ensureCapacity(l.len + items.len);
76 l.len += items.len;
92 pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
93 try self.ensureCapacity(self.len + items.len);
94 self.len += items.len;
7795
78 mem.copy(T, l.items[n+items.len..l.len], l.items[n..l.len-items.len]);
79 mem.copy(T, l.items[n..n+items.len], items);
96 mem.copyBackwards(T, self.items[n + items.len .. self.len], self.items[n .. self.len - items.len]);
97 mem.copy(T, self.items[n .. n + items.len], items);
8098 }
8199
82 pub fn append(l: &Self, item: &const T) !void {
83 const new_item_ptr = try l.addOne();
84 *new_item_ptr = *item;
100 pub fn append(self: *Self, item: T) !void {
101 const new_item_ptr = try self.addOne();
102 new_item_ptr.* = item;
85103 }
86104
87 pub fn appendSlice(l: &Self, items: []align(A) const T) !void {
88 try l.ensureCapacity(l.len + items.len);
89 mem.copy(T, l.items[l.len..], items);
90 l.len += items.len;
105 /// Removes the element at the specified index and returns it.
106 /// The empty slot is filled from the end of the list.
107 pub fn swapRemove(self: *Self, i: usize) T {
108 if (self.len - 1 == i) return self.pop();
109
110 const slice = self.toSlice();
111 const old_item = slice[i];
112 slice[i] = self.pop();
113 return old_item;
91114 }
92115
93 pub fn resize(l: &Self, new_len: usize) !void {
94 try l.ensureCapacity(new_len);
95 l.len = new_len;
116 /// Removes the element at the specified index and returns it
117 /// or an error.OutOfBounds is returned. If no error then
118 /// the empty slot is filled from the end of the list.
119 pub fn swapRemoveOrError(self: *Self, i: usize) !T {
120 if (i >= self.len) return error.OutOfBounds;
121 return self.swapRemove(i);
96122 }
97123
98 pub fn shrink(l: &Self, new_len: usize) void {
99 assert(new_len <= l.len);
100 l.len = new_len;
124 pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
125 try self.ensureCapacity(self.len + items.len);
126 mem.copy(T, self.items[self.len..], items);
127 self.len += items.len;
101128 }
102129
103 pub fn ensureCapacity(l: &Self, new_capacity: usize) !void {
104 var better_capacity = l.items.len;
130 pub fn resize(self: *Self, new_len: usize) !void {
131 try self.ensureCapacity(new_len);
132 self.len = new_len;
133 }
134
135 pub fn shrink(self: *Self, new_len: usize) void {
136 assert(new_len <= self.len);
137 self.len = new_len;
138 }
139
140 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
141 var better_capacity = self.items.len;
105142 if (better_capacity >= new_capacity) return;
106143 while (true) {
107144 better_capacity += better_capacity / 2 + 8;
108145 if (better_capacity >= new_capacity) break;
109146 }
110 l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity);
147 self.items = try self.allocator.alignedRealloc(T, A, self.items, better_capacity);
111148 }
112149
113 pub fn addOne(l: &Self) !&T {
114 const new_length = l.len + 1;
115 try l.ensureCapacity(new_length);
116 const result = &l.items[l.len];
117 l.len = new_length;
150 pub fn addOne(self: *Self) !*T {
151 const new_length = self.len + 1;
152 try self.ensureCapacity(new_length);
153 const result = &self.items[self.len];
154 self.len = new_length;
118155 return result;
119156 }
120157
121 pub fn pop(self: &Self) T {
158 pub fn pop(self: *Self) T {
122159 self.len -= 1;
123160 return self.items[self.len];
124161 }
125162
126 pub fn popOrNull(self: &Self) ?T {
127 if (self.len == 0)
128 return null;
163 pub fn popOrNull(self: *Self) ?T {
164 if (self.len == 0) return null;
129165 return self.pop();
130166 }
167
168 pub const Iterator = struct {
169 list: *const Self,
170 // how many items have we returned
171 count: usize,
172
173 pub fn next(it: *Iterator) ?T {
174 if (it.count >= it.list.len) return null;
175 const val = it.list.at(it.count);
176 it.count += 1;
177 return val;
178 }
179
180 pub fn reset(it: *Iterator) void {
181 it.count = 0;
182 }
183 };
184
185 pub fn iterator(self: *const Self) Iterator {
186 return Iterator{
187 .list = self,
188 .count = 0,
189 };
190 }
131191 };
132192}
133193
134test "basic ArrayList test" {
135 var list = ArrayList(i32).init(debug.global_allocator);
194test "std.ArrayList.basic" {
195 var bytes: [1024]u8 = undefined;
196 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
197
198 var list = ArrayList(i32).init(allocator);
136199 defer list.deinit();
137200
138 {var i: usize = 0; while (i < 10) : (i += 1) {
139 list.append(i32(i + 1)) catch unreachable;
140 }}
201 // setting on empty list is out of bounds
202 assertError(list.setOrError(0, 1), error.OutOfBounds);
141203
142 {var i: usize = 0; while (i < 10) : (i += 1) {
143 assert(list.items[i] == i32(i + 1));
144 }}
204 {
205 var i: usize = 0;
206 while (i < 10) : (i += 1) {
207 list.append(@intCast(i32, i + 1)) catch unreachable;
208 }
209 }
210
211 {
212 var i: usize = 0;
213 while (i < 10) : (i += 1) {
214 assert(list.items[i] == @intCast(i32, i + 1));
215 }
216 }
217
218 for (list.toSlice()) |v, i| {
219 assert(v == @intCast(i32, i + 1));
220 }
221
222 for (list.toSliceConst()) |v, i| {
223 assert(v == @intCast(i32, i + 1));
224 }
145225
146226 assert(list.pop() == 10);
147227 assert(list.len == 9);
148228
149 list.appendSlice([]const i32 { 1, 2, 3 }) catch unreachable;
229 list.appendSlice([]const i32{
230 1,
231 2,
232 3,
233 }) catch unreachable;
150234 assert(list.len == 12);
151235 assert(list.pop() == 3);
152236 assert(list.pop() == 2);
153237 assert(list.pop() == 1);
154238 assert(list.len == 9);
155239
156 list.appendSlice([]const i32 {}) catch unreachable;
240 list.appendSlice([]const i32{}) catch unreachable;
157241 assert(list.len == 9);
242
243 // can only set on indices < self.len
244 list.set(7, 33);
245 list.set(8, 42);
246
247 assertError(list.setOrError(9, 99), error.OutOfBounds);
248 assertError(list.setOrError(10, 123), error.OutOfBounds);
249
250 assert(list.pop() == 42);
251 assert(list.pop() == 33);
252}
253
254test "std.ArrayList.swapRemove" {
255 var list = ArrayList(i32).init(debug.global_allocator);
256 defer list.deinit();
257
258 try list.append(1);
259 try list.append(2);
260 try list.append(3);
261 try list.append(4);
262 try list.append(5);
263 try list.append(6);
264 try list.append(7);
265
266 //remove from middle
267 assert(list.swapRemove(3) == 4);
268 assert(list.at(3) == 7);
269 assert(list.len == 6);
270
271 //remove from end
272 assert(list.swapRemove(5) == 6);
273 assert(list.len == 5);
274
275 //remove from front
276 assert(list.swapRemove(0) == 1);
277 assert(list.at(0) == 5);
278 assert(list.len == 4);
279}
280
281test "std.ArrayList.swapRemoveOrError" {
282 var list = ArrayList(i32).init(debug.global_allocator);
283 defer list.deinit();
284
285 // Test just after initialization
286 assertError(list.swapRemoveOrError(0), error.OutOfBounds);
287
288 // Test after adding one item and remote it
289 try list.append(1);
290 assert((try list.swapRemoveOrError(0)) == 1);
291 assertError(list.swapRemoveOrError(0), error.OutOfBounds);
292
293 // Test after adding two items and remote both
294 try list.append(1);
295 try list.append(2);
296 assert((try list.swapRemoveOrError(1)) == 2);
297 assert((try list.swapRemoveOrError(0)) == 1);
298 assertError(list.swapRemoveOrError(0), error.OutOfBounds);
299
300 // Test out of bounds with one item
301 try list.append(1);
302 assertError(list.swapRemoveOrError(1), error.OutOfBounds);
303
304 // Test out of bounds with two items
305 try list.append(2);
306 assertError(list.swapRemoveOrError(2), error.OutOfBounds);
307}
308
309test "std.ArrayList.iterator" {
310 var list = ArrayList(i32).init(debug.global_allocator);
311 defer list.deinit();
312
313 try list.append(1);
314 try list.append(2);
315 try list.append(3);
316
317 var count: i32 = 0;
318 var it = list.iterator();
319 while (it.next()) |next| {
320 assert(next == count + 1);
321 count += 1;
322 }
323
324 assert(count == 3);
325 assert(it.next() == null);
326 it.reset();
327 count = 0;
328 while (it.next()) |next| {
329 assert(next == count + 1);
330 count += 1;
331 if (count == 2) break;
332 }
333
334 it.reset();
335 assert(it.next().? == 1);
158336}
159337
160test "insert ArrayList test" {
338test "std.ArrayList.insert" {
161339 var list = ArrayList(i32).init(debug.global_allocator);
162340 defer list.deinit();
163341
164342 try list.append(1);
343 try list.append(2);
344 try list.append(3);
165345 try list.insert(0, 5);
166346 assert(list.items[0] == 5);
167347 assert(list.items[1] == 1);
348 assert(list.items[2] == 2);
349 assert(list.items[3] == 3);
350}
168351
169 try list.insertSlice(1, []const i32 { 9, 8 });
170 assert(list.items[0] == 5);
352test "std.ArrayList.insertSlice" {
353 var list = ArrayList(i32).init(debug.global_allocator);
354 defer list.deinit();
355
356 try list.append(1);
357 try list.append(2);
358 try list.append(3);
359 try list.append(4);
360 try list.insertSlice(1, []const i32{
361 9,
362 8,
363 });
364 assert(list.items[0] == 1);
171365 assert(list.items[1] == 9);
172366 assert(list.items[2] == 8);
367 assert(list.items[3] == 2);
368 assert(list.items[4] == 3);
369 assert(list.items[5] == 4);
173370
174 const items = []const i32 { 1 };
371 const items = []const i32{1};
175372 try list.insertSlice(0, items[0..0]);
176 assert(list.items[0] == 5);
373 assert(list.len == 6);
374 assert(list.items[0] == 1);
177375}
std/atomic/index.zig created+9
......@@ -0,0 +1,9 @@
1pub const Stack = @import("stack.zig").Stack;
2pub const Queue = @import("queue.zig").Queue;
3pub const Int = @import("int.zig").Int;
4
5test "std.atomic" {
6 _ = @import("stack.zig");
7 _ = @import("queue.zig");
8 _ = @import("int.zig");
9}
std/atomic/int.zig created+33
......@@ -0,0 +1,33 @@
1const builtin = @import("builtin");
2const AtomicOrder = builtin.AtomicOrder;
3
4/// Thread-safe, lock-free integer
5pub fn Int(comptime T: type) type {
6 return struct {
7 unprotected_value: T,
8
9 pub const Self = this;
10
11 pub fn init(init_val: T) Self {
12 return Self{ .unprotected_value = init_val };
13 }
14
15 /// Returns previous value
16 pub fn incr(self: *Self) T {
17 return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
18 }
19
20 /// Returns previous value
21 pub fn decr(self: *Self) T {
22 return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
23 }
24
25 pub fn get(self: *Self) T {
26 return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst);
27 }
28
29 pub fn xchg(self: *Self, new_value: T) T {
30 return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst);
31 }
32 };
33}
std/atomic/queue.zig created+240
......@@ -0,0 +1,240 @@
1const builtin = @import("builtin");
2const AtomicOrder = builtin.AtomicOrder;
3const AtomicRmwOp = builtin.AtomicRmwOp;
4
5/// Many producer, many consumer, non-allocating, thread-safe.
6/// Uses a spinlock to protect get() and put().
7pub fn Queue(comptime T: type) type {
8 return struct {
9 head: ?*Node,
10 tail: ?*Node,
11 lock: u8,
12
13 pub const Self = this;
14
15 pub const Node = struct {
16 next: ?*Node,
17 data: T,
18 };
19
20 pub fn init() Self {
21 return Self{
22 .head = null,
23 .tail = null,
24 .lock = 0,
25 };
26 }
27
28 pub fn put(self: *Self, node: *Node) void {
29 node.next = null;
30
31 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
32 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
33
34 const opt_tail = self.tail;
35 self.tail = node;
36 if (opt_tail) |tail| {
37 tail.next = node;
38 } else {
39 assert(self.head == null);
40 self.head = node;
41 }
42 }
43
44 pub fn get(self: *Self) ?*Node {
45 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
46 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
47
48 const head = self.head orelse return null;
49 self.head = head.next;
50 if (head.next == null) self.tail = null;
51 return head;
52 }
53
54 pub fn unget(self: *Self, node: *Node) void {
55 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
56 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
57
58 const opt_head = self.head;
59 self.head = node;
60 if (opt_head) |head| {
61 head.next = node;
62 } else {
63 assert(self.tail == null);
64 self.tail = node;
65 }
66 }
67
68 pub fn isEmpty(self: *Self) bool {
69 return @atomicLoad(?*Node, &self.head, builtin.AtomicOrder.SeqCst) != null;
70 }
71
72 pub fn dump(self: *Self) void {
73 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
74 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
75
76 std.debug.warn("head: ");
77 dumpRecursive(self.head, 0);
78 std.debug.warn("tail: ");
79 dumpRecursive(self.tail, 0);
80 }
81
82 fn dumpRecursive(optional_node: ?*Node, indent: usize) void {
83 var stderr_file = std.io.getStdErr() catch return;
84 const stderr = &std.io.FileOutStream.init(&stderr_file).stream;
85 stderr.writeByteNTimes(' ', indent) catch return;
86 if (optional_node) |node| {
87 std.debug.warn("0x{x}={}\n", @ptrToInt(node), node.data);
88 dumpRecursive(node.next, indent + 1);
89 } else {
90 std.debug.warn("(null)\n");
91 }
92 }
93 };
94}
95
96const std = @import("../index.zig");
97const assert = std.debug.assert;
98
99const Context = struct {
100 allocator: *std.mem.Allocator,
101 queue: *Queue(i32),
102 put_sum: isize,
103 get_sum: isize,
104 get_count: usize,
105 puts_done: u8, // TODO make this a bool
106};
107
108// TODO add lazy evaluated build options and then put puts_per_thread behind
109// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
110// CI we would use a less aggressive setting since at 1 core, while we still
111// want this test to pass, we need a smaller value since there is so much thrashing
112// we would also use a less aggressive setting when running in valgrind
113const puts_per_thread = 500;
114const put_thread_count = 3;
115
116test "std.atomic.Queue" {
117 var direct_allocator = std.heap.DirectAllocator.init();
118 defer direct_allocator.deinit();
119
120 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
121 defer direct_allocator.allocator.free(plenty_of_memory);
122
123 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
124 var a = &fixed_buffer_allocator.allocator;
125
126 var queue = Queue(i32).init();
127 var context = Context{
128 .allocator = a,
129 .queue = &queue,
130 .put_sum = 0,
131 .get_sum = 0,
132 .puts_done = 0,
133 .get_count = 0,
134 };
135
136 var putters: [put_thread_count]*std.os.Thread = undefined;
137 for (putters) |*t| {
138 t.* = try std.os.spawnThread(&context, startPuts);
139 }
140 var getters: [put_thread_count]*std.os.Thread = undefined;
141 for (getters) |*t| {
142 t.* = try std.os.spawnThread(&context, startGets);
143 }
144
145 for (putters) |t|
146 t.wait();
147 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
148 for (getters) |t|
149 t.wait();
150
151 if (context.put_sum != context.get_sum) {
152 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
153 }
154
155 if (context.get_count != puts_per_thread * put_thread_count) {
156 std.debug.panic(
157 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
158 context.get_count,
159 u32(puts_per_thread),
160 u32(put_thread_count),
161 );
162 }
163}
164
165fn startPuts(ctx: *Context) u8 {
166 var put_count: usize = puts_per_thread;
167 var r = std.rand.DefaultPrng.init(0xdeadbeef);
168 while (put_count != 0) : (put_count -= 1) {
169 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
170 const x = @bitCast(i32, r.random.scalar(u32));
171 const node = ctx.allocator.create(Queue(i32).Node{
172 .next = undefined,
173 .data = x,
174 }) catch unreachable;
175 ctx.queue.put(node);
176 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
177 }
178 return 0;
179}
180
181fn startGets(ctx: *Context) u8 {
182 while (true) {
183 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
184
185 while (ctx.queue.get()) |node| {
186 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
187 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
188 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
189 }
190
191 if (last) return 0;
192 }
193}
194
195test "std.atomic.Queue single-threaded" {
196 var queue = Queue(i32).init();
197
198 var node_0 = Queue(i32).Node{
199 .data = 0,
200 .next = undefined,
201 };
202 queue.put(&node_0);
203
204 var node_1 = Queue(i32).Node{
205 .data = 1,
206 .next = undefined,
207 };
208 queue.put(&node_1);
209
210 assert(queue.get().?.data == 0);
211
212 var node_2 = Queue(i32).Node{
213 .data = 2,
214 .next = undefined,
215 };
216 queue.put(&node_2);
217
218 var node_3 = Queue(i32).Node{
219 .data = 3,
220 .next = undefined,
221 };
222 queue.put(&node_3);
223
224 assert(queue.get().?.data == 1);
225
226 assert(queue.get().?.data == 2);
227
228 var node_4 = Queue(i32).Node{
229 .data = 4,
230 .next = undefined,
231 };
232 queue.put(&node_4);
233
234 assert(queue.get().?.data == 3);
235 node_3.next = null;
236
237 assert(queue.get().?.data == 4);
238
239 assert(queue.get() == null);
240}
std/atomic/stack.zig created+150
......@@ -0,0 +1,150 @@
1const assert = std.debug.assert;
2const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;
4
5/// Many reader, many writer, non-allocating, thread-safe
6/// Uses a spinlock to protect push() and pop()
7pub fn Stack(comptime T: type) type {
8 return struct {
9 root: ?*Node,
10 lock: u8,
11
12 pub const Self = this;
13
14 pub const Node = struct {
15 next: ?*Node,
16 data: T,
17 };
18
19 pub fn init() Self {
20 return Self{
21 .root = null,
22 .lock = 0,
23 };
24 }
25
26 /// push operation, but only if you are the first item in the stack. if you did not succeed in
27 /// being the first item in the stack, returns the other item that was there.
28 pub fn pushFirst(self: *Self, node: *Node) ?*Node {
29 node.next = null;
30 return @cmpxchgStrong(?*Node, &self.root, null, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst);
31 }
32
33 pub fn push(self: *Self, node: *Node) void {
34 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
35 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
36
37 node.next = self.root;
38 self.root = node;
39 }
40
41 pub fn pop(self: *Self) ?*Node {
42 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
43 defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
44
45 const root = self.root orelse return null;
46 self.root = root.next;
47 return root;
48 }
49
50 pub fn isEmpty(self: *Self) bool {
51 return @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst) == null;
52 }
53 };
54}
55
56const std = @import("../index.zig");
57const Context = struct {
58 allocator: *std.mem.Allocator,
59 stack: *Stack(i32),
60 put_sum: isize,
61 get_sum: isize,
62 get_count: usize,
63 puts_done: u8, // TODO make this a bool
64};
65// TODO add lazy evaluated build options and then put puts_per_thread behind
66// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
67// CI we would use a less aggressive setting since at 1 core, while we still
68// want this test to pass, we need a smaller value since there is so much thrashing
69// we would also use a less aggressive setting when running in valgrind
70const puts_per_thread = 500;
71const put_thread_count = 3;
72
73test "std.atomic.stack" {
74 var direct_allocator = std.heap.DirectAllocator.init();
75 defer direct_allocator.deinit();
76
77 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
78 defer direct_allocator.allocator.free(plenty_of_memory);
79
80 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
81 var a = &fixed_buffer_allocator.allocator;
82
83 var stack = Stack(i32).init();
84 var context = Context{
85 .allocator = a,
86 .stack = &stack,
87 .put_sum = 0,
88 .get_sum = 0,
89 .puts_done = 0,
90 .get_count = 0,
91 };
92
93 var putters: [put_thread_count]*std.os.Thread = undefined;
94 for (putters) |*t| {
95 t.* = try std.os.spawnThread(&context, startPuts);
96 }
97 var getters: [put_thread_count]*std.os.Thread = undefined;
98 for (getters) |*t| {
99 t.* = try std.os.spawnThread(&context, startGets);
100 }
101
102 for (putters) |t|
103 t.wait();
104 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
105 for (getters) |t|
106 t.wait();
107
108 if (context.put_sum != context.get_sum) {
109 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
110 }
111
112 if (context.get_count != puts_per_thread * put_thread_count) {
113 std.debug.panic(
114 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
115 context.get_count,
116 u32(puts_per_thread),
117 u32(put_thread_count),
118 );
119 }
120}
121
122fn startPuts(ctx: *Context) u8 {
123 var put_count: usize = puts_per_thread;
124 var r = std.rand.DefaultPrng.init(0xdeadbeef);
125 while (put_count != 0) : (put_count -= 1) {
126 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
127 const x = @bitCast(i32, r.random.scalar(u32));
128 const node = ctx.allocator.create(Stack(i32).Node{
129 .next = undefined,
130 .data = x,
131 }) catch unreachable;
132 ctx.stack.push(node);
133 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
134 }
135 return 0;
136}
137
138fn startGets(ctx: *Context) u8 {
139 while (true) {
140 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
141
142 while (ctx.stack.pop()) |node| {
143 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
144 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
145 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
146 }
147
148 if (last) return 0;
149 }
150}
std/base64.zig+56-80
......@@ -32,7 +32,7 @@ pub const Base64Encoder = struct {
3232 }
3333
3434 /// dest.len must be what you get from ::calcSize.
35 pub fn encode(encoder: &const Base64Encoder, dest: []u8, source: []const u8) void {
35 pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) void {
3636 assert(dest.len == Base64Encoder.calcSize(source.len));
3737
3838 var i: usize = 0;
......@@ -41,12 +41,10 @@ pub const Base64Encoder = struct {
4141 dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
4242 out_index += 1;
4343
44 dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
45 ((source[i + 1] & 0xf0) >> 4)];
44 dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | ((source[i + 1] & 0xf0) >> 4)];
4645 out_index += 1;
4746
48 dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) |
49 ((source[i + 2] & 0xc0) >> 6)];
47 dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) | ((source[i + 2] & 0xc0) >> 6)];
5048 out_index += 1;
5149
5250 dest[out_index] = encoder.alphabet_chars[source[i + 2] & 0x3f];
......@@ -64,8 +62,7 @@ pub const Base64Encoder = struct {
6462 dest[out_index] = encoder.pad_char;
6563 out_index += 1;
6664 } else {
67 dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
68 ((source[i + 1] & 0xf0) >> 4)];
65 dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | ((source[i + 1] & 0xf0) >> 4)];
6966 out_index += 1;
7067
7168 dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2];
......@@ -84,6 +81,7 @@ pub const Base64Decoder = struct {
8481 /// e.g. 'A' => 0.
8582 /// undefined for any value not in the 64 alphabet chars.
8683 char_to_index: [256]u8,
84
8785 /// true only for the 64 chars in the alphabet, not the pad char.
8886 char_in_alphabet: [256]bool,
8987 pad_char: u8,
......@@ -101,7 +99,7 @@ pub const Base64Decoder = struct {
10199 assert(!result.char_in_alphabet[c]);
102100 assert(c != pad_char);
103101
104 result.char_to_index[c] = u8(i);
102 result.char_to_index[c] = @intCast(u8, i);
105103 result.char_in_alphabet[c] = true;
106104 }
107105
......@@ -109,7 +107,7 @@ pub const Base64Decoder = struct {
109107 }
110108
111109 /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding.
112 pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) !usize {
110 pub fn calcSize(decoder: *const Base64Decoder, source: []const u8) !usize {
113111 if (source.len % 4 != 0) return error.InvalidPadding;
114112 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
115113 }
......@@ -117,7 +115,7 @@ pub const Base64Decoder = struct {
117115 /// dest.len must be what you get from ::calcSize.
118116 /// invalid characters result in error.InvalidCharacter.
119117 /// invalid padding results in error.InvalidPadding.
120 pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) !void {
118 pub fn decode(decoder: *const Base64Decoder, dest: []u8, source: []const u8) !void {
121119 assert(dest.len == (decoder.calcSize(source) catch unreachable));
122120 assert(source.len % 4 == 0);
123121
......@@ -131,26 +129,20 @@ pub const Base64Decoder = struct {
131129 // common case
132130 if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
133131 if (!decoder.char_in_alphabet[source[src_cursor + 3]]) return error.InvalidCharacter;
134 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
135 decoder.char_to_index[source[src_cursor + 1]] >> 4;
136 dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
137 decoder.char_to_index[source[src_cursor + 2]] >> 2;
138 dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 |
139 decoder.char_to_index[source[src_cursor + 3]];
132 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
133 dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | decoder.char_to_index[source[src_cursor + 2]] >> 2;
134 dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 | decoder.char_to_index[source[src_cursor + 3]];
140135 dest_cursor += 3;
141136 } else if (source[src_cursor + 2] != decoder.pad_char) {
142137 // one pad char
143138 if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
144 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
145 decoder.char_to_index[source[src_cursor + 1]] >> 4;
146 dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
147 decoder.char_to_index[source[src_cursor + 2]] >> 2;
139 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
140 dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | decoder.char_to_index[source[src_cursor + 2]] >> 2;
148141 if (decoder.char_to_index[source[src_cursor + 2]] << 6 != 0) return error.InvalidPadding;
149142 dest_cursor += 2;
150143 } else {
151144 // two pad chars
152 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
153 decoder.char_to_index[source[src_cursor + 1]] >> 4;
145 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
154146 if (decoder.char_to_index[source[src_cursor + 1]] << 4 != 0) return error.InvalidPadding;
155147 dest_cursor += 1;
156148 }
......@@ -165,7 +157,7 @@ pub const Base64DecoderWithIgnore = struct {
165157 decoder: Base64Decoder,
166158 char_is_ignored: [256]bool,
167159 pub fn init(alphabet_chars: []const u8, pad_char: u8, ignore_chars: []const u8) Base64DecoderWithIgnore {
168 var result = Base64DecoderWithIgnore {
160 var result = Base64DecoderWithIgnore{
169161 .decoder = Base64Decoder.init(alphabet_chars, pad_char),
170162 .char_is_ignored = []bool{false} ** 256,
171163 };
......@@ -189,7 +181,7 @@ pub const Base64DecoderWithIgnore = struct {
189181 /// Invalid padding results in error.InvalidPadding.
190182 /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.
191183 /// Returns the number of bytes writen to dest.
192 pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) !usize {
184 pub fn decode(decoder_with_ignore: *const Base64DecoderWithIgnore, dest: []u8, source: []const u8) !usize {
193185 const decoder = &decoder_with_ignore.decoder;
194186
195187 var src_cursor: usize = 0;
......@@ -223,10 +215,12 @@ pub const Base64DecoderWithIgnore = struct {
223215 } else if (decoder_with_ignore.char_is_ignored[c]) {
224216 // we can even ignore chars during the padding
225217 continue;
226 } else return error.InvalidCharacter;
218 } else
219 return error.InvalidCharacter;
227220 }
228221 break;
229 } else return error.InvalidCharacter;
222 } else
223 return error.InvalidCharacter;
230224 }
231225
232226 switch (available_chars) {
......@@ -234,22 +228,17 @@ pub const Base64DecoderWithIgnore = struct {
234228 // common case
235229 if (dest_cursor + 3 > dest.len) return error.OutputTooSmall;
236230 assert(pad_char_count == 0);
237 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
238 decoder.char_to_index[next_4_chars[1]] >> 4;
239 dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
240 decoder.char_to_index[next_4_chars[2]] >> 2;
241 dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 |
242 decoder.char_to_index[next_4_chars[3]];
231 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
232 dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | decoder.char_to_index[next_4_chars[2]] >> 2;
233 dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 | decoder.char_to_index[next_4_chars[3]];
243234 dest_cursor += 3;
244235 continue;
245236 },
246237 3 => {
247238 if (dest_cursor + 2 > dest.len) return error.OutputTooSmall;
248239 if (pad_char_count != 1) return error.InvalidPadding;
249 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
250 decoder.char_to_index[next_4_chars[1]] >> 4;
251 dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
252 decoder.char_to_index[next_4_chars[2]] >> 2;
240 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
241 dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | decoder.char_to_index[next_4_chars[2]] >> 2;
253242 if (decoder.char_to_index[next_4_chars[2]] << 6 != 0) return error.InvalidPadding;
254243 dest_cursor += 2;
255244 break;
......@@ -257,8 +246,7 @@ pub const Base64DecoderWithIgnore = struct {
257246 2 => {
258247 if (dest_cursor + 1 > dest.len) return error.OutputTooSmall;
259248 if (pad_char_count != 2) return error.InvalidPadding;
260 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
261 decoder.char_to_index[next_4_chars[1]] >> 4;
249 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
262250 if (decoder.char_to_index[next_4_chars[1]] << 4 != 0) return error.InvalidPadding;
263251 dest_cursor += 1;
264252 break;
......@@ -280,7 +268,6 @@ pub const Base64DecoderWithIgnore = struct {
280268 }
281269};
282270
283
284271pub const standard_decoder_unsafe = Base64DecoderUnsafe.init(standard_alphabet_chars, standard_pad_char);
285272
286273pub const Base64DecoderUnsafe = struct {
......@@ -291,25 +278,25 @@ pub const Base64DecoderUnsafe = struct {
291278
292279 pub fn init(alphabet_chars: []const u8, pad_char: u8) Base64DecoderUnsafe {
293280 assert(alphabet_chars.len == 64);
294 var result = Base64DecoderUnsafe {
281 var result = Base64DecoderUnsafe{
295282 .char_to_index = undefined,
296283 .pad_char = pad_char,
297284 };
298285 for (alphabet_chars) |c, i| {
299286 assert(c != pad_char);
300 result.char_to_index[c] = u8(i);
287 result.char_to_index[c] = @intCast(u8, i);
301288 }
302289 return result;
303290 }
304291
305292 /// The source buffer must be valid.
306 pub fn calcSize(decoder: &const Base64DecoderUnsafe, source: []const u8) usize {
293 pub fn calcSize(decoder: *const Base64DecoderUnsafe, source: []const u8) usize {
307294 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
308295 }
309296
310297 /// dest.len must be what you get from ::calcDecodedSizeExactUnsafe.
311298 /// invalid characters or padding will result in undefined values.
312 pub fn decode(decoder: &const Base64DecoderUnsafe, dest: []u8, source: []const u8) void {
299 pub fn decode(decoder: *const Base64DecoderUnsafe, dest: []u8, source: []const u8) void {
313300 assert(dest.len == decoder.calcSize(source));
314301
315302 var src_index: usize = 0;
......@@ -321,16 +308,13 @@ pub const Base64DecoderUnsafe = struct {
321308 }
322309
323310 while (in_buf_len > 4) {
324 dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
325 decoder.char_to_index[source[src_index + 1]] >> 4;
311 dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | decoder.char_to_index[source[src_index + 1]] >> 4;
326312 dest_index += 1;
327313
328 dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
329 decoder.char_to_index[source[src_index + 2]] >> 2;
314 dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | decoder.char_to_index[source[src_index + 2]] >> 2;
330315 dest_index += 1;
331316
332 dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
333 decoder.char_to_index[source[src_index + 3]];
317 dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | decoder.char_to_index[source[src_index + 3]];
334318 dest_index += 1;
335319
336320 src_index += 4;
......@@ -338,18 +322,15 @@ pub const Base64DecoderUnsafe = struct {
338322 }
339323
340324 if (in_buf_len > 1) {
341 dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
342 decoder.char_to_index[source[src_index + 1]] >> 4;
325 dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | decoder.char_to_index[source[src_index + 1]] >> 4;
343326 dest_index += 1;
344327 }
345328 if (in_buf_len > 2) {
346 dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
347 decoder.char_to_index[source[src_index + 2]] >> 2;
329 dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | decoder.char_to_index[source[src_index + 2]] >> 2;
348330 dest_index += 1;
349331 }
350332 if (in_buf_len > 3) {
351 dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
352 decoder.char_to_index[source[src_index + 3]];
333 dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | decoder.char_to_index[source[src_index + 3]];
353334 dest_index += 1;
354335 }
355336 }
......@@ -367,7 +348,6 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize {
367348 return result;
368349}
369350
370
371351test "base64" {
372352 @setEvalBranchQuota(8000);
373353 testBase64() catch unreachable;
......@@ -375,26 +355,26 @@ test "base64" {
375355}
376356
377357fn testBase64() !void {
378 try testAllApis("", "");
379 try testAllApis("f", "Zg==");
380 try testAllApis("fo", "Zm8=");
381 try testAllApis("foo", "Zm9v");
382 try testAllApis("foob", "Zm9vYg==");
383 try testAllApis("fooba", "Zm9vYmE=");
358 try testAllApis("", "");
359 try testAllApis("f", "Zg==");
360 try testAllApis("fo", "Zm8=");
361 try testAllApis("foo", "Zm9v");
362 try testAllApis("foob", "Zm9vYg==");
363 try testAllApis("fooba", "Zm9vYmE=");
384364 try testAllApis("foobar", "Zm9vYmFy");
385365
386 try testDecodeIgnoreSpace("", " ");
387 try testDecodeIgnoreSpace("f", "Z g= =");
388 try testDecodeIgnoreSpace("fo", " Zm8=");
389 try testDecodeIgnoreSpace("foo", "Zm9v ");
390 try testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
391 try testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
366 try testDecodeIgnoreSpace("", " ");
367 try testDecodeIgnoreSpace("f", "Z g= =");
368 try testDecodeIgnoreSpace("fo", " Zm8=");
369 try testDecodeIgnoreSpace("foo", "Zm9v ");
370 try testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
371 try testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
392372 try testDecodeIgnoreSpace("foobar", " Z m 9 v Y m F y ");
393373
394374 // test getting some api errors
395 try testError("A", error.InvalidPadding);
396 try testError("AA", error.InvalidPadding);
397 try testError("AAA", error.InvalidPadding);
375 try testError("A", error.InvalidPadding);
376 try testError("AA", error.InvalidPadding);
377 try testError("AAA", error.InvalidPadding);
398378 try testError("A..A", error.InvalidCharacter);
399379 try testError("AA=A", error.InvalidCharacter);
400380 try testError("AA/=", error.InvalidPadding);
......@@ -427,8 +407,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
427407
428408 // Base64DecoderWithIgnore
429409 {
430 const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
431 standard_alphabet_chars, standard_pad_char, "");
410 const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, "");
432411 var buffer: [0x100]u8 = undefined;
433412 var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
434413 var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
......@@ -446,8 +425,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
446425}
447426
448427fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !void {
449 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
450 standard_alphabet_chars, standard_pad_char, " ");
428 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
451429 var buffer: [0x100]u8 = undefined;
452430 var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
453431 var written = try standard_decoder_ignore_space.decode(decoded, encoded);
......@@ -455,8 +433,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi
455433}
456434
457435fn testError(encoded: []const u8, expected_err: error) !void {
458 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
459 standard_alphabet_chars, standard_pad_char, " ");
436 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
460437 var buffer: [0x100]u8 = undefined;
461438 if (standard_decoder.calcSize(encoded)) |decoded_size| {
462439 var decoded = buffer[0..decoded_size];
......@@ -471,10 +448,9 @@ fn testError(encoded: []const u8, expected_err: error) !void {
471448}
472449
473450fn testOutputTooSmallError(encoded: []const u8) !void {
474 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
475 standard_alphabet_chars, standard_pad_char, " ");
451 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
476452 var buffer: [0x100]u8 = undefined;
477 var decoded = buffer[0..calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1];
453 var decoded = buffer[0 .. calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1];
478454 if (standard_decoder_ignore_space.decode(decoded, encoded)) |_| {
479455 return error.ExpectedError;
480456 } else |err| if (err != error.OutputTooSmall) return err;
std/buf_map.zig+17-19
......@@ -11,17 +11,15 @@ pub const BufMap = struct {
1111
1212 const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8);
1313
14 pub fn init(allocator: &Allocator) BufMap {
15 var self = BufMap {
16 .hash_map = BufMapHashMap.init(allocator),
17 };
14 pub fn init(allocator: *Allocator) BufMap {
15 var self = BufMap{ .hash_map = BufMapHashMap.init(allocator) };
1816 return self;
1917 }
2018
21 pub fn deinit(self: &BufMap) void {
19 pub fn deinit(self: *const BufMap) void {
2220 var it = self.hash_map.iterator();
2321 while (true) {
24 const entry = it.next() ?? break;
22 const entry = it.next() orelse break;
2523 self.free(entry.key);
2624 self.free(entry.value);
2725 }
......@@ -29,7 +27,7 @@ pub const BufMap = struct {
2927 self.hash_map.deinit();
3028 }
3129
32 pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void {
30 pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void {
3331 self.delete(key);
3432 const key_copy = try self.copy(key);
3533 errdefer self.free(key_copy);
......@@ -38,30 +36,30 @@ pub const BufMap = struct {
3836 _ = try self.hash_map.put(key_copy, value_copy);
3937 }
4038
41 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {
42 const entry = self.hash_map.get(key) ?? return null;
39 pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
40 const entry = self.hash_map.get(key) orelse return null;
4341 return entry.value;
4442 }
4543
46 pub fn delete(self: &BufMap, key: []const u8) void {
47 const entry = self.hash_map.remove(key) ?? return;
44 pub fn delete(self: *BufMap, key: []const u8) void {
45 const entry = self.hash_map.remove(key) orelse return;
4846 self.free(entry.key);
4947 self.free(entry.value);
5048 }
5149
52 pub fn count(self: &const BufMap) usize {
53 return self.hash_map.size;
50 pub fn count(self: *const BufMap) usize {
51 return self.hash_map.count();
5452 }
5553
56 pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator {
54 pub fn iterator(self: *const BufMap) BufMapHashMap.Iterator {
5755 return self.hash_map.iterator();
5856 }
5957
60 fn free(self: &BufMap, value: []const u8) void {
58 fn free(self: *const BufMap, value: []const u8) void {
6159 self.hash_map.allocator.free(value);
6260 }
6361
64 fn copy(self: &BufMap, value: []const u8) ![]const u8 {
62 fn copy(self: *const BufMap, value: []const u8) ![]const u8 {
6563 return mem.dupe(self.hash_map.allocator, u8, value);
6664 }
6765};
......@@ -74,15 +72,15 @@ test "BufMap" {
7472 defer bufmap.deinit();
7573
7674 try bufmap.set("x", "1");
77 assert(mem.eql(u8, ??bufmap.get("x"), "1"));
75 assert(mem.eql(u8, bufmap.get("x").?, "1"));
7876 assert(1 == bufmap.count());
7977
8078 try bufmap.set("x", "2");
81 assert(mem.eql(u8, ??bufmap.get("x"), "2"));
79 assert(mem.eql(u8, bufmap.get("x").?, "2"));
8280 assert(1 == bufmap.count());
8381
8482 try bufmap.set("x", "3");
85 assert(mem.eql(u8, ??bufmap.get("x"), "3"));
83 assert(mem.eql(u8, bufmap.get("x").?, "3"));
8684 assert(1 == bufmap.count());
8785
8886 bufmap.delete("x");
std/buf_set.zig+31-15
......@@ -1,30 +1,30 @@
1const std = @import("index.zig");
12const HashMap = @import("hash_map.zig").HashMap;
23const mem = @import("mem.zig");
34const Allocator = mem.Allocator;
5const assert = std.debug.assert;
46
57pub const BufSet = struct {
68 hash_map: BufSetHashMap,
79
810 const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
911
10 pub fn init(a: &Allocator) BufSet {
11 var self = BufSet {
12 .hash_map = BufSetHashMap.init(a),
13 };
12 pub fn init(a: *Allocator) BufSet {
13 var self = BufSet{ .hash_map = BufSetHashMap.init(a) };
1414 return self;
1515 }
1616
17 pub fn deinit(self: &BufSet) void {
17 pub fn deinit(self: *const BufSet) void {
1818 var it = self.hash_map.iterator();
1919 while (true) {
20 const entry = it.next() ?? break;
20 const entry = it.next() orelse break;
2121 self.free(entry.key);
2222 }
2323
2424 self.hash_map.deinit();
2525 }
2626
27 pub fn put(self: &BufSet, key: []const u8) !void {
27 pub fn put(self: *BufSet, key: []const u8) !void {
2828 if (self.hash_map.get(key) == null) {
2929 const key_copy = try self.copy(key);
3030 errdefer self.free(key_copy);
......@@ -32,31 +32,47 @@ pub const BufSet = struct {
3232 }
3333 }
3434
35 pub fn delete(self: &BufSet, key: []const u8) void {
36 const entry = self.hash_map.remove(key) ?? return;
35 pub fn delete(self: *BufSet, key: []const u8) void {
36 const entry = self.hash_map.remove(key) orelse return;
3737 self.free(entry.key);
3838 }
3939
40 pub fn count(self: &const BufSet) usize {
41 return self.hash_map.size;
40 pub fn count(self: *const BufSet) usize {
41 return self.hash_map.count();
4242 }
4343
44 pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator {
44 pub fn iterator(self: *const BufSet) BufSetHashMap.Iterator {
4545 return self.hash_map.iterator();
4646 }
4747
48 pub fn allocator(self: &const BufSet) &Allocator {
48 pub fn allocator(self: *const BufSet) *Allocator {
4949 return self.hash_map.allocator;
5050 }
5151
52 fn free(self: &BufSet, value: []const u8) void {
52 fn free(self: *const BufSet, value: []const u8) void {
5353 self.hash_map.allocator.free(value);
5454 }
5555
56 fn copy(self: &BufSet, value: []const u8) ![]const u8 {
56 fn copy(self: *const BufSet, value: []const u8) ![]const u8 {
5757 const result = try self.hash_map.allocator.alloc(u8, value.len);
5858 mem.copy(u8, result, value);
5959 return result;
6060 }
6161};
6262
63test "BufSet" {
64 var direct_allocator = std.heap.DirectAllocator.init();
65 defer direct_allocator.deinit();
66
67 var bufset = BufSet.init(&direct_allocator.allocator);
68 defer bufset.deinit();
69
70 try bufset.put("x");
71 assert(bufset.count() == 1);
72 bufset.delete("x");
73 assert(bufset.count() == 0);
74
75 try bufset.put("x");
76 try bufset.put("y");
77 try bufset.put("z");
78}
std/buffer.zig+41-52
......@@ -5,21 +5,19 @@ const Allocator = mem.Allocator;
55const assert = debug.assert;
66const ArrayList = std.ArrayList;
77
8const fmt = std.fmt;
9
108/// A buffer that allocates memory and maintains a null byte at the end.
119pub const Buffer = struct {
1210 list: ArrayList(u8),
1311
1412 /// Must deinitialize with deinit.
15 pub fn init(allocator: &Allocator, m: []const u8) !Buffer {
13 pub fn init(allocator: *Allocator, m: []const u8) !Buffer {
1614 var self = try initSize(allocator, m.len);
1715 mem.copy(u8, self.list.items, m);
1816 return self;
1917 }
2018
2119 /// Must deinitialize with deinit.
22 pub fn initSize(allocator: &Allocator, size: usize) !Buffer {
20 pub fn initSize(allocator: *Allocator, size: usize) !Buffer {
2321 var self = initNull(allocator);
2422 try self.resize(size);
2523 return self;
......@@ -28,122 +26,113 @@ pub const Buffer = struct {
2826 /// Must deinitialize with deinit.
2927 /// None of the other operations are valid until you do one of these:
3028 /// * ::replaceContents
31 /// * ::replaceContentsBuffer
3229 /// * ::resize
33 pub fn initNull(allocator: &Allocator) Buffer {
34 return Buffer {
35 .list = ArrayList(u8).init(allocator),
36 };
30 pub fn initNull(allocator: *Allocator) Buffer {
31 return Buffer{ .list = ArrayList(u8).init(allocator) };
3732 }
3833
3934 /// Must deinitialize with deinit.
40 pub fn initFromBuffer(buffer: &const Buffer) !Buffer {
35 pub fn initFromBuffer(buffer: *const Buffer) !Buffer {
4136 return Buffer.init(buffer.list.allocator, buffer.toSliceConst());
4237 }
4338
4439 /// Buffer takes ownership of the passed in slice. The slice must have been
4540 /// allocated with `allocator`.
4641 /// Must deinitialize with deinit.
47 pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) Buffer {
48 var self = Buffer {
49 .list = ArrayList(u8).fromOwnedSlice(allocator, slice),
50 };
51 self.list.append(0);
42 pub fn fromOwnedSlice(allocator: *Allocator, slice: []u8) !Buffer {
43 var self = Buffer{ .list = ArrayList(u8).fromOwnedSlice(allocator, slice) };
44 try self.list.append(0);
5245 return self;
5346 }
5447
5548 /// The caller owns the returned memory. The Buffer becomes null and
5649 /// is safe to `deinit`.
57 pub fn toOwnedSlice(self: &Buffer) []u8 {
50 pub fn toOwnedSlice(self: *Buffer) []u8 {
5851 const allocator = self.list.allocator;
5952 const result = allocator.shrink(u8, self.list.items, self.len());
60 *self = initNull(allocator);
53 self.* = initNull(allocator);
6154 return result;
6255 }
6356
57 pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: ...) !Buffer {
58 const countSize = struct {
59 fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
60 size.* += bytes.len;
61 }
62 }.countSize;
63 var size: usize = 0;
64 std.fmt.format(&size, error{}, countSize, format, args) catch |err| switch (err) {};
65 var self = try Buffer.initSize(allocator, size);
66 assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
67 return self;
68 }
6469
65 pub fn deinit(self: &Buffer) void {
70 pub fn deinit(self: *Buffer) void {
6671 self.list.deinit();
6772 }
6873
69 pub fn toSlice(self: &Buffer) []u8 {
74 pub fn toSlice(self: *const Buffer) []u8 {
7075 return self.list.toSlice()[0..self.len()];
7176 }
7277
73 pub fn toSliceConst(self: &const Buffer) []const u8 {
78 pub fn toSliceConst(self: *const Buffer) []const u8 {
7479 return self.list.toSliceConst()[0..self.len()];
7580 }
7681
77 pub fn shrink(self: &Buffer, new_len: usize) void {
82 pub fn shrink(self: *Buffer, new_len: usize) void {
7883 assert(new_len <= self.len());
7984 self.list.shrink(new_len + 1);
8085 self.list.items[self.len()] = 0;
8186 }
8287
83 pub fn resize(self: &Buffer, new_len: usize) !void {
88 pub fn resize(self: *Buffer, new_len: usize) !void {
8489 try self.list.resize(new_len + 1);
8590 self.list.items[self.len()] = 0;
8691 }
8792
88 pub fn isNull(self: &const Buffer) bool {
93 pub fn isNull(self: *const Buffer) bool {
8994 return self.list.len == 0;
9095 }
9196
92 pub fn len(self: &const Buffer) usize {
97 pub fn len(self: *const Buffer) usize {
9398 return self.list.len - 1;
9499 }
95100
96 pub fn append(self: &Buffer, m: []const u8) !void {
101 pub fn append(self: *Buffer, m: []const u8) !void {
97102 const old_len = self.len();
98103 try self.resize(old_len + m.len);
99104 mem.copy(u8, self.list.toSlice()[old_len..], m);
100105 }
101106
102 // TODO: remove, use OutStream for this
103 pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) !void {
104 return fmt.format(self, append, format, args);
105 }
106
107 // TODO: remove, use OutStream for this
108 pub fn appendByte(self: &Buffer, byte: u8) !void {
109 return self.appendByteNTimes(byte, 1);
110 }
111
112 // TODO: remove, use OutStream for this
113 pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) !void {
114 var prev_size: usize = self.len();
115 const new_size = prev_size + count;
116 try self.resize(new_size);
117
118 var i: usize = prev_size;
119 while (i < new_size) : (i += 1) {
120 self.list.items[i] = byte;
121 }
107 pub fn appendByte(self: *Buffer, byte: u8) !void {
108 const old_len = self.len();
109 try self.resize(old_len + 1);
110 self.list.toSlice()[old_len] = byte;
122111 }
123112
124 pub fn eql(self: &const Buffer, m: []const u8) bool {
113 pub fn eql(self: *const Buffer, m: []const u8) bool {
125114 return mem.eql(u8, self.toSliceConst(), m);
126115 }
127116
128 pub fn startsWith(self: &const Buffer, m: []const u8) bool {
117 pub fn startsWith(self: *const Buffer, m: []const u8) bool {
129118 if (self.len() < m.len) return false;
130119 return mem.eql(u8, self.list.items[0..m.len], m);
131120 }
132121
133 pub fn endsWith(self: &const Buffer, m: []const u8) bool {
122 pub fn endsWith(self: *const Buffer, m: []const u8) bool {
134123 const l = self.len();
135124 if (l < m.len) return false;
136125 const start = l - m.len;
137126 return mem.eql(u8, self.list.items[start..l], m);
138127 }
139128
140 pub fn replaceContents(self: &const Buffer, m: []const u8) !void {
129 pub fn replaceContents(self: *Buffer, m: []const u8) !void {
141130 try self.resize(m.len);
142131 mem.copy(u8, self.list.toSlice(), m);
143132 }
144133
145134 /// For passing to C functions.
146 pub fn ptr(self: &const Buffer) &u8 {
135 pub fn ptr(self: *const Buffer) [*]u8 {
147136 return self.list.items.ptr;
148137 }
149138};
......@@ -154,7 +143,7 @@ test "simple Buffer" {
154143 var buf = try Buffer.init(debug.global_allocator, "");
155144 assert(buf.len() == 0);
156145 try buf.append("hello");
157 try buf.appendByte(' ');
146 try buf.append(" ");
158147 try buf.append("world");
159148 assert(buf.eql("hello world"));
160149 assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
......@@ -166,5 +155,5 @@ test "simple Buffer" {
166155 assert(buf.endsWith("orld"));
167156
168157 try buf2.resize(4);
169 assert(buf.startsWith(buf2.toSliceConst()));
158 assert(buf.startsWith(buf2.toSlice()));
170159}
std/build.zig+298-297
......@@ -20,7 +20,7 @@ pub const Builder = struct {
2020 install_tls: TopLevelStep,
2121 have_uninstall_step: bool,
2222 have_install_step: bool,
23 allocator: &Allocator,
23 allocator: *Allocator,
2424 lib_paths: ArrayList([]const u8),
2525 include_paths: ArrayList([]const u8),
2626 rpaths: ArrayList([]const u8),
......@@ -36,9 +36,9 @@ pub const Builder = struct {
3636 verbose_cimport: bool,
3737 invalid_user_input: bool,
3838 zig_exe: []const u8,
39 default_step: &Step,
39 default_step: *Step,
4040 env_map: BufMap,
41 top_level_steps: ArrayList(&TopLevelStep),
41 top_level_steps: ArrayList(*TopLevelStep),
4242 prefix: []const u8,
4343 search_prefixes: ArrayList([]const u8),
4444 lib_dir: []const u8,
......@@ -82,10 +82,8 @@ pub const Builder = struct {
8282 description: []const u8,
8383 };
8484
85 pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8,
86 cache_root: []const u8) Builder
87 {
88 var self = Builder {
85 pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
86 var self = Builder{
8987 .zig_exe = zig_exe,
9088 .build_root = build_root,
9189 .cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,
......@@ -104,7 +102,7 @@ pub const Builder = struct {
104102 .user_input_options = UserInputOptionsMap.init(allocator),
105103 .available_options_map = AvailableOptionsMap.init(allocator),
106104 .available_options_list = ArrayList(AvailableOption).init(allocator),
107 .top_level_steps = ArrayList(&TopLevelStep).init(allocator),
105 .top_level_steps = ArrayList(*TopLevelStep).init(allocator),
108106 .default_step = undefined,
109107 .env_map = os.getEnvMap(allocator) catch unreachable,
110108 .prefix = undefined,
......@@ -112,12 +110,12 @@ pub const Builder = struct {
112110 .lib_dir = undefined,
113111 .exe_dir = undefined,
114112 .installed_files = ArrayList([]const u8).init(allocator),
115 .uninstall_tls = TopLevelStep {
113 .uninstall_tls = TopLevelStep{
116114 .step = Step.init("uninstall", allocator, makeUninstall),
117115 .description = "Remove build artifacts from prefix path",
118116 },
119117 .have_uninstall_step = false,
120 .install_tls = TopLevelStep {
118 .install_tls = TopLevelStep{
121119 .step = Step.initNoOp("install", allocator),
122120 .description = "Copy build artifacts to prefix path",
123121 },
......@@ -129,7 +127,7 @@ pub const Builder = struct {
129127 return self;
130128 }
131129
132 pub fn deinit(self: &Builder) void {
130 pub fn deinit(self: *Builder) void {
133131 self.lib_paths.deinit();
134132 self.include_paths.deinit();
135133 self.rpaths.deinit();
......@@ -137,110 +135,102 @@ pub const Builder = struct {
137135 self.top_level_steps.deinit();
138136 }
139137
140 pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) void {
141 self.prefix = maybe_prefix ?? "/usr/local"; // TODO better default
138 pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
139 self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
142140 self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
143141 self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
144142 }
145143
146 pub fn addExecutable(self: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
144 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
147145 return LibExeObjStep.createExecutable(self, name, root_src);
148146 }
149147
150 pub fn addObject(self: &Builder, name: []const u8, root_src: []const u8) &LibExeObjStep {
148 pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
151149 return LibExeObjStep.createObject(self, name, root_src);
152150 }
153151
154 pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8,
155 ver: &const Version) &LibExeObjStep
156 {
152 pub fn addSharedLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8, ver: *const Version) *LibExeObjStep {
157153 return LibExeObjStep.createSharedLibrary(self, name, root_src, ver);
158154 }
159155
160 pub fn addStaticLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
156 pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
161157 return LibExeObjStep.createStaticLibrary(self, name, root_src);
162158 }
163159
164 pub fn addTest(self: &Builder, root_src: []const u8) &TestStep {
165 const test_step = self.allocator.create(TestStep) catch unreachable;
166 *test_step = TestStep.init(self, root_src);
160 pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
161 const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable;
167162 return test_step;
168163 }
169164
170 pub fn addAssemble(self: &Builder, name: []const u8, src: []const u8) &LibExeObjStep {
165 pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
171166 const obj_step = LibExeObjStep.createObject(self, name, null);
172167 obj_step.addAssemblyFile(src);
173168 return obj_step;
174169 }
175170
176 pub fn addCStaticLibrary(self: &Builder, name: []const u8) &LibExeObjStep {
171 pub fn addCStaticLibrary(self: *Builder, name: []const u8) *LibExeObjStep {
177172 return LibExeObjStep.createCStaticLibrary(self, name);
178173 }
179174
180 pub fn addCSharedLibrary(self: &Builder, name: []const u8, ver: &const Version) &LibExeObjStep {
175 pub fn addCSharedLibrary(self: *Builder, name: []const u8, ver: *const Version) *LibExeObjStep {
181176 return LibExeObjStep.createCSharedLibrary(self, name, ver);
182177 }
183178
184 pub fn addCExecutable(self: &Builder, name: []const u8) &LibExeObjStep {
179 pub fn addCExecutable(self: *Builder, name: []const u8) *LibExeObjStep {
185180 return LibExeObjStep.createCExecutable(self, name);
186181 }
187182
188 pub fn addCObject(self: &Builder, name: []const u8, src: []const u8) &LibExeObjStep {
183 pub fn addCObject(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
189184 return LibExeObjStep.createCObject(self, name, src);
190185 }
191186
192187 /// ::argv is copied.
193 pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
194 argv: []const []const u8) &CommandStep
195 {
188 pub fn addCommand(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
196189 return CommandStep.create(self, cwd, env_map, argv);
197190 }
198191
199 pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) &WriteFileStep {
200 const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
201 *write_file_step = WriteFileStep.init(self, file_path, data);
192 pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
193 const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable;
202194 return write_file_step;
203195 }
204196
205 pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) &LogStep {
197 pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep {
206198 const data = self.fmt(format, args);
207 const log_step = self.allocator.create(LogStep) catch unreachable;
208 *log_step = LogStep.init(self, data);
199 const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable;
209200 return log_step;
210201 }
211202
212 pub fn addRemoveDirTree(self: &Builder, dir_path: []const u8) &RemoveDirStep {
213 const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
214 *remove_dir_step = RemoveDirStep.init(self, dir_path);
203 pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {
204 const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable;
215205 return remove_dir_step;
216206 }
217207
218 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) Version {
219 return Version {
208 pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) Version {
209 return Version{
220210 .major = major,
221211 .minor = minor,
222212 .patch = patch,
223213 };
224214 }
225215
226 pub fn addCIncludePath(self: &Builder, path: []const u8) void {
216 pub fn addCIncludePath(self: *Builder, path: []const u8) void {
227217 self.include_paths.append(path) catch unreachable;
228218 }
229219
230 pub fn addRPath(self: &Builder, path: []const u8) void {
220 pub fn addRPath(self: *Builder, path: []const u8) void {
231221 self.rpaths.append(path) catch unreachable;
232222 }
233223
234 pub fn addLibPath(self: &Builder, path: []const u8) void {
224 pub fn addLibPath(self: *Builder, path: []const u8) void {
235225 self.lib_paths.append(path) catch unreachable;
236226 }
237227
238 pub fn make(self: &Builder, step_names: []const []const u8) !void {
239 var wanted_steps = ArrayList(&Step).init(self.allocator);
228 pub fn make(self: *Builder, step_names: []const []const u8) !void {
229 var wanted_steps = ArrayList(*Step).init(self.allocator);
240230 defer wanted_steps.deinit();
241231
242232 if (step_names.len == 0) {
243 try wanted_steps.append(&self.default_step);
233 try wanted_steps.append(self.default_step);
244234 } else {
245235 for (step_names) |step_name| {
246236 const s = try self.getTopLevelStepByName(step_name);
......@@ -253,25 +243,23 @@ pub const Builder = struct {
253243 }
254244 }
255245
256 pub fn getInstallStep(self: &Builder) &Step {
257 if (self.have_install_step)
258 return &self.install_tls.step;
246 pub fn getInstallStep(self: *Builder) *Step {
247 if (self.have_install_step) return &self.install_tls.step;
259248
260249 self.top_level_steps.append(&self.install_tls) catch unreachable;
261250 self.have_install_step = true;
262251 return &self.install_tls.step;
263252 }
264253
265 pub fn getUninstallStep(self: &Builder) &Step {
266 if (self.have_uninstall_step)
267 return &self.uninstall_tls.step;
254 pub fn getUninstallStep(self: *Builder) *Step {
255 if (self.have_uninstall_step) return &self.uninstall_tls.step;
268256
269257 self.top_level_steps.append(&self.uninstall_tls) catch unreachable;
270258 self.have_uninstall_step = true;
271259 return &self.uninstall_tls.step;
272260 }
273261
274 fn makeUninstall(uninstall_step: &Step) error!void {
262 fn makeUninstall(uninstall_step: *Step) error!void {
275263 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
276264 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
277265
......@@ -285,7 +273,7 @@ pub const Builder = struct {
285273 // TODO remove empty directories
286274 }
287275
288 fn makeOneStep(self: &Builder, s: &Step) error!void {
276 fn makeOneStep(self: *Builder, s: *Step) error!void {
289277 if (s.loop_flag) {
290278 warn("Dependency loop detected:\n {}\n", s.name);
291279 return error.DependencyLoopDetected;
......@@ -306,7 +294,7 @@ pub const Builder = struct {
306294 try s.make();
307295 }
308296
309 fn getTopLevelStepByName(self: &Builder, name: []const u8) !&Step {
297 fn getTopLevelStepByName(self: *Builder, name: []const u8) !*Step {
310298 for (self.top_level_steps.toSliceConst()) |top_level_step| {
311299 if (mem.eql(u8, top_level_step.step.name, name)) {
312300 return &top_level_step.step;
......@@ -316,13 +304,13 @@ pub const Builder = struct {
316304 return error.InvalidStepName;
317305 }
318306
319 fn processNixOSEnvVars(self: &Builder) void {
307 fn processNixOSEnvVars(self: *Builder) void {
320308 if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
321309 var it = mem.split(nix_cflags_compile, " ");
322310 while (true) {
323 const word = it.next() ?? break;
311 const word = it.next() orelse break;
324312 if (mem.eql(u8, word, "-isystem")) {
325 const include_path = it.next() ?? {
313 const include_path = it.next() orelse {
326314 warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
327315 break;
328316 };
......@@ -338,9 +326,9 @@ pub const Builder = struct {
338326 if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
339327 var it = mem.split(nix_ldflags, " ");
340328 while (true) {
341 const word = it.next() ?? break;
329 const word = it.next() orelse break;
342330 if (mem.eql(u8, word, "-rpath")) {
343 const rpath = it.next() ?? {
331 const rpath = it.next() orelse {
344332 warn("Expected argument after -rpath in NIX_LDFLAGS\n");
345333 break;
346334 };
......@@ -358,9 +346,9 @@ pub const Builder = struct {
358346 }
359347 }
360348
361 pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
349 pub fn option(self: *Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
362350 const type_id = comptime typeToEnum(T);
363 const available_option = AvailableOption {
351 const available_option = AvailableOption{
364352 .name = name,
365353 .type_id = type_id,
366354 .description = description,
......@@ -370,7 +358,7 @@ pub const Builder = struct {
370358 }
371359 self.available_options_list.append(available_option) catch unreachable;
372360
373 const entry = self.user_input_options.get(name) ?? return null;
361 const entry = self.user_input_options.get(name) orelse return null;
374362 entry.value.used = true;
375363 switch (type_id) {
376364 TypeId.Bool => switch (entry.value.value) {
......@@ -411,30 +399,24 @@ pub const Builder = struct {
411399 }
412400 }
413401
414 pub fn step(self: &Builder, name: []const u8, description: []const u8) &Step {
415 const step_info = self.allocator.create(TopLevelStep) catch unreachable;
416 *step_info = TopLevelStep {
402 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
403 const step_info = self.allocator.create(TopLevelStep{
417404 .step = Step.initNoOp(name, self.allocator),
418405 .description = description,
419 };
406 }) catch unreachable;
420407 self.top_level_steps.append(step_info) catch unreachable;
421408 return &step_info.step;
422409 }
423410
424 pub fn standardReleaseOptions(self: &Builder) builtin.Mode {
411 pub fn standardReleaseOptions(self: *Builder) builtin.Mode {
425412 if (self.release_mode) |mode| return mode;
426413
427 const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
428 const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
429
430 const mode = if (release_safe and !release_fast)
431 builtin.Mode.ReleaseSafe
432 else if (release_fast and !release_safe)
433 builtin.Mode.ReleaseFast
434 else if (!release_fast and !release_safe)
435 builtin.Mode.Debug
436 else x: {
437 warn("Both -Drelease-safe and -Drelease-fast specified");
414 const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") orelse false;
415 const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") orelse false;
416 const release_small = self.option(bool, "release-small", "size optimizations on and safety off") orelse false;
417
418 const mode = if (release_safe and !release_fast and !release_small) builtin.Mode.ReleaseSafe else if (release_fast and !release_safe and !release_small) builtin.Mode.ReleaseFast else if (release_small and !release_fast and !release_safe) builtin.Mode.ReleaseSmall else if (!release_fast and !release_safe and !release_small) builtin.Mode.Debug else x: {
419 warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)");
438420 self.markInvalidUserInput();
439421 break :x builtin.Mode.Debug;
440422 };
......@@ -442,10 +424,10 @@ pub const Builder = struct {
442424 return mode;
443425 }
444426
445 pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) bool {
446 if (self.user_input_options.put(name, UserInputOption {
427 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) bool {
428 if (self.user_input_options.put(name, UserInputOption{
447429 .name = name,
448 .value = UserValue { .Scalar = value },
430 .value = UserValue{ .Scalar = value },
449431 .used = false,
450432 }) catch unreachable) |*prev_value| {
451433 // option already exists
......@@ -455,18 +437,18 @@ pub const Builder = struct {
455437 var list = ArrayList([]const u8).init(self.allocator);
456438 list.append(s) catch unreachable;
457439 list.append(value) catch unreachable;
458 _ = self.user_input_options.put(name, UserInputOption {
440 _ = self.user_input_options.put(name, UserInputOption{
459441 .name = name,
460 .value = UserValue { .List = list },
442 .value = UserValue{ .List = list },
461443 .used = false,
462444 }) catch unreachable;
463445 },
464446 UserValue.List => |*list| {
465447 // append to the list
466448 list.append(value) catch unreachable;
467 _ = self.user_input_options.put(name, UserInputOption {
449 _ = self.user_input_options.put(name, UserInputOption{
468450 .name = name,
469 .value = UserValue { .List = *list },
451 .value = UserValue{ .List = list.* },
470452 .used = false,
471453 }) catch unreachable;
472454 },
......@@ -479,10 +461,10 @@ pub const Builder = struct {
479461 return false;
480462 }
481463
482 pub fn addUserInputFlag(self: &Builder, name: []const u8) bool {
483 if (self.user_input_options.put(name, UserInputOption {
464 pub fn addUserInputFlag(self: *Builder, name: []const u8) bool {
465 if (self.user_input_options.put(name, UserInputOption{
484466 .name = name,
485 .value = UserValue {.Flag = {} },
467 .value = UserValue{ .Flag = {} },
486468 .used = false,
487469 }) catch unreachable) |*prev_value| {
488470 switch (prev_value.value) {
......@@ -513,7 +495,7 @@ pub const Builder = struct {
513495 };
514496 }
515497
516 fn markInvalidUserInput(self: &Builder) void {
498 fn markInvalidUserInput(self: *Builder) void {
517499 self.invalid_user_input = true;
518500 }
519501
......@@ -527,11 +509,11 @@ pub const Builder = struct {
527509 };
528510 }
529511
530 pub fn validateUserInputDidItFail(self: &Builder) bool {
512 pub fn validateUserInputDidItFail(self: *Builder) bool {
531513 // make sure all args are used
532514 var it = self.user_input_options.iterator();
533515 while (true) {
534 const entry = it.next() ?? break;
516 const entry = it.next() orelse break;
535517 if (!entry.value.used) {
536518 warn("Invalid option: -D{}\n\n", entry.key);
537519 self.markInvalidUserInput();
......@@ -541,7 +523,7 @@ pub const Builder = struct {
541523 return self.invalid_user_input;
542524 }
543525
544 fn spawnChild(self: &Builder, argv: []const []const u8) !void {
526 fn spawnChild(self: *Builder, argv: []const []const u8) !void {
545527 return self.spawnChildEnvMap(null, &self.env_map, argv);
546528 }
547529
......@@ -553,9 +535,7 @@ pub const Builder = struct {
553535 warn("\n");
554536 }
555537
556 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
557 argv: []const []const u8) !void
558 {
538 fn spawnChildEnvMap(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) !void {
559539 if (self.verbose) {
560540 printCmd(cwd, argv);
561541 }
......@@ -588,51 +568,50 @@ pub const Builder = struct {
588568 }
589569 }
590570
591 pub fn makePath(self: &Builder, path: []const u8) !void {
571 pub fn makePath(self: *Builder, path: []const u8) !void {
592572 os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {
593573 warn("Unable to create path {}: {}\n", path, @errorName(err));
594574 return err;
595575 };
596576 }
597577
598 pub fn installArtifact(self: &Builder, artifact: &LibExeObjStep) void {
578 pub fn installArtifact(self: *Builder, artifact: *LibExeObjStep) void {
599579 self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
600580 }
601581
602 pub fn addInstallArtifact(self: &Builder, artifact: &LibExeObjStep) &InstallArtifactStep {
582 pub fn addInstallArtifact(self: *Builder, artifact: *LibExeObjStep) *InstallArtifactStep {
603583 return InstallArtifactStep.create(self, artifact);
604584 }
605585
606586 ///::dest_rel_path is relative to prefix path or it can be an absolute path
607 pub fn installFile(self: &Builder, src_path: []const u8, dest_rel_path: []const u8) void {
587 pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
608588 self.getInstallStep().dependOn(&self.addInstallFile(src_path, dest_rel_path).step);
609589 }
610590
611591 ///::dest_rel_path is relative to prefix path or it can be an absolute path
612 pub fn addInstallFile(self: &Builder, src_path: []const u8, dest_rel_path: []const u8) &InstallFileStep {
592 pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
613593 const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;
614594 self.pushInstalledFile(full_dest_path);
615595
616 const install_step = self.allocator.create(InstallFileStep) catch unreachable;
617 *install_step = InstallFileStep.init(self, src_path, full_dest_path);
596 const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable;
618597 return install_step;
619598 }
620599
621 pub fn pushInstalledFile(self: &Builder, full_path: []const u8) void {
600 pub fn pushInstalledFile(self: *Builder, full_path: []const u8) void {
622601 _ = self.getUninstallStep();
623602 self.installed_files.append(full_path) catch unreachable;
624603 }
625604
626 fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) !void {
605 fn copyFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
627606 return self.copyFileMode(source_path, dest_path, os.default_file_mode);
628607 }
629608
630 fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: os.FileMode) !void {
609 fn copyFileMode(self: *Builder, source_path: []const u8, dest_path: []const u8, mode: os.FileMode) !void {
631610 if (self.verbose) {
632611 warn("cp {} {}\n", source_path, dest_path);
633612 }
634613
635 const dirname = os.path.dirname(dest_path);
614 const dirname = os.path.dirname(dest_path) orelse ".";
636615 const abs_source_path = self.pathFromRoot(source_path);
637616 os.makePath(self.allocator, dirname) catch |err| {
638617 warn("Unable to create path {}: {}\n", dirname, @errorName(err));
......@@ -644,37 +623,31 @@ pub const Builder = struct {
644623 };
645624 }
646625
647 fn pathFromRoot(self: &Builder, rel_path: []const u8) []u8 {
626 fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
648627 return os.path.resolve(self.allocator, self.build_root, rel_path) catch unreachable;
649628 }
650629
651 pub fn fmt(self: &Builder, comptime format: []const u8, args: ...) []u8 {
630 pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {
652631 return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;
653632 }
654633
655 fn getCCExe(self: &Builder) []const u8 {
634 fn getCCExe(self: *Builder) []const u8 {
656635 if (builtin.environ == builtin.Environ.msvc) {
657636 return "cl.exe";
658637 } else {
659 return os.getEnvVarOwned(self.allocator, "CC") catch |err|
660 if (err == error.EnvironmentVariableNotFound)
661 ([]const u8)("cc")
662 else
663 debug.panic("Unable to get environment variable: {}", err)
664 ;
638 return os.getEnvVarOwned(self.allocator, "CC") catch |err| if (err == error.EnvironmentVariableNotFound) ([]const u8)("cc") else debug.panic("Unable to get environment variable: {}", err);
665639 }
666640 }
667641
668 pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
642 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
669643 // TODO report error for ambiguous situations
670 const exe_extension = (Target { .Native = {}}).exeFileExt();
644 const exe_extension = (Target{ .Native = {} }).exeFileExt();
671645 for (self.search_prefixes.toSliceConst()) |search_prefix| {
672646 for (names) |name| {
673647 if (os.path.isAbsolute(name)) {
674648 return name;
675649 }
676 const full_path = try os.path.join(self.allocator, search_prefix, "bin",
677 self.fmt("{}{}", name, exe_extension));
650 const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
678651 if (os.path.real(self.allocator, full_path)) |real_path| {
679652 return real_path;
680653 } else |_| {
......@@ -714,7 +687,7 @@ pub const Builder = struct {
714687 return error.FileNotFound;
715688 }
716689
717 pub fn exec(self: &Builder, argv: []const []const u8) ![]u8 {
690 pub fn exec(self: *Builder, argv: []const []const u8) ![]u8 {
718691 const max_output_size = 100 * 1024;
719692 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
720693 switch (result.term) {
......@@ -736,7 +709,7 @@ pub const Builder = struct {
736709 }
737710 }
738711
739 pub fn addSearchPrefix(self: &Builder, search_prefix: []const u8) void {
712 pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void {
740713 self.search_prefixes.append(search_prefix) catch unreachable;
741714 }
742715};
......@@ -757,8 +730,8 @@ pub const Target = union(enum) {
757730 Native: void,
758731 Cross: CrossTarget,
759732
760 pub fn oFileExt(self: &const Target) []const u8 {
761 const environ = switch (*self) {
733 pub fn oFileExt(self: *const Target) []const u8 {
734 const environ = switch (self.*) {
762735 Target.Native => builtin.environ,
763736 Target.Cross => |t| t.environ,
764737 };
......@@ -768,49 +741,49 @@ pub const Target = union(enum) {
768741 };
769742 }
770743
771 pub fn exeFileExt(self: &const Target) []const u8 {
744 pub fn exeFileExt(self: *const Target) []const u8 {
772745 return switch (self.getOs()) {
773746 builtin.Os.windows => ".exe",
774747 else => "",
775748 };
776749 }
777750
778 pub fn libFileExt(self: &const Target) []const u8 {
751 pub fn libFileExt(self: *const Target) []const u8 {
779752 return switch (self.getOs()) {
780753 builtin.Os.windows => ".lib",
781754 else => ".a",
782755 };
783756 }
784757
785 pub fn getOs(self: &const Target) builtin.Os {
786 return switch (*self) {
758 pub fn getOs(self: *const Target) builtin.Os {
759 return switch (self.*) {
787760 Target.Native => builtin.os,
788761 Target.Cross => |t| t.os,
789762 };
790763 }
791764
792 pub fn isDarwin(self: &const Target) bool {
765 pub fn isDarwin(self: *const Target) bool {
793766 return switch (self.getOs()) {
794767 builtin.Os.ios, builtin.Os.macosx => true,
795768 else => false,
796769 };
797770 }
798771
799 pub fn isWindows(self: &const Target) bool {
772 pub fn isWindows(self: *const Target) bool {
800773 return switch (self.getOs()) {
801774 builtin.Os.windows => true,
802775 else => false,
803776 };
804777 }
805778
806 pub fn wantSharedLibSymLinks(self: &const Target) bool {
779 pub fn wantSharedLibSymLinks(self: *const Target) bool {
807780 return !self.isWindows();
808781 }
809782};
810783
811784pub const LibExeObjStep = struct {
812785 step: Step,
813 builder: &Builder,
786 builder: *Builder,
814787 name: []const u8,
815788 target: Target,
816789 link_libs: BufSet,
......@@ -834,6 +807,7 @@ pub const LibExeObjStep = struct {
834807 disable_libc: bool,
835808 frameworks: BufSet,
836809 verbose_link: bool,
810 no_rosegment: bool,
837811
838812 // zig only stuff
839813 root_src: ?[]const u8,
......@@ -841,6 +815,7 @@ pub const LibExeObjStep = struct {
841815 out_h_filename: []const u8,
842816 assembly_files: ArrayList([]const u8),
843817 packages: ArrayList(Pkg),
818 build_options_contents: std.Buffer,
844819
845820 // C only stuff
846821 source_files: ArrayList([]const u8),
......@@ -857,61 +832,50 @@ pub const LibExeObjStep = struct {
857832 Obj,
858833 };
859834
860 pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8,
861 ver: &const Version) &LibExeObjStep
862 {
863 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
864 *self = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
835 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: *const Version) *LibExeObjStep {
836 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable;
865837 return self;
866838 }
867839
868 pub fn createCSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) &LibExeObjStep {
869 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
870 *self = initC(builder, name, Kind.Lib, version, false);
840 pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: *const Version) *LibExeObjStep {
841 const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable;
871842 return self;
872843 }
873844
874 pub fn createStaticLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
875 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
876 *self = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
845 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
846 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable;
877847 return self;
878848 }
879849
880 pub fn createCStaticLibrary(builder: &Builder, name: []const u8) &LibExeObjStep {
881 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
882 *self = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
850 pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {
851 const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable;
883852 return self;
884853 }
885854
886 pub fn createObject(builder: &Builder, name: []const u8, root_src: []const u8) &LibExeObjStep {
887 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
888 *self = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
855 pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
856 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable;
889857 return self;
890858 }
891859
892 pub fn createCObject(builder: &Builder, name: []const u8, src: []const u8) &LibExeObjStep {
893 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
894 *self = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
860 pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
861 const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable;
895862 self.object_src = src;
896863 return self;
897864 }
898865
899 pub fn createExecutable(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
900 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
901 *self = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
866 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
867 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable;
902868 return self;
903869 }
904870
905 pub fn createCExecutable(builder: &Builder, name: []const u8) &LibExeObjStep {
906 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
907 *self = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
871 pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {
872 const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable;
908873 return self;
909874 }
910875
911 fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind,
912 static: bool, ver: &const Version) LibExeObjStep
913 {
914 var self = LibExeObjStep {
876 fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, static: bool, ver: *const Version) LibExeObjStep {
877 var self = LibExeObjStep{
878 .no_rosegment = false,
915879 .strip = false,
916880 .builder = builder,
917881 .verbose_link = false,
......@@ -927,7 +891,7 @@ pub const LibExeObjStep = struct {
927891 .step = Step.init(name, builder.allocator, make),
928892 .output_path = null,
929893 .output_h_path = null,
930 .version = *ver,
894 .version = ver.*,
931895 .out_filename = undefined,
932896 .out_h_filename = builder.fmt("{}.h", name),
933897 .major_only_filename = undefined,
......@@ -944,17 +908,19 @@ pub const LibExeObjStep = struct {
944908 .lib_paths = ArrayList([]const u8).init(builder.allocator),
945909 .object_src = undefined,
946910 .disable_libc = true,
911 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
947912 };
948913 self.computeOutFileNames();
949914 return self;
950915 }
951916
952 fn initC(builder: &Builder, name: []const u8, kind: Kind, version: &const Version, static: bool) LibExeObjStep {
953 var self = LibExeObjStep {
917 fn initC(builder: *Builder, name: []const u8, kind: Kind, version: *const Version, static: bool) LibExeObjStep {
918 var self = LibExeObjStep{
919 .no_rosegment = false,
954920 .builder = builder,
955921 .name = name,
956922 .kind = kind,
957 .version = *version,
923 .version = version.*,
958924 .static = static,
959925 .target = Target.Native,
960926 .cflags = ArrayList([]const u8).init(builder.allocator),
......@@ -984,12 +950,17 @@ pub const LibExeObjStep = struct {
984950 .out_h_filename = undefined,
985951 .assembly_files = undefined,
986952 .packages = undefined,
953 .build_options_contents = undefined,
987954 };
988955 self.computeOutFileNames();
989956 return self;
990957 }
991958
992 fn computeOutFileNames(self: &LibExeObjStep) void {
959 pub fn setNoRoSegment(self: *LibExeObjStep, value: bool) void {
960 self.no_rosegment = value;
961 }
962
963 fn computeOutFileNames(self: *LibExeObjStep) void {
993964 switch (self.kind) {
994965 Kind.Obj => {
995966 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt());
......@@ -1003,8 +974,7 @@ pub const LibExeObjStep = struct {
1003974 } else {
1004975 switch (self.target.getOs()) {
1005976 builtin.Os.ios, builtin.Os.macosx => {
1006 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib",
1007 self.name, self.version.major, self.version.minor, self.version.patch);
977 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
1008978 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
1009979 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
1010980 },
......@@ -1012,8 +982,7 @@ pub const LibExeObjStep = struct {
1012982 self.out_filename = self.builder.fmt("{}.dll", self.name);
1013983 },
1014984 else => {
1015 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
1016 self.name, self.version.major, self.version.minor, self.version.patch);
985 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
1017986 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
1018987 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
1019988 },
......@@ -1023,30 +992,28 @@ pub const LibExeObjStep = struct {
1023992 }
1024993 }
1025994
1026 pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
1027 target_environ: builtin.Environ) void
1028 {
1029 self.target = Target {
1030 .Cross = CrossTarget {
995 pub fn setTarget(self: *LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
996 self.target = Target{
997 .Cross = CrossTarget{
1031998 .arch = target_arch,
1032999 .os = target_os,
10331000 .environ = target_environ,
1034 }
1001 },
10351002 };
10361003 self.computeOutFileNames();
10371004 }
10381005
10391006 // TODO respect this in the C args
1040 pub fn setLinkerScriptPath(self: &LibExeObjStep, path: []const u8) void {
1007 pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void {
10411008 self.linker_script = path;
10421009 }
10431010
1044 pub fn linkFramework(self: &LibExeObjStep, framework_name: []const u8) void {
1011 pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {
10451012 assert(self.target.isDarwin());
10461013 self.frameworks.put(framework_name) catch unreachable;
10471014 }
10481015
1049 pub fn linkLibrary(self: &LibExeObjStep, lib: &LibExeObjStep) void {
1016 pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {
10501017 assert(self.kind != Kind.Obj);
10511018 assert(lib.kind == Kind.Lib);
10521019
......@@ -1067,26 +1034,26 @@ pub const LibExeObjStep = struct {
10671034 }
10681035 }
10691036
1070 pub fn linkSystemLibrary(self: &LibExeObjStep, name: []const u8) void {
1037 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
10711038 assert(self.kind != Kind.Obj);
10721039 self.link_libs.put(name) catch unreachable;
10731040 }
10741041
1075 pub fn addSourceFile(self: &LibExeObjStep, file: []const u8) void {
1042 pub fn addSourceFile(self: *LibExeObjStep, file: []const u8) void {
10761043 assert(self.kind != Kind.Obj);
10771044 assert(!self.is_zig);
10781045 self.source_files.append(file) catch unreachable;
10791046 }
10801047
1081 pub fn setVerboseLink(self: &LibExeObjStep, value: bool) void {
1048 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
10821049 self.verbose_link = value;
10831050 }
10841051
1085 pub fn setBuildMode(self: &LibExeObjStep, mode: builtin.Mode) void {
1052 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {
10861053 self.build_mode = mode;
10871054 }
10881055
1089 pub fn setOutputPath(self: &LibExeObjStep, file_path: []const u8) void {
1056 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
10901057 self.output_path = file_path;
10911058
10921059 // catch a common mistake
......@@ -1095,14 +1062,11 @@ pub const LibExeObjStep = struct {
10951062 }
10961063 }
10971064
1098 pub fn getOutputPath(self: &LibExeObjStep) []const u8 {
1099 return if (self.output_path) |output_path|
1100 output_path
1101 else
1102 os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable;
1065 pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
1066 return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable;
11031067 }
11041068
1105 pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) void {
1069 pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
11061070 self.output_h_path = file_path;
11071071
11081072 // catch a common mistake
......@@ -1111,24 +1075,21 @@ pub const LibExeObjStep = struct {
11111075 }
11121076 }
11131077
1114 pub fn getOutputHPath(self: &LibExeObjStep) []const u8 {
1115 return if (self.output_h_path) |output_h_path|
1116 output_h_path
1117 else
1118 os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable;
1078 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
1079 return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable;
11191080 }
11201081
1121 pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) void {
1082 pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
11221083 self.assembly_files.append(path) catch unreachable;
11231084 }
11241085
1125 pub fn addObjectFile(self: &LibExeObjStep, path: []const u8) void {
1086 pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void {
11261087 assert(self.kind != Kind.Obj);
11271088
11281089 self.object_files.append(path) catch unreachable;
11291090 }
11301091
1131 pub fn addObject(self: &LibExeObjStep, obj: &LibExeObjStep) void {
1092 pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void {
11321093 assert(obj.kind == Kind.Obj);
11331094 assert(self.kind != Kind.Obj);
11341095
......@@ -1145,40 +1106,46 @@ pub const LibExeObjStep = struct {
11451106 self.include_dirs.append(self.builder.cache_root) catch unreachable;
11461107 }
11471108
1148 pub fn addIncludeDir(self: &LibExeObjStep, path: []const u8) void {
1109 pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
1110 assert(self.is_zig);
1111 const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;
1112 out.print("pub const {} = {};\n", name, value) catch unreachable;
1113 }
1114
1115 pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void {
11491116 self.include_dirs.append(path) catch unreachable;
11501117 }
11511118
1152 pub fn addLibPath(self: &LibExeObjStep, path: []const u8) void {
1119 pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void {
11531120 self.lib_paths.append(path) catch unreachable;
11541121 }
11551122
1156 pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
1123 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
11571124 assert(self.is_zig);
11581125
1159 self.packages.append(Pkg {
1126 self.packages.append(Pkg{
11601127 .name = name,
11611128 .path = pkg_index_path,
11621129 }) catch unreachable;
11631130 }
11641131
1165 pub fn addCompileFlags(self: &LibExeObjStep, flags: []const []const u8) void {
1132 pub fn addCompileFlags(self: *LibExeObjStep, flags: []const []const u8) void {
11661133 for (flags) |flag| {
11671134 self.cflags.append(flag) catch unreachable;
11681135 }
11691136 }
11701137
1171 pub fn setNoStdLib(self: &LibExeObjStep, disable: bool) void {
1138 pub fn setNoStdLib(self: *LibExeObjStep, disable: bool) void {
11721139 assert(!self.is_zig);
11731140 self.disable_libc = disable;
11741141 }
11751142
1176 fn make(step: &Step) !void {
1143 fn make(step: *Step) !void {
11771144 const self = @fieldParentPtr(LibExeObjStep, "step", step);
11781145 return if (self.is_zig) self.makeZig() else self.makeC();
11791146 }
11801147
1181 fn makeZig(self: &LibExeObjStep) !void {
1148 fn makeZig(self: *LibExeObjStep) !void {
11821149 const builder = self.builder;
11831150
11841151 assert(self.is_zig);
......@@ -1204,6 +1171,15 @@ pub const LibExeObjStep = struct {
12041171 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
12051172 }
12061173
1174 if (self.build_options_contents.len() > 0) {
1175 const build_options_file = try os.path.join(builder.allocator, builder.cache_root, builder.fmt("{}_build_options.zig", self.name));
1176 try std.io.writeFile(builder.allocator, build_options_file, self.build_options_contents.toSliceConst());
1177 try zig_args.append("--pkg-begin");
1178 try zig_args.append("build_options");
1179 try zig_args.append(builder.pathFromRoot(build_options_file));
1180 try zig_args.append("--pkg-end");
1181 }
1182
12071183 for (self.object_files.toSliceConst()) |object_file| {
12081184 zig_args.append("--object") catch unreachable;
12091185 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
......@@ -1229,6 +1205,7 @@ pub const LibExeObjStep = struct {
12291205 builtin.Mode.Debug => {},
12301206 builtin.Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
12311207 builtin.Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
1208 builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
12321209 }
12331210
12341211 zig_args.append("--cache-dir") catch unreachable;
......@@ -1280,7 +1257,7 @@ pub const LibExeObjStep = struct {
12801257 {
12811258 var it = self.link_libs.iterator();
12821259 while (true) {
1283 const entry = it.next() ?? break;
1260 const entry = it.next() orelse break;
12841261 zig_args.append("--library") catch unreachable;
12851262 zig_args.append(entry.key) catch unreachable;
12861263 }
......@@ -1336,15 +1313,18 @@ pub const LibExeObjStep = struct {
13361313 }
13371314 }
13381315
1316 if (self.no_rosegment) {
1317 try zig_args.append("--no-rosegment");
1318 }
1319
13391320 try builder.spawnChild(zig_args.toSliceConst());
13401321
13411322 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
1342 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
1343 self.name_only_filename);
1323 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
13441324 }
13451325 }
13461326
1347 fn appendCompileFlags(self: &LibExeObjStep, args: &ArrayList([]const u8)) void {
1327 fn appendCompileFlags(self: *LibExeObjStep, args: *ArrayList([]const u8)) void {
13481328 if (!self.strip) {
13491329 args.append("-g") catch unreachable;
13501330 }
......@@ -1369,7 +1349,7 @@ pub const LibExeObjStep = struct {
13691349 args.append("ssp-buffer-size=4") catch unreachable;
13701350 }
13711351 },
1372 builtin.Mode.ReleaseFast => {
1352 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {
13731353 args.append("-O2") catch unreachable;
13741354 args.append("-fno-stack-protector") catch unreachable;
13751355 },
......@@ -1389,7 +1369,7 @@ pub const LibExeObjStep = struct {
13891369 }
13901370 }
13911371
1392 fn makeC(self: &LibExeObjStep) !void {
1372 fn makeC(self: *LibExeObjStep) !void {
13931373 const builder = self.builder;
13941374
13951375 const cc = builder.getCCExe();
......@@ -1430,8 +1410,9 @@ pub const LibExeObjStep = struct {
14301410 cc_args.append(abs_source_file) catch unreachable;
14311411
14321412 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
1433 const cache_o_dir = os.path.dirname(cache_o_src);
1434 try builder.makePath(cache_o_dir);
1413 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1414 try builder.makePath(cache_o_dir);
1415 }
14351416 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
14361417 cc_args.append("-o") catch unreachable;
14371418 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
......@@ -1501,8 +1482,7 @@ pub const LibExeObjStep = struct {
15011482 }
15021483
15031484 if (!is_darwin) {
1504 const rpath_arg = builder.fmt("-Wl,-rpath,{}",
1505 os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
1485 const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
15061486 defer builder.allocator.free(rpath_arg);
15071487 cc_args.append(rpath_arg) catch unreachable;
15081488
......@@ -1531,8 +1511,7 @@ pub const LibExeObjStep = struct {
15311511 try builder.spawnChild(cc_args.toSliceConst());
15321512
15331513 if (self.target.wantSharedLibSymLinks()) {
1534 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
1535 self.name_only_filename);
1514 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
15361515 }
15371516 }
15381517 },
......@@ -1546,8 +1525,9 @@ pub const LibExeObjStep = struct {
15461525 cc_args.append(abs_source_file) catch unreachable;
15471526
15481527 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
1549 const cache_o_dir = os.path.dirname(cache_o_src);
1550 try builder.makePath(cache_o_dir);
1528 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1529 try builder.makePath(cache_o_dir);
1530 }
15511531 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
15521532 cc_args.append("-o") catch unreachable;
15531533 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
......@@ -1577,8 +1557,7 @@ pub const LibExeObjStep = struct {
15771557 cc_args.append("-o") catch unreachable;
15781558 cc_args.append(output_path) catch unreachable;
15791559
1580 const rpath_arg = builder.fmt("-Wl,-rpath,{}",
1581 os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
1560 const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
15821561 defer builder.allocator.free(rpath_arg);
15831562 cc_args.append(rpath_arg) catch unreachable;
15841563
......@@ -1618,7 +1597,7 @@ pub const LibExeObjStep = struct {
16181597
16191598pub const TestStep = struct {
16201599 step: Step,
1621 builder: &Builder,
1600 builder: *Builder,
16221601 root_src: []const u8,
16231602 build_mode: builtin.Mode,
16241603 verbose: bool,
......@@ -1628,10 +1607,13 @@ pub const TestStep = struct {
16281607 target: Target,
16291608 exec_cmd_args: ?[]const ?[]const u8,
16301609 include_dirs: ArrayList([]const u8),
1610 lib_paths: ArrayList([]const u8),
1611 object_files: ArrayList([]const u8),
1612 no_rosegment: bool,
16311613
1632 pub fn init(builder: &Builder, root_src: []const u8) TestStep {
1614 pub fn init(builder: *Builder, root_src: []const u8) TestStep {
16331615 const step_name = builder.fmt("test {}", root_src);
1634 return TestStep {
1616 return TestStep{
16351617 .step = Step.init(step_name, builder.allocator, make),
16361618 .builder = builder,
16371619 .root_src = root_src,
......@@ -1640,53 +1622,66 @@ pub const TestStep = struct {
16401622 .name_prefix = "",
16411623 .filter = null,
16421624 .link_libs = BufSet.init(builder.allocator),
1643 .target = Target { .Native = {} },
1625 .target = Target{ .Native = {} },
16441626 .exec_cmd_args = null,
16451627 .include_dirs = ArrayList([]const u8).init(builder.allocator),
1628 .lib_paths = ArrayList([]const u8).init(builder.allocator),
1629 .object_files = ArrayList([]const u8).init(builder.allocator),
1630 .no_rosegment = false,
16461631 };
16471632 }
16481633
1649 pub fn setVerbose(self: &TestStep, value: bool) void {
1634 pub fn setNoRoSegment(self: *TestStep, value: bool) void {
1635 self.no_rosegment = value;
1636 }
1637
1638 pub fn addLibPath(self: *TestStep, path: []const u8) void {
1639 self.lib_paths.append(path) catch unreachable;
1640 }
1641
1642 pub fn setVerbose(self: *TestStep, value: bool) void {
16501643 self.verbose = value;
16511644 }
16521645
1653 pub fn addIncludeDir(self: &TestStep, path: []const u8) void {
1646 pub fn addIncludeDir(self: *TestStep, path: []const u8) void {
16541647 self.include_dirs.append(path) catch unreachable;
16551648 }
16561649
1657 pub fn setBuildMode(self: &TestStep, mode: builtin.Mode) void {
1650 pub fn setBuildMode(self: *TestStep, mode: builtin.Mode) void {
16581651 self.build_mode = mode;
16591652 }
16601653
1661 pub fn linkSystemLibrary(self: &TestStep, name: []const u8) void {
1654 pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void {
16621655 self.link_libs.put(name) catch unreachable;
16631656 }
16641657
1665 pub fn setNamePrefix(self: &TestStep, text: []const u8) void {
1658 pub fn setNamePrefix(self: *TestStep, text: []const u8) void {
16661659 self.name_prefix = text;
16671660 }
16681661
1669 pub fn setFilter(self: &TestStep, text: ?[]const u8) void {
1662 pub fn setFilter(self: *TestStep, text: ?[]const u8) void {
16701663 self.filter = text;
16711664 }
16721665
1673 pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,
1674 target_environ: builtin.Environ) void
1675 {
1676 self.target = Target {
1677 .Cross = CrossTarget {
1666 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
1667 self.object_files.append(path) catch unreachable;
1668 }
1669
1670 pub fn setTarget(self: *TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
1671 self.target = Target{
1672 .Cross = CrossTarget{
16781673 .arch = target_arch,
16791674 .os = target_os,
16801675 .environ = target_environ,
1681 }
1676 },
16821677 };
16831678 }
16841679
1685 pub fn setExecCmd(self: &TestStep, args: []const ?[]const u8) void {
1680 pub fn setExecCmd(self: *TestStep, args: []const ?[]const u8) void {
16861681 self.exec_cmd_args = args;
16871682 }
16881683
1689 fn make(step: &Step) !void {
1684 fn make(step: *Step) !void {
16901685 const self = @fieldParentPtr(TestStep, "step", step);
16911686 const builder = self.builder;
16921687
......@@ -1706,6 +1701,7 @@ pub const TestStep = struct {
17061701 builtin.Mode.Debug => {},
17071702 builtin.Mode.ReleaseSafe => try zig_args.append("--release-safe"),
17081703 builtin.Mode.ReleaseFast => try zig_args.append("--release-fast"),
1704 builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
17091705 }
17101706
17111707 switch (self.target) {
......@@ -1732,10 +1728,15 @@ pub const TestStep = struct {
17321728 try zig_args.append(self.name_prefix);
17331729 }
17341730
1731 for (self.object_files.toSliceConst()) |object_file| {
1732 try zig_args.append("--object");
1733 try zig_args.append(builder.pathFromRoot(object_file));
1734 }
1735
17351736 {
17361737 var it = self.link_libs.iterator();
17371738 while (true) {
1738 const entry = it.next() ?? break;
1739 const entry = it.next() orelse break;
17391740 try zig_args.append("--library");
17401741 try zig_args.append(entry.key);
17411742 }
......@@ -1767,40 +1768,47 @@ pub const TestStep = struct {
17671768 try zig_args.append(rpath);
17681769 }
17691770
1771 for (self.lib_paths.toSliceConst()) |lib_path| {
1772 try zig_args.append("--library-path");
1773 try zig_args.append(lib_path);
1774 }
1775
17701776 for (builder.lib_paths.toSliceConst()) |lib_path| {
17711777 try zig_args.append("--library-path");
17721778 try zig_args.append(lib_path);
17731779 }
17741780
1781 if (self.no_rosegment) {
1782 try zig_args.append("--no-rosegment");
1783 }
1784
17751785 try builder.spawnChild(zig_args.toSliceConst());
17761786 }
17771787};
17781788
17791789pub const CommandStep = struct {
17801790 step: Step,
1781 builder: &Builder,
1791 builder: *Builder,
17821792 argv: [][]const u8,
17831793 cwd: ?[]const u8,
1784 env_map: &const BufMap,
1794 env_map: *const BufMap,
17851795
17861796 /// ::argv is copied.
1787 pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
1788 argv: []const []const u8) &CommandStep
1789 {
1790 const self = builder.allocator.create(CommandStep) catch unreachable;
1791 *self = CommandStep {
1797 pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
1798 const self = builder.allocator.create(CommandStep{
17921799 .builder = builder,
17931800 .step = Step.init(argv[0], builder.allocator, make),
17941801 .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
17951802 .cwd = cwd,
17961803 .env_map = env_map,
1797 };
1804 }) catch unreachable;
1805
17981806 mem.copy([]const u8, self.argv, argv);
17991807 self.step.name = self.argv[0];
18001808 return self;
18011809 }
18021810
1803 fn make(step: &Step) !void {
1811 fn make(step: *Step) !void {
18041812 const self = @fieldParentPtr(CommandStep, "step", step);
18051813
18061814 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
......@@ -1810,37 +1818,34 @@ pub const CommandStep = struct {
18101818
18111819const InstallArtifactStep = struct {
18121820 step: Step,
1813 builder: &Builder,
1814 artifact: &LibExeObjStep,
1821 builder: *Builder,
1822 artifact: *LibExeObjStep,
18151823 dest_file: []const u8,
18161824
18171825 const Self = this;
18181826
1819 pub fn create(builder: &Builder, artifact: &LibExeObjStep) &Self {
1820 const self = builder.allocator.create(Self) catch unreachable;
1827 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
18211828 const dest_dir = switch (artifact.kind) {
18221829 LibExeObjStep.Kind.Obj => unreachable,
18231830 LibExeObjStep.Kind.Exe => builder.exe_dir,
18241831 LibExeObjStep.Kind.Lib => builder.lib_dir,
18251832 };
1826 *self = Self {
1833 const self = builder.allocator.create(Self{
18271834 .builder = builder,
18281835 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
18291836 .artifact = artifact,
18301837 .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
1831 };
1838 }) catch unreachable;
18321839 self.step.dependOn(&artifact.step);
18331840 builder.pushInstalledFile(self.dest_file);
18341841 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
1835 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir,
1836 artifact.major_only_filename) catch unreachable);
1837 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir,
1838 artifact.name_only_filename) catch unreachable);
1842 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable);
1843 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable);
18391844 }
18401845 return self;
18411846 }
18421847
1843 fn make(step: &Step) !void {
1848 fn make(step: *Step) !void {
18441849 const self = @fieldParentPtr(Self, "step", step);
18451850 const builder = self.builder;
18461851
......@@ -1854,20 +1859,19 @@ const InstallArtifactStep = struct {
18541859 };
18551860 try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
18561861 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
1857 try doAtomicSymLinks(builder.allocator, self.dest_file,
1858 self.artifact.major_only_filename, self.artifact.name_only_filename);
1862 try doAtomicSymLinks(builder.allocator, self.dest_file, self.artifact.major_only_filename, self.artifact.name_only_filename);
18591863 }
18601864 }
18611865};
18621866
18631867pub const InstallFileStep = struct {
18641868 step: Step,
1865 builder: &Builder,
1869 builder: *Builder,
18661870 src_path: []const u8,
18671871 dest_path: []const u8,
18681872
1869 pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) InstallFileStep {
1870 return InstallFileStep {
1873 pub fn init(builder: *Builder, src_path: []const u8, dest_path: []const u8) InstallFileStep {
1874 return InstallFileStep{
18711875 .builder = builder,
18721876 .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),
18731877 .src_path = src_path,
......@@ -1875,7 +1879,7 @@ pub const InstallFileStep = struct {
18751879 };
18761880 }
18771881
1878 fn make(step: &Step) !void {
1882 fn make(step: *Step) !void {
18791883 const self = @fieldParentPtr(InstallFileStep, "step", step);
18801884 try self.builder.copyFile(self.src_path, self.dest_path);
18811885 }
......@@ -1883,12 +1887,12 @@ pub const InstallFileStep = struct {
18831887
18841888pub const WriteFileStep = struct {
18851889 step: Step,
1886 builder: &Builder,
1890 builder: *Builder,
18871891 file_path: []const u8,
18881892 data: []const u8,
18891893
1890 pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) WriteFileStep {
1891 return WriteFileStep {
1894 pub fn init(builder: *Builder, file_path: []const u8, data: []const u8) WriteFileStep {
1895 return WriteFileStep{
18921896 .builder = builder,
18931897 .step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make),
18941898 .file_path = file_path,
......@@ -1896,10 +1900,10 @@ pub const WriteFileStep = struct {
18961900 };
18971901 }
18981902
1899 fn make(step: &Step) !void {
1903 fn make(step: *Step) !void {
19001904 const self = @fieldParentPtr(WriteFileStep, "step", step);
19011905 const full_path = self.builder.pathFromRoot(self.file_path);
1902 const full_path_dir = os.path.dirname(full_path);
1906 const full_path_dir = os.path.dirname(full_path) orelse ".";
19031907 os.makePath(self.builder.allocator, full_path_dir) catch |err| {
19041908 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
19051909 return err;
......@@ -1913,18 +1917,18 @@ pub const WriteFileStep = struct {
19131917
19141918pub const LogStep = struct {
19151919 step: Step,
1916 builder: &Builder,
1920 builder: *Builder,
19171921 data: []const u8,
19181922
1919 pub fn init(builder: &Builder, data: []const u8) LogStep {
1920 return LogStep {
1923 pub fn init(builder: *Builder, data: []const u8) LogStep {
1924 return LogStep{
19211925 .builder = builder,
19221926 .step = Step.init(builder.fmt("log {}", data), builder.allocator, make),
19231927 .data = data,
19241928 };
19251929 }
19261930
1927 fn make(step: &Step) error!void {
1931 fn make(step: *Step) error!void {
19281932 const self = @fieldParentPtr(LogStep, "step", step);
19291933 warn("{}", self.data);
19301934 }
......@@ -1932,18 +1936,18 @@ pub const LogStep = struct {
19321936
19331937pub const RemoveDirStep = struct {
19341938 step: Step,
1935 builder: &Builder,
1939 builder: *Builder,
19361940 dir_path: []const u8,
19371941
1938 pub fn init(builder: &Builder, dir_path: []const u8) RemoveDirStep {
1939 return RemoveDirStep {
1942 pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep {
1943 return RemoveDirStep{
19401944 .builder = builder,
19411945 .step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make),
19421946 .dir_path = dir_path,
19431947 };
19441948 }
19451949
1946 fn make(step: &Step) !void {
1950 fn make(step: *Step) !void {
19471951 const self = @fieldParentPtr(RemoveDirStep, "step", step);
19481952
19491953 const full_path = self.builder.pathFromRoot(self.dir_path);
......@@ -1956,43 +1960,40 @@ pub const RemoveDirStep = struct {
19561960
19571961pub const Step = struct {
19581962 name: []const u8,
1959 makeFn: fn(self: &Step) error!void,
1960 dependencies: ArrayList(&Step),
1963 makeFn: fn (self: *Step) error!void,
1964 dependencies: ArrayList(*Step),
19611965 loop_flag: bool,
19621966 done_flag: bool,
19631967
1964 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step {
1965 return Step {
1968 pub fn init(name: []const u8, allocator: *Allocator, makeFn: fn (*Step) error!void) Step {
1969 return Step{
19661970 .name = name,
19671971 .makeFn = makeFn,
1968 .dependencies = ArrayList(&Step).init(allocator),
1972 .dependencies = ArrayList(*Step).init(allocator),
19691973 .loop_flag = false,
19701974 .done_flag = false,
19711975 };
19721976 }
1973 pub fn initNoOp(name: []const u8, allocator: &Allocator) Step {
1977 pub fn initNoOp(name: []const u8, allocator: *Allocator) Step {
19741978 return init(name, allocator, makeNoOp);
19751979 }
19761980
1977 pub fn make(self: &Step) !void {
1978 if (self.done_flag)
1979 return;
1981 pub fn make(self: *Step) !void {
1982 if (self.done_flag) return;
19801983
19811984 try self.makeFn(self);
19821985 self.done_flag = true;
19831986 }
19841987
1985 pub fn dependOn(self: &Step, other: &Step) void {
1988 pub fn dependOn(self: *Step, other: *Step) void {
19861989 self.dependencies.append(other) catch unreachable;
19871990 }
19881991
1989 fn makeNoOp(self: &Step) error!void {}
1992 fn makeNoOp(self: *Step) error!void {}
19901993};
19911994
1992fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
1993 filename_name_only: []const u8) !void
1994{
1995 const out_dir = os.path.dirname(output_path);
1995fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1996 const out_dir = os.path.dirname(output_path) orelse ".";
19961997 const out_basename = os.path.basename(output_path);
19971998 // sym link for libfoo.so.1 to libfoo.so.1.2.3
19981999 const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
std/c/darwin.zig+100-5
......@@ -1,12 +1,54 @@
1extern "c" fn __error() &c_int;
2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
1extern "c" fn __error() *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;
4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize;
55
6pub use @import("../os/darwin_errno.zig");
6pub extern "c" fn mach_absolute_time() u64;
7pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void;
8
9pub extern "c" fn kqueue() c_int;
10pub extern "c" fn kevent(
11 kq: c_int,
12 changelist: [*]const Kevent,
13 nchanges: c_int,
14 eventlist: [*]Kevent,
15 nevents: c_int,
16 timeout: ?*const timespec,
17) c_int;
18
19pub extern "c" fn kevent64(
20 kq: c_int,
21 changelist: [*]const kevent64_s,
22 nchanges: c_int,
23 eventlist: [*]kevent64_s,
24 nevents: c_int,
25 flags: c_uint,
26 timeout: ?*const timespec,
27) c_int;
28
29pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
30pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
31pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
32
33pub use @import("../os/darwin/errno.zig");
734
835pub const _errno = __error;
936
37pub const timeval = extern struct {
38 tv_sec: isize,
39 tv_usec: isize,
40};
41
42pub const timezone = extern struct {
43 tz_minuteswest: i32,
44 tz_dsttime: i32,
45};
46
47pub const mach_timebase_info_data = extern struct {
48 numer: u32,
49 denom: u32,
50};
51
1052/// Renamed to Stat to not conflict with the stat function.
1153pub const Stat = extern struct {
1254 dev: i32,
......@@ -42,7 +84,7 @@ pub const sigset_t = u32;
4284
4385/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
4486pub const Sigaction = extern struct {
45 handler: extern fn(c_int)void,
87 handler: extern fn (c_int) void,
4688 sa_mask: sigset_t,
4789 sa_flags: c_int,
4890};
......@@ -63,3 +105,56 @@ pub const sockaddr = extern struct {
63105};
64106
65107pub const sa_family_t = u8;
108
109pub const pthread_attr_t = extern struct {
110 __sig: c_long,
111 __opaque: [56]u8,
112};
113
114/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
115pub const Kevent = extern struct {
116 ident: usize,
117 filter: i16,
118 flags: u16,
119 fflags: u32,
120 data: isize,
121 udata: usize,
122};
123
124// sys/types.h on macos uses #pragma pack(4) so these checks are
125// to make sure the struct is laid out the same. These values were
126// produced from C code using the offsetof macro.
127const std = @import("../index.zig");
128const assert = std.debug.assert;
129
130comptime {
131 assert(@offsetOf(Kevent, "ident") == 0);
132 assert(@offsetOf(Kevent, "filter") == 8);
133 assert(@offsetOf(Kevent, "flags") == 10);
134 assert(@offsetOf(Kevent, "fflags") == 12);
135 assert(@offsetOf(Kevent, "data") == 16);
136 assert(@offsetOf(Kevent, "udata") == 24);
137}
138
139pub const kevent64_s = extern struct {
140 ident: u64,
141 filter: i16,
142 flags: u16,
143 fflags: u32,
144 data: i64,
145 udata: u64,
146 ext: [2]u64,
147};
148
149// sys/types.h on macos uses #pragma pack() so these checks are
150// to make sure the struct is laid out the same. These values were
151// produced from C code using the offsetof macro.
152comptime {
153 assert(@offsetOf(kevent64_s, "ident") == 0);
154 assert(@offsetOf(kevent64_s, "filter") == 8);
155 assert(@offsetOf(kevent64_s, "flags") == 10);
156 assert(@offsetOf(kevent64_s, "fflags") == 12);
157 assert(@offsetOf(kevent64_s, "data") == 16);
158 assert(@offsetOf(kevent64_s, "udata") == 24);
159 assert(@offsetOf(kevent64_s, "ext") == 32);
160}
std/c/index.zig+41-32
......@@ -1,7 +1,7 @@
11const builtin = @import("builtin");
22const Os = builtin.Os;
33
4pub use switch(builtin.os) {
4pub use switch (builtin.os) {
55 Os.linux => @import("linux.zig"),
66 Os.windows => @import("windows.zig"),
77 Os.macosx, Os.ios => @import("darwin.zig"),
......@@ -9,46 +9,55 @@ pub use switch(builtin.os) {
99};
1010const empty_import = @import("../empty.zig");
1111
12// TODO https://github.com/ziglang/zig/issues/265 on this whole file
13
1214pub extern "c" fn abort() noreturn;
1315pub extern "c" fn exit(code: c_int) noreturn;
1416pub extern "c" fn isatty(fd: c_int) c_int;
1517pub extern "c" fn close(fd: c_int) c_int;
16pub extern "c" fn fstat(fd: c_int, buf: &Stat) c_int;
17pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: &Stat) c_int;
18pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;
19pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
1820pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
19pub extern "c" fn open(path: &const u8, oflag: c_int, ...) c_int;
21pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
2022pub extern "c" fn raise(sig: c_int) c_int;
21pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize;
22pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int;
23pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) isize;
24pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int,
25 fd: c_int, offset: isize) ?&c_void;
26pub extern "c" fn munmap(addr: &c_void, len: usize) c_int;
27pub extern "c" fn unlink(path: &const u8) c_int;
28pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;
29pub extern "c" fn waitpid(pid: c_int, stat_loc: &c_int, options: c_int) c_int;
23pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
24pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
25pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
26pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
27pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
28pub extern "c" fn unlink(path: [*]const u8) c_int;
29pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
30pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
3031pub extern "c" fn fork() c_int;
31pub extern "c" fn access(path: &const u8, mode: c_uint) c_int;
32pub extern "c" fn pipe(fds: &c_int) c_int;
33pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;
34pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int;
35pub extern "c" fn rename(old: &const u8, new: &const u8) c_int;
36pub extern "c" fn chdir(path: &const u8) c_int;
37pub extern "c" fn execve(path: &const u8, argv: &const ?&const u8,
38 envp: &const ?&const u8) c_int;
32pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
33pub extern "c" fn pipe(fds: *[2]c_int) c_int;
34pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
35pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
36pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
37pub extern "c" fn chdir(path: [*]const u8) c_int;
38pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
3939pub extern "c" fn dup(fd: c_int) c_int;
4040pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
41pub extern "c" fn readlink(noalias path: &const u8, noalias buf: &u8, bufsize: usize) isize;
42pub extern "c" fn realpath(noalias file_name: &const u8, noalias resolved_name: &u8) ?&u8;
43pub extern "c" fn sigprocmask(how: c_int, noalias set: &const sigset_t, noalias oset: ?&sigset_t) c_int;
44pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias oact: ?&Sigaction) c_int;
45pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
41pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
42pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
43pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
44pub extern "c" fn gettimeofday(tv: ?*timeval, tz: ?*timezone) c_int;
45pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
46pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
4647pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
4748pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
48pub extern "c" fn rmdir(path: &const u8) c_int;
49pub extern "c" fn rmdir(path: [*]const u8) c_int;
50
51pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
52pub extern "c" fn malloc(usize) ?*c_void;
53pub extern "c" fn realloc(*c_void, usize) ?*c_void;
54pub extern "c" fn free(*c_void) void;
55pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
56
57pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
58pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
59pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
60pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
61pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
4962
50pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
51pub extern "c" fn malloc(usize) ?&c_void;
52pub extern "c" fn realloc(&c_void, usize) ?&c_void;
53pub extern "c" fn free(&c_void) void;
54pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) c_int;
63pub const pthread_t = *@OpaqueType();
std/c/linux.zig+7-2
......@@ -1,5 +1,10 @@
11pub use @import("../os/linux/errno.zig");
22
3pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) c_int;
4extern "c" fn __errno_location() &c_int;
3pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;
4extern "c" fn __errno_location() *c_int;
55pub const _errno = __errno_location;
6
7pub const pthread_attr_t = extern struct {
8 __size: [56]u8,
9 __align: c_long,
10};
std/c/windows.zig+1-1
......@@ -1 +1 @@
1pub extern "c" fn _errno() &c_int;
1pub extern "c" fn _errno() *c_int;
std/crypto/blake2.zig+266-241
......@@ -6,11 +6,23 @@ const builtin = @import("builtin");
66const htest = @import("test.zig");
77
88const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
9 a: usize,
10 b: usize,
11 c: usize,
12 d: usize,
13 x: usize,
14 y: usize,
1015};
1116
1217fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
13 return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
18 return RoundParam{
19 .a = a,
20 .b = b,
21 .c = c,
22 .d = d,
23 .x = x,
24 .y = y,
25 };
1426}
1527
1628/////////////////////
......@@ -19,145 +31,153 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
1931pub const Blake2s224 = Blake2s(224);
2032pub const Blake2s256 = Blake2s(256);
2133
22fn Blake2s(comptime out_len: usize) type { return struct {
23 const Self = this;
24 const block_size = 64;
25 const digest_size = out_len / 8;
34fn Blake2s(comptime out_len: usize) type {
35 return struct {
36 const Self = this;
37 const block_size = 64;
38 const digest_size = out_len / 8;
39
40 const iv = [8]u32{
41 0x6A09E667,
42 0xBB67AE85,
43 0x3C6EF372,
44 0xA54FF53A,
45 0x510E527F,
46 0x9B05688C,
47 0x1F83D9AB,
48 0x5BE0CD19,
49 };
2650
27 const iv = [8]u32 {
28 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
29 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
30 };
51 const sigma = [10][16]u8{
52 []const u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
53 []const u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
54 []const u8{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
55 []const u8{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
56 []const u8{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
57 []const u8{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
58 []const u8{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
59 []const u8{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
60 []const u8{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
61 []const u8{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
62 };
3163
32 const sigma = [10][16]u8 {
33 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
34 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
35 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
36 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
37 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
38 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
39 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
40 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
41 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
42 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
43 };
64 h: [8]u32,
65 t: u64,
66 // Streaming cache
67 buf: [64]u8,
68 buf_len: u8,
4469
45 h: [8]u32,
46 t: u64,
47 // Streaming cache
48 buf: [64]u8,
49 buf_len: u8,
50
51 pub fn init() Self {
52 debug.assert(8 <= out_len and out_len <= 512);
53
54 var s: Self = undefined;
55 s.reset();
56 return s;
57 }
58
59 pub fn reset(d: &Self) void {
60 mem.copy(u32, d.h[0..], iv[0..]);
61
62 // No key plus default parameters
63 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
64 d.t = 0;
65 d.buf_len = 0;
66 }
67
68 pub fn hash(b: []const u8, out: []u8) void {
69 var d = Self.init();
70 d.update(b);
71 d.final(out);
72 }
73
74 pub fn update(d: &Self, b: []const u8) void {
75 var off: usize = 0;
76
77 // Partial buffer exists from previous update. Copy into buffer then hash.
78 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
79 off += 64 - d.buf_len;
80 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
81 d.t += 64;
82 d.round(d.buf[0..], false);
83 d.buf_len = 0;
70 pub fn init() Self {
71 debug.assert(8 <= out_len and out_len <= 512);
72
73 var s: Self = undefined;
74 s.reset();
75 return s;
8476 }
8577
86 // Full middle blocks.
87 while (off + 64 <= b.len) : (off += 64) {
88 d.t += 64;
89 d.round(b[off..off + 64], false);
78 pub fn reset(d: *Self) void {
79 mem.copy(u32, d.h[0..], iv[0..]);
80
81 // No key plus default parameters
82 d.h[0] ^= 0x01010000 ^ @intCast(u32, out_len >> 3);
83 d.t = 0;
84 d.buf_len = 0;
9085 }
9186
92 // Copy any remainder for next pass.
93 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
94 d.buf_len += u8(b[off..].len);
95 }
87 pub fn hash(b: []const u8, out: []u8) void {
88 var d = Self.init();
89 d.update(b);
90 d.final(out);
91 }
9692
97 pub fn final(d: &Self, out: []u8) void {
98 debug.assert(out.len >= out_len / 8);
93 pub fn update(d: *Self, b: []const u8) void {
94 var off: usize = 0;
9995
100 mem.set(u8, d.buf[d.buf_len..], 0);
101 d.t += d.buf_len;
102 d.round(d.buf[0..], true);
96 // Partial buffer exists from previous update. Copy into buffer then hash.
97 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
98 off += 64 - d.buf_len;
99 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
100 d.t += 64;
101 d.round(d.buf[0..], false);
102 d.buf_len = 0;
103 }
103104
104 const rr = d.h[0 .. out_len / 32];
105 // Full middle blocks.
106 while (off + 64 <= b.len) : (off += 64) {
107 d.t += 64;
108 d.round(b[off .. off + 64], false);
109 }
105110
106 for (rr) |s, j| {
107 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
111 // Copy any remainder for next pass.
112 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
113 d.buf_len += @intCast(u8, b[off..].len);
108114 }
109 }
110115
111 fn round(d: &Self, b: []const u8, last: bool) void {
112 debug.assert(b.len == 64);
116 pub fn final(d: *Self, out: []u8) void {
117 debug.assert(out.len >= out_len / 8);
113118
114 var m: [16]u32 = undefined;
115 var v: [16]u32 = undefined;
119 mem.set(u8, d.buf[d.buf_len..], 0);
120 d.t += d.buf_len;
121 d.round(d.buf[0..], true);
116122
117 for (m) |*r, i| {
118 *r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
119 }
123 const rr = d.h[0 .. out_len / 32];
120124
121 var k: usize = 0;
122 while (k < 8) : (k += 1) {
123 v[k] = d.h[k];
124 v[k+8] = iv[k];
125 for (rr) |s, j| {
126 mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
127 }
125128 }
126129
127 v[12] ^= @truncate(u32, d.t);
128 v[13] ^= u32(d.t >> 32);
129 if (last) v[14] = ~v[14];
130
131 const rounds = comptime []RoundParam {
132 Rp(0, 4, 8, 12, 0, 1),
133 Rp(1, 5, 9, 13, 2, 3),
134 Rp(2, 6, 10, 14, 4, 5),
135 Rp(3, 7, 11, 15, 6, 7),
136 Rp(0, 5, 10, 15, 8, 9),
137 Rp(1, 6, 11, 12, 10, 11),
138 Rp(2, 7, 8, 13, 12, 13),
139 Rp(3, 4, 9, 14, 14, 15),
140 };
130 fn round(d: *Self, b: []const u8, last: bool) void {
131 debug.assert(b.len == 64);
141132
142 comptime var j: usize = 0;
143 inline while (j < 10) : (j += 1) {
144 inline for (rounds) |r| {
145 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
146 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
147 v[r.c] = v[r.c] +% v[r.d];
148 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
149 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
150 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
151 v[r.c] = v[r.c] +% v[r.d];
152 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
133 var m: [16]u32 = undefined;
134 var v: [16]u32 = undefined;
135
136 for (m) |*r, i| {
137 r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]);
153138 }
154 }
155139
156 for (d.h) |*r, i| {
157 *r ^= v[i] ^ v[i + 8];
140 var k: usize = 0;
141 while (k < 8) : (k += 1) {
142 v[k] = d.h[k];
143 v[k + 8] = iv[k];
144 }
145
146 v[12] ^= @truncate(u32, d.t);
147 v[13] ^= @intCast(u32, d.t >> 32);
148 if (last) v[14] = ~v[14];
149
150 const rounds = comptime []RoundParam{
151 Rp(0, 4, 8, 12, 0, 1),
152 Rp(1, 5, 9, 13, 2, 3),
153 Rp(2, 6, 10, 14, 4, 5),
154 Rp(3, 7, 11, 15, 6, 7),
155 Rp(0, 5, 10, 15, 8, 9),
156 Rp(1, 6, 11, 12, 10, 11),
157 Rp(2, 7, 8, 13, 12, 13),
158 Rp(3, 4, 9, 14, 14, 15),
159 };
160
161 comptime var j: usize = 0;
162 inline while (j < 10) : (j += 1) {
163 inline for (rounds) |r| {
164 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
165 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
166 v[r.c] = v[r.c] +% v[r.d];
167 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
168 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
169 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
170 v[r.c] = v[r.c] +% v[r.d];
171 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
172 }
173 }
174
175 for (d.h) |*r, i| {
176 r.* ^= v[i] ^ v[i + 8];
177 }
158178 }
159 }
160};}
179 };
180}
161181
162182test "blake2s224 single" {
163183 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
......@@ -230,7 +250,7 @@ test "blake2s256 streaming" {
230250}
231251
232252test "blake2s256 aligned final" {
233 var block = []u8 {0} ** Blake2s256.block_size;
253 var block = []u8{0} ** Blake2s256.block_size;
234254 var out: [Blake2s256.digest_size]u8 = undefined;
235255
236256 var h = Blake2s256.init();
......@@ -238,154 +258,159 @@ test "blake2s256 aligned final" {
238258 h.final(out[0..]);
239259}
240260
241
242261/////////////////////
243262// Blake2b
244263
245264pub const Blake2b384 = Blake2b(384);
246265pub const Blake2b512 = Blake2b(512);
247266
248fn Blake2b(comptime out_len: usize) type { return struct {
249 const Self = this;
250 const block_size = 128;
251 const digest_size = out_len / 8;
267fn Blake2b(comptime out_len: usize) type {
268 return struct {
269 const Self = this;
270 const block_size = 128;
271 const digest_size = out_len / 8;
272
273 const iv = [8]u64{
274 0x6a09e667f3bcc908,
275 0xbb67ae8584caa73b,
276 0x3c6ef372fe94f82b,
277 0xa54ff53a5f1d36f1,
278 0x510e527fade682d1,
279 0x9b05688c2b3e6c1f,
280 0x1f83d9abfb41bd6b,
281 0x5be0cd19137e2179,
282 };
252283
253 const iv = [8]u64 {
254 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
255 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
256 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
257 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
258 };
284 const sigma = [12][16]u8{
285 []const u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
286 []const u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
287 []const u8{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
288 []const u8{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
289 []const u8{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
290 []const u8{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
291 []const u8{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
292 []const u8{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
293 []const u8{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
294 []const u8{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
295 []const u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
296 []const u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
297 };
259298
260 const sigma = [12][16]u8 {
261 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
262 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
263 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
264 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
265 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
266 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
267 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
268 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
269 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
270 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
271 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
272 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
273 };
299 h: [8]u64,
300 t: u128,
301 // Streaming cache
302 buf: [128]u8,
303 buf_len: u8,
274304
275 h: [8]u64,
276 t: u128,
277 // Streaming cache
278 buf: [128]u8,
279 buf_len: u8,
280
281 pub fn init() Self {
282 debug.assert(8 <= out_len and out_len <= 512);
283
284 var s: Self = undefined;
285 s.reset();
286 return s;
287 }
288
289 pub fn reset(d: &Self) void {
290 mem.copy(u64, d.h[0..], iv[0..]);
291
292 // No key plus default parameters
293 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
294 d.t = 0;
295 d.buf_len = 0;
296 }
297
298 pub fn hash(b: []const u8, out: []u8) void {
299 var d = Self.init();
300 d.update(b);
301 d.final(out);
302 }
303
304 pub fn update(d: &Self, b: []const u8) void {
305 var off: usize = 0;
306
307 // Partial buffer exists from previous update. Copy into buffer then hash.
308 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
309 off += 128 - d.buf_len;
310 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
311 d.t += 128;
312 d.round(d.buf[0..], false);
305 pub fn init() Self {
306 debug.assert(8 <= out_len and out_len <= 512);
307
308 var s: Self = undefined;
309 s.reset();
310 return s;
311 }
312
313 pub fn reset(d: *Self) void {
314 mem.copy(u64, d.h[0..], iv[0..]);
315
316 // No key plus default parameters
317 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
318 d.t = 0;
313319 d.buf_len = 0;
314320 }
315321
316 // Full middle blocks.
317 while (off + 128 <= b.len) : (off += 128) {
318 d.t += 128;
319 d.round(b[off..off + 128], false);
322 pub fn hash(b: []const u8, out: []u8) void {
323 var d = Self.init();
324 d.update(b);
325 d.final(out);
320326 }
321327
322 // Copy any remainder for next pass.
323 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
324 d.buf_len += u8(b[off..].len);
325 }
328 pub fn update(d: *Self, b: []const u8) void {
329 var off: usize = 0;
326330
327 pub fn final(d: &Self, out: []u8) void {
328 mem.set(u8, d.buf[d.buf_len..], 0);
329 d.t += d.buf_len;
330 d.round(d.buf[0..], true);
331 // Partial buffer exists from previous update. Copy into buffer then hash.
332 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
333 off += 128 - d.buf_len;
334 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
335 d.t += 128;
336 d.round(d.buf[0..], false);
337 d.buf_len = 0;
338 }
331339
332 const rr = d.h[0 .. out_len / 64];
340 // Full middle blocks.
341 while (off + 128 <= b.len) : (off += 128) {
342 d.t += 128;
343 d.round(b[off .. off + 128], false);
344 }
333345
334 for (rr) |s, j| {
335 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
346 // Copy any remainder for next pass.
347 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
348 d.buf_len += @intCast(u8, b[off..].len);
336349 }
337 }
338350
339 fn round(d: &Self, b: []const u8, last: bool) void {
340 debug.assert(b.len == 128);
351 pub fn final(d: *Self, out: []u8) void {
352 mem.set(u8, d.buf[d.buf_len..], 0);
353 d.t += d.buf_len;
354 d.round(d.buf[0..], true);
341355
342 var m: [16]u64 = undefined;
343 var v: [16]u64 = undefined;
356 const rr = d.h[0 .. out_len / 64];
344357
345 for (m) |*r, i| {
346 *r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
358 for (rr) |s, j| {
359 mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little);
360 }
347361 }
348362
349 var k: usize = 0;
350 while (k < 8) : (k += 1) {
351 v[k] = d.h[k];
352 v[k+8] = iv[k];
353 }
363 fn round(d: *Self, b: []const u8, last: bool) void {
364 debug.assert(b.len == 128);
354365
355 v[12] ^= @truncate(u64, d.t);
356 v[13] ^= u64(d.t >> 64);
357 if (last) v[14] = ~v[14];
358
359 const rounds = comptime []RoundParam {
360 Rp(0, 4, 8, 12, 0, 1),
361 Rp(1, 5, 9, 13, 2, 3),
362 Rp(2, 6, 10, 14, 4, 5),
363 Rp(3, 7, 11, 15, 6, 7),
364 Rp(0, 5, 10, 15, 8, 9),
365 Rp(1, 6, 11, 12, 10, 11),
366 Rp(2, 7, 8, 13, 12, 13),
367 Rp(3, 4, 9, 14, 14, 15),
368 };
366 var m: [16]u64 = undefined;
367 var v: [16]u64 = undefined;
369368
370 comptime var j: usize = 0;
371 inline while (j < 12) : (j += 1) {
372 inline for (rounds) |r| {
373 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
374 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
375 v[r.c] = v[r.c] +% v[r.d];
376 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
377 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
378 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
379 v[r.c] = v[r.c] +% v[r.d];
380 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
369 for (m) |*r, i| {
370 r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]);
371 }
372
373 var k: usize = 0;
374 while (k < 8) : (k += 1) {
375 v[k] = d.h[k];
376 v[k + 8] = iv[k];
381377 }
382 }
383378
384 for (d.h) |*r, i| {
385 *r ^= v[i] ^ v[i + 8];
379 v[12] ^= @truncate(u64, d.t);
380 v[13] ^= @intCast(u64, d.t >> 64);
381 if (last) v[14] = ~v[14];
382
383 const rounds = comptime []RoundParam{
384 Rp(0, 4, 8, 12, 0, 1),
385 Rp(1, 5, 9, 13, 2, 3),
386 Rp(2, 6, 10, 14, 4, 5),
387 Rp(3, 7, 11, 15, 6, 7),
388 Rp(0, 5, 10, 15, 8, 9),
389 Rp(1, 6, 11, 12, 10, 11),
390 Rp(2, 7, 8, 13, 12, 13),
391 Rp(3, 4, 9, 14, 14, 15),
392 };
393
394 comptime var j: usize = 0;
395 inline while (j < 12) : (j += 1) {
396 inline for (rounds) |r| {
397 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
398 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
399 v[r.c] = v[r.c] +% v[r.d];
400 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
401 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
402 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
403 v[r.c] = v[r.c] +% v[r.d];
404 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
405 }
406 }
407
408 for (d.h) |*r, i| {
409 r.* ^= v[i] ^ v[i + 8];
410 }
386411 }
387 }
388};}
412 };
413}
389414
390415test "blake2b384 single" {
391416 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
......@@ -458,7 +483,7 @@ test "blake2b512 streaming" {
458483}
459484
460485test "blake2b512 aligned final" {
461 var block = []u8 {0} ** Blake2b512.block_size;
486 var block = []u8{0} ** Blake2b512.block_size;
462487 var out: [Blake2b512.digest_size]u8 = undefined;
463488
464489 var h = Blake2b512.init();
std/crypto/hmac.zig+2-2
......@@ -29,12 +29,12 @@ pub fn Hmac(comptime H: type) type {
2929
3030 var o_key_pad: [H.block_size]u8 = undefined;
3131 for (o_key_pad) |*b, i| {
32 *b = scratch[i] ^ 0x5c;
32 b.* = scratch[i] ^ 0x5c;
3333 }
3434
3535 var i_key_pad: [H.block_size]u8 = undefined;
3636 for (i_key_pad) |*b, i| {
37 *b = scratch[i] ^ 0x36;
37 b.* = scratch[i] ^ 0x36;
3838 }
3939
4040 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation
std/crypto/md5.zig+85-69
......@@ -6,12 +6,25 @@ const debug = @import("../debug/index.zig");
66const fmt = @import("../fmt/index.zig");
77
88const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize,
10 k: usize, s: u32, t: u32
9 a: usize,
10 b: usize,
11 c: usize,
12 d: usize,
13 k: usize,
14 s: u32,
15 t: u32,
1116};
1217
1318fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundParam {
14 return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t };
19 return RoundParam{
20 .a = a,
21 .b = b,
22 .c = c,
23 .d = d,
24 .k = k,
25 .s = s,
26 .t = t,
27 };
1528}
1629
1730pub const Md5 = struct {
......@@ -31,7 +44,7 @@ pub const Md5 = struct {
3144 return d;
3245 }
3346
34 pub fn reset(d: &Self) void {
47 pub fn reset(d: *Self) void {
3548 d.s[0] = 0x67452301;
3649 d.s[1] = 0xEFCDAB89;
3750 d.s[2] = 0x98BADCFE;
......@@ -46,7 +59,7 @@ pub const Md5 = struct {
4659 d.final(out);
4760 }
4861
49 pub fn update(d: &Self, b: []const u8) void {
62 pub fn update(d: *Self, b: []const u8) void {
5063 var off: usize = 0;
5164
5265 // Partial buffer exists from previous update. Copy into buffer then hash.
......@@ -60,18 +73,18 @@ pub const Md5 = struct {
6073
6174 // Full middle blocks.
6275 while (off + 64 <= b.len) : (off += 64) {
63 d.round(b[off..off + 64]);
76 d.round(b[off .. off + 64]);
6477 }
6578
6679 // Copy any remainder for next pass.
6780 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
68 d.buf_len += u8(b[off..].len);
81 d.buf_len += @intCast(u8, b[off..].len);
6982
7083 // Md5 uses the bottom 64-bits for length padding
7184 d.total_len +%= b.len;
7285 }
7386
74 pub fn final(d: &Self, out: []u8) void {
87 pub fn final(d: *Self, out: []u8) void {
7588 debug.assert(out.len >= 16);
7689
7790 // The buffer here will never be completely full.
......@@ -90,20 +103,20 @@ pub const Md5 = struct {
90103 // Append message length.
91104 var i: usize = 1;
92105 var len = d.total_len >> 5;
93 d.buf[56] = u8(d.total_len & 0x1f) << 3;
106 d.buf[56] = @intCast(u8, d.total_len & 0x1f) << 3;
94107 while (i < 8) : (i += 1) {
95 d.buf[56 + i] = u8(len & 0xff);
108 d.buf[56 + i] = @intCast(u8, len & 0xff);
96109 len >>= 8;
97110 }
98111
99112 d.round(d.buf[0..]);
100113
101114 for (d.s) |s, j| {
102 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
115 mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
103116 }
104117 }
105118
106 fn round(d: &Self, b: []const u8) void {
119 fn round(d: *Self, b: []const u8) void {
107120 debug.assert(b.len == 64);
108121
109122 var s: [16]u32 = undefined;
......@@ -112,30 +125,33 @@ pub const Md5 = struct {
112125 while (i < 16) : (i += 1) {
113126 // NOTE: Performing or's separately improves perf by ~10%
114127 s[i] = 0;
115 s[i] |= u32(b[i*4+0]);
116 s[i] |= u32(b[i*4+1]) << 8;
117 s[i] |= u32(b[i*4+2]) << 16;
118 s[i] |= u32(b[i*4+3]) << 24;
128 s[i] |= u32(b[i * 4 + 0]);
129 s[i] |= u32(b[i * 4 + 1]) << 8;
130 s[i] |= u32(b[i * 4 + 2]) << 16;
131 s[i] |= u32(b[i * 4 + 3]) << 24;
119132 }
120133
121 var v: [4]u32 = []u32 {
122 d.s[0], d.s[1], d.s[2], d.s[3],
134 var v: [4]u32 = []u32{
135 d.s[0],
136 d.s[1],
137 d.s[2],
138 d.s[3],
123139 };
124140
125 const round0 = comptime []RoundParam {
126 Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
127 Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
128 Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
129 Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
130 Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
131 Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
132 Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
133 Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
134 Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
135 Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
141 const round0 = comptime []RoundParam{
142 Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
143 Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
144 Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
145 Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
146 Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
147 Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
148 Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
149 Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
150 Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
151 Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
136152 Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
137153 Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
138 Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
154 Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
139155 Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
140156 Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
141157 Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
......@@ -145,22 +161,22 @@ pub const Md5 = struct {
145161 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
146162 }
147163
148 const round1 = comptime []RoundParam {
149 Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
150 Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
164 const round1 = comptime []RoundParam{
165 Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
166 Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
151167 Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
152 Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
153 Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
154 Rp(3, 0, 1, 2, 10, 9, 0x02441453),
168 Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
169 Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
170 Rp(3, 0, 1, 2, 10, 9, 0x02441453),
155171 Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
156 Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
157 Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
158 Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
159 Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
160 Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
161 Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
162 Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
163 Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
172 Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
173 Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
174 Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
175 Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
176 Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
177 Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
178 Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
179 Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
164180 Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
165181 };
166182 inline for (round1) |r| {
......@@ -168,46 +184,46 @@ pub const Md5 = struct {
168184 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
169185 }
170186
171 const round2 = comptime []RoundParam {
172 Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
173 Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
187 const round2 = comptime []RoundParam{
188 Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
189 Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
174190 Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
175191 Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
176 Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
177 Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
178 Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
192 Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
193 Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
194 Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
179195 Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
180 Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
181 Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
182 Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
183 Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
184 Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
196 Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
197 Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
198 Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
199 Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
200 Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
185201 Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
186202 Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
187 Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
203 Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
188204 };
189205 inline for (round2) |r| {
190206 v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
191207 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
192208 }
193209
194 const round3 = comptime []RoundParam {
195 Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
196 Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
210 const round3 = comptime []RoundParam{
211 Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
212 Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
197213 Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
198 Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
199 Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
200 Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
214 Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
215 Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
216 Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
201217 Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
202 Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
203 Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
218 Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
219 Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
204220 Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
205 Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
221 Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
206222 Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
207 Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
223 Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
208224 Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
209 Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
210 Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
225 Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
226 Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
211227 };
212228 inline for (round3) |r| {
213229 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];
......@@ -255,7 +271,7 @@ test "md5 streaming" {
255271}
256272
257273test "md5 aligned final" {
258 var block = []u8 {0} ** Md5.block_size;
274 var block = []u8{0} ** Md5.block_size;
259275 var out: [Md5.digest_size]u8 = undefined;
260276
261277 var h = Md5.init();
std/crypto/sha1.zig+55-49
......@@ -4,14 +4,24 @@ const endian = @import("../endian.zig");
44const debug = @import("../debug/index.zig");
55const builtin = @import("builtin");
66
7pub const u160 = @IntType(false, 160);
8
97const RoundParam = struct {
10 a: usize, b: usize, c: usize, d: usize, e: usize, i: u32,
8 a: usize,
9 b: usize,
10 c: usize,
11 d: usize,
12 e: usize,
13 i: u32,
1114};
1215
1316fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
14 return RoundParam { .a = a, .b = b, .c = c, .d = d, .e = e, .i = i };
17 return RoundParam{
18 .a = a,
19 .b = b,
20 .c = c,
21 .d = d,
22 .e = e,
23 .i = i,
24 };
1525}
1626
1727pub const Sha1 = struct {
......@@ -31,7 +41,7 @@ pub const Sha1 = struct {
3141 return d;
3242 }
3343
34 pub fn reset(d: &Self) void {
44 pub fn reset(d: *Self) void {
3545 d.s[0] = 0x67452301;
3646 d.s[1] = 0xEFCDAB89;
3747 d.s[2] = 0x98BADCFE;
......@@ -47,7 +57,7 @@ pub const Sha1 = struct {
4757 d.final(out);
4858 }
4959
50 pub fn update(d: &Self, b: []const u8) void {
60 pub fn update(d: *Self, b: []const u8) void {
5161 var off: usize = 0;
5262
5363 // Partial buffer exists from previous update. Copy into buffer then hash.
......@@ -61,17 +71,17 @@ pub const Sha1 = struct {
6171
6272 // Full middle blocks.
6373 while (off + 64 <= b.len) : (off += 64) {
64 d.round(b[off..off + 64]);
74 d.round(b[off .. off + 64]);
6575 }
6676
6777 // Copy any remainder for next pass.
6878 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
69 d.buf_len += u8(b[off..].len);
79 d.buf_len += @intCast(u8, b[off..].len);
7080
7181 d.total_len += b.len;
7282 }
7383
74 pub fn final(d: &Self, out: []u8) void {
84 pub fn final(d: *Self, out: []u8) void {
7585 debug.assert(out.len >= 20);
7686
7787 // The buffer here will never be completely full.
......@@ -90,39 +100,43 @@ pub const Sha1 = struct {
90100 // Append message length.
91101 var i: usize = 1;
92102 var len = d.total_len >> 5;
93 d.buf[63] = u8(d.total_len & 0x1f) << 3;
103 d.buf[63] = @intCast(u8, d.total_len & 0x1f) << 3;
94104 while (i < 8) : (i += 1) {
95 d.buf[63 - i] = u8(len & 0xff);
105 d.buf[63 - i] = @intCast(u8, len & 0xff);
96106 len >>= 8;
97107 }
98108
99109 d.round(d.buf[0..]);
100110
101111 for (d.s) |s, j| {
102 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
112 mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
103113 }
104114 }
105115
106 fn round(d: &Self, b: []const u8) void {
116 fn round(d: *Self, b: []const u8) void {
107117 debug.assert(b.len == 64);
108118
109119 var s: [16]u32 = undefined;
110120
111 var v: [5]u32 = []u32 {
112 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4],
121 var v: [5]u32 = []u32{
122 d.s[0],
123 d.s[1],
124 d.s[2],
125 d.s[3],
126 d.s[4],
113127 };
114128
115 const round0a = comptime []RoundParam {
116 Rp(0, 1, 2, 3, 4, 0),
117 Rp(4, 0, 1, 2, 3, 1),
118 Rp(3, 4, 0, 1, 2, 2),
119 Rp(2, 3, 4, 0, 1, 3),
120 Rp(1, 2, 3, 4, 0, 4),
121 Rp(0, 1, 2, 3, 4, 5),
122 Rp(4, 0, 1, 2, 3, 6),
123 Rp(3, 4, 0, 1, 2, 7),
124 Rp(2, 3, 4, 0, 1, 8),
125 Rp(1, 2, 3, 4, 0, 9),
129 const round0a = comptime []RoundParam{
130 Rp(0, 1, 2, 3, 4, 0),
131 Rp(4, 0, 1, 2, 3, 1),
132 Rp(3, 4, 0, 1, 2, 2),
133 Rp(2, 3, 4, 0, 1, 3),
134 Rp(1, 2, 3, 4, 0, 4),
135 Rp(0, 1, 2, 3, 4, 5),
136 Rp(4, 0, 1, 2, 3, 6),
137 Rp(3, 4, 0, 1, 2, 7),
138 Rp(2, 3, 4, 0, 1, 8),
139 Rp(1, 2, 3, 4, 0, 9),
126140 Rp(0, 1, 2, 3, 4, 10),
127141 Rp(4, 0, 1, 2, 3, 11),
128142 Rp(3, 4, 0, 1, 2, 12),
......@@ -131,32 +145,27 @@ pub const Sha1 = struct {
131145 Rp(0, 1, 2, 3, 4, 15),
132146 };
133147 inline for (round0a) |r| {
134 s[r.i] = (u32(b[r.i * 4 + 0]) << 24) |
135 (u32(b[r.i * 4 + 1]) << 16) |
136 (u32(b[r.i * 4 + 2]) << 8) |
137 (u32(b[r.i * 4 + 3]) << 0);
148 s[r.i] = (u32(b[r.i * 4 + 0]) << 24) | (u32(b[r.i * 4 + 1]) << 16) | (u32(b[r.i * 4 + 2]) << 8) | (u32(b[r.i * 4 + 3]) << 0);
138149
139 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
140 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
150 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
141151 v[r.b] = math.rotl(u32, v[r.b], u32(30));
142152 }
143153
144 const round0b = comptime []RoundParam {
154 const round0b = comptime []RoundParam{
145155 Rp(4, 0, 1, 2, 3, 16),
146156 Rp(3, 4, 0, 1, 2, 17),
147157 Rp(2, 3, 4, 0, 1, 18),
148158 Rp(1, 2, 3, 4, 0, 19),
149159 };
150160 inline for (round0b) |r| {
151 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
161 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
152162 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
153163
154 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
155 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
164 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
156165 v[r.b] = math.rotl(u32, v[r.b], u32(30));
157166 }
158167
159 const round1 = comptime []RoundParam {
168 const round1 = comptime []RoundParam{
160169 Rp(0, 1, 2, 3, 4, 20),
161170 Rp(4, 0, 1, 2, 3, 21),
162171 Rp(3, 4, 0, 1, 2, 22),
......@@ -179,15 +188,14 @@ pub const Sha1 = struct {
179188 Rp(1, 2, 3, 4, 0, 39),
180189 };
181190 inline for (round1) |r| {
182 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
191 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
183192 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
184193
185 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf]
186 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
194 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
187195 v[r.b] = math.rotl(u32, v[r.b], u32(30));
188196 }
189197
190 const round2 = comptime []RoundParam {
198 const round2 = comptime []RoundParam{
191199 Rp(0, 1, 2, 3, 4, 40),
192200 Rp(4, 0, 1, 2, 3, 41),
193201 Rp(3, 4, 0, 1, 2, 42),
......@@ -210,15 +218,14 @@ pub const Sha1 = struct {
210218 Rp(1, 2, 3, 4, 0, 59),
211219 };
212220 inline for (round2) |r| {
213 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
221 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
214222 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
215223
216 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf]
217 +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
224 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
218225 v[r.b] = math.rotl(u32, v[r.b], u32(30));
219226 }
220227
221 const round3 = comptime []RoundParam {
228 const round3 = comptime []RoundParam{
222229 Rp(0, 1, 2, 3, 4, 60),
223230 Rp(4, 0, 1, 2, 3, 61),
224231 Rp(3, 4, 0, 1, 2, 62),
......@@ -241,11 +248,10 @@ pub const Sha1 = struct {
241248 Rp(1, 2, 3, 4, 0, 79),
242249 };
243250 inline for (round3) |r| {
244 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
251 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
245252 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
246253
247 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf]
248 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
254 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
249255 v[r.b] = math.rotl(u32, v[r.b], u32(30));
250256 }
251257
......@@ -286,7 +292,7 @@ test "sha1 streaming" {
286292}
287293
288294test "sha1 aligned final" {
289 var block = []u8 {0} ** Sha1.block_size;
295 var block = []u8{0} ** Sha1.block_size;
290296 var out: [Sha1.digest_size]u8 = undefined;
291297
292298 var h = Sha1.init();
std/crypto/sha2.zig+448-413
......@@ -9,12 +9,31 @@ const htest = @import("test.zig");
99// Sha224 + Sha256
1010
1111const RoundParam256 = struct {
12 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
13 i: usize, k: u32,
12 a: usize,
13 b: usize,
14 c: usize,
15 d: usize,
16 e: usize,
17 f: usize,
18 g: usize,
19 h: usize,
20 i: usize,
21 k: u32,
1422};
1523
1624fn Rp256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) RoundParam256 {
17 return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
25 return RoundParam256{
26 .a = a,
27 .b = b,
28 .c = c,
29 .d = d,
30 .e = e,
31 .f = f,
32 .g = g,
33 .h = h,
34 .i = i,
35 .k = k,
36 };
1837}
1938
2039const Sha2Params32 = struct {
......@@ -29,7 +48,7 @@ const Sha2Params32 = struct {
2948 out_len: usize,
3049};
3150
32const Sha224Params = Sha2Params32 {
51const Sha224Params = Sha2Params32{
3352 .iv0 = 0xC1059ED8,
3453 .iv1 = 0x367CD507,
3554 .iv2 = 0x3070DD17,
......@@ -41,7 +60,7 @@ const Sha224Params = Sha2Params32 {
4160 .out_len = 224,
4261};
4362
44const Sha256Params = Sha2Params32 {
63const Sha256Params = Sha2Params32{
4564 .iv0 = 0x6A09E667,
4665 .iv1 = 0xBB67AE85,
4766 .iv2 = 0x3C6EF372,
......@@ -56,216 +75,215 @@ const Sha256Params = Sha2Params32 {
5675pub const Sha224 = Sha2_32(Sha224Params);
5776pub const Sha256 = Sha2_32(Sha256Params);
5877
59fn Sha2_32(comptime params: Sha2Params32) type { return struct {
60 const Self = this;
61 const block_size = 64;
62 const digest_size = params.out_len / 8;
63
64 s: [8]u32,
65 // Streaming Cache
66 buf: [64]u8,
67 buf_len: u8,
68 total_len: u64,
69
70 pub fn init() Self {
71 var d: Self = undefined;
72 d.reset();
73 return d;
74 }
75
76 pub fn reset(d: &Self) void {
77 d.s[0] = params.iv0;
78 d.s[1] = params.iv1;
79 d.s[2] = params.iv2;
80 d.s[3] = params.iv3;
81 d.s[4] = params.iv4;
82 d.s[5] = params.iv5;
83 d.s[6] = params.iv6;
84 d.s[7] = params.iv7;
85 d.buf_len = 0;
86 d.total_len = 0;
87 }
88
89 pub fn hash(b: []const u8, out: []u8) void {
90 var d = Self.init();
91 d.update(b);
92 d.final(out);
93 }
94
95 pub fn update(d: &Self, b: []const u8) void {
96 var off: usize = 0;
97
98 // Partial buffer exists from previous update. Copy into buffer then hash.
99 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
100 off += 64 - d.buf_len;
101 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
78fn Sha2_32(comptime params: Sha2Params32) type {
79 return struct {
80 const Self = this;
81 const block_size = 64;
82 const digest_size = params.out_len / 8;
83
84 s: [8]u32,
85 // Streaming Cache
86 buf: [64]u8,
87 buf_len: u8,
88 total_len: u64,
89
90 pub fn init() Self {
91 var d: Self = undefined;
92 d.reset();
93 return d;
94 }
10295
103 d.round(d.buf[0..]);
96 pub fn reset(d: *Self) void {
97 d.s[0] = params.iv0;
98 d.s[1] = params.iv1;
99 d.s[2] = params.iv2;
100 d.s[3] = params.iv3;
101 d.s[4] = params.iv4;
102 d.s[5] = params.iv5;
103 d.s[6] = params.iv6;
104 d.s[7] = params.iv7;
104105 d.buf_len = 0;
106 d.total_len = 0;
105107 }
106108
107 // Full middle blocks.
108 while (off + 64 <= b.len) : (off += 64) {
109 d.round(b[off..off + 64]);
109 pub fn hash(b: []const u8, out: []u8) void {
110 var d = Self.init();
111 d.update(b);
112 d.final(out);
110113 }
111114
112 // Copy any remainder for next pass.
113 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
114 d.buf_len += u8(b[off..].len);
115 pub fn update(d: *Self, b: []const u8) void {
116 var off: usize = 0;
115117
116 d.total_len += b.len;
117 }
118 // Partial buffer exists from previous update. Copy into buffer then hash.
119 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
120 off += 64 - d.buf_len;
121 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
118122
119 pub fn final(d: &Self, out: []u8) void {
120 debug.assert(out.len >= params.out_len / 8);
123 d.round(d.buf[0..]);
124 d.buf_len = 0;
125 }
121126
122 // The buffer here will never be completely full.
123 mem.set(u8, d.buf[d.buf_len..], 0);
127 // Full middle blocks.
128 while (off + 64 <= b.len) : (off += 64) {
129 d.round(b[off .. off + 64]);
130 }
124131
125 // Append padding bits.
126 d.buf[d.buf_len] = 0x80;
127 d.buf_len += 1;
132 // Copy any remainder for next pass.
133 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
134 d.buf_len += @intCast(u8, b[off..].len);
128135
129 // > 448 mod 512 so need to add an extra round to wrap around.
130 if (64 - d.buf_len < 8) {
131 d.round(d.buf[0..]);
132 mem.set(u8, d.buf[0..], 0);
136 d.total_len += b.len;
133137 }
134138
135 // Append message length.
136 var i: usize = 1;
137 var len = d.total_len >> 5;
138 d.buf[63] = u8(d.total_len & 0x1f) << 3;
139 while (i < 8) : (i += 1) {
140 d.buf[63 - i] = u8(len & 0xff);
141 len >>= 8;
142 }
139 pub fn final(d: *Self, out: []u8) void {
140 debug.assert(out.len >= params.out_len / 8);
143141
144 d.round(d.buf[0..]);
142 // The buffer here will never be completely full.
143 mem.set(u8, d.buf[d.buf_len..], 0);
145144
146 // May truncate for possible 224 output
147 const rr = d.s[0 .. params.out_len / 32];
145 // Append padding bits.
146 d.buf[d.buf_len] = 0x80;
147 d.buf_len += 1;
148148
149 for (rr) |s, j| {
150 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
151 }
152 }
149 // > 448 mod 512 so need to add an extra round to wrap around.
150 if (64 - d.buf_len < 8) {
151 d.round(d.buf[0..]);
152 mem.set(u8, d.buf[0..], 0);
153 }
154
155 // Append message length.
156 var i: usize = 1;
157 var len = d.total_len >> 5;
158 d.buf[63] = @intCast(u8, d.total_len & 0x1f) << 3;
159 while (i < 8) : (i += 1) {
160 d.buf[63 - i] = @intCast(u8, len & 0xff);
161 len >>= 8;
162 }
153163
154 fn round(d: &Self, b: []const u8) void {
155 debug.assert(b.len == 64);
164 d.round(d.buf[0..]);
156165
157 var s: [64]u32 = undefined;
166 // May truncate for possible 224 output
167 const rr = d.s[0 .. params.out_len / 32];
158168
159 var i: usize = 0;
160 while (i < 16) : (i += 1) {
161 s[i] = 0;
162 s[i] |= u32(b[i*4+0]) << 24;
163 s[i] |= u32(b[i*4+1]) << 16;
164 s[i] |= u32(b[i*4+2]) << 8;
165 s[i] |= u32(b[i*4+3]) << 0;
166 }
167 while (i < 64) : (i += 1) {
168 s[i] =
169 s[i-16] +% s[i-7] +%
170 (math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +%
171 (math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10));
169 for (rr) |s, j| {
170 mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
171 }
172172 }
173173
174 var v: [8]u32 = []u32 {
175 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
176 };
177
178 const round0 = comptime []RoundParam256 {
179 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
180 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
181 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
182 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
183 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
184 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
185 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
186 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
187 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
188 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
189 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
190 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
191 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
192 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
193 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
194 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
195 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
196 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
197 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
198 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
199 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
200 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
201 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
202 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
203 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
204 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
205 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
206 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
207 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
208 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
209 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
210 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
211 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
212 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
213 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
214 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
215 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
216 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
217 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
218 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
219 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
220 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
221 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
222 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
223 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
224 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
225 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
226 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
227 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
228 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
229 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
230 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
231 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
232 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
233 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
234 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
235 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
236 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
237 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
238 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
239 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
240 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
241 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
242 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
243 };
244 inline for (round0) |r| {
245 v[r.h] =
246 v[r.h] +%
247 (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +%
248 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
249 r.k +% s[r.i];
250
251 v[r.d] = v[r.d] +% v[r.h];
252
253 v[r.h] =
254 v[r.h] +%
255 (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +%
256 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
174 fn round(d: *Self, b: []const u8) void {
175 debug.assert(b.len == 64);
176
177 var s: [64]u32 = undefined;
178
179 var i: usize = 0;
180 while (i < 16) : (i += 1) {
181 s[i] = 0;
182 s[i] |= u32(b[i * 4 + 0]) << 24;
183 s[i] |= u32(b[i * 4 + 1]) << 16;
184 s[i] |= u32(b[i * 4 + 2]) << 8;
185 s[i] |= u32(b[i * 4 + 3]) << 0;
186 }
187 while (i < 64) : (i += 1) {
188 s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u32, s[i - 15], u32(7)) ^ math.rotr(u32, s[i - 15], u32(18)) ^ (s[i - 15] >> 3)) +% (math.rotr(u32, s[i - 2], u32(17)) ^ math.rotr(u32, s[i - 2], u32(19)) ^ (s[i - 2] >> 10));
189 }
190
191 var v: [8]u32 = []u32{
192 d.s[0],
193 d.s[1],
194 d.s[2],
195 d.s[3],
196 d.s[4],
197 d.s[5],
198 d.s[6],
199 d.s[7],
200 };
201
202 const round0 = comptime []RoundParam256{
203 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
204 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
205 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
206 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
207 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
208 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
209 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
210 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
211 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
212 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
213 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
214 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
215 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
216 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
217 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
218 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
219 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
220 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
221 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
222 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
223 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
224 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
225 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
226 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
227 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
228 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
229 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
230 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
231 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
232 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
233 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
234 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
235 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
236 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
237 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
238 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
239 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
240 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
241 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
242 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
243 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
244 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
245 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
246 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
247 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
248 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
249 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
250 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
251 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
252 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
253 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
254 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
255 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
256 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
257 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
258 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
259 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
260 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
261 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
262 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
263 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
264 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
265 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
266 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
267 };
268 inline for (round0) |r| {
269 v[r.h] = v[r.h] +% (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
270
271 v[r.d] = v[r.d] +% v[r.h];
272
273 v[r.h] = v[r.h] +% (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
274 }
275
276 d.s[0] +%= v[0];
277 d.s[1] +%= v[1];
278 d.s[2] +%= v[2];
279 d.s[3] +%= v[3];
280 d.s[4] +%= v[4];
281 d.s[5] +%= v[5];
282 d.s[6] +%= v[6];
283 d.s[7] +%= v[7];
257284 }
258
259 d.s[0] +%= v[0];
260 d.s[1] +%= v[1];
261 d.s[2] +%= v[2];
262 d.s[3] +%= v[3];
263 d.s[4] +%= v[4];
264 d.s[5] +%= v[5];
265 d.s[6] +%= v[6];
266 d.s[7] +%= v[7];
267 }
268};}
285 };
286}
269287
270288test "sha224 single" {
271289 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
......@@ -320,7 +338,7 @@ test "sha256 streaming" {
320338}
321339
322340test "sha256 aligned final" {
323 var block = []u8 {0} ** Sha256.block_size;
341 var block = []u8{0} ** Sha256.block_size;
324342 var out: [Sha256.digest_size]u8 = undefined;
325343
326344 var h = Sha256.init();
......@@ -328,17 +346,35 @@ test "sha256 aligned final" {
328346 h.final(out[0..]);
329347}
330348
331
332349/////////////////////
333350// Sha384 + Sha512
334351
335352const RoundParam512 = struct {
336 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
337 i: usize, k: u64,
353 a: usize,
354 b: usize,
355 c: usize,
356 d: usize,
357 e: usize,
358 f: usize,
359 g: usize,
360 h: usize,
361 i: usize,
362 k: u64,
338363};
339364
340365fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
341 return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
366 return RoundParam512{
367 .a = a,
368 .b = b,
369 .c = c,
370 .d = d,
371 .e = e,
372 .f = f,
373 .g = g,
374 .h = h,
375 .i = i,
376 .k = k,
377 };
342378}
343379
344380const Sha2Params64 = struct {
......@@ -353,7 +389,7 @@ const Sha2Params64 = struct {
353389 out_len: usize,
354390};
355391
356const Sha384Params = Sha2Params64 {
392const Sha384Params = Sha2Params64{
357393 .iv0 = 0xCBBB9D5DC1059ED8,
358394 .iv1 = 0x629A292A367CD507,
359395 .iv2 = 0x9159015A3070DD17,
......@@ -365,7 +401,7 @@ const Sha384Params = Sha2Params64 {
365401 .out_len = 384,
366402};
367403
368const Sha512Params = Sha2Params64 {
404const Sha512Params = Sha2Params64{
369405 .iv0 = 0x6A09E667F3BCC908,
370406 .iv1 = 0xBB67AE8584CAA73B,
371407 .iv2 = 0x3C6EF372FE94F82B,
......@@ -374,242 +410,241 @@ const Sha512Params = Sha2Params64 {
374410 .iv5 = 0x9B05688C2B3E6C1F,
375411 .iv6 = 0x1F83D9ABFB41BD6B,
376412 .iv7 = 0x5BE0CD19137E2179,
377 .out_len = 512
413 .out_len = 512,
378414};
379415
380416pub const Sha384 = Sha2_64(Sha384Params);
381417pub const Sha512 = Sha2_64(Sha512Params);
382418
383fn Sha2_64(comptime params: Sha2Params64) type { return struct {
384 const Self = this;
385 const block_size = 128;
386 const digest_size = params.out_len / 8;
387
388 s: [8]u64,
389 // Streaming Cache
390 buf: [128]u8,
391 buf_len: u8,
392 total_len: u128,
393
394 pub fn init() Self {
395 var d: Self = undefined;
396 d.reset();
397 return d;
398 }
399
400 pub fn reset(d: &Self) void {
401 d.s[0] = params.iv0;
402 d.s[1] = params.iv1;
403 d.s[2] = params.iv2;
404 d.s[3] = params.iv3;
405 d.s[4] = params.iv4;
406 d.s[5] = params.iv5;
407 d.s[6] = params.iv6;
408 d.s[7] = params.iv7;
409 d.buf_len = 0;
410 d.total_len = 0;
411 }
412
413 pub fn hash(b: []const u8, out: []u8) void {
414 var d = Self.init();
415 d.update(b);
416 d.final(out);
417 }
418
419 pub fn update(d: &Self, b: []const u8) void {
420 var off: usize = 0;
421
422 // Partial buffer exists from previous update. Copy into buffer then hash.
423 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
424 off += 128 - d.buf_len;
425 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
419fn Sha2_64(comptime params: Sha2Params64) type {
420 return struct {
421 const Self = this;
422 const block_size = 128;
423 const digest_size = params.out_len / 8;
424
425 s: [8]u64,
426 // Streaming Cache
427 buf: [128]u8,
428 buf_len: u8,
429 total_len: u128,
430
431 pub fn init() Self {
432 var d: Self = undefined;
433 d.reset();
434 return d;
435 }
426436
427 d.round(d.buf[0..]);
437 pub fn reset(d: *Self) void {
438 d.s[0] = params.iv0;
439 d.s[1] = params.iv1;
440 d.s[2] = params.iv2;
441 d.s[3] = params.iv3;
442 d.s[4] = params.iv4;
443 d.s[5] = params.iv5;
444 d.s[6] = params.iv6;
445 d.s[7] = params.iv7;
428446 d.buf_len = 0;
447 d.total_len = 0;
429448 }
430449
431 // Full middle blocks.
432 while (off + 128 <= b.len) : (off += 128) {
433 d.round(b[off..off + 128]);
450 pub fn hash(b: []const u8, out: []u8) void {
451 var d = Self.init();
452 d.update(b);
453 d.final(out);
434454 }
435455
436 // Copy any remainder for next pass.
437 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
438 d.buf_len += u8(b[off..].len);
456 pub fn update(d: *Self, b: []const u8) void {
457 var off: usize = 0;
439458
440 d.total_len += b.len;
441 }
459 // Partial buffer exists from previous update. Copy into buffer then hash.
460 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
461 off += 128 - d.buf_len;
462 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
442463
443 pub fn final(d: &Self, out: []u8) void {
444 debug.assert(out.len >= params.out_len / 8);
464 d.round(d.buf[0..]);
465 d.buf_len = 0;
466 }
445467
446 // The buffer here will never be completely full.
447 mem.set(u8, d.buf[d.buf_len..], 0);
468 // Full middle blocks.
469 while (off + 128 <= b.len) : (off += 128) {
470 d.round(b[off .. off + 128]);
471 }
448472
449 // Append padding bits.
450 d.buf[d.buf_len] = 0x80;
451 d.buf_len += 1;
473 // Copy any remainder for next pass.
474 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
475 d.buf_len += @intCast(u8, b[off..].len);
452476
453 // > 896 mod 1024 so need to add an extra round to wrap around.
454 if (128 - d.buf_len < 16) {
455 d.round(d.buf[0..]);
456 mem.set(u8, d.buf[0..], 0);
477 d.total_len += b.len;
457478 }
458479
459 // Append message length.
460 var i: usize = 1;
461 var len = d.total_len >> 5;
462 d.buf[127] = u8(d.total_len & 0x1f) << 3;
463 while (i < 16) : (i += 1) {
464 d.buf[127 - i] = u8(len & 0xff);
465 len >>= 8;
466 }
480 pub fn final(d: *Self, out: []u8) void {
481 debug.assert(out.len >= params.out_len / 8);
467482
468 d.round(d.buf[0..]);
483 // The buffer here will never be completely full.
484 mem.set(u8, d.buf[d.buf_len..], 0);
469485
470 // May truncate for possible 384 output
471 const rr = d.s[0 .. params.out_len / 64];
486 // Append padding bits.
487 d.buf[d.buf_len] = 0x80;
488 d.buf_len += 1;
472489
473 for (rr) |s, j| {
474 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
475 }
476 }
477
478 fn round(d: &Self, b: []const u8) void {
479 debug.assert(b.len == 128);
480
481 var s: [80]u64 = undefined;
482
483 var i: usize = 0;
484 while (i < 16) : (i += 1) {
485 s[i] = 0;
486 s[i] |= u64(b[i*8+0]) << 56;
487 s[i] |= u64(b[i*8+1]) << 48;
488 s[i] |= u64(b[i*8+2]) << 40;
489 s[i] |= u64(b[i*8+3]) << 32;
490 s[i] |= u64(b[i*8+4]) << 24;
491 s[i] |= u64(b[i*8+5]) << 16;
492 s[i] |= u64(b[i*8+6]) << 8;
493 s[i] |= u64(b[i*8+7]) << 0;
494 }
495 while (i < 80) : (i += 1) {
496 s[i] =
497 s[i-16] +% s[i-7] +%
498 (math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +%
499 (math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6));
500 }
490 // > 896 mod 1024 so need to add an extra round to wrap around.
491 if (128 - d.buf_len < 16) {
492 d.round(d.buf[0..]);
493 mem.set(u8, d.buf[0..], 0);
494 }
501495
502 var v: [8]u64 = []u64 {
503 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
504 };
505
506 const round0 = comptime []RoundParam512 {
507 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
508 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
509 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
510 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
511 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
512 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
513 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
514 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
515 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
516 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
517 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
518 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
519 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
520 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
521 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
522 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
523 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
524 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
525 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
526 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
527 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
528 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
529 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
530 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
531 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
532 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
533 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
534 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
535 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
536 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
537 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
538 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
539 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
540 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
541 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
542 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
543 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
544 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
545 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
546 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
547 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
548 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
549 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
550 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
551 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
552 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
553 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
554 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
555 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
556 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
557 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
558 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
559 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
560 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
561 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
562 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
563 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
564 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
565 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
566 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
567 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
568 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
569 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
570 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
571 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
572 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
573 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
574 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
575 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
576 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
577 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
578 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
579 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
580 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
581 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
582 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
583 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
584 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
585 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
586 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
587 };
588 inline for (round0) |r| {
589 v[r.h] =
590 v[r.h] +%
591 (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +%
592 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
593 r.k +% s[r.i];
594
595 v[r.d] = v[r.d] +% v[r.h];
596
597 v[r.h] =
598 v[r.h] +%
599 (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +%
600 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
496 // Append message length.
497 var i: usize = 1;
498 var len = d.total_len >> 5;
499 d.buf[127] = @intCast(u8, d.total_len & 0x1f) << 3;
500 while (i < 16) : (i += 1) {
501 d.buf[127 - i] = @intCast(u8, len & 0xff);
502 len >>= 8;
503 }
504
505 d.round(d.buf[0..]);
506
507 // May truncate for possible 384 output
508 const rr = d.s[0 .. params.out_len / 64];
509
510 for (rr) |s, j| {
511 mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big);
512 }
601513 }
602514
603 d.s[0] +%= v[0];
604 d.s[1] +%= v[1];
605 d.s[2] +%= v[2];
606 d.s[3] +%= v[3];
607 d.s[4] +%= v[4];
608 d.s[5] +%= v[5];
609 d.s[6] +%= v[6];
610 d.s[7] +%= v[7];
611 }
612};}
515 fn round(d: *Self, b: []const u8) void {
516 debug.assert(b.len == 128);
517
518 var s: [80]u64 = undefined;
519
520 var i: usize = 0;
521 while (i < 16) : (i += 1) {
522 s[i] = 0;
523 s[i] |= u64(b[i * 8 + 0]) << 56;
524 s[i] |= u64(b[i * 8 + 1]) << 48;
525 s[i] |= u64(b[i * 8 + 2]) << 40;
526 s[i] |= u64(b[i * 8 + 3]) << 32;
527 s[i] |= u64(b[i * 8 + 4]) << 24;
528 s[i] |= u64(b[i * 8 + 5]) << 16;
529 s[i] |= u64(b[i * 8 + 6]) << 8;
530 s[i] |= u64(b[i * 8 + 7]) << 0;
531 }
532 while (i < 80) : (i += 1) {
533 s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u64, s[i - 15], u64(1)) ^ math.rotr(u64, s[i - 15], u64(8)) ^ (s[i - 15] >> 7)) +% (math.rotr(u64, s[i - 2], u64(19)) ^ math.rotr(u64, s[i - 2], u64(61)) ^ (s[i - 2] >> 6));
534 }
535
536 var v: [8]u64 = []u64{
537 d.s[0],
538 d.s[1],
539 d.s[2],
540 d.s[3],
541 d.s[4],
542 d.s[5],
543 d.s[6],
544 d.s[7],
545 };
546
547 const round0 = comptime []RoundParam512{
548 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
549 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
550 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
551 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
552 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
553 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
554 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
555 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
556 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
557 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
558 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
559 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
560 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
561 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
562 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
563 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
564 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
565 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
566 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
567 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
568 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
569 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
570 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
571 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
572 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
573 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
574 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
575 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
576 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
577 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
578 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
579 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
580 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
581 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
582 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
583 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
584 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
585 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
586 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
587 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
588 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
589 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
590 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
591 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
592 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
593 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
594 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
595 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
596 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
597 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
598 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
599 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
600 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
601 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
602 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
603 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
604 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
605 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
606 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
607 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
608 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
609 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
610 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
611 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
612 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
613 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
614 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
615 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
616 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
617 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
618 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
619 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
620 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
621 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
622 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
623 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
624 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
625 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
626 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
627 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
628 };
629 inline for (round0) |r| {
630 v[r.h] = v[r.h] +% (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
631
632 v[r.d] = v[r.d] +% v[r.h];
633
634 v[r.h] = v[r.h] +% (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
635 }
636
637 d.s[0] +%= v[0];
638 d.s[1] +%= v[1];
639 d.s[2] +%= v[2];
640 d.s[3] +%= v[3];
641 d.s[4] +%= v[4];
642 d.s[5] +%= v[5];
643 d.s[6] +%= v[6];
644 d.s[7] +%= v[7];
645 }
646 };
647}
613648
614649test "sha384 single" {
615650 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
......@@ -680,7 +715,7 @@ test "sha512 streaming" {
680715}
681716
682717test "sha512 aligned final" {
683 var block = []u8 {0} ** Sha512.block_size;
718 var block = []u8{0} ** Sha512.block_size;
684719 var out: [Sha512.digest_size]u8 = undefined;
685720
686721 var h = Sha512.init();
std/crypto/sha3.zig+180-101
......@@ -10,148 +10,228 @@ pub const Sha3_256 = Keccak(256, 0x06);
1010pub const Sha3_384 = Keccak(384, 0x06);
1111pub const Sha3_512 = Keccak(512, 0x06);
1212
13fn Keccak(comptime bits: usize, comptime delim: u8) type { return struct {
14 const Self = this;
15 const block_size = 200;
16 const digest_size = bits / 8;
17
18 s: [200]u8,
19 offset: usize,
20 rate: usize,
21
22 pub fn init() Self {
23 var d: Self = undefined;
24 d.reset();
25 return d;
26 }
13fn Keccak(comptime bits: usize, comptime delim: u8) type {
14 return struct {
15 const Self = this;
16 const block_size = 200;
17 const digest_size = bits / 8;
18
19 s: [200]u8,
20 offset: usize,
21 rate: usize,
22
23 pub fn init() Self {
24 var d: Self = undefined;
25 d.reset();
26 return d;
27 }
2728
28 pub fn reset(d: &Self) void {
29 mem.set(u8, d.s[0..], 0);
30 d.offset = 0;
31 d.rate = 200 - (bits / 4);
32 }
29 pub fn reset(d: *Self) void {
30 mem.set(u8, d.s[0..], 0);
31 d.offset = 0;
32 d.rate = 200 - (bits / 4);
33 }
3334
34 pub fn hash(b: []const u8, out: []u8) void {
35 var d = Self.init();
36 d.update(b);
37 d.final(out);
38 }
35 pub fn hash(b: []const u8, out: []u8) void {
36 var d = Self.init();
37 d.update(b);
38 d.final(out);
39 }
3940
40 pub fn update(d: &Self, b: []const u8) void {
41 var ip: usize = 0;
42 var len = b.len;
43 var rate = d.rate - d.offset;
44 var offset = d.offset;
41 pub fn update(d: *Self, b: []const u8) void {
42 var ip: usize = 0;
43 var len = b.len;
44 var rate = d.rate - d.offset;
45 var offset = d.offset;
4546
46 // absorb
47 while (len >= rate) {
48 for (d.s[offset .. offset + rate]) |*r, i|
49 *r ^= b[ip..][i];
47 // absorb
48 while (len >= rate) {
49 for (d.s[offset .. offset + rate]) |*r, i|
50 r.* ^= b[ip..][i];
5051
51 keccak_f(1600, d.s[0..]);
52 keccak_f(1600, d.s[0..]);
5253
53 ip += rate;
54 len -= rate;
55 rate = d.rate;
56 offset = 0;
57 }
54 ip += rate;
55 len -= rate;
56 rate = d.rate;
57 offset = 0;
58 }
5859
59 for (d.s[offset .. offset + len]) |*r, i|
60 *r ^= b[ip..][i];
60 for (d.s[offset .. offset + len]) |*r, i|
61 r.* ^= b[ip..][i];
6162
62 d.offset = offset + len;
63 }
63 d.offset = offset + len;
64 }
6465
65 pub fn final(d: &Self, out: []u8) void {
66 // padding
67 d.s[d.offset] ^= delim;
68 d.s[d.rate - 1] ^= 0x80;
66 pub fn final(d: *Self, out: []u8) void {
67 // padding
68 d.s[d.offset] ^= delim;
69 d.s[d.rate - 1] ^= 0x80;
6970
70 keccak_f(1600, d.s[0..]);
71 keccak_f(1600, d.s[0..]);
7172
72 // squeeze
73 var op: usize = 0;
74 var len: usize = bits / 8;
73 // squeeze
74 var op: usize = 0;
75 var len: usize = bits / 8;
7576
76 while (len >= d.rate) {
77 mem.copy(u8, out[op..], d.s[0..d.rate]);
78 keccak_f(1600, d.s[0..]);
79 op += d.rate;
80 len -= d.rate;
77 while (len >= d.rate) {
78 mem.copy(u8, out[op..], d.s[0..d.rate]);
79 keccak_f(1600, d.s[0..]);
80 op += d.rate;
81 len -= d.rate;
82 }
83
84 mem.copy(u8, out[op..], d.s[0..len]);
8185 }
86 };
87}
8288
83 mem.copy(u8, out[op..], d.s[0..len]);
84 }
85};}
86
87const RC = []const u64 {
88 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
89 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
90 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
91 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
92 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
93 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
89const RC = []const u64{
90 0x0000000000000001,
91 0x0000000000008082,
92 0x800000000000808a,
93 0x8000000080008000,
94 0x000000000000808b,
95 0x0000000080000001,
96 0x8000000080008081,
97 0x8000000000008009,
98 0x000000000000008a,
99 0x0000000000000088,
100 0x0000000080008009,
101 0x000000008000000a,
102 0x000000008000808b,
103 0x800000000000008b,
104 0x8000000000008089,
105 0x8000000000008003,
106 0x8000000000008002,
107 0x8000000000000080,
108 0x000000000000800a,
109 0x800000008000000a,
110 0x8000000080008081,
111 0x8000000000008080,
112 0x0000000080000001,
113 0x8000000080008008,
94114};
95115
96const ROTC = []const usize {
97 1, 3, 6, 10, 15, 21, 28, 36,
98 45, 55, 2, 14, 27, 41, 56, 8,
99 25, 43, 62, 18, 39, 61, 20, 44
116const ROTC = []const usize{
117 1,
118 3,
119 6,
120 10,
121 15,
122 21,
123 28,
124 36,
125 45,
126 55,
127 2,
128 14,
129 27,
130 41,
131 56,
132 8,
133 25,
134 43,
135 62,
136 18,
137 39,
138 61,
139 20,
140 44,
100141};
101142
102const PIL = []const usize {
103 10, 7, 11, 17, 18, 3, 5, 16,
104 8, 21, 24, 4, 15, 23, 19, 13,
105 12, 2, 20, 14, 22, 9, 6, 1
143const PIL = []const usize{
144 10,
145 7,
146 11,
147 17,
148 18,
149 3,
150 5,
151 16,
152 8,
153 21,
154 24,
155 4,
156 15,
157 23,
158 19,
159 13,
160 12,
161 2,
162 20,
163 14,
164 22,
165 9,
166 6,
167 1,
106168};
107169
108const M5 = []const usize {
109 0, 1, 2, 3, 4, 0, 1, 2, 3, 4
170const M5 = []const usize{
171 0,
172 1,
173 2,
174 3,
175 4,
176 0,
177 1,
178 2,
179 3,
180 4,
110181};
111182
112183fn keccak_f(comptime F: usize, d: []u8) void {
113184 debug.assert(d.len == F / 8);
114185
115186 const B = F / 25;
116 const no_rounds = comptime x: { break :x 12 + 2 * math.log2(B); };
187 const no_rounds = comptime x: {
188 break :x 12 + 2 * math.log2(B);
189 };
117190
118 var s = []const u64 {0} ** 25;
119 var t = []const u64 {0} ** 1;
120 var c = []const u64 {0} ** 5;
191 var s = []const u64{0} ** 25;
192 var t = []const u64{0} ** 1;
193 var c = []const u64{0} ** 5;
121194
122195 for (s) |*r, i| {
123 *r = mem.readIntLE(u64, d[8*i .. 8*i + 8]);
196 r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]);
124197 }
125198
126199 comptime var x: usize = 0;
127200 comptime var y: usize = 0;
128201 for (RC[0..no_rounds]) |round| {
129202 // theta
130 x = 0; inline while (x < 5) : (x += 1) {
131 c[x] = s[x] ^ s[x+5] ^ s[x+10] ^ s[x+15] ^ s[x+20];
203 x = 0;
204 inline while (x < 5) : (x += 1) {
205 c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20];
132206 }
133 x = 0; inline while (x < 5) : (x += 1) {
134 t[0] = c[M5[x+4]] ^ math.rotl(u64, c[M5[x+1]], usize(1));
135 y = 0; inline while (y < 5) : (y += 1) {
136 s[x + y*5] ^= t[0];
207 x = 0;
208 inline while (x < 5) : (x += 1) {
209 t[0] = c[M5[x + 4]] ^ math.rotl(u64, c[M5[x + 1]], usize(1));
210 y = 0;
211 inline while (y < 5) : (y += 1) {
212 s[x + y * 5] ^= t[0];
137213 }
138214 }
139215
140216 // rho+pi
141217 t[0] = s[1];
142 x = 0; inline while (x < 24) : (x += 1) {
218 x = 0;
219 inline while (x < 24) : (x += 1) {
143220 c[0] = s[PIL[x]];
144221 s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);
145222 t[0] = c[0];
146223 }
147224
148225 // chi
149 y = 0; inline while (y < 5) : (y += 1) {
150 x = 0; inline while (x < 5) : (x += 1) {
151 c[x] = s[x + y*5];
226 y = 0;
227 inline while (y < 5) : (y += 1) {
228 x = 0;
229 inline while (x < 5) : (x += 1) {
230 c[x] = s[x + y * 5];
152231 }
153 x = 0; inline while (x < 5) : (x += 1) {
154 s[x + y*5] = c[x] ^ (~c[M5[x+1]] & c[M5[x+2]]);
232 x = 0;
233 inline while (x < 5) : (x += 1) {
234 s[x + y * 5] = c[x] ^ (~c[M5[x + 1]] & c[M5[x + 2]]);
155235 }
156236 }
157237
......@@ -160,11 +240,10 @@ fn keccak_f(comptime F: usize, d: []u8) void {
160240 }
161241
162242 for (s) |r, i| {
163 mem.writeInt(d[8*i .. 8*i + 8], r, builtin.Endian.Little);
243 mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little);
164244 }
165245}
166246
167
168247test "sha3-224 single" {
169248 htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");
170249 htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");
......@@ -192,7 +271,7 @@ test "sha3-224 streaming" {
192271}
193272
194273test "sha3-256 single" {
195 htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" , "");
274 htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", "");
196275 htest.assertEqualHash(Sha3_256, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc");
197276 htest.assertEqualHash(Sha3_256, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
198277}
......@@ -218,7 +297,7 @@ test "sha3-256 streaming" {
218297}
219298
220299test "sha3-256 aligned final" {
221 var block = []u8 {0} ** Sha3_256.block_size;
300 var block = []u8{0} ** Sha3_256.block_size;
222301 var out: [Sha3_256.digest_size]u8 = undefined;
223302
224303 var h = Sha3_256.init();
......@@ -228,7 +307,7 @@ test "sha3-256 aligned final" {
228307
229308test "sha3-384 single" {
230309 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
231 htest.assertEqualHash(Sha3_384, h1 , "");
310 htest.assertEqualHash(Sha3_384, h1, "");
232311 const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
233312 htest.assertEqualHash(Sha3_384, h2, "abc");
234313 const h3 = "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7";
......@@ -259,7 +338,7 @@ test "sha3-384 streaming" {
259338
260339test "sha3-512 single" {
261340 const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
262 htest.assertEqualHash(Sha3_512, h1 , "");
341 htest.assertEqualHash(Sha3_512, h1, "");
263342 const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
264343 htest.assertEqualHash(Sha3_512, h2, "abc");
265344 const h3 = "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185";
......@@ -289,7 +368,7 @@ test "sha3-512 streaming" {
289368}
290369
291370test "sha3-512 aligned final" {
292 var block = []u8 {0} ** Sha3_512.block_size;
371 var block = []u8{0} ** Sha3_512.block_size;
293372 var out: [Sha3_512.digest_size]u8 = undefined;
294373
295374 var h = Sha3_512.init();
std/crypto/test.zig+1-2
......@@ -14,9 +14,8 @@ pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, inpu
1414pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
1515 var expected_bytes: [expected.len / 2]u8 = undefined;
1616 for (expected_bytes) |*r, i| {
17 *r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;
17 r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable;
1818 }
1919
2020 debug.assert(mem.eql(u8, expected_bytes, input));
2121}
22
std/crypto/throughput_test.zig+12-17
......@@ -1,22 +1,17 @@
11// Modify the HashFunction variable to the one wanted to test.
22//
3// NOTE: The throughput measurement may be slightly lower than other measurements since we run
4// through our block alignment functions as well. Be aware when comparing against other tests.
5//
63// ```
7// zig build-exe --release-fast --library c throughput_test.zig
4// zig build-exe --release-fast throughput_test.zig
85// ./throughput_test
96// ```
10const HashFunction = @import("md5.zig").Md5;
11const BytesToHash = 1024 * Mb;
127
138const std = @import("std");
9const time = std.os.time;
10const Timer = time.Timer;
11const HashFunction = @import("md5.zig").Md5;
1412
15const c = @cImport({
16 @cInclude("time.h");
17});
18
19const Mb = 1024 * 1024;
13const MiB = 1024 * 1024;
14const BytesToHash = 1024 * MiB;
2015
2116pub fn main() !void {
2217 var stdout_file = try std.io.getStdOut();
......@@ -29,15 +24,15 @@ pub fn main() !void {
2924 var h = HashFunction.init();
3025 var offset: usize = 0;
3126
32 const start = c.clock();
27 var timer = try Timer.start();
28 const start = timer.lap();
3329 while (offset < BytesToHash) : (offset += block.len) {
3430 h.update(block[0..]);
3531 }
36 const end = c.clock();
32 const end = timer.read();
3733
38 const elapsed_s = f64((end - start) * c.CLOCKS_PER_SEC) / 1000000;
39 const throughput = u64(BytesToHash / elapsed_s);
34 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
35 const throughput = @floatToInt(u64, BytesToHash / elapsed_s);
4036
41 try stdout.print("{}: ", @typeName(HashFunction));
42 try stdout.print("{} Mb/s\n", throughput);
37 try stdout.print("{}: {} MiB/s\n", @typeName(HashFunction), throughput / (1 * MiB));
4338}
std/cstr.zig+15-17
......@@ -9,14 +9,13 @@ pub const line_sep = switch (builtin.os) {
99 else => "\n",
1010};
1111
12
13pub fn len(ptr: &const u8) usize {
12pub fn len(ptr: [*]const u8) usize {
1413 var count: usize = 0;
1514 while (ptr[count] != 0) : (count += 1) {}
1615 return count;
1716}
1817
19pub fn cmp(a: &const u8, b: &const u8) i8 {
18pub fn cmp(a: [*]const u8, b: [*]const u8) i8 {
2019 var index: usize = 0;
2120 while (a[index] == b[index] and a[index] != 0) : (index += 1) {}
2221 if (a[index] > b[index]) {
......@@ -28,11 +27,11 @@ pub fn cmp(a: &const u8, b: &const u8) i8 {
2827 }
2928}
3029
31pub fn toSliceConst(str: &const u8) []const u8 {
30pub fn toSliceConst(str: [*]const u8) []const u8 {
3231 return str[0..len(str)];
3332}
3433
35pub fn toSlice(str: &u8) []u8 {
34pub fn toSlice(str: [*]u8) []u8 {
3635 return str[0..len(str)];
3736}
3837
......@@ -48,7 +47,7 @@ fn testCStrFnsImpl() void {
4847
4948/// Returns a mutable slice with 1 more byte of length which is a null byte.
5049/// Caller owns the returned memory.
51pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) ![]u8 {
50pub fn addNullByte(allocator: *mem.Allocator, slice: []const u8) ![]u8 {
5251 const result = try allocator.alloc(u8, slice.len + 1);
5352 mem.copy(u8, result, slice);
5453 result[slice.len] = 0;
......@@ -56,13 +55,13 @@ pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) ![]u8 {
5655}
5756
5857pub const NullTerminated2DArray = struct {
59 allocator: &mem.Allocator,
58 allocator: *mem.Allocator,
6059 byte_count: usize,
61 ptr: ?&?&u8,
60 ptr: ?[*]?[*]u8,
6261
6362 /// Takes N lists of strings, concatenates the lists together, and adds a null terminator
6463 /// Caller must deinit result
65 pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) !NullTerminated2DArray {
64 pub fn fromSlices(allocator: *mem.Allocator, slices: []const []const []const u8) !NullTerminated2DArray {
6665 var new_len: usize = 1; // 1 for the list null
6766 var byte_count: usize = 0;
6867 for (slices) |slice| {
......@@ -76,16 +75,16 @@ pub const NullTerminated2DArray = struct {
7675 const index_size = @sizeOf(usize) * new_len; // size of the ptrs
7776 byte_count += index_size;
7877
79 const buf = try allocator.alignedAlloc(u8, @alignOf(?&u8), byte_count);
78 const buf = try allocator.alignedAlloc(u8, @alignOf(?*u8), byte_count);
8079 errdefer allocator.free(buf);
8180
8281 var write_index = index_size;
83 const index_buf = ([]?&u8)(buf);
82 const index_buf = @bytesToSlice(?[*]u8, buf);
8483
8584 var i: usize = 0;
8685 for (slices) |slice| {
8786 for (slice) |inner| {
88 index_buf[i] = &buf[write_index];
87 index_buf[i] = buf.ptr + write_index;
8988 i += 1;
9089 mem.copy(u8, buf[write_index..], inner);
9190 write_index += inner.len;
......@@ -95,16 +94,15 @@ pub const NullTerminated2DArray = struct {
9594 }
9695 index_buf[i] = null;
9796
98 return NullTerminated2DArray {
97 return NullTerminated2DArray{
9998 .allocator = allocator,
10099 .byte_count = byte_count,
101 .ptr = @ptrCast(?&?&u8, buf.ptr),
100 .ptr = @ptrCast(?[*]?[*]u8, buf.ptr),
102101 };
103102 }
104103
105 pub fn deinit(self: &NullTerminated2DArray) void {
106 const buf = @ptrCast(&u8, self.ptr);
104 pub fn deinit(self: *NullTerminated2DArray) void {
105 const buf = @ptrCast([*]u8, self.ptr);
107106 self.allocator.free(buf[0..self.byte_count]);
108107 }
109108};
110
std/debug/failing_allocator.zig+7-7
......@@ -7,20 +7,20 @@ pub const FailingAllocator = struct {
77 allocator: mem.Allocator,
88 index: usize,
99 fail_index: usize,
10 internal_allocator: &mem.Allocator,
10 internal_allocator: *mem.Allocator,
1111 allocated_bytes: usize,
1212 freed_bytes: usize,
1313 deallocations: usize,
1414
15 pub fn init(allocator: &mem.Allocator, fail_index: usize) FailingAllocator {
16 return FailingAllocator {
15 pub fn init(allocator: *mem.Allocator, fail_index: usize) FailingAllocator {
16 return FailingAllocator{
1717 .internal_allocator = allocator,
1818 .fail_index = fail_index,
1919 .index = 0,
2020 .allocated_bytes = 0,
2121 .freed_bytes = 0,
2222 .deallocations = 0,
23 .allocator = mem.Allocator {
23 .allocator = mem.Allocator{
2424 .allocFn = alloc,
2525 .reallocFn = realloc,
2626 .freeFn = free,
......@@ -28,7 +28,7 @@ pub const FailingAllocator = struct {
2828 };
2929 }
3030
31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) ![]u8 {
31 fn alloc(allocator: *mem.Allocator, n: usize, alignment: u29) ![]u8 {
3232 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
3333 if (self.index == self.fail_index) {
3434 return error.OutOfMemory;
......@@ -39,7 +39,7 @@ pub const FailingAllocator = struct {
3939 return result;
4040 }
4141
42 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
42 fn realloc(allocator: *mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
4343 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
4444 if (new_size <= old_mem.len) {
4545 self.freed_bytes += old_mem.len - new_size;
......@@ -55,7 +55,7 @@ pub const FailingAllocator = struct {
5555 return result;
5656 }
5757
58 fn free(allocator: &mem.Allocator, bytes: []u8) void {
58 fn free(allocator: *mem.Allocator, bytes: []u8) void {
5959 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
6060 self.freed_bytes += bytes.len;
6161 self.deallocations += 1;
std/debug/index.zig+242-216
......@@ -10,18 +10,24 @@ const ArrayList = std.ArrayList;
1010const builtin = @import("builtin");
1111
1212pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
13pub const failing_allocator = FailingAllocator.init(global_allocator, 0);
14
15pub const runtime_safety = switch (builtin.mode) {
16 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,
17 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
18};
1319
1420/// Tries to write to stderr, unbuffered, and ignores any error returned.
1521/// Does not append a newline.
1622/// TODO atomic/multithread support
1723var stderr_file: os.File = undefined;
1824var stderr_file_out_stream: io.FileOutStream = undefined;
19var stderr_stream: ?&io.OutStream(io.FileOutStream.Error) = null;
25var stderr_stream: ?*io.OutStream(io.FileOutStream.Error) = null;
2026pub fn warn(comptime fmt: []const u8, args: ...) void {
2127 const stderr = getStderrStream() catch return;
2228 stderr.print(fmt, args) catch return;
2329}
24fn getStderrStream() !&io.OutStream(io.FileOutStream.Error) {
30pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) {
2531 if (stderr_stream) |st| {
2632 return st;
2733 } else {
......@@ -33,17 +39,23 @@ fn getStderrStream() !&io.OutStream(io.FileOutStream.Error) {
3339 }
3440}
3541
36var self_debug_info: ?&ElfStackTrace = null;
37pub fn getSelfDebugInfo() !&ElfStackTrace {
42var self_debug_info: ?*ElfStackTrace = null;
43pub fn getSelfDebugInfo() !*ElfStackTrace {
3844 if (self_debug_info) |info| {
3945 return info;
4046 } else {
41 const info = try openSelfDebugInfo(global_allocator);
47 const info = try openSelfDebugInfo(getDebugInfoAllocator());
4248 self_debug_info = info;
4349 return info;
4450 }
4551}
4652
53fn wantTtyColor() bool {
54 var bytes: [128]u8 = undefined;
55 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
56 return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
57}
58
4759/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
4860pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
4961 const stderr = getStderrStream() catch return;
......@@ -51,20 +63,20 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
5163 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
5264 return;
5365 };
54 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), start_addr) catch |err| {
66 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, wantTtyColor(), start_addr) catch |err| {
5567 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
5668 return;
5769 };
5870}
5971
6072/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
61pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) void {
73pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {
6274 const stderr = getStderrStream() catch return;
6375 const debug_info = getSelfDebugInfo() catch |err| {
6476 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
6577 return;
6678 };
67 writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
79 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {
6880 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
6981 return;
7082 };
......@@ -88,6 +100,16 @@ pub fn assert(ok: bool) void {
88100 }
89101}
90102
103/// TODO: add `==` operator for `error_union == error_set`, and then
104/// remove this function
105pub fn assertError(value: var, expected_error: error) void {
106 if (value) {
107 @panic("expected error");
108 } else |actual_error| {
109 assert(actual_error == expected_error);
110 }
111}
112
91113/// Call this function when you want to panic if the condition is not true.
92114/// If `ok` is `false`, this function will panic in every release mode.
93115pub fn assertOrPanic(ok: bool) void {
......@@ -104,9 +126,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
104126
105127var panicking: u8 = 0; // TODO make this a bool
106128
107pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize,
108 comptime format: []const u8, args: ...) noreturn
109{
129pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
110130 @setCold(true);
111131
112132 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
......@@ -132,9 +152,7 @@ const WHITE = "\x1b[37;1m";
132152const DIM = "\x1b[2m";
133153const RESET = "\x1b[0m";
134154
135pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
136 debug_info: &ElfStackTrace, tty_color: bool) !void
137{
155pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *ElfStackTrace, tty_color: bool) !void {
138156 var frame_index: usize = undefined;
139157 var frames_left: usize = undefined;
140158 if (stack_trace.index < stack_trace.instruction_addresses.len) {
......@@ -150,13 +168,21 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
150168 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
151169 }) {
152170 const return_address = stack_trace.instruction_addresses[frame_index];
153 try printSourceAtAddress(debug_info, out_stream, return_address);
171 try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
172 }
173}
174
175pub inline fn getReturnAddress(frame_count: usize) usize {
176 var fp = @ptrToInt(@frameAddress());
177 var i: usize = 0;
178 while (fp != 0 and i < frame_count) {
179 fp = @intToPtr(*const usize, fp).*;
180 i += 1;
154181 }
182 return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
155183}
156184
157pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
158 debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void
159{
185pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *ElfStackTrace, tty_color: bool, start_addr: ?usize) !void {
160186 const AddressState = union(enum) {
161187 NotLookingForStartAddress,
162188 LookingForStartAddress: usize,
......@@ -166,14 +192,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
166192 // else AddressState.NotLookingForStartAddress;
167193 var addr_state: AddressState = undefined;
168194 if (start_addr) |addr| {
169 addr_state = AddressState { .LookingForStartAddress = addr };
195 addr_state = AddressState{ .LookingForStartAddress = addr };
170196 } else {
171197 addr_state = AddressState.NotLookingForStartAddress;
172198 }
173199
174200 var fp = @ptrToInt(@frameAddress());
175 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
176 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
201 while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) {
202 const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*;
177203
178204 switch (addr_state) {
179205 AddressState.NotLookingForStartAddress => {},
......@@ -185,13 +211,11 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
185211 }
186212 },
187213 }
188 try printSourceAtAddress(debug_info, out_stream, return_address);
214 try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
189215 }
190216}
191217
192fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: usize) !void {
193 const ptr_hex = "0x{x}";
194
218pub fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: usize, tty_color: bool) !void {
195219 switch (builtin.os) {
196220 builtin.Os.windows => return error.UnsupportedDebugInfo,
197221 builtin.Os.macosx => {
......@@ -200,41 +224,63 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
200224 // in practice because the compiler dumps everything in a single
201225 // object file. Future improvement: use external dSYM data when
202226 // available.
203 const unknown = macho.Symbol { .name = "???", .address = address };
204 const symbol = debug_info.symbol_table.search(address) ?? &unknown;
205 try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++
206 DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n",
207 symbol.name, address);
227 const unknown = macho.Symbol{
228 .name = "???",
229 .address = address,
230 };
231 const symbol = debug_info.symbol_table.search(address) orelse &unknown;
232 try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ "0x{x}" ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address);
208233 },
209234 else => {
210235 const compile_unit = findCompileUnit(debug_info, address) catch {
211 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
212 address);
236 if (tty_color) {
237 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n ???\n\n", address);
238 } else {
239 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n ???\n\n", address);
240 }
213241 return;
214242 };
215243 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
216244 if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
217245 defer line_info.deinit();
218 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
219 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
220 line_info.file_name, line_info.line, line_info.column,
221 address, compile_unit_name);
222 if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
223 if (line_info.column == 0) {
224 try out_stream.write("\n");
225 } else {
226 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
227 try out_stream.writeByte(' ');
228 }}
229 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
246 if (tty_color) {
247 try out_stream.print(
248 WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n",
249 line_info.file_name,
250 line_info.line,
251 line_info.column,
252 address,
253 compile_unit_name,
254 );
255 if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
256 if (line_info.column == 0) {
257 try out_stream.write("\n");
258 } else {
259 {
260 var col_i: usize = 1;
261 while (col_i < line_info.column) : (col_i += 1) {
262 try out_stream.writeByte(' ');
263 }
264 }
265 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
266 }
267 } else |err| switch (err) {
268 error.EndOfFile => {},
269 else => return err,
230270 }
231 } else |err| switch (err) {
232 error.EndOfFile => {},
233 else => return err,
271 } else {
272 try out_stream.print(
273 "{}:{}:{}: 0x{x} in ??? ({})\n",
274 line_info.file_name,
275 line_info.line,
276 line_info.column,
277 address,
278 compile_unit_name,
279 );
234280 }
235281 } else |err| switch (err) {
236282 error.MissingDebugInfo, error.InvalidDebugInfo => {
237 try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
283 try out_stream.print("0x{x} in ??? ({})\n", address, compile_unit_name);
238284 },
239285 else => return err,
240286 }
......@@ -242,12 +288,10 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
242288 }
243289}
244290
245pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
291pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
246292 switch (builtin.object_format) {
247293 builtin.ObjectFormat.elf => {
248 const st = try allocator.create(ElfStackTrace);
249 errdefer allocator.destroy(st);
250 *st = ElfStackTrace {
294 const st = try allocator.create(ElfStackTrace{
251295 .self_exe_file = undefined,
252296 .elf = undefined,
253297 .debug_info = undefined,
......@@ -257,17 +301,18 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
257301 .debug_ranges = null,
258302 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
259303 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
260 };
304 });
305 errdefer allocator.destroy(st);
261306 st.self_exe_file = try os.openSelfExe();
262307 errdefer st.self_exe_file.close();
263308
264309 try st.elf.openFile(allocator, &st.self_exe_file);
265310 errdefer st.elf.close();
266311
267 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
268 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
269 st.debug_str = (try st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
270 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
312 st.debug_info = (try st.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
313 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo;
314 st.debug_str = (try st.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo;
315 st.debug_line = (try st.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo;
271316 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
272317 try scanAllCompileUnits(st);
273318 return st;
......@@ -276,13 +321,8 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
276321 var exe_file = try os.openSelfExe();
277322 defer exe_file.close();
278323
279 const st = try allocator.create(ElfStackTrace);
324 const st = try allocator.create(ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) });
280325 errdefer allocator.destroy(st);
281
282 *st = ElfStackTrace {
283 .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)),
284 };
285
286326 return st;
287327 },
288328 builtin.ObjectFormat.coff => {
......@@ -297,7 +337,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
297337 }
298338}
299339
300fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &const LineInfo) !void {
340fn printLineFromFile(allocator: *mem.Allocator, out_stream: var, line_info: *const LineInfo) !void {
301341 var f = try os.File.openRead(allocator, line_info.file_name);
302342 defer f.close();
303343 // TODO fstat and make sure that the file has the correct size
......@@ -325,8 +365,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &con
325365 }
326366 }
327367
328 if (amt_read < buf.len)
329 return error.EndOfFile;
368 if (amt_read < buf.len) return error.EndOfFile;
330369 }
331370}
332371
......@@ -334,32 +373,32 @@ pub const ElfStackTrace = switch (builtin.os) {
334373 builtin.Os.macosx => struct {
335374 symbol_table: macho.SymbolTable,
336375
337 pub fn close(self: &ElfStackTrace) void {
376 pub fn close(self: *ElfStackTrace) void {
338377 self.symbol_table.deinit();
339378 }
340379 },
341380 else => struct {
342381 self_exe_file: os.File,
343382 elf: elf.Elf,
344 debug_info: &elf.SectionHeader,
345 debug_abbrev: &elf.SectionHeader,
346 debug_str: &elf.SectionHeader,
347 debug_line: &elf.SectionHeader,
348 debug_ranges: ?&elf.SectionHeader,
383 debug_info: *elf.SectionHeader,
384 debug_abbrev: *elf.SectionHeader,
385 debug_str: *elf.SectionHeader,
386 debug_line: *elf.SectionHeader,
387 debug_ranges: ?*elf.SectionHeader,
349388 abbrev_table_list: ArrayList(AbbrevTableHeader),
350389 compile_unit_list: ArrayList(CompileUnit),
351390
352 pub fn allocator(self: &const ElfStackTrace) &mem.Allocator {
391 pub fn allocator(self: *const ElfStackTrace) *mem.Allocator {
353392 return self.abbrev_table_list.allocator;
354393 }
355394
356 pub fn readString(self: &ElfStackTrace) ![]u8 {
395 pub fn readString(self: *ElfStackTrace) ![]u8 {
357396 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
358397 const in_stream = &in_file_stream.stream;
359398 return readStringRaw(self.allocator(), in_stream);
360399 }
361400
362 pub fn close(self: &ElfStackTrace) void {
401 pub fn close(self: *ElfStackTrace) void {
363402 self.self_exe_file.close();
364403 self.elf.close();
365404 }
......@@ -374,7 +413,7 @@ const PcRange = struct {
374413const CompileUnit = struct {
375414 version: u16,
376415 is_64: bool,
377 die: &Die,
416 die: *Die,
378417 index: usize,
379418 pc_range: ?PcRange,
380419};
......@@ -417,11 +456,9 @@ const Constant = struct {
417456 payload: []u8,
418457 signed: bool,
419458
420 fn asUnsignedLe(self: &const Constant) !u64 {
421 if (self.payload.len > @sizeOf(u64))
422 return error.InvalidDebugInfo;
423 if (self.signed)
424 return error.InvalidDebugInfo;
459 fn asUnsignedLe(self: *const Constant) !u64 {
460 if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
461 if (self.signed) return error.InvalidDebugInfo;
425462 return mem.readInt(self.payload, u64, builtin.Endian.Little);
426463 }
427464};
......@@ -436,42 +473,41 @@ const Die = struct {
436473 value: FormValue,
437474 };
438475
439 fn getAttr(self: &const Die, id: u64) ?&const FormValue {
476 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
440477 for (self.attrs.toSliceConst()) |*attr| {
441 if (attr.id == id)
442 return &attr.value;
478 if (attr.id == id) return &attr.value;
443479 }
444480 return null;
445481 }
446482
447 fn getAttrAddr(self: &const Die, id: u64) !u64 {
448 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
449 return switch (*form_value) {
483 fn getAttrAddr(self: *const Die, id: u64) !u64 {
484 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
485 return switch (form_value.*) {
450486 FormValue.Address => |value| value,
451487 else => error.InvalidDebugInfo,
452488 };
453489 }
454490
455 fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
456 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
457 return switch (*form_value) {
491 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
492 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
493 return switch (form_value.*) {
458494 FormValue.Const => |value| value.asUnsignedLe(),
459495 FormValue.SecOffset => |value| value,
460496 else => error.InvalidDebugInfo,
461497 };
462498 }
463499
464 fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
465 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
466 return switch (*form_value) {
500 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
501 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
502 return switch (form_value.*) {
467503 FormValue.Const => |value| value.asUnsignedLe(),
468504 else => error.InvalidDebugInfo,
469505 };
470506 }
471507
472 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
473 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
474 return switch (*form_value) {
508 fn getAttrString(self: *const Die, st: *ElfStackTrace, id: u64) ![]u8 {
509 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
510 return switch (form_value.*) {
475511 FormValue.String => |value| value,
476512 FormValue.StrPtr => |offset| getString(st, offset),
477513 else => error.InvalidDebugInfo,
......@@ -490,9 +526,9 @@ const LineInfo = struct {
490526 line: usize,
491527 column: usize,
492528 file_name: []u8,
493 allocator: &mem.Allocator,
529 allocator: *mem.Allocator,
494530
495 fn deinit(self: &const LineInfo) void {
531 fn deinit(self: *const LineInfo) void {
496532 self.allocator.free(self.file_name);
497533 }
498534};
......@@ -508,7 +544,7 @@ const LineNumberProgram = struct {
508544
509545 target_address: usize,
510546 include_dirs: []const []const u8,
511 file_entries: &ArrayList(FileEntry),
547 file_entries: *ArrayList(FileEntry),
512548
513549 prev_address: usize,
514550 prev_file: usize,
......@@ -518,10 +554,8 @@ const LineNumberProgram = struct {
518554 prev_basic_block: bool,
519555 prev_end_sequence: bool,
520556
521 pub fn init(is_stmt: bool, include_dirs: []const []const u8,
522 file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram
523 {
524 return LineNumberProgram {
557 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
558 return LineNumberProgram{
525559 .address = 0,
526560 .file = 1,
527561 .line = 1,
......@@ -542,21 +576,23 @@ const LineNumberProgram = struct {
542576 };
543577 }
544578
545 pub fn checkLineMatch(self: &LineNumberProgram) !?LineInfo {
579 pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {
546580 if (self.target_address >= self.prev_address and self.target_address < self.address) {
547581 const file_entry = if (self.prev_file == 0) {
548582 return error.MissingDebugInfo;
549583 } else if (self.prev_file - 1 >= self.file_entries.len) {
550584 return error.InvalidDebugInfo;
551 } else &self.file_entries.items[self.prev_file - 1];
585 } else
586 &self.file_entries.items[self.prev_file - 1];
552587
553588 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
554589 return error.InvalidDebugInfo;
555 } else self.include_dirs[file_entry.dir_index];
590 } else
591 self.include_dirs[file_entry.dir_index];
556592 const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
557593 errdefer self.file_entries.allocator.free(file_name);
558 return LineInfo {
559 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
594 return LineInfo{
595 .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
560596 .column = self.prev_column,
561597 .file_name = file_name,
562598 .allocator = self.file_entries.allocator,
......@@ -574,83 +610,80 @@ const LineNumberProgram = struct {
574610 }
575611};
576612
577fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
613fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
578614 var buf = ArrayList(u8).init(allocator);
579615 while (true) {
580616 const byte = try in_stream.readByte();
581 if (byte == 0)
582 break;
617 if (byte == 0) break;
583618 try buf.append(byte);
584619 }
585620 return buf.toSlice();
586621}
587622
588fn getString(st: &ElfStackTrace, offset: u64) ![]u8 {
623fn getString(st: *ElfStackTrace, offset: u64) ![]u8 {
589624 const pos = st.debug_str.offset + offset;
590625 try st.self_exe_file.seekTo(pos);
591626 return st.readString();
592627}
593628
594fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8 {
595 const buf = try global_allocator.alloc(u8, size);
596 errdefer global_allocator.free(buf);
629fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
630 const buf = try allocator.alloc(u8, size);
631 errdefer allocator.free(buf);
597632 if ((try in_stream.read(buf)) < size) return error.EndOfFile;
598633 return buf;
599634}
600635
601fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
636fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
602637 const buf = try readAllocBytes(allocator, in_stream, size);
603 return FormValue { .Block = buf };
638 return FormValue{ .Block = buf };
604639}
605640
606fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
641fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
607642 const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);
608643 return parseFormValueBlockLen(allocator, in_stream, block_len);
609644}
610645
611fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
612 return FormValue { .Const = Constant {
613 .signed = signed,
614 .payload = try readAllocBytes(allocator, in_stream, size),
615 }};
646fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
647 return FormValue{
648 .Const = Constant{
649 .signed = signed,
650 .payload = try readAllocBytes(allocator, in_stream, size),
651 },
652 };
616653}
617654
618655fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
619 return if (is_64) try in_stream.readIntLe(u64)
620 else u64(try in_stream.readIntLe(u32)) ;
656 return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
621657}
622658
623659fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
624 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))
625 else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)
626 else unreachable;
660 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
627661}
628662
629fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
663fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
630664 const buf = try readAllocBytes(allocator, in_stream, size);
631 return FormValue { .Ref = buf };
665 return FormValue{ .Ref = buf };
632666}
633667
634fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
668fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
635669 const block_len = try in_stream.readIntLe(T);
636670 return parseFormValueRefLen(allocator, in_stream, block_len);
637671}
638672
639const ParseFormValueError = error {
673const ParseFormValueError = error{
640674 EndOfStream,
641675 Io,
642676 BadFd,
643677 Unexpected,
644678 InvalidDebugInfo,
645679 EndOfFile,
680 IsDir,
646681 OutOfMemory,
647682};
648683
649fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)
650 ParseFormValueError!FormValue
651{
684fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
652685 return switch (form_id) {
653 DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },
686 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
654687 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
655688 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
656689 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
......@@ -670,11 +703,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
670703 DW.FORM_exprloc => {
671704 const size = try readULeb128(in_stream);
672705 const buf = try readAllocBytes(allocator, in_stream, size);
673 return FormValue { .ExprLoc = buf };
706 return FormValue{ .ExprLoc = buf };
674707 },
675 DW.FORM_flag => FormValue { .Flag = (try in_stream.readByte()) != 0 },
676 DW.FORM_flag_present => FormValue { .Flag = true },
677 DW.FORM_sec_offset => FormValue { .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
708 DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
709 DW.FORM_flag_present => FormValue{ .Flag = true },
710 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
678711
679712 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
680713 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
......@@ -685,11 +718,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
685718 return parseFormValueRefLen(allocator, in_stream, ref_len);
686719 },
687720
688 DW.FORM_ref_addr => FormValue { .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
689 DW.FORM_ref_sig8 => FormValue { .RefSig8 = try in_stream.readIntLe(u64) },
721 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
722 DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
690723
691 DW.FORM_string => FormValue { .String = try readStringRaw(allocator, in_stream) },
692 DW.FORM_strp => FormValue { .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
724 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
725 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
693726 DW.FORM_indirect => {
694727 const child_form_id = try readULeb128(in_stream);
695728 return parseFormValue(allocator, in_stream, child_form_id, is_64);
......@@ -698,16 +731,15 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
698731 };
699732}
700733
701fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
734fn parseAbbrevTable(st: *ElfStackTrace) !AbbrevTable {
702735 const in_file = &st.self_exe_file;
703736 var in_file_stream = io.FileInStream.init(in_file);
704737 const in_stream = &in_file_stream.stream;
705738 var result = AbbrevTable.init(st.allocator());
706739 while (true) {
707740 const abbrev_code = try readULeb128(in_stream);
708 if (abbrev_code == 0)
709 return result;
710 try result.append(AbbrevTableEntry {
741 if (abbrev_code == 0) return result;
742 try result.append(AbbrevTableEntry{
711743 .abbrev_code = abbrev_code,
712744 .tag_id = try readULeb128(in_stream),
713745 .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
......@@ -718,9 +750,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
718750 while (true) {
719751 const attr_id = try readULeb128(in_stream);
720752 const form_id = try readULeb128(in_stream);
721 if (attr_id == 0 and form_id == 0)
722 break;
723 try attrs.append(AbbrevAttr {
753 if (attr_id == 0 and form_id == 0) break;
754 try attrs.append(AbbrevAttr{
724755 .attr_id = attr_id,
725756 .form_id = form_id,
726757 });
......@@ -730,43 +761,42 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
730761
731762/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
732763/// seeks in the stream and parses it.
733fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
764fn getAbbrevTable(st: *ElfStackTrace, abbrev_offset: u64) !*const AbbrevTable {
734765 for (st.abbrev_table_list.toSlice()) |*header| {
735766 if (header.offset == abbrev_offset) {
736767 return &header.table;
737768 }
738769 }
739770 try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
740 try st.abbrev_table_list.append(AbbrevTableHeader {
771 try st.abbrev_table_list.append(AbbrevTableHeader{
741772 .offset = abbrev_offset,
742773 .table = try parseAbbrevTable(st),
743774 });
744775 return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
745776}
746777
747fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {
778fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
748779 for (abbrev_table.toSliceConst()) |*table_entry| {
749 if (table_entry.abbrev_code == abbrev_code)
750 return table_entry;
780 if (table_entry.abbrev_code == abbrev_code) return table_entry;
751781 }
752782 return null;
753783}
754784
755fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !Die {
785fn parseDie(st: *ElfStackTrace, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
756786 const in_file = &st.self_exe_file;
757787 var in_file_stream = io.FileInStream.init(in_file);
758788 const in_stream = &in_file_stream.stream;
759789 const abbrev_code = try readULeb128(in_stream);
760 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
790 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
761791
762 var result = Die {
792 var result = Die{
763793 .tag_id = table_entry.tag_id,
764794 .has_children = table_entry.has_children,
765795 .attrs = ArrayList(Die.Attr).init(st.allocator()),
766796 };
767797 try result.attrs.resize(table_entry.attrs.len);
768798 for (table_entry.attrs.toSliceConst()) |attr, i| {
769 result.attrs.items[i] = Die.Attr {
799 result.attrs.items[i] = Die.Attr{
770800 .id = attr.attr_id,
771801 .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
772802 };
......@@ -774,7 +804,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !
774804 return result;
775805}
776806
777fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) !LineInfo {
807fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
778808 const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir);
779809
780810 const in_file = &st.self_exe_file;
......@@ -790,8 +820,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
790820
791821 var is_64: bool = undefined;
792822 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
793 if (unit_length == 0)
794 return error.MissingDebugInfo;
823 if (unit_length == 0) return error.MissingDebugInfo;
795824 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
796825
797826 if (compile_unit.index != this_index) {
......@@ -803,8 +832,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
803832 // TODO support 3 and 5
804833 if (version != 2 and version != 4) return error.InvalidDebugInfo;
805834
806 const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64)
807 else try in_stream.readInt(st.elf.endian, u32);
835 const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
808836 const prog_start_offset = (try in_file.getPos()) + prologue_length;
809837
810838 const minimum_instruction_length = try in_stream.readByte();
......@@ -819,38 +847,37 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
819847 const line_base = try in_stream.readByteSigned();
820848
821849 const line_range = try in_stream.readByte();
822 if (line_range == 0)
823 return error.InvalidDebugInfo;
850 if (line_range == 0) return error.InvalidDebugInfo;
824851
825852 const opcode_base = try in_stream.readByte();
826853
827854 const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);
828855
829 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
830 standard_opcode_lengths[i] = try in_stream.readByte();
831 }}
856 {
857 var i: usize = 0;
858 while (i < opcode_base - 1) : (i += 1) {
859 standard_opcode_lengths[i] = try in_stream.readByte();
860 }
861 }
832862
833863 var include_directories = ArrayList([]u8).init(st.allocator());
834864 try include_directories.append(compile_unit_cwd);
835865 while (true) {
836866 const dir = try st.readString();
837 if (dir.len == 0)
838 break;
867 if (dir.len == 0) break;
839868 try include_directories.append(dir);
840869 }
841870
842871 var file_entries = ArrayList(FileEntry).init(st.allocator());
843 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
844 &file_entries, target_address);
872 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
845873
846874 while (true) {
847875 const file_name = try st.readString();
848 if (file_name.len == 0)
849 break;
876 if (file_name.len == 0) break;
850877 const dir_index = try readULeb128(in_stream);
851878 const mtime = try readULeb128(in_stream);
852879 const len_bytes = try readULeb128(in_stream);
853 try file_entries.append(FileEntry {
880 try file_entries.append(FileEntry{
854881 .file_name = file_name,
855882 .dir_index = dir_index,
856883 .mtime = mtime,
......@@ -866,8 +893,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
866893 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
867894 if (opcode == DW.LNS_extended_op) {
868895 const op_size = try readULeb128(in_stream);
869 if (op_size < 1)
870 return error.InvalidDebugInfo;
896 if (op_size < 1) return error.InvalidDebugInfo;
871897 sub_op = try in_stream.readByte();
872898 switch (sub_op) {
873899 DW.LNE_end_sequence => {
......@@ -884,7 +910,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
884910 const dir_index = try readULeb128(in_stream);
885911 const mtime = try readULeb128(in_stream);
886912 const len_bytes = try readULeb128(in_stream);
887 try file_entries.append(FileEntry {
913 try file_entries.append(FileEntry{
888914 .file_name = file_name,
889915 .dir_index = dir_index,
890916 .mtime = mtime,
......@@ -941,11 +967,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
941967 const arg = try in_stream.readInt(st.elf.endian, u16);
942968 prog.address += arg;
943969 },
944 DW.LNS_set_prologue_end => {
945 },
970 DW.LNS_set_prologue_end => {},
946971 else => {
947 if (opcode - 1 >= standard_opcode_lengths.len)
948 return error.InvalidDebugInfo;
972 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
949973 const len_bytes = standard_opcode_lengths[opcode - 1];
950974 try in_file.seekForward(len_bytes);
951975 },
......@@ -959,7 +983,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
959983 return error.MissingDebugInfo;
960984}
961985
962fn scanAllCompileUnits(st: &ElfStackTrace) !void {
986fn scanAllCompileUnits(st: *ElfStackTrace) !void {
963987 const debug_info_end = st.debug_info.offset + st.debug_info.size;
964988 var this_unit_offset = st.debug_info.offset;
965989 var cu_index: usize = 0;
......@@ -972,16 +996,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
972996
973997 var is_64: bool = undefined;
974998 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
975 if (unit_length == 0)
976 return;
999 if (unit_length == 0) return;
9771000 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
9781001
9791002 const version = try in_stream.readInt(st.elf.endian, u16);
9801003 if (version < 2 or version > 5) return error.InvalidDebugInfo;
9811004
982 const debug_abbrev_offset =
983 if (is_64) try in_stream.readInt(st.elf.endian, u64)
984 else try in_stream.readInt(st.elf.endian, u32);
1005 const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
9851006
9861007 const address_size = try in_stream.readByte();
9871008 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
......@@ -991,16 +1012,14 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
9911012
9921013 try st.self_exe_file.seekTo(compile_unit_pos);
9931014
994 const compile_unit_die = try st.allocator().create(Die);
995 *compile_unit_die = try parseDie(st, abbrev_table, is_64);
1015 const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
9961016
997 if (compile_unit_die.tag_id != DW.TAG_compile_unit)
998 return error.InvalidDebugInfo;
1017 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
9991018
10001019 const pc_range = x: {
10011020 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
10021021 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
1003 const pc_end = switch (*high_pc_value) {
1022 const pc_end = switch (high_pc_value.*) {
10041023 FormValue.Address => |value| value,
10051024 FormValue.Const => |value| b: {
10061025 const offset = try value.asUnsignedLe();
......@@ -1008,7 +1027,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
10081027 },
10091028 else => return error.InvalidDebugInfo,
10101029 };
1011 break :x PcRange {
1030 break :x PcRange{
10121031 .start = low_pc,
10131032 .end = pc_end,
10141033 };
......@@ -1016,13 +1035,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
10161035 break :x null;
10171036 }
10181037 } else |err| {
1019 if (err != error.MissingDebugInfo)
1020 return err;
1038 if (err != error.MissingDebugInfo) return err;
10211039 break :x null;
10221040 }
10231041 };
10241042
1025 try st.compile_unit_list.append(CompileUnit {
1043 try st.compile_unit_list.append(CompileUnit{
10261044 .version = version,
10271045 .is_64 = is_64,
10281046 .pc_range = pc_range,
......@@ -1035,13 +1053,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
10351053 }
10361054}
10371055
1038fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit {
1056fn findCompileUnit(st: *ElfStackTrace, target_address: u64) !*const CompileUnit {
10391057 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
10401058 const in_stream = &in_file_stream.stream;
10411059 for (st.compile_unit_list.toSlice()) |*compile_unit| {
10421060 if (compile_unit.pc_range) |range| {
1043 if (target_address >= range.start and target_address < range.end)
1044 return compile_unit;
1061 if (target_address >= range.start and target_address < range.end) return compile_unit;
10451062 }
10461063 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
10471064 var base_address: usize = 0;
......@@ -1063,18 +1080,17 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
10631080 }
10641081 }
10651082 } else |err| {
1066 if (err != error.MissingDebugInfo)
1067 return err;
1083 if (err != error.MissingDebugInfo) return err;
10681084 continue;
10691085 }
10701086 }
10711087 return error.MissingDebugInfo;
10721088}
10731089
1074fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
1090fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
10751091 const first_32_bits = try in_stream.readIntLe(u32);
1076 *is_64 = (first_32_bits == 0xffffffff);
1077 if (*is_64) {
1092 is_64.* = (first_32_bits == 0xffffffff);
1093 if (is_64.*) {
10781094 return in_stream.readIntLe(u64);
10791095 } else {
10801096 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
......@@ -1091,13 +1107,11 @@ fn readULeb128(in_stream: var) !u64 {
10911107
10921108 var operand: u64 = undefined;
10931109
1094 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
1095 return error.InvalidDebugInfo;
1110 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
10961111
10971112 result |= operand;
10981113
1099 if ((byte & 0b10000000) == 0)
1100 return result;
1114 if ((byte & 0b10000000) == 0) return result;
11011115
11021116 shift += 7;
11031117 }
......@@ -1112,20 +1126,32 @@ fn readILeb128(in_stream: var) !i64 {
11121126
11131127 var operand: i64 = undefined;
11141128
1115 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
1116 return error.InvalidDebugInfo;
1129 if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
11171130
11181131 result |= operand;
11191132 shift += 7;
11201133
11211134 if ((byte & 0b10000000) == 0) {
1122 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
1123 result |= -(i64(1) << u6(shift));
1135 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
11241136 return result;
11251137 }
11261138 }
11271139}
11281140
1141/// This should only be used in temporary test programs.
11291142pub const global_allocator = &global_fixed_allocator.allocator;
1130var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
1143var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);
11311144var global_allocator_mem: [100 * 1024]u8 = undefined;
1145
1146// TODO make thread safe
1147var debug_info_allocator: ?*mem.Allocator = null;
1148var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
1149var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
1150fn getDebugInfoAllocator() *mem.Allocator {
1151 if (debug_info_allocator) |a| return a;
1152
1153 debug_info_direct_allocator = std.heap.DirectAllocator.init();
1154 debug_info_arena_allocator = std.heap.ArenaAllocator.init(&debug_info_direct_allocator.allocator);
1155 debug_info_allocator = &debug_info_arena_allocator.allocator;
1156 return &debug_info_arena_allocator.allocator;
1157}
std/dwarf.zig+37-2
......@@ -337,7 +337,6 @@ pub const AT_PGI_lbase = 0x3a00;
337337pub const AT_PGI_soffset = 0x3a01;
338338pub const AT_PGI_lstride = 0x3a02;
339339
340
341340pub const OP_addr = 0x03;
342341pub const OP_deref = 0x06;
343342pub const OP_const1u = 0x08;
......@@ -577,7 +576,6 @@ pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.
577576pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.
578577pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.
579578
580
581579pub const CFA_advance_loc = 0x40;
582580pub const CFA_offset = 0x80;
583581pub const CFA_restore = 0xc0;
......@@ -641,3 +639,40 @@ pub const LNE_define_file = 0x03;
641639pub const LNE_set_discriminator = 0x04;
642640pub const LNE_lo_user = 0x80;
643641pub const LNE_hi_user = 0xff;
642
643pub const LANG_C89 = 0x0001;
644pub const LANG_C = 0x0002;
645pub const LANG_Ada83 = 0x0003;
646pub const LANG_C_plus_plus = 0x0004;
647pub const LANG_Cobol74 = 0x0005;
648pub const LANG_Cobol85 = 0x0006;
649pub const LANG_Fortran77 = 0x0007;
650pub const LANG_Fortran90 = 0x0008;
651pub const LANG_Pascal83 = 0x0009;
652pub const LANG_Modula2 = 0x000a;
653pub const LANG_Java = 0x000b;
654pub const LANG_C99 = 0x000c;
655pub const LANG_Ada95 = 0x000d;
656pub const LANG_Fortran95 = 0x000e;
657pub const LANG_PLI = 0x000f;
658pub const LANG_ObjC = 0x0010;
659pub const LANG_ObjC_plus_plus = 0x0011;
660pub const LANG_UPC = 0x0012;
661pub const LANG_D = 0x0013;
662pub const LANG_Python = 0x0014;
663pub const LANG_Go = 0x0016;
664pub const LANG_C_plus_plus_11 = 0x001a;
665pub const LANG_Rust = 0x001c;
666pub const LANG_C11 = 0x001d;
667pub const LANG_C_plus_plus_14 = 0x0021;
668pub const LANG_Fortran03 = 0x0022;
669pub const LANG_Fortran08 = 0x0023;
670pub const LANG_lo_user = 0x8000;
671pub const LANG_hi_user = 0xffff;
672pub const LANG_Mips_Assembler = 0x8001;
673pub const LANG_Upc = 0x8765;
674pub const LANG_HP_Bliss = 0x8003;
675pub const LANG_HP_Basic91 = 0x8004;
676pub const LANG_HP_Pascal91 = 0x8005;
677pub const LANG_HP_IMacro = 0x8006;
678pub const LANG_HP_Assembler = 0x8007;
std/dynamic_library.zig created+156
......@@ -0,0 +1,156 @@
1const std = @import("index.zig");
2const mem = std.mem;
3const elf = std.elf;
4const cstr = std.cstr;
5const linux = std.os.linux;
6
7pub const DynLib = struct {
8 allocator: *mem.Allocator,
9 elf_lib: ElfLib,
10 fd: i32,
11 map_addr: usize,
12 map_size: usize,
13
14 /// Trusts the file
15 pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {
16 const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
17 errdefer std.os.close(fd);
18
19 const size = @intCast(usize, (try std.os.posixFStat(fd)).size);
20
21 const addr = linux.mmap(
22 null,
23 size,
24 linux.PROT_READ | linux.PROT_EXEC,
25 linux.MAP_PRIVATE | linux.MAP_LOCKED,
26 fd,
27 0,
28 );
29 errdefer _ = linux.munmap(addr, size);
30
31 const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size];
32
33 return DynLib{
34 .allocator = allocator,
35 .elf_lib = try ElfLib.init(bytes),
36 .fd = fd,
37 .map_addr = addr,
38 .map_size = size,
39 };
40 }
41
42 pub fn close(self: *DynLib) void {
43 _ = linux.munmap(self.map_addr, self.map_size);
44 std.os.close(self.fd);
45 self.* = undefined;
46 }
47
48 pub fn lookup(self: *DynLib, name: []const u8) ?usize {
49 return self.elf_lib.lookup("", name);
50 }
51};
52
53pub const ElfLib = struct {
54 strings: [*]u8,
55 syms: [*]elf.Sym,
56 hashtab: [*]linux.Elf_Symndx,
57 versym: ?[*]u16,
58 verdef: ?*elf.Verdef,
59 base: usize,
60
61 // Trusts the memory
62 pub fn init(bytes: []align(@alignOf(elf.Ehdr)) u8) !ElfLib {
63 const eh = @ptrCast(*elf.Ehdr, bytes.ptr);
64 if (!mem.eql(u8, eh.e_ident[0..4], "\x7fELF")) return error.NotElfFile;
65 if (eh.e_type != elf.ET_DYN) return error.NotDynamicLibrary;
66
67 const elf_addr = @ptrToInt(bytes.ptr);
68 var ph_addr: usize = elf_addr + eh.e_phoff;
69
70 var base: usize = @maxValue(usize);
71 var maybe_dynv: ?[*]usize = null;
72 {
73 var i: usize = 0;
74 while (i < eh.e_phnum) : ({
75 i += 1;
76 ph_addr += eh.e_phentsize;
77 }) {
78 const ph = @intToPtr(*elf.Phdr, ph_addr);
79 switch (ph.p_type) {
80 elf.PT_LOAD => base = elf_addr + ph.p_offset - ph.p_vaddr,
81 elf.PT_DYNAMIC => maybe_dynv = @intToPtr([*]usize, elf_addr + ph.p_offset),
82 else => {},
83 }
84 }
85 }
86 const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation;
87 if (base == @maxValue(usize)) return error.BaseNotFound;
88
89 var maybe_strings: ?[*]u8 = null;
90 var maybe_syms: ?[*]elf.Sym = null;
91 var maybe_hashtab: ?[*]linux.Elf_Symndx = null;
92 var maybe_versym: ?[*]u16 = null;
93 var maybe_verdef: ?*elf.Verdef = null;
94
95 {
96 var i: usize = 0;
97 while (dynv[i] != 0) : (i += 2) {
98 const p = base + dynv[i + 1];
99 switch (dynv[i]) {
100 elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
101 elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
102 elf.DT_HASH => maybe_hashtab = @intToPtr([*]linux.Elf_Symndx, p),
103 elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p),
104 elf.DT_VERDEF => maybe_verdef = @intToPtr(*elf.Verdef, p),
105 else => {},
106 }
107 }
108 }
109
110 return ElfLib{
111 .base = base,
112 .strings = maybe_strings orelse return error.ElfStringSectionNotFound,
113 .syms = maybe_syms orelse return error.ElfSymSectionNotFound,
114 .hashtab = maybe_hashtab orelse return error.ElfHashTableNotFound,
115 .versym = maybe_versym,
116 .verdef = maybe_verdef,
117 };
118 }
119
120 /// Returns the address of the symbol
121 pub fn lookup(self: *const ElfLib, vername: []const u8, name: []const u8) ?usize {
122 const maybe_versym = if (self.verdef == null) null else self.versym;
123
124 const OK_TYPES = (1 << elf.STT_NOTYPE | 1 << elf.STT_OBJECT | 1 << elf.STT_FUNC | 1 << elf.STT_COMMON);
125 const OK_BINDS = (1 << elf.STB_GLOBAL | 1 << elf.STB_WEAK | 1 << elf.STB_GNU_UNIQUE);
126
127 var i: usize = 0;
128 while (i < self.hashtab[1]) : (i += 1) {
129 if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info & 0xf) & OK_TYPES)) continue;
130 if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info >> 4) & OK_BINDS)) continue;
131 if (0 == self.syms[i].st_shndx) continue;
132 if (!mem.eql(u8, name, cstr.toSliceConst(self.strings + self.syms[i].st_name))) continue;
133 if (maybe_versym) |versym| {
134 if (!checkver(self.verdef.?, versym[i], vername, self.strings))
135 continue;
136 }
137 return self.base + self.syms[i].st_value;
138 }
139
140 return null;
141 }
142};
143
144fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool {
145 var def = def_arg;
146 const vsym = @bitCast(u32, vsym_arg) & 0x7fff;
147 while (true) {
148 if (0 == (def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)
149 break;
150 if (def.vd_next == 0)
151 return false;
152 def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
153 }
154 const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
155 return mem.eql(u8, vername, cstr.toSliceConst(strings + aux.vda_name));
156}
std/elf.zig+642-24
......@@ -7,6 +7,241 @@ const mem = std.mem;
77const debug = std.debug;
88const InStream = std.stream.InStream;
99
10pub const AT_NULL = 0;
11pub const AT_IGNORE = 1;
12pub const AT_EXECFD = 2;
13pub const AT_PHDR = 3;
14pub const AT_PHENT = 4;
15pub const AT_PHNUM = 5;
16pub const AT_PAGESZ = 6;
17pub const AT_BASE = 7;
18pub const AT_FLAGS = 8;
19pub const AT_ENTRY = 9;
20pub const AT_NOTELF = 10;
21pub const AT_UID = 11;
22pub const AT_EUID = 12;
23pub const AT_GID = 13;
24pub const AT_EGID = 14;
25pub const AT_CLKTCK = 17;
26pub const AT_PLATFORM = 15;
27pub const AT_HWCAP = 16;
28pub const AT_FPUCW = 18;
29pub const AT_DCACHEBSIZE = 19;
30pub const AT_ICACHEBSIZE = 20;
31pub const AT_UCACHEBSIZE = 21;
32pub const AT_IGNOREPPC = 22;
33pub const AT_SECURE = 23;
34pub const AT_BASE_PLATFORM = 24;
35pub const AT_RANDOM = 25;
36pub const AT_HWCAP2 = 26;
37pub const AT_EXECFN = 31;
38pub const AT_SYSINFO = 32;
39pub const AT_SYSINFO_EHDR = 33;
40pub const AT_L1I_CACHESHAPE = 34;
41pub const AT_L1D_CACHESHAPE = 35;
42pub const AT_L2_CACHESHAPE = 36;
43pub const AT_L3_CACHESHAPE = 37;
44pub const AT_L1I_CACHESIZE = 40;
45pub const AT_L1I_CACHEGEOMETRY = 41;
46pub const AT_L1D_CACHESIZE = 42;
47pub const AT_L1D_CACHEGEOMETRY = 43;
48pub const AT_L2_CACHESIZE = 44;
49pub const AT_L2_CACHEGEOMETRY = 45;
50pub const AT_L3_CACHESIZE = 46;
51pub const AT_L3_CACHEGEOMETRY = 47;
52
53pub const DT_NULL = 0;
54pub const DT_NEEDED = 1;
55pub const DT_PLTRELSZ = 2;
56pub const DT_PLTGOT = 3;
57pub const DT_HASH = 4;
58pub const DT_STRTAB = 5;
59pub const DT_SYMTAB = 6;
60pub const DT_RELA = 7;
61pub const DT_RELASZ = 8;
62pub const DT_RELAENT = 9;
63pub const DT_STRSZ = 10;
64pub const DT_SYMENT = 11;
65pub const DT_INIT = 12;
66pub const DT_FINI = 13;
67pub const DT_SONAME = 14;
68pub const DT_RPATH = 15;
69pub const DT_SYMBOLIC = 16;
70pub const DT_REL = 17;
71pub const DT_RELSZ = 18;
72pub const DT_RELENT = 19;
73pub const DT_PLTREL = 20;
74pub const DT_DEBUG = 21;
75pub const DT_TEXTREL = 22;
76pub const DT_JMPREL = 23;
77pub const DT_BIND_NOW = 24;
78pub const DT_INIT_ARRAY = 25;
79pub const DT_FINI_ARRAY = 26;
80pub const DT_INIT_ARRAYSZ = 27;
81pub const DT_FINI_ARRAYSZ = 28;
82pub const DT_RUNPATH = 29;
83pub const DT_FLAGS = 30;
84pub const DT_ENCODING = 32;
85pub const DT_PREINIT_ARRAY = 32;
86pub const DT_PREINIT_ARRAYSZ = 33;
87pub const DT_SYMTAB_SHNDX = 34;
88pub const DT_NUM = 35;
89pub const DT_LOOS = 0x6000000d;
90pub const DT_HIOS = 0x6ffff000;
91pub const DT_LOPROC = 0x70000000;
92pub const DT_HIPROC = 0x7fffffff;
93pub const DT_PROCNUM = DT_MIPS_NUM;
94
95pub const DT_VALRNGLO = 0x6ffffd00;
96pub const DT_GNU_PRELINKED = 0x6ffffdf5;
97pub const DT_GNU_CONFLICTSZ = 0x6ffffdf6;
98pub const DT_GNU_LIBLISTSZ = 0x6ffffdf7;
99pub const DT_CHECKSUM = 0x6ffffdf8;
100pub const DT_PLTPADSZ = 0x6ffffdf9;
101pub const DT_MOVEENT = 0x6ffffdfa;
102pub const DT_MOVESZ = 0x6ffffdfb;
103pub const DT_FEATURE_1 = 0x6ffffdfc;
104pub const DT_POSFLAG_1 = 0x6ffffdfd;
105
106pub const DT_SYMINSZ = 0x6ffffdfe;
107pub const DT_SYMINENT = 0x6ffffdff;
108pub const DT_VALRNGHI = 0x6ffffdff;
109pub const DT_VALNUM = 12;
110
111pub const DT_ADDRRNGLO = 0x6ffffe00;
112pub const DT_GNU_HASH = 0x6ffffef5;
113pub const DT_TLSDESC_PLT = 0x6ffffef6;
114pub const DT_TLSDESC_GOT = 0x6ffffef7;
115pub const DT_GNU_CONFLICT = 0x6ffffef8;
116pub const DT_GNU_LIBLIST = 0x6ffffef9;
117pub const DT_CONFIG = 0x6ffffefa;
118pub const DT_DEPAUDIT = 0x6ffffefb;
119pub const DT_AUDIT = 0x6ffffefc;
120pub const DT_PLTPAD = 0x6ffffefd;
121pub const DT_MOVETAB = 0x6ffffefe;
122pub const DT_SYMINFO = 0x6ffffeff;
123pub const DT_ADDRRNGHI = 0x6ffffeff;
124pub const DT_ADDRNUM = 11;
125
126pub const DT_VERSYM = 0x6ffffff0;
127
128pub const DT_RELACOUNT = 0x6ffffff9;
129pub const DT_RELCOUNT = 0x6ffffffa;
130
131pub const DT_FLAGS_1 = 0x6ffffffb;
132pub const DT_VERDEF = 0x6ffffffc;
133
134pub const DT_VERDEFNUM = 0x6ffffffd;
135pub const DT_VERNEED = 0x6ffffffe;
136
137pub const DT_VERNEEDNUM = 0x6fffffff;
138pub const DT_VERSIONTAGNUM = 16;
139
140pub const DT_AUXILIARY = 0x7ffffffd;
141pub const DT_FILTER = 0x7fffffff;
142pub const DT_EXTRANUM = 3;
143
144pub const DT_SPARC_REGISTER = 0x70000001;
145pub const DT_SPARC_NUM = 2;
146
147pub const DT_MIPS_RLD_VERSION = 0x70000001;
148pub const DT_MIPS_TIME_STAMP = 0x70000002;
149pub const DT_MIPS_ICHECKSUM = 0x70000003;
150pub const DT_MIPS_IVERSION = 0x70000004;
151pub const DT_MIPS_FLAGS = 0x70000005;
152pub const DT_MIPS_BASE_ADDRESS = 0x70000006;
153pub const DT_MIPS_MSYM = 0x70000007;
154pub const DT_MIPS_CONFLICT = 0x70000008;
155pub const DT_MIPS_LIBLIST = 0x70000009;
156pub const DT_MIPS_LOCAL_GOTNO = 0x7000000a;
157pub const DT_MIPS_CONFLICTNO = 0x7000000b;
158pub const DT_MIPS_LIBLISTNO = 0x70000010;
159pub const DT_MIPS_SYMTABNO = 0x70000011;
160pub const DT_MIPS_UNREFEXTNO = 0x70000012;
161pub const DT_MIPS_GOTSYM = 0x70000013;
162pub const DT_MIPS_HIPAGENO = 0x70000014;
163pub const DT_MIPS_RLD_MAP = 0x70000016;
164pub const DT_MIPS_DELTA_CLASS = 0x70000017;
165pub const DT_MIPS_DELTA_CLASS_NO = 0x70000018;
166
167pub const DT_MIPS_DELTA_INSTANCE = 0x70000019;
168pub const DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a;
169
170pub const DT_MIPS_DELTA_RELOC = 0x7000001b;
171pub const DT_MIPS_DELTA_RELOC_NO = 0x7000001c;
172
173pub const DT_MIPS_DELTA_SYM = 0x7000001d;
174
175pub const DT_MIPS_DELTA_SYM_NO = 0x7000001e;
176
177pub const DT_MIPS_DELTA_CLASSSYM = 0x70000020;
178
179pub const DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021;
180
181pub const DT_MIPS_CXX_FLAGS = 0x70000022;
182pub const DT_MIPS_PIXIE_INIT = 0x70000023;
183pub const DT_MIPS_SYMBOL_LIB = 0x70000024;
184pub const DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025;
185pub const DT_MIPS_LOCAL_GOTIDX = 0x70000026;
186pub const DT_MIPS_HIDDEN_GOTIDX = 0x70000027;
187pub const DT_MIPS_PROTECTED_GOTIDX = 0x70000028;
188pub const DT_MIPS_OPTIONS = 0x70000029;
189pub const DT_MIPS_INTERFACE = 0x7000002a;
190pub const DT_MIPS_DYNSTR_ALIGN = 0x7000002b;
191pub const DT_MIPS_INTERFACE_SIZE = 0x7000002c;
192pub const DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d;
193
194pub const DT_MIPS_PERF_SUFFIX = 0x7000002e;
195
196pub const DT_MIPS_COMPACT_SIZE = 0x7000002f;
197pub const DT_MIPS_GP_VALUE = 0x70000030;
198pub const DT_MIPS_AUX_DYNAMIC = 0x70000031;
199
200pub const DT_MIPS_PLTGOT = 0x70000032;
201
202pub const DT_MIPS_RWPLT = 0x70000034;
203pub const DT_MIPS_RLD_MAP_REL = 0x70000035;
204pub const DT_MIPS_NUM = 0x36;
205
206pub const DT_ALPHA_PLTRO = (DT_LOPROC + 0);
207pub const DT_ALPHA_NUM = 1;
208
209pub const DT_PPC_GOT = (DT_LOPROC + 0);
210pub const DT_PPC_OPT = (DT_LOPROC + 1);
211pub const DT_PPC_NUM = 2;
212
213pub const DT_PPC64_GLINK = (DT_LOPROC + 0);
214pub const DT_PPC64_OPD = (DT_LOPROC + 1);
215pub const DT_PPC64_OPDSZ = (DT_LOPROC + 2);
216pub const DT_PPC64_OPT = (DT_LOPROC + 3);
217pub const DT_PPC64_NUM = 4;
218
219pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0);
220pub const DT_IA_64_NUM = 1;
221
222pub const DT_NIOS2_GP = 0x70000002;
223
224pub const PT_NULL = 0;
225pub const PT_LOAD = 1;
226pub const PT_DYNAMIC = 2;
227pub const PT_INTERP = 3;
228pub const PT_NOTE = 4;
229pub const PT_SHLIB = 5;
230pub const PT_PHDR = 6;
231pub const PT_TLS = 7;
232pub const PT_NUM = 8;
233pub const PT_LOOS = 0x60000000;
234pub const PT_GNU_EH_FRAME = 0x6474e550;
235pub const PT_GNU_STACK = 0x6474e551;
236pub const PT_GNU_RELRO = 0x6474e552;
237pub const PT_LOSUNW = 0x6ffffffa;
238pub const PT_SUNWBSS = 0x6ffffffa;
239pub const PT_SUNWSTACK = 0x6ffffffb;
240pub const PT_HISUNW = 0x6fffffff;
241pub const PT_HIOS = 0x6fffffff;
242pub const PT_LOPROC = 0x70000000;
243pub const PT_HIPROC = 0x7fffffff;
244
10245pub const SHT_NULL = 0;
11246pub const SHT_PROGBITS = 1;
12247pub const SHT_SYMTAB = 2;
......@@ -31,6 +266,60 @@ pub const SHT_HIPROC = 0x7fffffff;
31266pub const SHT_LOUSER = 0x80000000;
32267pub const SHT_HIUSER = 0xffffffff;
33268
269pub const STB_LOCAL = 0;
270pub const STB_GLOBAL = 1;
271pub const STB_WEAK = 2;
272pub const STB_NUM = 3;
273pub const STB_LOOS = 10;
274pub const STB_GNU_UNIQUE = 10;
275pub const STB_HIOS = 12;
276pub const STB_LOPROC = 13;
277pub const STB_HIPROC = 15;
278
279pub const STB_MIPS_SPLIT_COMMON = 13;
280
281pub const STT_NOTYPE = 0;
282pub const STT_OBJECT = 1;
283pub const STT_FUNC = 2;
284pub const STT_SECTION = 3;
285pub const STT_FILE = 4;
286pub const STT_COMMON = 5;
287pub const STT_TLS = 6;
288pub const STT_NUM = 7;
289pub const STT_LOOS = 10;
290pub const STT_GNU_IFUNC = 10;
291pub const STT_HIOS = 12;
292pub const STT_LOPROC = 13;
293pub const STT_HIPROC = 15;
294
295pub const STT_SPARC_REGISTER = 13;
296
297pub const STT_PARISC_MILLICODE = 13;
298
299pub const STT_HP_OPAQUE = (STT_LOOS + 0x1);
300pub const STT_HP_STUB = (STT_LOOS + 0x2);
301
302pub const STT_ARM_TFUNC = STT_LOPROC;
303pub const STT_ARM_16BIT = STT_HIPROC;
304
305pub const VER_FLG_BASE = 0x1;
306pub const VER_FLG_WEAK = 0x2;
307
308/// An unknown type.
309pub const ET_NONE = 0;
310
311/// A relocatable file.
312pub const ET_REL = 1;
313
314/// An executable file.
315pub const ET_EXEC = 2;
316
317/// A shared object.
318pub const ET_DYN = 3;
319
320/// A core file.
321pub const ET_CORE = 4;
322
34323pub const FileType = enum {
35324 Relocatable,
36325 Executable,
......@@ -64,7 +353,7 @@ pub const SectionHeader = struct {
64353};
65354
66355pub const Elf = struct {
67 in_file: &os.File,
356 in_file: *os.File,
68357 auto_close_stream: bool,
69358 is_64: bool,
70359 endian: builtin.Endian,
......@@ -74,20 +363,20 @@ pub const Elf = struct {
74363 program_header_offset: u64,
75364 section_header_offset: u64,
76365 string_section_index: u64,
77 string_section: &SectionHeader,
366 string_section: *SectionHeader,
78367 section_headers: []SectionHeader,
79 allocator: &mem.Allocator,
368 allocator: *mem.Allocator,
80369 prealloc_file: os.File,
81370
82371 /// Call close when done.
83 pub fn openPath(elf: &Elf, allocator: &mem.Allocator, path: []const u8) !void {
372 pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
84373 try elf.prealloc_file.open(path);
85 try elf.openFile(allocator, &elf.prealloc_file);
374 try elf.openFile(allocator, *elf.prealloc_file);
86375 elf.auto_close_stream = true;
87376 }
88377
89378 /// Call close when done.
90 pub fn openFile(elf: &Elf, allocator: &mem.Allocator, file: &os.File) !void {
379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: *os.File) !void {
91380 elf.allocator = allocator;
92381 elf.in_file = file;
93382 elf.auto_close_stream = false;
......@@ -155,9 +444,7 @@ pub const Elf = struct {
155444 try elf.in_file.seekForward(4);
156445
157446 const header_size = try in.readInt(elf.endian, u16);
158 if ((elf.is_64 and header_size != 64) or
159 (!elf.is_64 and header_size != 52))
160 {
447 if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
161448 return error.InvalidFormat;
162449 }
163450
......@@ -188,16 +475,16 @@ pub const Elf = struct {
188475 if (sh_entry_size != 64) return error.InvalidFormat;
189476
190477 for (elf.section_headers) |*elf_section| {
191 elf_section.name = try in.readInt(elf.endian, u32);
192 elf_section.sh_type = try in.readInt(elf.endian, u32);
193 elf_section.flags = try in.readInt(elf.endian, u64);
194 elf_section.addr = try in.readInt(elf.endian, u64);
195 elf_section.offset = try in.readInt(elf.endian, u64);
196 elf_section.size = try in.readInt(elf.endian, u64);
197 elf_section.link = try in.readInt(elf.endian, u32);
198 elf_section.info = try in.readInt(elf.endian, u32);
199 elf_section.addr_align = try in.readInt(elf.endian, u64);
200 elf_section.ent_size = try in.readInt(elf.endian, u64);
478 elf_section.name = try in.readInt(elf.endian, u32);
479 elf_section.sh_type = try in.readInt(elf.endian, u32);
480 elf_section.flags = try in.readInt(elf.endian, u64);
481 elf_section.addr = try in.readInt(elf.endian, u64);
482 elf_section.offset = try in.readInt(elf.endian, u64);
483 elf_section.size = try in.readInt(elf.endian, u64);
484 elf_section.link = try in.readInt(elf.endian, u32);
485 elf_section.info = try in.readInt(elf.endian, u32);
486 elf_section.addr_align = try in.readInt(elf.endian, u64);
487 elf_section.ent_size = try in.readInt(elf.endian, u64);
201488 }
202489 } else {
203490 if (sh_entry_size != 40) return error.InvalidFormat;
......@@ -231,14 +518,13 @@ pub const Elf = struct {
231518 }
232519 }
233520
234 pub fn close(elf: &Elf) void {
521 pub fn close(elf: *Elf) void {
235522 elf.allocator.free(elf.section_headers);
236523
237 if (elf.auto_close_stream)
238 elf.in_file.close();
524 if (elf.auto_close_stream) elf.in_file.close();
239525 }
240526
241 pub fn findSection(elf: &Elf, name: []const u8) !?&SectionHeader {
527 pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
242528 var file_stream = io.FileInStream.init(elf.in_file);
243529 const in = &file_stream.stream;
244530
......@@ -262,7 +548,339 @@ pub const Elf = struct {
262548 return null;
263549 }
264550
265 pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) !void {
551 pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
266552 try elf.in_file.seekTo(elf_section.offset);
267553 }
268554};
555
556pub const EI_NIDENT = 16;
557pub const Elf32_Half = u16;
558pub const Elf64_Half = u16;
559pub const Elf32_Word = u32;
560pub const Elf32_Sword = i32;
561pub const Elf64_Word = u32;
562pub const Elf64_Sword = i32;
563pub const Elf32_Xword = u64;
564pub const Elf32_Sxword = i64;
565pub const Elf64_Xword = u64;
566pub const Elf64_Sxword = i64;
567pub const Elf32_Addr = u32;
568pub const Elf64_Addr = u64;
569pub const Elf32_Off = u32;
570pub const Elf64_Off = u64;
571pub const Elf32_Section = u16;
572pub const Elf64_Section = u16;
573pub const Elf32_Versym = Elf32_Half;
574pub const Elf64_Versym = Elf64_Half;
575pub const Elf32_Ehdr = extern struct {
576 e_ident: [EI_NIDENT]u8,
577 e_type: Elf32_Half,
578 e_machine: Elf32_Half,
579 e_version: Elf32_Word,
580 e_entry: Elf32_Addr,
581 e_phoff: Elf32_Off,
582 e_shoff: Elf32_Off,
583 e_flags: Elf32_Word,
584 e_ehsize: Elf32_Half,
585 e_phentsize: Elf32_Half,
586 e_phnum: Elf32_Half,
587 e_shentsize: Elf32_Half,
588 e_shnum: Elf32_Half,
589 e_shstrndx: Elf32_Half,
590};
591pub const Elf64_Ehdr = extern struct {
592 e_ident: [EI_NIDENT]u8,
593 e_type: Elf64_Half,
594 e_machine: Elf64_Half,
595 e_version: Elf64_Word,
596 e_entry: Elf64_Addr,
597 e_phoff: Elf64_Off,
598 e_shoff: Elf64_Off,
599 e_flags: Elf64_Word,
600 e_ehsize: Elf64_Half,
601 e_phentsize: Elf64_Half,
602 e_phnum: Elf64_Half,
603 e_shentsize: Elf64_Half,
604 e_shnum: Elf64_Half,
605 e_shstrndx: Elf64_Half,
606};
607pub const Elf32_Shdr = extern struct {
608 sh_name: Elf32_Word,
609 sh_type: Elf32_Word,
610 sh_flags: Elf32_Word,
611 sh_addr: Elf32_Addr,
612 sh_offset: Elf32_Off,
613 sh_size: Elf32_Word,
614 sh_link: Elf32_Word,
615 sh_info: Elf32_Word,
616 sh_addralign: Elf32_Word,
617 sh_entsize: Elf32_Word,
618};
619pub const Elf64_Shdr = extern struct {
620 sh_name: Elf64_Word,
621 sh_type: Elf64_Word,
622 sh_flags: Elf64_Xword,
623 sh_addr: Elf64_Addr,
624 sh_offset: Elf64_Off,
625 sh_size: Elf64_Xword,
626 sh_link: Elf64_Word,
627 sh_info: Elf64_Word,
628 sh_addralign: Elf64_Xword,
629 sh_entsize: Elf64_Xword,
630};
631pub const Elf32_Chdr = extern struct {
632 ch_type: Elf32_Word,
633 ch_size: Elf32_Word,
634 ch_addralign: Elf32_Word,
635};
636pub const Elf64_Chdr = extern struct {
637 ch_type: Elf64_Word,
638 ch_reserved: Elf64_Word,
639 ch_size: Elf64_Xword,
640 ch_addralign: Elf64_Xword,
641};
642pub const Elf32_Sym = extern struct {
643 st_name: Elf32_Word,
644 st_value: Elf32_Addr,
645 st_size: Elf32_Word,
646 st_info: u8,
647 st_other: u8,
648 st_shndx: Elf32_Section,
649};
650pub const Elf64_Sym = extern struct {
651 st_name: Elf64_Word,
652 st_info: u8,
653 st_other: u8,
654 st_shndx: Elf64_Section,
655 st_value: Elf64_Addr,
656 st_size: Elf64_Xword,
657};
658pub const Elf32_Syminfo = extern struct {
659 si_boundto: Elf32_Half,
660 si_flags: Elf32_Half,
661};
662pub const Elf64_Syminfo = extern struct {
663 si_boundto: Elf64_Half,
664 si_flags: Elf64_Half,
665};
666pub const Elf32_Rel = extern struct {
667 r_offset: Elf32_Addr,
668 r_info: Elf32_Word,
669};
670pub const Elf64_Rel = extern struct {
671 r_offset: Elf64_Addr,
672 r_info: Elf64_Xword,
673};
674pub const Elf32_Rela = extern struct {
675 r_offset: Elf32_Addr,
676 r_info: Elf32_Word,
677 r_addend: Elf32_Sword,
678};
679pub const Elf64_Rela = extern struct {
680 r_offset: Elf64_Addr,
681 r_info: Elf64_Xword,
682 r_addend: Elf64_Sxword,
683};
684pub const Elf32_Phdr = extern struct {
685 p_type: Elf32_Word,
686 p_offset: Elf32_Off,
687 p_vaddr: Elf32_Addr,
688 p_paddr: Elf32_Addr,
689 p_filesz: Elf32_Word,
690 p_memsz: Elf32_Word,
691 p_flags: Elf32_Word,
692 p_align: Elf32_Word,
693};
694pub const Elf64_Phdr = extern struct {
695 p_type: Elf64_Word,
696 p_flags: Elf64_Word,
697 p_offset: Elf64_Off,
698 p_vaddr: Elf64_Addr,
699 p_paddr: Elf64_Addr,
700 p_filesz: Elf64_Xword,
701 p_memsz: Elf64_Xword,
702 p_align: Elf64_Xword,
703};
704pub const Elf32_Dyn = extern struct {
705 d_tag: Elf32_Sword,
706 d_un: extern union {
707 d_val: Elf32_Word,
708 d_ptr: Elf32_Addr,
709 },
710};
711pub const Elf64_Dyn = extern struct {
712 d_tag: Elf64_Sxword,
713 d_un: extern union {
714 d_val: Elf64_Xword,
715 d_ptr: Elf64_Addr,
716 },
717};
718pub const Elf32_Verdef = extern struct {
719 vd_version: Elf32_Half,
720 vd_flags: Elf32_Half,
721 vd_ndx: Elf32_Half,
722 vd_cnt: Elf32_Half,
723 vd_hash: Elf32_Word,
724 vd_aux: Elf32_Word,
725 vd_next: Elf32_Word,
726};
727pub const Elf64_Verdef = extern struct {
728 vd_version: Elf64_Half,
729 vd_flags: Elf64_Half,
730 vd_ndx: Elf64_Half,
731 vd_cnt: Elf64_Half,
732 vd_hash: Elf64_Word,
733 vd_aux: Elf64_Word,
734 vd_next: Elf64_Word,
735};
736pub const Elf32_Verdaux = extern struct {
737 vda_name: Elf32_Word,
738 vda_next: Elf32_Word,
739};
740pub const Elf64_Verdaux = extern struct {
741 vda_name: Elf64_Word,
742 vda_next: Elf64_Word,
743};
744pub const Elf32_Verneed = extern struct {
745 vn_version: Elf32_Half,
746 vn_cnt: Elf32_Half,
747 vn_file: Elf32_Word,
748 vn_aux: Elf32_Word,
749 vn_next: Elf32_Word,
750};
751pub const Elf64_Verneed = extern struct {
752 vn_version: Elf64_Half,
753 vn_cnt: Elf64_Half,
754 vn_file: Elf64_Word,
755 vn_aux: Elf64_Word,
756 vn_next: Elf64_Word,
757};
758pub const Elf32_Vernaux = extern struct {
759 vna_hash: Elf32_Word,
760 vna_flags: Elf32_Half,
761 vna_other: Elf32_Half,
762 vna_name: Elf32_Word,
763 vna_next: Elf32_Word,
764};
765pub const Elf64_Vernaux = extern struct {
766 vna_hash: Elf64_Word,
767 vna_flags: Elf64_Half,
768 vna_other: Elf64_Half,
769 vna_name: Elf64_Word,
770 vna_next: Elf64_Word,
771};
772pub const Elf32_auxv_t = extern struct {
773 a_type: u32,
774 a_un: extern union {
775 a_val: u32,
776 },
777};
778pub const Elf64_auxv_t = extern struct {
779 a_type: u64,
780 a_un: extern union {
781 a_val: u64,
782 },
783};
784pub const Elf32_Nhdr = extern struct {
785 n_namesz: Elf32_Word,
786 n_descsz: Elf32_Word,
787 n_type: Elf32_Word,
788};
789pub const Elf64_Nhdr = extern struct {
790 n_namesz: Elf64_Word,
791 n_descsz: Elf64_Word,
792 n_type: Elf64_Word,
793};
794pub const Elf32_Move = extern struct {
795 m_value: Elf32_Xword,
796 m_info: Elf32_Word,
797 m_poffset: Elf32_Word,
798 m_repeat: Elf32_Half,
799 m_stride: Elf32_Half,
800};
801pub const Elf64_Move = extern struct {
802 m_value: Elf64_Xword,
803 m_info: Elf64_Xword,
804 m_poffset: Elf64_Xword,
805 m_repeat: Elf64_Half,
806 m_stride: Elf64_Half,
807};
808pub const Elf32_gptab = extern union {
809 gt_header: extern struct {
810 gt_current_g_value: Elf32_Word,
811 gt_unused: Elf32_Word,
812 },
813 gt_entry: extern struct {
814 gt_g_value: Elf32_Word,
815 gt_bytes: Elf32_Word,
816 },
817};
818pub const Elf32_RegInfo = extern struct {
819 ri_gprmask: Elf32_Word,
820 ri_cprmask: [4]Elf32_Word,
821 ri_gp_value: Elf32_Sword,
822};
823pub const Elf_Options = extern struct {
824 kind: u8,
825 size: u8,
826 @"section": Elf32_Section,
827 info: Elf32_Word,
828};
829pub const Elf_Options_Hw = extern struct {
830 hwp_flags1: Elf32_Word,
831 hwp_flags2: Elf32_Word,
832};
833pub const Elf32_Lib = extern struct {
834 l_name: Elf32_Word,
835 l_time_stamp: Elf32_Word,
836 l_checksum: Elf32_Word,
837 l_version: Elf32_Word,
838 l_flags: Elf32_Word,
839};
840pub const Elf64_Lib = extern struct {
841 l_name: Elf64_Word,
842 l_time_stamp: Elf64_Word,
843 l_checksum: Elf64_Word,
844 l_version: Elf64_Word,
845 l_flags: Elf64_Word,
846};
847pub const Elf32_Conflict = Elf32_Addr;
848pub const Elf_MIPS_ABIFlags_v0 = extern struct {
849 version: Elf32_Half,
850 isa_level: u8,
851 isa_rev: u8,
852 gpr_size: u8,
853 cpr1_size: u8,
854 cpr2_size: u8,
855 fp_abi: u8,
856 isa_ext: Elf32_Word,
857 ases: Elf32_Word,
858 flags1: Elf32_Word,
859 flags2: Elf32_Word,
860};
861
862pub const Ehdr = switch (@sizeOf(usize)) {
863 4 => Elf32_Ehdr,
864 8 => Elf64_Ehdr,
865 else => @compileError("expected pointer size of 32 or 64"),
866};
867pub const Phdr = switch (@sizeOf(usize)) {
868 4 => Elf32_Phdr,
869 8 => Elf64_Phdr,
870 else => @compileError("expected pointer size of 32 or 64"),
871};
872pub const Sym = switch (@sizeOf(usize)) {
873 4 => Elf32_Sym,
874 8 => Elf64_Sym,
875 else => @compileError("expected pointer size of 32 or 64"),
876};
877pub const Verdef = switch (@sizeOf(usize)) {
878 4 => Elf32_Verdef,
879 8 => Elf64_Verdef,
880 else => @compileError("expected pointer size of 32 or 64"),
881};
882pub const Verdaux = switch (@sizeOf(usize)) {
883 4 => Elf32_Verdaux,
884 8 => Elf64_Verdaux,
885 else => @compileError("expected pointer size of 32 or 64"),
886};
std/event.zig+16-234
......@@ -1,235 +1,17 @@
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();
1pub const Locked = @import("event/locked.zig").Locked;
2pub const Loop = @import("event/loop.zig").Loop;
3pub const Lock = @import("event/lock.zig").Lock;
4pub const tcp = @import("event/tcp.zig");
5pub const Channel = @import("event/channel.zig").Channel;
6pub const Group = @import("event/group.zig").Group;
7pub const Future = @import("event/future.zig").Future;
8
9test "import event tests" {
10 _ = @import("event/locked.zig");
11 _ = @import("event/loop.zig");
12 _ = @import("event/lock.zig");
13 _ = @import("event/tcp.zig");
14 _ = @import("event/channel.zig");
15 _ = @import("event/group.zig");
16 _ = @import("event/future.zig");
23517}
std/event/channel.zig created+235
......@@ -0,0 +1,235 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const AtomicRmwOp = builtin.AtomicRmwOp;
5const AtomicOrder = builtin.AtomicOrder;
6const Loop = std.event.Loop;
7
8/// many producer, many consumer, thread-safe, lock-free, runtime configurable buffer size
9/// when buffer is empty, consumers suspend and are resumed by producers
10/// when buffer is full, producers suspend and are resumed by consumers
11pub fn Channel(comptime T: type) type {
12 return struct {
13 loop: *Loop,
14
15 getters: std.atomic.Queue(GetNode),
16 putters: std.atomic.Queue(PutNode),
17 get_count: usize,
18 put_count: usize,
19 dispatch_lock: u8, // TODO make this a bool
20 need_dispatch: u8, // TODO make this a bool
21
22 // simple fixed size ring buffer
23 buffer_nodes: []T,
24 buffer_index: usize,
25 buffer_len: usize,
26
27 const SelfChannel = this;
28 const GetNode = struct {
29 ptr: *T,
30 tick_node: *Loop.NextTickNode,
31 };
32 const PutNode = struct {
33 data: T,
34 tick_node: *Loop.NextTickNode,
35 };
36
37 /// call destroy when done
38 pub fn create(loop: *Loop, capacity: usize) !*SelfChannel {
39 const buffer_nodes = try loop.allocator.alloc(T, capacity);
40 errdefer loop.allocator.free(buffer_nodes);
41
42 const self = try loop.allocator.create(SelfChannel{
43 .loop = loop,
44 .buffer_len = 0,
45 .buffer_nodes = buffer_nodes,
46 .buffer_index = 0,
47 .dispatch_lock = 0,
48 .need_dispatch = 0,
49 .getters = std.atomic.Queue(GetNode).init(),
50 .putters = std.atomic.Queue(PutNode).init(),
51 .get_count = 0,
52 .put_count = 0,
53 });
54 errdefer loop.allocator.destroy(self);
55
56 return self;
57 }
58
59 /// must be called when all calls to put and get have suspended and no more calls occur
60 pub fn destroy(self: *SelfChannel) void {
61 while (self.getters.get()) |get_node| {
62 cancel get_node.data.tick_node.data;
63 }
64 while (self.putters.get()) |put_node| {
65 cancel put_node.data.tick_node.data;
66 }
67 self.loop.allocator.free(self.buffer_nodes);
68 self.loop.allocator.destroy(self);
69 }
70
71 /// puts a data item in the channel. The promise completes when the value has been added to the
72 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.
73 pub async fn put(self: *SelfChannel, data: T) void {
74 suspend {
75 var my_tick_node = Loop.NextTickNode{
76 .next = undefined,
77 .data = @handle(),
78 };
79 var queue_node = std.atomic.Queue(PutNode).Node{
80 .data = PutNode{
81 .tick_node = &my_tick_node,
82 .data = data,
83 },
84 .next = undefined,
85 };
86 self.putters.put(&queue_node);
87 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
88
89 self.dispatch();
90 }
91 }
92
93 /// await this function to get an item from the channel. If the buffer is empty, the promise will
94 /// complete when the next item is put in the channel.
95 pub async fn get(self: *SelfChannel) T {
96 // TODO integrate this function with named return values
97 // so we can get rid of this extra result copy
98 var result: T = undefined;
99 suspend {
100 var my_tick_node = Loop.NextTickNode{
101 .next = undefined,
102 .data = @handle(),
103 };
104 var queue_node = std.atomic.Queue(GetNode).Node{
105 .data = GetNode{
106 .ptr = &result,
107 .tick_node = &my_tick_node,
108 },
109 .next = undefined,
110 };
111 self.getters.put(&queue_node);
112 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
113
114 self.dispatch();
115 }
116 return result;
117 }
118
119 fn dispatch(self: *SelfChannel) void {
120 // set the "need dispatch" flag
121 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
122
123 lock: while (true) {
124 // set the lock flag
125 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
126 if (prev_lock != 0) return;
127
128 // clear the need_dispatch flag since we're about to do it
129 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
130
131 while (true) {
132 one_dispatch: {
133 // later we correct these extra subtractions
134 var get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
135 var put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
136
137 // transfer self.buffer to self.getters
138 while (self.buffer_len != 0) {
139 if (get_count == 0) break :one_dispatch;
140
141 const get_node = &self.getters.get().?.data;
142 get_node.ptr.* = self.buffer_nodes[self.buffer_index -% self.buffer_len];
143 self.loop.onNextTick(get_node.tick_node);
144 self.buffer_len -= 1;
145
146 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
147 }
148
149 // direct transfer self.putters to self.getters
150 while (get_count != 0 and put_count != 0) {
151 const get_node = &self.getters.get().?.data;
152 const put_node = &self.putters.get().?.data;
153
154 get_node.ptr.* = put_node.data;
155 self.loop.onNextTick(get_node.tick_node);
156 self.loop.onNextTick(put_node.tick_node);
157
158 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
159 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
160 }
161
162 // transfer self.putters to self.buffer
163 while (self.buffer_len != self.buffer_nodes.len and put_count != 0) {
164 const put_node = &self.putters.get().?.data;
165
166 self.buffer_nodes[self.buffer_index] = put_node.data;
167 self.loop.onNextTick(put_node.tick_node);
168 self.buffer_index +%= 1;
169 self.buffer_len += 1;
170
171 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
172 }
173 }
174
175 // undo the extra subtractions
176 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
177 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
178
179 // clear need-dispatch flag
180 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
181 if (need_dispatch != 0) continue;
182
183 const my_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
184 assert(my_lock != 0);
185
186 // we have to check again now that we unlocked
187 if (@atomicLoad(u8, &self.need_dispatch, AtomicOrder.SeqCst) != 0) continue :lock;
188
189 return;
190 }
191 }
192 }
193 };
194}
195
196test "std.event.Channel" {
197 var da = std.heap.DirectAllocator.init();
198 defer da.deinit();
199
200 const allocator = &da.allocator;
201
202 var loop: Loop = undefined;
203 // TODO make a multi threaded test
204 try loop.initSingleThreaded(allocator);
205 defer loop.deinit();
206
207 const channel = try Channel(i32).create(&loop, 0);
208 defer channel.destroy();
209
210 const handle = try async<allocator> testChannelGetter(&loop, channel);
211 defer cancel handle;
212
213 const putter = try async<allocator> testChannelPutter(channel);
214 defer cancel putter;
215
216 loop.run();
217}
218
219async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
220 errdefer @panic("test failed");
221
222 const value1_promise = try async channel.get();
223 const value1 = await value1_promise;
224 assert(value1 == 1234);
225
226 const value2_promise = try async channel.get();
227 const value2 = await value2_promise;
228 assert(value2 == 4567);
229}
230
231async fn testChannelPutter(channel: *Channel(i32)) void {
232 await (async channel.put(1234) catch @panic("out of memory"));
233 await (async channel.put(4567) catch @panic("out of memory"));
234}
235
std/event/future.zig created+130
......@@ -0,0 +1,130 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");
4const AtomicRmwOp = builtin.AtomicRmwOp;
5const AtomicOrder = builtin.AtomicOrder;
6const Lock = std.event.Lock;
7const Loop = std.event.Loop;
8
9/// This is a value that starts out unavailable, until resolve() is called
10/// While it is unavailable, coroutines suspend when they try to get() it,
11/// and then are resumed when resolve() is called.
12/// At this point the value remains forever available, and another resolve() is not allowed.
13pub fn Future(comptime T: type) type {
14 return struct {
15 lock: Lock,
16 data: T,
17
18 /// TODO make this an enum
19 /// 0 - not started
20 /// 1 - started
21 /// 2 - finished
22 available: u8,
23
24 const Self = this;
25 const Queue = std.atomic.Queue(promise);
26
27 pub fn init(loop: *Loop) Self {
28 return Self{
29 .lock = Lock.initLocked(loop),
30 .available = 0,
31 .data = undefined,
32 };
33 }
34
35 /// Obtain the value. If it's not available, wait until it becomes
36 /// available.
37 /// Thread-safe.
38 pub async fn get(self: *Self) *T {
39 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
40 return &self.data;
41 }
42 const held = await (async self.lock.acquire() catch unreachable);
43 held.release();
44
45 return &self.data;
46 }
47
48 /// Gets the data without waiting for it. If it's available, a pointer is
49 /// returned. Otherwise, null is returned.
50 pub fn getOrNull(self: *Self) ?*T {
51 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
52 return &self.data;
53 } else {
54 return null;
55 }
56 }
57
58 /// If someone else has started working on the data, wait for them to complete
59 /// and return a pointer to the data. Otherwise, return null, and the caller
60 /// should start working on the data.
61 /// It's not required to call start() before resolve() but it can be useful since
62 /// this method is thread-safe.
63 pub async fn start(self: *Self) ?*T {
64 const state = @cmpxchgStrong(u8, &self.available, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;
65 switch (state) {
66 1 => {
67 const held = await (async self.lock.acquire() catch unreachable);
68 held.release();
69 return &self.data;
70 },
71 2 => return &self.data,
72 else => unreachable,
73 }
74 }
75
76 /// Make the data become available. May be called only once.
77 /// Before calling this, modify the `data` property.
78 pub fn resolve(self: *Self) void {
79 const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);
80 assert(prev == 0 or prev == 1); // resolve() called twice
81 Lock.Held.release(Lock.Held{ .lock = &self.lock });
82 }
83 };
84}
85
86test "std.event.Future" {
87 var da = std.heap.DirectAllocator.init();
88 defer da.deinit();
89
90 const allocator = &da.allocator;
91
92 var loop: Loop = undefined;
93 try loop.initMultiThreaded(allocator);
94 defer loop.deinit();
95
96 const handle = try async<allocator> testFuture(&loop);
97 defer cancel handle;
98
99 loop.run();
100}
101
102async fn testFuture(loop: *Loop) void {
103 suspend {
104 resume @handle();
105 }
106 var future = Future(i32).init(loop);
107
108 const a = async waitOnFuture(&future) catch @panic("memory");
109 const b = async waitOnFuture(&future) catch @panic("memory");
110 const c = async resolveFuture(&future) catch @panic("memory");
111
112 const result = (await a) + (await b);
113 cancel c;
114 assert(result == 12);
115}
116
117async fn waitOnFuture(future: *Future(i32)) i32 {
118 suspend {
119 resume @handle();
120 }
121 return (await (async future.get() catch @panic("memory"))).*;
122}
123
124async fn resolveFuture(future: *Future(i32)) void {
125 suspend {
126 resume @handle();
127 }
128 future.data = 6;
129 future.resolve();
130}
std/event/group.zig created+170
......@@ -0,0 +1,170 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const Lock = std.event.Lock;
4const Loop = std.event.Loop;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const assert = std.debug.assert;
8
9/// ReturnType must be `void` or `E!void`
10pub fn Group(comptime ReturnType: type) type {
11 return struct {
12 coro_stack: Stack,
13 alloc_stack: Stack,
14 lock: Lock,
15
16 const Self = this;
17
18 const Error = switch (@typeInfo(ReturnType)) {
19 builtin.TypeId.ErrorUnion => |payload| payload.error_set,
20 else => void,
21 };
22 const Stack = std.atomic.Stack(promise->ReturnType);
23
24 pub fn init(loop: *Loop) Self {
25 return Self{
26 .coro_stack = Stack.init(),
27 .alloc_stack = Stack.init(),
28 .lock = Lock.init(loop),
29 };
30 }
31
32 /// Add a promise to the group. Thread-safe.
33 pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) {
34 const node = try self.lock.loop.allocator.create(Stack.Node{
35 .next = undefined,
36 .data = handle,
37 });
38 self.alloc_stack.push(node);
39 }
40
41 /// Add a node to the group. Thread-safe. Cannot fail.
42 /// `node.data` should be the promise handle to add to the group.
43 /// The node's memory should be in the coroutine frame of
44 /// the handle that is in the node, or somewhere guaranteed to live
45 /// at least as long.
46 pub fn addNode(self: *Self, node: *Stack.Node) void {
47 self.coro_stack.push(node);
48 }
49
50 /// This is equivalent to an async call, but the async function is added to the group, instead
51 /// of returning a promise. func must be async and have return type ReturnType.
52 /// Thread-safe.
53 pub fn call(self: *Self, comptime func: var, args: ...) (error{OutOfMemory}!void) {
54 const S = struct {
55 async fn asyncFunc(node: **Stack.Node, args2: ...) ReturnType {
56 // TODO this is a hack to make the memory following be inside the coro frame
57 suspend {
58 var my_node: Stack.Node = undefined;
59 node.* = &my_node;
60 resume @handle();
61 }
62
63 // TODO this allocation elision should be guaranteed because we await it in
64 // this coro frame
65 return await (async func(args2) catch unreachable);
66 }
67 };
68 var node: *Stack.Node = undefined;
69 const handle = try async<self.lock.loop.allocator> S.asyncFunc(&node, args);
70 node.* = Stack.Node{
71 .next = undefined,
72 .data = handle,
73 };
74 self.coro_stack.push(node);
75 }
76
77 /// Wait for all the calls and promises of the group to complete.
78 /// Thread-safe.
79 /// Safe to call any number of times.
80 pub async fn wait(self: *Self) ReturnType {
81 // TODO catch unreachable because the allocation can be grouped with
82 // the coro frame allocation
83 const held = await (async self.lock.acquire() catch unreachable);
84 defer held.release();
85
86 while (self.coro_stack.pop()) |node| {
87 if (Error == void) {
88 await node.data;
89 } else {
90 (await node.data) catch |err| {
91 self.cancelAll();
92 return err;
93 };
94 }
95 }
96 while (self.alloc_stack.pop()) |node| {
97 const handle = node.data;
98 self.lock.loop.allocator.destroy(node);
99 if (Error == void) {
100 await handle;
101 } else {
102 (await handle) catch |err| {
103 self.cancelAll();
104 return err;
105 };
106 }
107 }
108 }
109
110 /// Cancel all the outstanding promises. May only be called if wait was never called.
111 /// TODO These should be `cancelasync` not `cancel`.
112 /// See https://github.com/ziglang/zig/issues/1261
113 pub fn cancelAll(self: *Self) void {
114 while (self.coro_stack.pop()) |node| {
115 cancel node.data;
116 }
117 while (self.alloc_stack.pop()) |node| {
118 cancel node.data;
119 self.lock.loop.allocator.destroy(node);
120 }
121 }
122 };
123}
124
125test "std.event.Group" {
126 var da = std.heap.DirectAllocator.init();
127 defer da.deinit();
128
129 const allocator = &da.allocator;
130
131 var loop: Loop = undefined;
132 try loop.initMultiThreaded(allocator);
133 defer loop.deinit();
134
135 const handle = try async<allocator> testGroup(&loop);
136 defer cancel handle;
137
138 loop.run();
139}
140
141async fn testGroup(loop: *Loop) void {
142 var count: usize = 0;
143 var group = Group(void).init(loop);
144 group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory");
145 group.call(increaseByTen, &count) catch @panic("memory");
146 await (async group.wait() catch @panic("memory"));
147 assert(count == 11);
148
149 var another = Group(error!void).init(loop);
150 another.add(async somethingElse() catch @panic("memory")) catch @panic("memory");
151 another.call(doSomethingThatFails) catch @panic("memory");
152 std.debug.assertError(await (async another.wait() catch @panic("memory")), error.ItBroke);
153}
154
155async fn sleepALittle(count: *usize) void {
156 std.os.time.sleep(0, 1000000);
157 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
158}
159
160async fn increaseByTen(count: *usize) void {
161 var i: usize = 0;
162 while (i < 10) : (i += 1) {
163 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
164 }
165}
166
167async fn doSomethingThatFails() error!void {}
168async fn somethingElse() error!void {
169 return error.ItBroke;
170}
std/event/lock.zig created+190
......@@ -0,0 +1,190 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const mem = std.mem;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const Loop = std.event.Loop;
8
9/// Thread-safe async/await lock.
10/// Does not make any syscalls - coroutines which are waiting for the lock are suspended, and
11/// are resumed when the lock is released, in order.
12pub const Lock = struct {
13 loop: *Loop,
14 shared_bit: u8, // TODO make this a bool
15 queue: Queue,
16 queue_empty_bit: u8, // TODO make this a bool
17
18 const Queue = std.atomic.Queue(promise);
19
20 pub const Held = struct {
21 lock: *Lock,
22
23 pub fn release(self: Held) void {
24 // Resume the next item from the queue.
25 if (self.lock.queue.get()) |node| {
26 self.lock.loop.onNextTick(node);
27 return;
28 }
29
30 // We need to release the lock.
31 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
32 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
33
34 // There might be a queue item. If we know the queue is empty, we can be done,
35 // because the other actor will try to obtain the lock.
36 // But if there's a queue item, we are the actor which must loop and attempt
37 // to grab the lock again.
38 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
39 return;
40 }
41
42 while (true) {
43 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
44 if (old_bit != 0) {
45 // We did not obtain the lock. Great, the queue is someone else's problem.
46 return;
47 }
48
49 // Resume the next item from the queue.
50 if (self.lock.queue.get()) |node| {
51 self.lock.loop.onNextTick(node);
52 return;
53 }
54
55 // Release the lock again.
56 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
57 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
58
59 // Find out if we can be done.
60 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
61 return;
62 }
63 }
64 }
65 };
66
67 pub fn init(loop: *Loop) Lock {
68 return Lock{
69 .loop = loop,
70 .shared_bit = 0,
71 .queue = Queue.init(),
72 .queue_empty_bit = 1,
73 };
74 }
75
76 pub fn initLocked(loop: *Loop) Lock {
77 return Lock{
78 .loop = loop,
79 .shared_bit = 1,
80 .queue = Queue.init(),
81 .queue_empty_bit = 1,
82 };
83 }
84
85 /// Must be called when not locked. Not thread safe.
86 /// All calls to acquire() and release() must complete before calling deinit().
87 pub fn deinit(self: *Lock) void {
88 assert(self.shared_bit == 0);
89 while (self.queue.get()) |node| cancel node.data;
90 }
91
92 pub async fn acquire(self: *Lock) Held {
93 suspend {
94 // TODO explicitly put this memory in the coroutine frame #1194
95 var my_tick_node = Loop.NextTickNode{
96 .data = @handle(),
97 .next = undefined,
98 };
99
100 self.queue.put(&my_tick_node);
101
102 // At this point, we are in the queue, so we might have already been resumed and this coroutine
103 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
104
105 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
106 // will attempt to grab the lock.
107 _ = @atomicRmw(u8, &self.queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
108
109 const old_bit = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
110 if (old_bit == 0) {
111 if (self.queue.get()) |node| {
112 // Whether this node is us or someone else, we tail resume it.
113 resume node.data;
114 }
115 }
116 }
117
118 return Held{ .lock = self };
119 }
120};
121
122test "std.event.Lock" {
123 var da = std.heap.DirectAllocator.init();
124 defer da.deinit();
125
126 const allocator = &da.allocator;
127
128 var loop: Loop = undefined;
129 try loop.initMultiThreaded(allocator);
130 defer loop.deinit();
131
132 var lock = Lock.init(&loop);
133 defer lock.deinit();
134
135 const handle = try async<allocator> testLock(&loop, &lock);
136 defer cancel handle;
137 loop.run();
138
139 assert(mem.eql(i32, shared_test_data, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len));
140}
141
142async fn testLock(loop: *Loop, lock: *Lock) void {
143 // TODO explicitly put next tick node memory in the coroutine frame #1194
144 suspend {
145 resume @handle();
146 }
147 const handle1 = async lockRunner(lock) catch @panic("out of memory");
148 var tick_node1 = Loop.NextTickNode{
149 .next = undefined,
150 .data = handle1,
151 };
152 loop.onNextTick(&tick_node1);
153
154 const handle2 = async lockRunner(lock) catch @panic("out of memory");
155 var tick_node2 = Loop.NextTickNode{
156 .next = undefined,
157 .data = handle2,
158 };
159 loop.onNextTick(&tick_node2);
160
161 const handle3 = async lockRunner(lock) catch @panic("out of memory");
162 var tick_node3 = Loop.NextTickNode{
163 .next = undefined,
164 .data = handle3,
165 };
166 loop.onNextTick(&tick_node3);
167
168 await handle1;
169 await handle2;
170 await handle3;
171}
172
173var shared_test_data = [1]i32{0} ** 10;
174var shared_test_index: usize = 0;
175
176async fn lockRunner(lock: *Lock) void {
177 suspend; // resumed by onNextTick
178
179 var i: usize = 0;
180 while (i < shared_test_data.len) : (i += 1) {
181 const lock_promise = async lock.acquire() catch @panic("out of memory");
182 const handle = await lock_promise;
183 defer handle.release();
184
185 shared_test_index = 0;
186 while (shared_test_index < shared_test_data.len) : (shared_test_index += 1) {
187 shared_test_data[shared_test_index] = shared_test_data[shared_test_index] + 1;
188 }
189 }
190}
std/event/locked.zig created+43
......@@ -0,0 +1,43 @@
1const std = @import("../index.zig");
2const Lock = std.event.Lock;
3const Loop = std.event.Loop;
4
5/// Thread-safe async/await lock that protects one piece of data.
6/// Does not make any syscalls - coroutines which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.
8pub fn Locked(comptime T: type) type {
9 return struct {
10 lock: Lock,
11 private_data: T,
12
13 const Self = this;
14
15 pub const HeldLock = struct {
16 value: *T,
17 held: Lock.Held,
18
19 pub fn release(self: HeldLock) void {
20 self.held.release();
21 }
22 };
23
24 pub fn init(loop: *Loop, data: T) Self {
25 return Self{
26 .lock = Lock.init(loop),
27 .private_data = data,
28 };
29 }
30
31 pub fn deinit(self: *Self) void {
32 self.lock.deinit();
33 }
34
35 pub async fn acquire(self: *Self) HeldLock {
36 return HeldLock{
37 // TODO guaranteed allocation elision
38 .held = await (async self.lock.acquire() catch unreachable),
39 .value = &self.private_data,
40 };
41 }
42 };
43}
std/event/loop.zig created+634
......@@ -0,0 +1,634 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const mem = std.mem;
5const posix = std.os.posix;
6const windows = std.os.windows;
7const AtomicRmwOp = builtin.AtomicRmwOp;
8const AtomicOrder = builtin.AtomicOrder;
9
10pub const Loop = struct {
11 allocator: *mem.Allocator,
12 next_tick_queue: std.atomic.Queue(promise),
13 os_data: OsData,
14 final_resume_node: ResumeNode,
15 pending_event_count: usize,
16 extra_threads: []*std.os.Thread,
17
18 // pre-allocated eventfds. all permanently active.
19 // this is how we send promises to be resumed on other threads.
20 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),
21 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,
22
23 pub const NextTickNode = std.atomic.Queue(promise).Node;
24
25 pub const ResumeNode = struct {
26 id: Id,
27 handle: promise,
28
29 pub const Id = enum {
30 Basic,
31 Stop,
32 EventFd,
33 };
34
35 pub const EventFd = switch (builtin.os) {
36 builtin.Os.macosx => MacOsEventFd,
37 builtin.Os.linux => struct {
38 base: ResumeNode,
39 epoll_op: u32,
40 eventfd: i32,
41 },
42 builtin.Os.windows => struct {
43 base: ResumeNode,
44 completion_key: usize,
45 },
46 else => @compileError("unsupported OS"),
47 };
48
49 const MacOsEventFd = struct {
50 base: ResumeNode,
51 kevent: posix.Kevent,
52 };
53 };
54
55 /// After initialization, call run().
56 /// TODO copy elision / named return values so that the threads referencing *Loop
57 /// have the correct pointer value.
58 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {
59 return self.initInternal(allocator, 1);
60 }
61
62 /// The allocator must be thread-safe because we use it for multiplexing
63 /// coroutines onto kernel threads.
64 /// After initialization, call run().
65 /// TODO copy elision / named return values so that the threads referencing *Loop
66 /// have the correct pointer value.
67 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
68 const core_count = try std.os.cpuCount(allocator);
69 return self.initInternal(allocator, core_count);
70 }
71
72 /// Thread count is the total thread count. The thread pool size will be
73 /// max(thread_count - 1, 0)
74 fn initInternal(self: *Loop, allocator: *mem.Allocator, thread_count: usize) !void {
75 self.* = Loop{
76 .pending_event_count = 1,
77 .allocator = allocator,
78 .os_data = undefined,
79 .next_tick_queue = std.atomic.Queue(promise).init(),
80 .extra_threads = undefined,
81 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),
82 .eventfd_resume_nodes = undefined,
83 .final_resume_node = ResumeNode{
84 .id = ResumeNode.Id.Stop,
85 .handle = undefined,
86 },
87 };
88 const extra_thread_count = thread_count - 1;
89 self.eventfd_resume_nodes = try self.allocator.alloc(
90 std.atomic.Stack(ResumeNode.EventFd).Node,
91 extra_thread_count,
92 );
93 errdefer self.allocator.free(self.eventfd_resume_nodes);
94
95 self.extra_threads = try self.allocator.alloc(*std.os.Thread, extra_thread_count);
96 errdefer self.allocator.free(self.extra_threads);
97
98 try self.initOsData(extra_thread_count);
99 errdefer self.deinitOsData();
100 }
101
102 pub fn deinit(self: *Loop) void {
103 self.deinitOsData();
104 self.allocator.free(self.extra_threads);
105 }
106
107 const InitOsDataError = std.os.LinuxEpollCreateError || mem.Allocator.Error || std.os.LinuxEventFdError ||
108 std.os.SpawnThreadError || std.os.LinuxEpollCtlError || std.os.BsdKEventError ||
109 std.os.WindowsCreateIoCompletionPortError;
110
111 const wakeup_bytes = []u8{0x1} ** 8;
112
113 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
114 switch (builtin.os) {
115 builtin.Os.linux => {
116 errdefer {
117 while (self.available_eventfd_resume_nodes.pop()) |node| std.os.close(node.data.eventfd);
118 }
119 for (self.eventfd_resume_nodes) |*eventfd_node| {
120 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
121 .data = ResumeNode.EventFd{
122 .base = ResumeNode{
123 .id = ResumeNode.Id.EventFd,
124 .handle = undefined,
125 },
126 .eventfd = try std.os.linuxEventFd(1, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK),
127 .epoll_op = posix.EPOLL_CTL_ADD,
128 },
129 .next = undefined,
130 };
131 self.available_eventfd_resume_nodes.push(eventfd_node);
132 }
133
134 self.os_data.epollfd = try std.os.linuxEpollCreate(posix.EPOLL_CLOEXEC);
135 errdefer std.os.close(self.os_data.epollfd);
136
137 self.os_data.final_eventfd = try std.os.linuxEventFd(0, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK);
138 errdefer std.os.close(self.os_data.final_eventfd);
139
140 self.os_data.final_eventfd_event = posix.epoll_event{
141 .events = posix.EPOLLIN,
142 .data = posix.epoll_data{ .ptr = @ptrToInt(&self.final_resume_node) },
143 };
144 try std.os.linuxEpollCtl(
145 self.os_data.epollfd,
146 posix.EPOLL_CTL_ADD,
147 self.os_data.final_eventfd,
148 &self.os_data.final_eventfd_event,
149 );
150
151 var extra_thread_index: usize = 0;
152 errdefer {
153 // writing 8 bytes to an eventfd cannot fail
154 std.os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
155 while (extra_thread_index != 0) {
156 extra_thread_index -= 1;
157 self.extra_threads[extra_thread_index].wait();
158 }
159 }
160 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
161 self.extra_threads[extra_thread_index] = try std.os.spawnThread(self, workerRun);
162 }
163 },
164 builtin.Os.macosx => {
165 self.os_data.kqfd = try std.os.bsdKQueue();
166 errdefer std.os.close(self.os_data.kqfd);
167
168 self.os_data.kevents = try self.allocator.alloc(posix.Kevent, extra_thread_count);
169 errdefer self.allocator.free(self.os_data.kevents);
170
171 const eventlist = ([*]posix.Kevent)(undefined)[0..0];
172
173 for (self.eventfd_resume_nodes) |*eventfd_node, i| {
174 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
175 .data = ResumeNode.EventFd{
176 .base = ResumeNode{
177 .id = ResumeNode.Id.EventFd,
178 .handle = undefined,
179 },
180 // this one is for sending events
181 .kevent = posix.Kevent{
182 .ident = i,
183 .filter = posix.EVFILT_USER,
184 .flags = posix.EV_CLEAR | posix.EV_ADD | posix.EV_DISABLE,
185 .fflags = 0,
186 .data = 0,
187 .udata = @ptrToInt(&eventfd_node.data.base),
188 },
189 },
190 .next = undefined,
191 };
192 self.available_eventfd_resume_nodes.push(eventfd_node);
193 const kevent_array = (*[1]posix.Kevent)(&eventfd_node.data.kevent);
194 _ = try std.os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null);
195 eventfd_node.data.kevent.flags = posix.EV_CLEAR | posix.EV_ENABLE;
196 eventfd_node.data.kevent.fflags = posix.NOTE_TRIGGER;
197 // this one is for waiting for events
198 self.os_data.kevents[i] = posix.Kevent{
199 .ident = i,
200 .filter = posix.EVFILT_USER,
201 .flags = 0,
202 .fflags = 0,
203 .data = 0,
204 .udata = @ptrToInt(&eventfd_node.data.base),
205 };
206 }
207
208 // Pre-add so that we cannot get error.SystemResources
209 // later when we try to activate it.
210 self.os_data.final_kevent = posix.Kevent{
211 .ident = extra_thread_count,
212 .filter = posix.EVFILT_USER,
213 .flags = posix.EV_ADD | posix.EV_DISABLE,
214 .fflags = 0,
215 .data = 0,
216 .udata = @ptrToInt(&self.final_resume_node),
217 };
218 const kevent_array = (*[1]posix.Kevent)(&self.os_data.final_kevent);
219 _ = try std.os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null);
220 self.os_data.final_kevent.flags = posix.EV_ENABLE;
221 self.os_data.final_kevent.fflags = posix.NOTE_TRIGGER;
222
223 var extra_thread_index: usize = 0;
224 errdefer {
225 _ = std.os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null) catch unreachable;
226 while (extra_thread_index != 0) {
227 extra_thread_index -= 1;
228 self.extra_threads[extra_thread_index].wait();
229 }
230 }
231 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
232 self.extra_threads[extra_thread_index] = try std.os.spawnThread(self, workerRun);
233 }
234 },
235 builtin.Os.windows => {
236 self.os_data.io_port = try std.os.windowsCreateIoCompletionPort(
237 windows.INVALID_HANDLE_VALUE,
238 null,
239 undefined,
240 undefined,
241 );
242 errdefer std.os.close(self.os_data.io_port);
243
244 for (self.eventfd_resume_nodes) |*eventfd_node, i| {
245 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
246 .data = ResumeNode.EventFd{
247 .base = ResumeNode{
248 .id = ResumeNode.Id.EventFd,
249 .handle = undefined,
250 },
251 // this one is for sending events
252 .completion_key = @ptrToInt(&eventfd_node.data.base),
253 },
254 .next = undefined,
255 };
256 self.available_eventfd_resume_nodes.push(eventfd_node);
257 }
258
259 var extra_thread_index: usize = 0;
260 errdefer {
261 var i: usize = 0;
262 while (i < extra_thread_index) : (i += 1) {
263 while (true) {
264 const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
265 std.os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;
266 break;
267 }
268 }
269 while (extra_thread_index != 0) {
270 extra_thread_index -= 1;
271 self.extra_threads[extra_thread_index].wait();
272 }
273 }
274 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
275 self.extra_threads[extra_thread_index] = try std.os.spawnThread(self, workerRun);
276 }
277 },
278 else => {},
279 }
280 }
281
282 fn deinitOsData(self: *Loop) void {
283 switch (builtin.os) {
284 builtin.Os.linux => {
285 std.os.close(self.os_data.final_eventfd);
286 while (self.available_eventfd_resume_nodes.pop()) |node| std.os.close(node.data.eventfd);
287 std.os.close(self.os_data.epollfd);
288 self.allocator.free(self.eventfd_resume_nodes);
289 },
290 builtin.Os.macosx => {
291 self.allocator.free(self.os_data.kevents);
292 std.os.close(self.os_data.kqfd);
293 },
294 builtin.Os.windows => {
295 std.os.close(self.os_data.io_port);
296 },
297 else => {},
298 }
299 }
300
301 /// resume_node must live longer than the promise that it holds a reference to.
302 pub fn addFd(self: *Loop, fd: i32, resume_node: *ResumeNode) !void {
303 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
304 errdefer {
305 self.finishOneEvent();
306 }
307 try self.modFd(
308 fd,
309 posix.EPOLL_CTL_ADD,
310 std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,
311 resume_node,
312 );
313 }
314
315 pub fn modFd(self: *Loop, fd: i32, op: u32, events: u32, resume_node: *ResumeNode) !void {
316 var ev = std.os.linux.epoll_event{
317 .events = events,
318 .data = std.os.linux.epoll_data{ .ptr = @ptrToInt(resume_node) },
319 };
320 try std.os.linuxEpollCtl(self.os_data.epollfd, op, fd, &ev);
321 }
322
323 pub fn removeFd(self: *Loop, fd: i32) void {
324 self.removeFdNoCounter(fd);
325 self.finishOneEvent();
326 }
327
328 fn removeFdNoCounter(self: *Loop, fd: i32) void {
329 std.os.linuxEpollCtl(self.os_data.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
330 }
331
332 pub async fn waitFd(self: *Loop, fd: i32) !void {
333 defer self.removeFd(fd);
334 suspend {
335 // TODO explicitly put this memory in the coroutine frame #1194
336 var resume_node = ResumeNode{
337 .id = ResumeNode.Id.Basic,
338 .handle = @handle(),
339 };
340 try self.addFd(fd, &resume_node);
341 }
342 }
343
344 fn dispatch(self: *Loop) void {
345 while (self.available_eventfd_resume_nodes.pop()) |resume_stack_node| {
346 const next_tick_node = self.next_tick_queue.get() orelse {
347 self.available_eventfd_resume_nodes.push(resume_stack_node);
348 return;
349 };
350 const eventfd_node = &resume_stack_node.data;
351 eventfd_node.base.handle = next_tick_node.data;
352 switch (builtin.os) {
353 builtin.Os.macosx => {
354 const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent);
355 const eventlist = ([*]posix.Kevent)(undefined)[0..0];
356 _ = std.os.bsdKEvent(self.os_data.kqfd, kevent_array, eventlist, null) catch {
357 self.next_tick_queue.unget(next_tick_node);
358 self.available_eventfd_resume_nodes.push(resume_stack_node);
359 return;
360 };
361 },
362 builtin.Os.linux => {
363 // the pending count is already accounted for
364 const epoll_events = posix.EPOLLONESHOT | std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT |
365 std.os.linux.EPOLLET;
366 self.modFd(
367 eventfd_node.eventfd,
368 eventfd_node.epoll_op,
369 epoll_events,
370 &eventfd_node.base,
371 ) catch {
372 self.next_tick_queue.unget(next_tick_node);
373 self.available_eventfd_resume_nodes.push(resume_stack_node);
374 return;
375 };
376 },
377 builtin.Os.windows => {
378 // this value is never dereferenced but we need it to be non-null so that
379 // the consumer code can decide whether to read the completion key.
380 // it has to do this for normal I/O, so we match that behavior here.
381 const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
382 std.os.windowsPostQueuedCompletionStatus(
383 self.os_data.io_port,
384 undefined,
385 eventfd_node.completion_key,
386 overlapped,
387 ) catch {
388 self.next_tick_queue.unget(next_tick_node);
389 self.available_eventfd_resume_nodes.push(resume_stack_node);
390 return;
391 };
392 },
393 else => @compileError("unsupported OS"),
394 }
395 }
396 }
397
398 /// Bring your own linked list node. This means it can't fail.
399 pub fn onNextTick(self: *Loop, node: *NextTickNode) void {
400 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
401 self.next_tick_queue.put(node);
402 self.dispatch();
403 }
404
405 pub fn run(self: *Loop) void {
406 self.finishOneEvent(); // the reference we start with
407
408 self.workerRun();
409 for (self.extra_threads) |extra_thread| {
410 extra_thread.wait();
411 }
412 }
413
414 /// This is equivalent to an async call, except instead of beginning execution of the async function,
415 /// it immediately returns to the caller, and the async function is queued in the event loop. It still
416 /// returns a promise to be awaited.
417 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {
418 const S = struct {
419 async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
420 suspend {
421 handle.* = @handle();
422 var my_tick_node = Loop.NextTickNode{
423 .next = undefined,
424 .data = @handle(),
425 };
426 loop.onNextTick(&my_tick_node);
427 }
428 // TODO guaranteed allocation elision for await in same func as async
429 return await (async func(args2) catch unreachable);
430 }
431 };
432 var handle: promise->@typeOf(func).ReturnType = undefined;
433 return async<self.allocator> S.asyncFunc(self, &handle, args);
434 }
435
436 /// Awaiting a yield lets the event loop run, starting any unstarted async operations.
437 /// Note that async operations automatically start when a function yields for any other reason,
438 /// for example, when async I/O is performed. This function is intended to be used only when
439 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
440 /// is performed.
441 pub async fn yield(self: *Loop) void {
442 suspend {
443 var my_tick_node = Loop.NextTickNode{
444 .next = undefined,
445 .data = @handle(),
446 };
447 self.onNextTick(&my_tick_node);
448 }
449 }
450
451 fn finishOneEvent(self: *Loop) void {
452 if (@atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst) == 1) {
453 // cause all the threads to stop
454 switch (builtin.os) {
455 builtin.Os.linux => {
456 // writing 8 bytes to an eventfd cannot fail
457 std.os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
458 return;
459 },
460 builtin.Os.macosx => {
461 const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent);
462 const eventlist = ([*]posix.Kevent)(undefined)[0..0];
463 // cannot fail because we already added it and this just enables it
464 _ = std.os.bsdKEvent(self.os_data.kqfd, final_kevent, eventlist, null) catch unreachable;
465 return;
466 },
467 builtin.Os.windows => {
468 var i: usize = 0;
469 while (i < self.extra_threads.len + 1) : (i += 1) {
470 while (true) {
471 const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
472 std.os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;
473 break;
474 }
475 }
476 return;
477 },
478 else => @compileError("unsupported OS"),
479 }
480 }
481 }
482
483 fn workerRun(self: *Loop) void {
484 while (true) {
485 while (true) {
486 const next_tick_node = self.next_tick_queue.get() orelse break;
487 self.dispatch();
488 resume next_tick_node.data;
489 self.finishOneEvent();
490 }
491
492 switch (builtin.os) {
493 builtin.Os.linux => {
494 // only process 1 event so we don't steal from other threads
495 var events: [1]std.os.linux.epoll_event = undefined;
496 const count = std.os.linuxEpollWait(self.os_data.epollfd, events[0..], -1);
497 for (events[0..count]) |ev| {
498 const resume_node = @intToPtr(*ResumeNode, ev.data.ptr);
499 const handle = resume_node.handle;
500 const resume_node_id = resume_node.id;
501 switch (resume_node_id) {
502 ResumeNode.Id.Basic => {},
503 ResumeNode.Id.Stop => return,
504 ResumeNode.Id.EventFd => {
505 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
506 event_fd_node.epoll_op = posix.EPOLL_CTL_MOD;
507 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
508 self.available_eventfd_resume_nodes.push(stack_node);
509 },
510 }
511 resume handle;
512 if (resume_node_id == ResumeNode.Id.EventFd) {
513 self.finishOneEvent();
514 }
515 }
516 },
517 builtin.Os.macosx => {
518 var eventlist: [1]posix.Kevent = undefined;
519 const count = std.os.bsdKEvent(self.os_data.kqfd, self.os_data.kevents, eventlist[0..], null) catch unreachable;
520 for (eventlist[0..count]) |ev| {
521 const resume_node = @intToPtr(*ResumeNode, ev.udata);
522 const handle = resume_node.handle;
523 const resume_node_id = resume_node.id;
524 switch (resume_node_id) {
525 ResumeNode.Id.Basic => {},
526 ResumeNode.Id.Stop => return,
527 ResumeNode.Id.EventFd => {
528 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
529 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
530 self.available_eventfd_resume_nodes.push(stack_node);
531 },
532 }
533 resume handle;
534 if (resume_node_id == ResumeNode.Id.EventFd) {
535 self.finishOneEvent();
536 }
537 }
538 },
539 builtin.Os.windows => {
540 var completion_key: usize = undefined;
541 while (true) {
542 var nbytes: windows.DWORD = undefined;
543 var overlapped: ?*windows.OVERLAPPED = undefined;
544 switch (std.os.windowsGetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
545 std.os.WindowsWaitResult.Aborted => return,
546 std.os.WindowsWaitResult.Normal => {},
547 }
548 if (overlapped != null) break;
549 }
550 const resume_node = @intToPtr(*ResumeNode, completion_key);
551 const handle = resume_node.handle;
552 const resume_node_id = resume_node.id;
553 switch (resume_node_id) {
554 ResumeNode.Id.Basic => {},
555 ResumeNode.Id.Stop => return,
556 ResumeNode.Id.EventFd => {
557 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
558 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
559 self.available_eventfd_resume_nodes.push(stack_node);
560 },
561 }
562 resume handle;
563 if (resume_node_id == ResumeNode.Id.EventFd) {
564 self.finishOneEvent();
565 }
566 },
567 else => @compileError("unsupported OS"),
568 }
569 }
570 }
571
572 const OsData = switch (builtin.os) {
573 builtin.Os.linux => struct {
574 epollfd: i32,
575 final_eventfd: i32,
576 final_eventfd_event: std.os.linux.epoll_event,
577 },
578 builtin.Os.macosx => MacOsData,
579 builtin.Os.windows => struct {
580 io_port: windows.HANDLE,
581 extra_thread_count: usize,
582 },
583 else => struct {},
584 };
585
586 const MacOsData = struct {
587 kqfd: i32,
588 final_kevent: posix.Kevent,
589 kevents: []posix.Kevent,
590 };
591};
592
593test "std.event.Loop - basic" {
594 var da = std.heap.DirectAllocator.init();
595 defer da.deinit();
596
597 const allocator = &da.allocator;
598
599 var loop: Loop = undefined;
600 try loop.initMultiThreaded(allocator);
601 defer loop.deinit();
602
603 loop.run();
604}
605
606test "std.event.Loop - call" {
607 var da = std.heap.DirectAllocator.init();
608 defer da.deinit();
609
610 const allocator = &da.allocator;
611
612 var loop: Loop = undefined;
613 try loop.initMultiThreaded(allocator);
614 defer loop.deinit();
615
616 var did_it = false;
617 const handle = try loop.call(testEventLoop);
618 const handle2 = try loop.call(testEventLoop2, handle, &did_it);
619 defer cancel handle2;
620
621 loop.run();
622
623 assert(did_it);
624}
625
626async fn testEventLoop() i32 {
627 return 1234;
628}
629
630async fn testEventLoop2(h: promise->i32, did_it: *bool) void {
631 const value = await h;
632 assert(value == 1234);
633 did_it.* = true;
634}
std/event/tcp.zig created+184
......@@ -0,0 +1,184 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const event = std.event;
5const mem = std.mem;
6const posix = std.os.posix;
7const windows = std.os.windows;
8const Loop = std.event.Loop;
9
10pub const Server = struct {
11 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, *const std.os.File) void,
12
13 loop: *Loop,
14 sockfd: ?i32,
15 accept_coro: ?promise,
16 listen_address: std.net.Address,
17
18 waiting_for_emfile_node: PromiseNode,
19 listen_resume_node: event.Loop.ResumeNode,
20
21 const PromiseNode = std.LinkedList(promise).Node;
22
23 pub fn init(loop: *Loop) Server {
24 // TODO can't initialize handler coroutine here because we need well defined copy elision
25 return Server{
26 .loop = loop,
27 .sockfd = null,
28 .accept_coro = null,
29 .handleRequestFn = undefined,
30 .waiting_for_emfile_node = undefined,
31 .listen_address = undefined,
32 .listen_resume_node = event.Loop.ResumeNode{
33 .id = event.Loop.ResumeNode.Id.Basic,
34 .handle = undefined,
35 },
36 };
37 }
38
39 pub fn listen(
40 self: *Server,
41 address: *const std.net.Address,
42 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, *const std.os.File) void,
43 ) !void {
44 self.handleRequestFn = handleRequestFn;
45
46 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
47 errdefer std.os.close(sockfd);
48 self.sockfd = sockfd;
49
50 try std.os.posixBind(sockfd, &address.os_addr);
51 try std.os.posixListen(sockfd, posix.SOMAXCONN);
52 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(sockfd));
53
54 self.accept_coro = try async<self.loop.allocator> Server.handler(self);
55 errdefer cancel self.accept_coro.?;
56
57 self.listen_resume_node.handle = self.accept_coro.?;
58 try self.loop.addFd(sockfd, &self.listen_resume_node);
59 errdefer self.loop.removeFd(sockfd);
60 }
61
62 /// Stop listening
63 pub fn close(self: *Server) void {
64 self.loop.removeFd(self.sockfd.?);
65 std.os.close(self.sockfd.?);
66 }
67
68 pub fn deinit(self: *Server) void {
69 if (self.accept_coro) |accept_coro| cancel accept_coro;
70 if (self.sockfd) |sockfd| std.os.close(sockfd);
71 }
72
73 pub async fn handler(self: *Server) void {
74 while (true) {
75 var accepted_addr: std.net.Address = undefined;
76 if (std.os.posixAccept(self.sockfd.?, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {
77 var socket = std.os.File.openHandle(accepted_fd);
78 _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
79 error.OutOfMemory => {
80 socket.close();
81 continue;
82 },
83 };
84 } else |err| switch (err) {
85 error.WouldBlock => {
86 suspend; // we will get resumed by epoll_wait in the event loop
87 continue;
88 },
89 error.ProcessFdQuotaExceeded => {
90 errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
91 suspend {
92 self.waiting_for_emfile_node = PromiseNode.init( @handle() );
93 std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
94 }
95 continue;
96 },
97 error.ConnectionAborted, error.FileDescriptorClosed => continue,
98
99 error.PageFault => unreachable,
100 error.InvalidSyscall => unreachable,
101 error.FileDescriptorNotASocket => unreachable,
102 error.OperationNotSupported => unreachable,
103
104 error.SystemFdQuotaExceeded, error.SystemResources, error.ProtocolFailure, error.BlockedByFirewall, error.Unexpected => {
105 @panic("TODO handle this error");
106 },
107 }
108 }
109 }
110};
111
112pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {
113 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733
114
115 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
116 errdefer std.os.close(sockfd);
117
118 try std.os.posixConnectAsync(sockfd, &address.os_addr);
119 try await try async loop.waitFd(sockfd);
120 try std.os.posixGetSockOptConnectError(sockfd);
121
122 return std.os.File.openHandle(sockfd);
123}
124
125test "listen on a port, send bytes, receive bytes" {
126 if (builtin.os != builtin.Os.linux) {
127 // TODO build abstractions for other operating systems
128 return error.SkipZigTest;
129 }
130
131 const MyServer = struct {
132 tcp_server: Server,
133
134 const Self = this;
135 async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: *const std.os.File) void {
136 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
137 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
138 defer socket.close();
139 // TODO guarantee elision of this allocation
140 const next_handler = async errorableHandler(self, _addr, socket) catch unreachable;
141 (await next_handler) catch |err| {
142 std.debug.panic("unable to handle connection: {}\n", err);
143 };
144 suspend {
145 cancel @handle();
146 }
147 }
148 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: *const std.os.File) !void {
149 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
150 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
151
152 var adapter = std.io.FileOutStream.init(&socket);
153 var stream = &adapter.stream;
154 try stream.print("hello from server\n");
155 }
156 };
157
158 const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable;
159 const addr = std.net.Address.initIp4(ip4addr, 0);
160
161 var loop: Loop = undefined;
162 try loop.initSingleThreaded(std.debug.global_allocator);
163 var server = MyServer{ .tcp_server = Server.init(&loop) };
164 defer server.tcp_server.deinit();
165 try server.tcp_server.listen(addr, MyServer.handler);
166
167 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address, &server.tcp_server);
168 defer cancel p;
169 loop.run();
170}
171
172async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {
173 errdefer @panic("test failure");
174
175 var socket_file = try await try async connect(loop, address);
176 defer socket_file.close();
177
178 var buf: [512]u8 = undefined;
179 const amt_read = try socket_file.read(buf[0..]);
180 const msg = buf[0..amt_read];
181 assert(mem.eql(u8, msg, "hello from server\n"));
182 server.close();
183}
184
std/fmt/errol/enum3.zig+3-4
......@@ -1,4 +1,4 @@
1pub const enum3 = []u64 {
1pub const enum3 = []u64{
22 0x4e2e2785c3a2a20b,
33 0x240a28877a09a4e1,
44 0x728fca36c06cf106,
......@@ -439,13 +439,13 @@ const Slab = struct {
439439};
440440
441441fn slab(str: []const u8, exp: i32) Slab {
442 return Slab {
442 return Slab{
443443 .str = str,
444444 .exp = exp,
445445 };
446446}
447447
448pub const enum3_data = []Slab {
448pub const enum3_data = []Slab{
449449 slab("40648030339495312", 69),
450450 slab("4498645355592131", -134),
451451 slab("678321594594593", 244),
......@@ -879,4 +879,3 @@ pub const enum3_data = []Slab {
879879 slab("32216657306260762", 218),
880880 slab("30423431424080128", 219),
881881};
882
std/fmt/errol/index.zig+139-77
......@@ -12,15 +12,81 @@ pub const FloatDecimal = struct {
1212 exp: i32,
1313};
1414
15pub const RoundMode = enum {
16 // Round only the fractional portion (e.g. 1234.23 has precision 2)
17 Decimal,
18 // Round the entire whole/fractional portion (e.g. 1.23423e3 has precision 5)
19 Scientific,
20};
21
22/// Round a FloatDecimal as returned by errol3 to the specified fractional precision.
23/// All digits after the specified precision should be considered invalid.
24pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: RoundMode) void {
25 // The round digit refers to the index which we should look at to determine
26 // whether we need to round to match the specified precision.
27 var round_digit: usize = 0;
28
29 switch (mode) {
30 RoundMode.Decimal => {
31 if (float_decimal.exp >= 0) {
32 round_digit = precision + @intCast(usize, float_decimal.exp);
33 } else {
34 // if a small negative exp, then adjust we need to offset by the number
35 // of leading zeros that will occur.
36 const min_exp_required = @intCast(usize, -float_decimal.exp);
37 if (precision > min_exp_required) {
38 round_digit = precision - min_exp_required;
39 }
40 }
41 },
42 RoundMode.Scientific => {
43 round_digit = 1 + precision;
44 },
45 }
46
47 // It suffices to look at just this digit. We don't round and propagate say 0.04999 to 0.05
48 // first, and then to 0.1 in the case of a {.1} single precision.
49
50 // Find the digit which will signify the round point and start rounding backwards.
51 if (round_digit < float_decimal.digits.len and float_decimal.digits[round_digit] - '0' >= 5) {
52 assert(round_digit >= 0);
53
54 var i = round_digit;
55 while (true) {
56 if (i == 0) {
57 // Rounded all the way past the start. This was of the form 9.999...
58 // Slot the new digit in place and increase the exponent.
59 float_decimal.exp += 1;
60
61 // Re-size the buffer to use the reserved leading byte.
62 const one_before = @intToPtr([*]u8, @ptrToInt(&float_decimal.digits[0]) - 1);
63 float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
64 float_decimal.digits[0] = '1';
65 return;
66 }
67
68 i -= 1;
69
70 const new_value = (float_decimal.digits[i] - '0' + 1) % 10;
71 float_decimal.digits[i] = new_value + '0';
72
73 // must continue rounding until non-9
74 if (new_value != 0) {
75 return;
76 }
77 }
78 }
79}
80
1581/// Corrected Errol3 double to ASCII conversion.
1682pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
1783 const bits = @bitCast(u64, value);
1884 const i = tableLowerBound(bits);
1985 if (i < enum3.len and enum3[i] == bits) {
2086 const data = enum3_data[i];
21 const digits = buffer[0..data.str.len];
87 const digits = buffer[1 .. data.str.len + 1];
2288 mem.copy(u8, digits, data.str);
23 return FloatDecimal {
89 return FloatDecimal{
2490 .digits = digits,
2591 .exp = data.exp,
2692 };
......@@ -32,27 +98,25 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
3298/// Uncorrected Errol3 double to ASCII conversion.
3399fn errol3u(val: f64, buffer: []u8) FloatDecimal {
34100 // check if in integer or fixed range
35
36101 if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
37102 return errolInt(val, buffer);
38103 } else if (val >= 16.0 and val < 9.007199254740992e15) {
39104 return errolFixed(val, buffer);
40105 }
41106
42
43107 // normalize the midpoint
44108
45109 const e = math.frexp(val).exponent;
46 var exp = i16(math.floor(307 + f64(e) * 0.30103));
110 var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103));
47111 if (exp < 20) {
48112 exp = 20;
49 } else if (usize(exp) >= lookup_table.len) {
50 exp = i16(lookup_table.len - 1);
113 } else if (@intCast(usize, exp) >= lookup_table.len) {
114 exp = @intCast(i16, lookup_table.len - 1);
51115 }
52116
53 var mid = lookup_table[usize(exp)];
117 var mid = lookup_table[@intCast(usize, exp)];
54118 mid = hpProd(mid, val);
55 const lten = lookup_table[usize(exp)].val;
119 const lten = lookup_table[@intCast(usize, exp)].val;
56120
57121 exp -= 307;
58122
......@@ -71,11 +135,11 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
71135 }
72136
73137 // compute boundaries
74 var high = HP {
138 var high = HP{
75139 .val = mid.val,
76140 .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
77141 };
78 var low = HP {
142 var low = HP{
79143 .val = mid.val,
80144 .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
81145 };
......@@ -98,37 +162,37 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
98162 }
99163
100164 // digit generation
101 var buf_index: usize = 0;
165
166 // We generate digits starting at index 1. If rounding a buffer later then it may be
167 // required to generate a preceeding digit in some cases (9.999) in which case we use
168 // the 0-index for this extra digit.
169 var buf_index: usize = 1;
102170 while (true) {
103 var hdig = u8(math.floor(high.val));
104 if ((high.val == f64(hdig)) and (high.off < 0))
105 hdig -= 1;
171 var hdig = @floatToInt(u8, math.floor(high.val));
172 if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1;
106173
107 var ldig = u8(math.floor(low.val));
108 if ((low.val == f64(ldig)) and (low.off < 0))
109 ldig -= 1;
174 var ldig = @floatToInt(u8, math.floor(low.val));
175 if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1;
110176
111 if (ldig != hdig)
112 break;
177 if (ldig != hdig) break;
113178
114179 buffer[buf_index] = hdig + '0';
115180 buf_index += 1;
116 high.val -= f64(hdig);
117 low.val -= f64(ldig);
181 high.val -= @intToFloat(f64, hdig);
182 low.val -= @intToFloat(f64, ldig);
118183 hpMul10(&high);
119184 hpMul10(&low);
120185 }
121186
122187 const tmp = (high.val + low.val) / 2.0;
123 var mdig = u8(math.floor(tmp + 0.5));
124 if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0)
125 mdig -= 1;
188 var mdig = @floatToInt(u8, math.floor(tmp + 0.5));
189 if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
126190
127191 buffer[buf_index] = mdig + '0';
128192 buf_index += 1;
129193
130 return FloatDecimal {
131 .digits = buffer[0..buf_index],
194 return FloatDecimal{
195 .digits = buffer[1..buf_index],
132196 .exp = exp,
133197 };
134198}
......@@ -153,7 +217,7 @@ fn tableLowerBound(k: u64) usize {
153217/// @in: The HP number.
154218/// @val: The double.
155219/// &returns: The HP number.
156fn hpProd(in: &const HP, val: f64) HP {
220fn hpProd(in: *const HP, val: f64) HP {
157221 var hi: f64 = undefined;
158222 var lo: f64 = undefined;
159223 split(in.val, &hi, &lo);
......@@ -165,7 +229,7 @@ fn hpProd(in: &const HP, val: f64) HP {
165229 const p = in.val * val;
166230 const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
167231
168 return HP {
232 return HP{
169233 .val = p,
170234 .off = in.off * val + e,
171235 };
......@@ -175,9 +239,9 @@ fn hpProd(in: &const HP, val: f64) HP {
175239/// @val: The double.
176240/// @hi: The high bits.
177241/// @lo: The low bits.
178fn split(val: f64, hi: &f64, lo: &f64) void {
179 *hi = gethi(val);
180 *lo = val - *hi;
242fn split(val: f64, hi: *f64, lo: *f64) void {
243 hi.* = gethi(val);
244 lo.* = val - hi.*;
181245}
182246
183247fn gethi(in: f64) f64 {
......@@ -188,7 +252,10 @@ fn gethi(in: f64) f64 {
188252
189253/// Normalize the number by factoring in the error.
190254/// @hp: The float pair.
191fn hpNormalize(hp: &HP) void {
255fn hpNormalize(hp: *HP) void {
256 // Required to avoid segfaults causing buffer overrun during errol3 digit output termination.
257 @setFloatMode(this, @import("builtin").FloatMode.Strict);
258
192259 const val = hp.val;
193260
194261 hp.val += hp.off;
......@@ -197,7 +264,7 @@ fn hpNormalize(hp: &HP) void {
197264
198265/// Divide the high-precision number by ten.
199266/// @hp: The high-precision number
200fn hpDiv10(hp: &HP) void {
267fn hpDiv10(hp: *HP) void {
201268 var val = hp.val;
202269
203270 hp.val /= 10.0;
......@@ -213,7 +280,7 @@ fn hpDiv10(hp: &HP) void {
213280
214281/// Multiply the high-precision number by ten.
215282/// @hp: The high-precision number
216fn hpMul10(hp: &HP) void {
283fn hpMul10(hp: *HP) void {
217284 const val = hp.val;
218285
219286 hp.val *= 10.0;
......@@ -228,7 +295,6 @@ fn hpMul10(hp: &HP) void {
228295 hpNormalize(hp);
229296}
230297
231
232298/// Integer conversion algorithm, guaranteed correct, optimal, and best.
233299/// @val: The val.
234300/// @buf: The output buffer.
......@@ -238,7 +304,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
238304
239305 assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
240306
241 var mid = u128(val);
307 var mid = @floatToInt(u128, val);
242308 var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
243309 var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);
244310
......@@ -248,11 +314,11 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
248314 low -= 1;
249315 }
250316
251 var l64 = u64(low % pow19);
252 const lf = u64((low / pow19) % pow19);
317 var l64 = @intCast(u64, low % pow19);
318 const lf = @intCast(u64, (low / pow19) % pow19);
253319
254 var h64 = u64(high % pow19);
255 const hf = u64((high / pow19) % pow19);
320 var h64 = @intCast(u64, high % pow19);
321 const hf = @intCast(u64, (high / pow19) % pow19);
256322
257323 if (lf != hf) {
258324 l64 = lf;
......@@ -263,27 +329,26 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
263329 var mi: i32 = mismatch10(l64, h64);
264330 var x: u64 = 1;
265331 {
266 var i = i32(lf == hf);
332 var i: i32 = @boolToInt(lf == hf);
267333 while (i < mi) : (i += 1) {
268334 x *= 10;
269335 }
270336 }
271337 const m64 = @truncate(u64, @divTrunc(mid, x));
272338
273 if (lf != hf)
274 mi += 19;
339 if (lf != hf) mi += 19;
275340
276341 var buf_index = u64toa(m64, buffer) - 1;
277342
278343 if (mi != 0) {
279 buffer[buf_index - 1] += u8(buffer[buf_index] >= '5');
344 buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
280345 } else {
281346 buf_index += 1;
282347 }
283348
284 return FloatDecimal {
349 return FloatDecimal{
285350 .digits = buffer[0..buf_index],
286 .exp = i32(buf_index) + mi,
351 .exp = @intCast(i32, buf_index) + mi,
287352 };
288353}
289354
......@@ -294,54 +359,53 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
294359fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
295360 assert((val >= 16.0) and (val < 9.007199254740992e15));
296361
297 const u = u64(val);
298 const n = f64(u);
362 const u = @floatToInt(u64, val);
363 const n = @intToFloat(f64, u);
299364
300365 var mid = val - n;
301366 var lo = ((fpprev(val) - n) + mid) / 2.0;
302367 var hi = ((fpnext(val) - n) + mid) / 2.0;
303368
304369 var buf_index = u64toa(u, buffer);
305 var exp = i32(buf_index);
370 var exp = @intCast(i32, buf_index);
306371 var j = buf_index;
307372 buffer[j] = 0;
308373
309374 if (mid != 0.0) {
310375 while (mid != 0.0) {
311376 lo *= 10.0;
312 const ldig = i32(lo);
313 lo -= f64(ldig);
377 const ldig = @floatToInt(i32, lo);
378 lo -= @intToFloat(f64, ldig);
314379
315380 mid *= 10.0;
316 const mdig = i32(mid);
317 mid -= f64(mdig);
381 const mdig = @floatToInt(i32, mid);
382 mid -= @intToFloat(f64, mdig);
318383
319384 hi *= 10.0;
320 const hdig = i32(hi);
321 hi -= f64(hdig);
385 const hdig = @floatToInt(i32, hi);
386 hi -= @intToFloat(f64, hdig);
322387
323 buffer[j] = u8(mdig + '0');
388 buffer[j] = @intCast(u8, mdig + '0');
324389 j += 1;
325390
326 if(hdig != ldig or j > 50)
327 break;
391 if (hdig != ldig or j > 50) break;
328392 }
329393
330394 if (mid > 0.5) {
331 buffer[j-1] += 1;
332 } else if ((mid == 0.5) and (buffer[j-1] & 0x1) != 0) {
333 buffer[j-1] += 1;
395 buffer[j - 1] += 1;
396 } else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
397 buffer[j - 1] += 1;
334398 }
335399 } else {
336 while (buffer[j-1] == '0') {
337 buffer[j-1] = 0;
400 while (buffer[j - 1] == '0') {
401 buffer[j - 1] = 0;
338402 j -= 1;
339403 }
340404 }
341405
342406 buffer[j] = 0;
343407
344 return FloatDecimal {
408 return FloatDecimal{
345409 .digits = buffer[0..j],
346410 .exp = exp,
347411 };
......@@ -355,7 +419,7 @@ fn fpprev(val: f64) f64 {
355419 return @bitCast(f64, @bitCast(u64, val) -% 1);
356420}
357421
358pub const c_digits_lut = []u8 {
422pub const c_digits_lut = []u8{
359423 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
360424 '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
361425 '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
......@@ -388,7 +452,7 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
388452 var buf_index: usize = 0;
389453
390454 if (value < kTen8) {
391 const v = u32(value);
455 const v = @intCast(u32, value);
392456 if (v < 10000) {
393457 const d1: u32 = (v / 100) << 1;
394458 const d2: u32 = (v % 100) << 1;
......@@ -443,8 +507,8 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
443507 buf_index += 1;
444508 }
445509 } else if (value < kTen16) {
446 const v0: u32 = u32(value / kTen8);
447 const v1: u32 = u32(value % kTen8);
510 const v0: u32 = @intCast(u32, value / kTen8);
511 const v1: u32 = @intCast(u32, value % kTen8);
448512
449513 const b0: u32 = v0 / 10000;
450514 const c0: u32 = v0 % 10000;
......@@ -514,11 +578,11 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
514578 buffer[buf_index] = c_digits_lut[d8 + 1];
515579 buf_index += 1;
516580 } else {
517 const a = u32(value / kTen16); // 1 to 1844
581 const a = @intCast(u32, value / kTen16); // 1 to 1844
518582 value %= kTen16;
519583
520584 if (a < 10) {
521 buffer[buf_index] = '0' + u8(a);
585 buffer[buf_index] = '0' + @intCast(u8, a);
522586 buf_index += 1;
523587 } else if (a < 100) {
524588 const i: u32 = a << 1;
......@@ -527,7 +591,7 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
527591 buffer[buf_index] = c_digits_lut[i + 1];
528592 buf_index += 1;
529593 } else if (a < 1000) {
530 buffer[buf_index] = '0' + u8(a / 100);
594 buffer[buf_index] = '0' + @intCast(u8, a / 100);
531595 buf_index += 1;
532596
533597 const i: u32 = (a % 100) << 1;
......@@ -548,8 +612,8 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
548612 buf_index += 1;
549613 }
550614
551 const v0 = u32(value / kTen8);
552 const v1 = u32(value % kTen8);
615 const v0 = @intCast(u32, value / kTen8);
616 const v1 = @intCast(u32, value % kTen8);
553617
554618 const b0: u32 = v0 / 10000;
555619 const c0: u32 = v0 % 10000;
......@@ -613,7 +677,6 @@ fn fpeint(from: f64) u128 {
613677 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
614678}
615679
616
617680/// Given two different integers with the same length in terms of the number
618681/// of decimal digits, index the digits from the right-most position starting
619682/// from zero, find the first index where the digits in the two integers
......@@ -640,7 +703,6 @@ fn mismatch10(a: u64, b: u64) i32 {
640703 a_copy /= 10;
641704 b_copy /= 10;
642705
643 if (a_copy == b_copy)
644 return i;
706 if (a_copy == b_copy) return i;
645707 }
646708}
std/fmt/errol/lookup.zig+600-600
......@@ -3,604 +3,604 @@ pub const HP = struct {
33 off: f64,
44};
55pub const lookup_table = []HP{
6 HP{.val=1.000000e+308, .off= -1.097906362944045488e+291 },
7 HP{.val=1.000000e+307, .off= 1.396894023974354241e+290 },
8 HP{.val=1.000000e+306, .off= -1.721606459673645508e+289 },
9 HP{.val=1.000000e+305, .off= 6.074644749446353973e+288 },
10 HP{.val=1.000000e+304, .off= 6.074644749446353567e+287 },
11 HP{.val=1.000000e+303, .off= -1.617650767864564452e+284 },
12 HP{.val=1.000000e+302, .off= -7.629703079084895055e+285 },
13 HP{.val=1.000000e+301, .off= -5.250476025520442286e+284 },
14 HP{.val=1.000000e+300, .off= -5.250476025520441956e+283 },
15 HP{.val=1.000000e+299, .off= -5.250476025520441750e+282 },
16 HP{.val=1.000000e+298, .off= 4.043379652465702264e+281 },
17 HP{.val=1.000000e+297, .off= -1.765280146275637946e+280 },
18 HP{.val=1.000000e+296, .off= 1.865132227937699609e+279 },
19 HP{.val=1.000000e+295, .off= 1.865132227937699609e+278 },
20 HP{.val=1.000000e+294, .off= -6.643646774124810287e+277 },
21 HP{.val=1.000000e+293, .off= 7.537651562646039934e+276 },
22 HP{.val=1.000000e+292, .off= -1.325659897835741608e+275 },
23 HP{.val=1.000000e+291, .off= 4.213909764965371606e+274 },
24 HP{.val=1.000000e+290, .off= -6.172783352786715670e+273 },
25 HP{.val=1.000000e+289, .off= -6.172783352786715670e+272 },
26 HP{.val=1.000000e+288, .off= -7.630473539575035471e+270 },
27 HP{.val=1.000000e+287, .off= -7.525217352494018700e+270 },
28 HP{.val=1.000000e+286, .off= -3.298861103408696612e+269 },
29 HP{.val=1.000000e+285, .off= 1.984084207947955778e+268 },
30 HP{.val=1.000000e+284, .off= -7.921438250845767591e+267 },
31 HP{.val=1.000000e+283, .off= 4.460464822646386735e+266 },
32 HP{.val=1.000000e+282, .off= -3.278224598286209647e+265 },
33 HP{.val=1.000000e+281, .off= -3.278224598286209737e+264 },
34 HP{.val=1.000000e+280, .off= -3.278224598286209961e+263 },
35 HP{.val=1.000000e+279, .off= -5.797329227496039232e+262 },
36 HP{.val=1.000000e+278, .off= 3.649313132040821498e+261 },
37 HP{.val=1.000000e+277, .off= -2.867878510995372374e+259 },
38 HP{.val=1.000000e+276, .off= -5.206914080024985409e+259 },
39 HP{.val=1.000000e+275, .off= 4.018322599210230404e+258 },
40 HP{.val=1.000000e+274, .off= 7.862171215558236495e+257 },
41 HP{.val=1.000000e+273, .off= 5.459765830340732821e+256 },
42 HP{.val=1.000000e+272, .off= -6.552261095746788047e+255 },
43 HP{.val=1.000000e+271, .off= 4.709014147460262298e+254 },
44 HP{.val=1.000000e+270, .off= -4.675381888545612729e+253 },
45 HP{.val=1.000000e+269, .off= -4.675381888545612892e+252 },
46 HP{.val=1.000000e+268, .off= 2.656177514583977380e+251 },
47 HP{.val=1.000000e+267, .off= 2.656177514583977190e+250 },
48 HP{.val=1.000000e+266, .off= -3.071603269111014892e+249 },
49 HP{.val=1.000000e+265, .off= -6.651466258920385440e+248 },
50 HP{.val=1.000000e+264, .off= -4.414051890289528972e+247 },
51 HP{.val=1.000000e+263, .off= -1.617283929500958387e+246 },
52 HP{.val=1.000000e+262, .off= -1.617283929500958241e+245 },
53 HP{.val=1.000000e+261, .off= 7.122615947963323868e+244 },
54 HP{.val=1.000000e+260, .off= -6.533477610574617382e+243 },
55 HP{.val=1.000000e+259, .off= 7.122615947963323982e+242 },
56 HP{.val=1.000000e+258, .off= -5.679971763165996225e+241 },
57 HP{.val=1.000000e+257, .off= -3.012765990014054219e+240 },
58 HP{.val=1.000000e+256, .off= -3.012765990014054219e+239 },
59 HP{.val=1.000000e+255, .off= 1.154743030535854616e+238 },
60 HP{.val=1.000000e+254, .off= 6.364129306223240767e+237 },
61 HP{.val=1.000000e+253, .off= 6.364129306223241129e+236 },
62 HP{.val=1.000000e+252, .off= -9.915202805299840595e+235 },
63 HP{.val=1.000000e+251, .off= -4.827911520448877980e+234 },
64 HP{.val=1.000000e+250, .off= 7.890316691678530146e+233 },
65 HP{.val=1.000000e+249, .off= 7.890316691678529484e+232 },
66 HP{.val=1.000000e+248, .off= -4.529828046727141859e+231 },
67 HP{.val=1.000000e+247, .off= 4.785280507077111924e+230 },
68 HP{.val=1.000000e+246, .off= -6.858605185178205305e+229 },
69 HP{.val=1.000000e+245, .off= -4.432795665958347728e+228 },
70 HP{.val=1.000000e+244, .off= -7.465057564983169531e+227 },
71 HP{.val=1.000000e+243, .off= -7.465057564983169741e+226 },
72 HP{.val=1.000000e+242, .off= -5.096102956370027445e+225 },
73 HP{.val=1.000000e+241, .off= -5.096102956370026952e+224 },
74 HP{.val=1.000000e+240, .off= -1.394611380411992474e+223 },
75 HP{.val=1.000000e+239, .off= 9.188208545617793960e+221 },
76 HP{.val=1.000000e+238, .off= -4.864759732872650359e+221 },
77 HP{.val=1.000000e+237, .off= 5.979453868566904629e+220 },
78 HP{.val=1.000000e+236, .off= -5.316601966265964857e+219 },
79 HP{.val=1.000000e+235, .off= -5.316601966265964701e+218 },
80 HP{.val=1.000000e+234, .off= -1.786584517880693123e+217 },
81 HP{.val=1.000000e+233, .off= 2.625937292600896716e+216 },
82 HP{.val=1.000000e+232, .off= -5.647541102052084079e+215 },
83 HP{.val=1.000000e+231, .off= -5.647541102052083888e+214 },
84 HP{.val=1.000000e+230, .off= -9.956644432600511943e+213 },
85 HP{.val=1.000000e+229, .off= 8.161138937705571862e+211 },
86 HP{.val=1.000000e+228, .off= 7.549087847752475275e+211 },
87 HP{.val=1.000000e+227, .off= -9.283347037202319948e+210 },
88 HP{.val=1.000000e+226, .off= 3.866992716668613820e+209 },
89 HP{.val=1.000000e+225, .off= 7.154577655136347262e+208 },
90 HP{.val=1.000000e+224, .off= 3.045096482051680688e+207 },
91 HP{.val=1.000000e+223, .off= -4.660180717482069567e+206 },
92 HP{.val=1.000000e+222, .off= -4.660180717482070101e+205 },
93 HP{.val=1.000000e+221, .off= -4.660180717482069544e+204 },
94 HP{.val=1.000000e+220, .off= 3.562757926310489022e+202 },
95 HP{.val=1.000000e+219, .off= 3.491561111451748149e+202 },
96 HP{.val=1.000000e+218, .off= -8.265758834125874135e+201 },
97 HP{.val=1.000000e+217, .off= 3.981449442517482365e+200 },
98 HP{.val=1.000000e+216, .off= -2.142154695804195936e+199 },
99 HP{.val=1.000000e+215, .off= 9.339603063548950188e+198 },
100 HP{.val=1.000000e+214, .off= 4.555537330485139746e+197 },
101 HP{.val=1.000000e+213, .off= 1.565496247320257804e+196 },
102 HP{.val=1.000000e+212, .off= 9.040598955232462036e+195 },
103 HP{.val=1.000000e+211, .off= 4.368659762787334780e+194 },
104 HP{.val=1.000000e+210, .off= 7.288621758065539072e+193 },
105 HP{.val=1.000000e+209, .off= -7.311188218325485628e+192 },
106 HP{.val=1.000000e+208, .off= 1.813693016918905189e+191 },
107 HP{.val=1.000000e+207, .off= -3.889357755108838992e+190 },
108 HP{.val=1.000000e+206, .off= -3.889357755108838992e+189 },
109 HP{.val=1.000000e+205, .off= -1.661603547285501360e+188 },
110 HP{.val=1.000000e+204, .off= 1.123089212493670643e+187 },
111 HP{.val=1.000000e+203, .off= 1.123089212493670643e+186 },
112 HP{.val=1.000000e+202, .off= 9.825254086803583029e+185 },
113 HP{.val=1.000000e+201, .off= -3.771878529305654999e+184 },
114 HP{.val=1.000000e+200, .off= 3.026687778748963675e+183 },
115 HP{.val=1.000000e+199, .off= -9.720624048853446693e+182 },
116 HP{.val=1.000000e+198, .off= -1.753554156601940139e+181 },
117 HP{.val=1.000000e+197, .off= 4.885670753607648963e+180 },
118 HP{.val=1.000000e+196, .off= 4.885670753607648963e+179 },
119 HP{.val=1.000000e+195, .off= 2.292223523057028076e+178 },
120 HP{.val=1.000000e+194, .off= 5.534032561245303825e+177 },
121 HP{.val=1.000000e+193, .off= -6.622751331960730683e+176 },
122 HP{.val=1.000000e+192, .off= -4.090088020876139692e+175 },
123 HP{.val=1.000000e+191, .off= -7.255917159731877552e+174 },
124 HP{.val=1.000000e+190, .off= -7.255917159731877992e+173 },
125 HP{.val=1.000000e+189, .off= -2.309309130269787104e+172 },
126 HP{.val=1.000000e+188, .off= -2.309309130269787019e+171 },
127 HP{.val=1.000000e+187, .off= 9.284303438781988230e+170 },
128 HP{.val=1.000000e+186, .off= 2.038295583124628364e+169 },
129 HP{.val=1.000000e+185, .off= 2.038295583124628532e+168 },
130 HP{.val=1.000000e+184, .off= -1.735666841696912925e+167 },
131 HP{.val=1.000000e+183, .off= 5.340512704843477241e+166 },
132 HP{.val=1.000000e+182, .off= -6.453119872723839321e+165 },
133 HP{.val=1.000000e+181, .off= 8.288920849235306587e+164 },
134 HP{.val=1.000000e+180, .off= -9.248546019891598293e+162 },
135 HP{.val=1.000000e+179, .off= 1.954450226518486016e+162 },
136 HP{.val=1.000000e+178, .off= -5.243811844750628197e+161 },
137 HP{.val=1.000000e+177, .off= -7.448980502074320639e+159 },
138 HP{.val=1.000000e+176, .off= -7.448980502074319858e+158 },
139 HP{.val=1.000000e+175, .off= 6.284654753766312753e+158 },
140 HP{.val=1.000000e+174, .off= -6.895756753684458388e+157 },
141 HP{.val=1.000000e+173, .off= -1.403918625579970616e+156 },
142 HP{.val=1.000000e+172, .off= -8.268716285710580522e+155 },
143 HP{.val=1.000000e+171, .off= 4.602779327034313170e+154 },
144 HP{.val=1.000000e+170, .off= -3.441905430931244940e+153 },
145 HP{.val=1.000000e+169, .off= 6.613950516525702884e+152 },
146 HP{.val=1.000000e+168, .off= 6.613950516525702652e+151 },
147 HP{.val=1.000000e+167, .off= -3.860899428741951187e+150 },
148 HP{.val=1.000000e+166, .off= 5.959272394946474605e+149 },
149 HP{.val=1.000000e+165, .off= 1.005101065481665103e+149 },
150 HP{.val=1.000000e+164, .off= -1.783349948587918355e+146 },
151 HP{.val=1.000000e+163, .off= 6.215006036188360099e+146 },
152 HP{.val=1.000000e+162, .off= 6.215006036188360099e+145 },
153 HP{.val=1.000000e+161, .off= -3.774589324822814903e+144 },
154 HP{.val=1.000000e+160, .off= -6.528407745068226929e+142 },
155 HP{.val=1.000000e+159, .off= 7.151530601283157561e+142 },
156 HP{.val=1.000000e+158, .off= 4.712664546348788765e+141 },
157 HP{.val=1.000000e+157, .off= 1.664081977680827856e+140 },
158 HP{.val=1.000000e+156, .off= 1.664081977680827750e+139 },
159 HP{.val=1.000000e+155, .off= -7.176231540910168265e+137 },
160 HP{.val=1.000000e+154, .off= -3.694754568805822650e+137 },
161 HP{.val=1.000000e+153, .off= 2.665969958768462622e+134 },
162 HP{.val=1.000000e+152, .off= -4.625108135904199522e+135 },
163 HP{.val=1.000000e+151, .off= -1.717753238721771919e+134 },
164 HP{.val=1.000000e+150, .off= 1.916440382756262433e+133 },
165 HP{.val=1.000000e+149, .off= -4.897672657515052040e+132 },
166 HP{.val=1.000000e+148, .off= -4.897672657515052198e+131 },
167 HP{.val=1.000000e+147, .off= 2.200361759434233991e+130 },
168 HP{.val=1.000000e+146, .off= 6.636633270027537273e+129 },
169 HP{.val=1.000000e+145, .off= 1.091293881785907977e+128 },
170 HP{.val=1.000000e+144, .off= -2.374543235865110597e+127 },
171 HP{.val=1.000000e+143, .off= -2.374543235865110537e+126 },
172 HP{.val=1.000000e+142, .off= -5.082228484029969099e+125 },
173 HP{.val=1.000000e+141, .off= -1.697621923823895943e+124 },
174 HP{.val=1.000000e+140, .off= -5.928380124081487212e+123 },
175 HP{.val=1.000000e+139, .off= -3.284156248920492522e+122 },
176 HP{.val=1.000000e+138, .off= -3.284156248920492706e+121 },
177 HP{.val=1.000000e+137, .off= -3.284156248920492476e+120 },
178 HP{.val=1.000000e+136, .off= -5.866406127007401066e+119 },
179 HP{.val=1.000000e+135, .off= 3.817030915818506056e+118 },
180 HP{.val=1.000000e+134, .off= 7.851796350329300951e+117 },
181 HP{.val=1.000000e+133, .off= -2.235117235947686077e+116 },
182 HP{.val=1.000000e+132, .off= 9.170432597638723691e+114 },
183 HP{.val=1.000000e+131, .off= 8.797444499042767883e+114 },
184 HP{.val=1.000000e+130, .off= -5.978307824605161274e+113 },
185 HP{.val=1.000000e+129, .off= 1.782556435814758516e+111 },
186 HP{.val=1.000000e+128, .off= -7.517448691651820362e+111 },
187 HP{.val=1.000000e+127, .off= 4.507089332150205498e+110 },
188 HP{.val=1.000000e+126, .off= 7.513223838100711695e+109 },
189 HP{.val=1.000000e+125, .off= 7.513223838100712113e+108 },
190 HP{.val=1.000000e+124, .off= 5.164681255326878494e+107 },
191 HP{.val=1.000000e+123, .off= 2.229003026859587122e+106 },
192 HP{.val=1.000000e+122, .off= -1.440594758724527399e+105 },
193 HP{.val=1.000000e+121, .off= -3.734093374714598783e+104 },
194 HP{.val=1.000000e+120, .off= 1.999653165260579757e+103 },
195 HP{.val=1.000000e+119, .off= 5.583244752745066693e+102 },
196 HP{.val=1.000000e+118, .off= 3.343500010567262234e+101 },
197 HP{.val=1.000000e+117, .off= -5.055542772599503556e+100 },
198 HP{.val=1.000000e+116, .off= -1.555941612946684331e+99 },
199 HP{.val=1.000000e+115, .off= -1.555941612946684331e+98 },
200 HP{.val=1.000000e+114, .off= -1.555941612946684293e+97 },
201 HP{.val=1.000000e+113, .off= -1.555941612946684246e+96 },
202 HP{.val=1.000000e+112, .off= 6.988006530736955847e+95 },
203 HP{.val=1.000000e+111, .off= 4.318022735835818244e+94 },
204 HP{.val=1.000000e+110, .off= -2.356936751417025578e+93 },
205 HP{.val=1.000000e+109, .off= 1.814912928116001926e+92 },
206 HP{.val=1.000000e+108, .off= -3.399899171300282744e+91 },
207 HP{.val=1.000000e+107, .off= 3.118615952970072913e+90 },
208 HP{.val=1.000000e+106, .off= -9.103599905036843605e+89 },
209 HP{.val=1.000000e+105, .off= 6.174169917471802325e+88 },
210 HP{.val=1.000000e+104, .off= -1.915675085734668657e+86 },
211 HP{.val=1.000000e+103, .off= -1.915675085734668864e+85 },
212 HP{.val=1.000000e+102, .off= 2.295048673475466221e+85 },
213 HP{.val=1.000000e+101, .off= 2.295048673475466135e+84 },
214 HP{.val=1.000000e+100, .off= -1.590289110975991792e+83 },
215 HP{.val=1.000000e+99, .off= 3.266383119588331155e+82 },
216 HP{.val=1.000000e+98, .off= 2.309629754856292029e+80 },
217 HP{.val=1.000000e+97, .off= -7.357587384771124533e+80 },
218 HP{.val=1.000000e+96, .off= -4.986165397190889509e+79 },
219 HP{.val=1.000000e+95, .off= -2.021887912715594741e+78 },
220 HP{.val=1.000000e+94, .off= -2.021887912715594638e+77 },
221 HP{.val=1.000000e+93, .off= -4.337729697461918675e+76 },
222 HP{.val=1.000000e+92, .off= -4.337729697461918997e+75 },
223 HP{.val=1.000000e+91, .off= -7.956232486128049702e+74 },
224 HP{.val=1.000000e+90, .off= 3.351588728453609882e+73 },
225 HP{.val=1.000000e+89, .off= 5.246334248081951113e+71 },
226 HP{.val=1.000000e+88, .off= 4.058327554364963672e+71 },
227 HP{.val=1.000000e+87, .off= 4.058327554364963918e+70 },
228 HP{.val=1.000000e+86, .off= -1.463069523067487266e+69 },
229 HP{.val=1.000000e+85, .off= -1.463069523067487314e+68 },
230 HP{.val=1.000000e+84, .off= -5.776660989811589441e+67 },
231 HP{.val=1.000000e+83, .off= -3.080666323096525761e+66 },
232 HP{.val=1.000000e+82, .off= 3.659320343691134468e+65 },
233 HP{.val=1.000000e+81, .off= 7.871812010433421235e+64 },
234 HP{.val=1.000000e+80, .off= -2.660986470836727449e+61 },
235 HP{.val=1.000000e+79, .off= 3.264399249934044627e+62 },
236 HP{.val=1.000000e+78, .off= -8.493621433689703070e+60 },
237 HP{.val=1.000000e+77, .off= 1.721738727445414063e+60 },
238 HP{.val=1.000000e+76, .off= -4.706013449590547218e+59 },
239 HP{.val=1.000000e+75, .off= 7.346021882351880518e+58 },
240 HP{.val=1.000000e+74, .off= 4.835181188197207515e+57 },
241 HP{.val=1.000000e+73, .off= 1.696630320503867482e+56 },
242 HP{.val=1.000000e+72, .off= 5.619818905120542959e+55 },
243 HP{.val=1.000000e+71, .off= -4.188152556421145598e+54 },
244 HP{.val=1.000000e+70, .off= -7.253143638152923145e+53 },
245 HP{.val=1.000000e+69, .off= -7.253143638152923145e+52 },
246 HP{.val=1.000000e+68, .off= 4.719477774861832896e+51 },
247 HP{.val=1.000000e+67, .off= 1.726322421608144052e+50 },
248 HP{.val=1.000000e+66, .off= 5.467766613175255107e+49 },
249 HP{.val=1.000000e+65, .off= 7.909613737163661911e+47 },
250 HP{.val=1.000000e+64, .off= -2.132041900945439564e+47 },
251 HP{.val=1.000000e+63, .off= -5.785795994272697265e+46 },
252 HP{.val=1.000000e+62, .off= -3.502199685943161329e+45 },
253 HP{.val=1.000000e+61, .off= 5.061286470292598274e+44 },
254 HP{.val=1.000000e+60, .off= 5.061286470292598472e+43 },
255 HP{.val=1.000000e+59, .off= 2.831211950439536034e+42 },
256 HP{.val=1.000000e+58, .off= 5.618805100255863927e+41 },
257 HP{.val=1.000000e+57, .off= -4.834669211555366251e+40 },
258 HP{.val=1.000000e+56, .off= -9.190283508143378583e+39 },
259 HP{.val=1.000000e+55, .off= -1.023506702040855158e+38 },
260 HP{.val=1.000000e+54, .off= -7.829154040459624616e+37 },
261 HP{.val=1.000000e+53, .off= 6.779051325638372659e+35 },
262 HP{.val=1.000000e+52, .off= 6.779051325638372290e+34 },
263 HP{.val=1.000000e+51, .off= 6.779051325638371598e+33 },
264 HP{.val=1.000000e+50, .off= -7.629769841091887392e+33 },
265 HP{.val=1.000000e+49, .off= 5.350972305245182400e+32 },
266 HP{.val=1.000000e+48, .off= -4.384584304507619764e+31 },
267 HP{.val=1.000000e+47, .off= -4.384584304507619876e+30 },
268 HP{.val=1.000000e+46, .off= 6.860180964052978705e+28 },
269 HP{.val=1.000000e+45, .off= 7.024271097546444878e+28 },
270 HP{.val=1.000000e+44, .off= -8.821361405306422641e+27 },
271 HP{.val=1.000000e+43, .off= -1.393721169594140991e+26 },
272 HP{.val=1.000000e+42, .off= -4.488571267807591679e+25 },
273 HP{.val=1.000000e+41, .off= -6.200086450407783195e+23 },
274 HP{.val=1.000000e+40, .off= -3.037860284270036669e+23 },
275 HP{.val=1.000000e+39, .off= 6.029083362839682141e+22 },
276 HP{.val=1.000000e+38, .off= 2.251190176543965970e+21 },
277 HP{.val=1.000000e+37, .off= 4.612373417978788577e+20 },
278 HP{.val=1.000000e+36, .off= -4.242063737401796198e+19 },
279 HP{.val=1.000000e+35, .off= 3.136633892082024448e+18 },
280 HP{.val=1.000000e+34, .off= 5.442476901295718400e+17 },
281 HP{.val=1.000000e+33, .off= 5.442476901295718400e+16 },
282 HP{.val=1.000000e+32, .off= -5.366162204393472000e+15 },
283 HP{.val=1.000000e+31, .off= 3.641037050347520000e+14 },
284 HP{.val=1.000000e+30, .off= -1.988462483865600000e+13 },
285 HP{.val=1.000000e+29, .off= 8.566849142784000000e+12 },
286 HP{.val=1.000000e+28, .off= 4.168802631680000000e+11 },
287 HP{.val=1.000000e+27, .off= -1.328755507200000000e+10 },
288 HP{.val=1.000000e+26, .off= -4.764729344000000000e+09 },
289 HP{.val=1.000000e+25, .off= -9.059696640000000000e+08 },
290 HP{.val=1.000000e+24, .off= 1.677721600000000000e+07 },
291 HP{.val=1.000000e+23, .off= 8.388608000000000000e+06 },
292 HP{.val=1.000000e+22, .off= 0.000000000000000000e+00 },
293 HP{.val=1.000000e+21, .off= 0.000000000000000000e+00 },
294 HP{.val=1.000000e+20, .off= 0.000000000000000000e+00 },
295 HP{.val=1.000000e+19, .off= 0.000000000000000000e+00 },
296 HP{.val=1.000000e+18, .off= 0.000000000000000000e+00 },
297 HP{.val=1.000000e+17, .off= 0.000000000000000000e+00 },
298 HP{.val=1.000000e+16, .off= 0.000000000000000000e+00 },
299 HP{.val=1.000000e+15, .off= 0.000000000000000000e+00 },
300 HP{.val=1.000000e+14, .off= 0.000000000000000000e+00 },
301 HP{.val=1.000000e+13, .off= 0.000000000000000000e+00 },
302 HP{.val=1.000000e+12, .off= 0.000000000000000000e+00 },
303 HP{.val=1.000000e+11, .off= 0.000000000000000000e+00 },
304 HP{.val=1.000000e+10, .off= 0.000000000000000000e+00 },
305 HP{.val=1.000000e+09, .off= 0.000000000000000000e+00 },
306 HP{.val=1.000000e+08, .off= 0.000000000000000000e+00 },
307 HP{.val=1.000000e+07, .off= 0.000000000000000000e+00 },
308 HP{.val=1.000000e+06, .off= 0.000000000000000000e+00 },
309 HP{.val=1.000000e+05, .off= 0.000000000000000000e+00 },
310 HP{.val=1.000000e+04, .off= 0.000000000000000000e+00 },
311 HP{.val=1.000000e+03, .off= 0.000000000000000000e+00 },
312 HP{.val=1.000000e+02, .off= 0.000000000000000000e+00 },
313 HP{.val=1.000000e+01, .off= 0.000000000000000000e+00 },
314 HP{.val=1.000000e+00, .off= 0.000000000000000000e+00 },
315 HP{.val=1.000000e-01, .off= -5.551115123125783010e-18 },
316 HP{.val=1.000000e-02, .off= -2.081668171172168436e-19 },
317 HP{.val=1.000000e-03, .off= -2.081668171172168557e-20 },
318 HP{.val=1.000000e-04, .off= -4.792173602385929943e-21 },
319 HP{.val=1.000000e-05, .off= -8.180305391403130547e-22 },
320 HP{.val=1.000000e-06, .off= 4.525188817411374069e-23 },
321 HP{.val=1.000000e-07, .off= 4.525188817411373922e-24 },
322 HP{.val=1.000000e-08, .off= -2.092256083012847109e-25 },
323 HP{.val=1.000000e-09, .off= -6.228159145777985254e-26 },
324 HP{.val=1.000000e-10, .off= -3.643219731549774344e-27 },
325 HP{.val=1.000000e-11, .off= 6.050303071806019080e-28 },
326 HP{.val=1.000000e-12, .off= 2.011335237074438524e-29 },
327 HP{.val=1.000000e-13, .off= -3.037374556340037101e-30 },
328 HP{.val=1.000000e-14, .off= 1.180690645440101289e-32 },
329 HP{.val=1.000000e-15, .off= -7.770539987666107583e-32 },
330 HP{.val=1.000000e-16, .off= 2.090221327596539779e-33 },
331 HP{.val=1.000000e-17, .off= -7.154242405462192144e-34 },
332 HP{.val=1.000000e-18, .off= -7.154242405462192572e-35 },
333 HP{.val=1.000000e-19, .off= 2.475407316473986894e-36 },
334 HP{.val=1.000000e-20, .off= 5.484672854579042914e-37 },
335 HP{.val=1.000000e-21, .off= 9.246254777210362522e-38 },
336 HP{.val=1.000000e-22, .off= -4.859677432657087182e-39 },
337 HP{.val=1.000000e-23, .off= 3.956530198510069291e-40 },
338 HP{.val=1.000000e-24, .off= 7.629950044829717753e-41 },
339 HP{.val=1.000000e-25, .off= -3.849486974919183692e-42 },
340 HP{.val=1.000000e-26, .off= -3.849486974919184170e-43 },
341 HP{.val=1.000000e-27, .off= -3.849486974919184070e-44 },
342 HP{.val=1.000000e-28, .off= 2.876745653839937870e-45 },
343 HP{.val=1.000000e-29, .off= 5.679342582489572168e-46 },
344 HP{.val=1.000000e-30, .off= -8.333642060758598930e-47 },
345 HP{.val=1.000000e-31, .off= -8.333642060758597958e-48 },
346 HP{.val=1.000000e-32, .off= -5.596730997624190224e-49 },
347 HP{.val=1.000000e-33, .off= -5.596730997624190604e-50 },
348 HP{.val=1.000000e-34, .off= 7.232539610818348498e-51 },
349 HP{.val=1.000000e-35, .off= -7.857545194582380514e-53 },
350 HP{.val=1.000000e-36, .off= 5.896157255772251528e-53 },
351 HP{.val=1.000000e-37, .off= -6.632427322784915796e-54 },
352 HP{.val=1.000000e-38, .off= 3.808059826012723592e-55 },
353 HP{.val=1.000000e-39, .off= 7.070712060011985131e-56 },
354 HP{.val=1.000000e-40, .off= 7.070712060011985584e-57 },
355 HP{.val=1.000000e-41, .off= -5.761291134237854167e-59 },
356 HP{.val=1.000000e-42, .off= -3.762312935688689794e-59 },
357 HP{.val=1.000000e-43, .off= -7.745042713519821150e-60 },
358 HP{.val=1.000000e-44, .off= 4.700987842202462817e-61 },
359 HP{.val=1.000000e-45, .off= 1.589480203271891964e-62 },
360 HP{.val=1.000000e-46, .off= -2.299904345391321765e-63 },
361 HP{.val=1.000000e-47, .off= 2.561826340437695261e-64 },
362 HP{.val=1.000000e-48, .off= 2.561826340437695345e-65 },
363 HP{.val=1.000000e-49, .off= 6.360053438741614633e-66 },
364 HP{.val=1.000000e-50, .off= -7.616223705782342295e-68 },
365 HP{.val=1.000000e-51, .off= -7.616223705782343324e-69 },
366 HP{.val=1.000000e-52, .off= -7.616223705782342295e-70 },
367 HP{.val=1.000000e-53, .off= -3.079876214757872338e-70 },
368 HP{.val=1.000000e-54, .off= -3.079876214757872821e-71 },
369 HP{.val=1.000000e-55, .off= 5.423954167728123147e-73 },
370 HP{.val=1.000000e-56, .off= -3.985444122640543680e-73 },
371 HP{.val=1.000000e-57, .off= 4.504255013759498850e-74 },
372 HP{.val=1.000000e-58, .off= -2.570494266573869991e-75 },
373 HP{.val=1.000000e-59, .off= -2.570494266573869930e-76 },
374 HP{.val=1.000000e-60, .off= 2.956653608686574324e-77 },
375 HP{.val=1.000000e-61, .off= -3.952281235388981376e-78 },
376 HP{.val=1.000000e-62, .off= -3.952281235388981376e-79 },
377 HP{.val=1.000000e-63, .off= -6.651083908855995172e-80 },
378 HP{.val=1.000000e-64, .off= 3.469426116645307030e-81 },
379 HP{.val=1.000000e-65, .off= 7.686305293937516319e-82 },
380 HP{.val=1.000000e-66, .off= 2.415206322322254927e-83 },
381 HP{.val=1.000000e-67, .off= 5.709643179581793251e-84 },
382 HP{.val=1.000000e-68, .off= -6.644495035141475923e-85 },
383 HP{.val=1.000000e-69, .off= 3.650620143794581913e-86 },
384 HP{.val=1.000000e-70, .off= 4.333966503770636492e-88 },
385 HP{.val=1.000000e-71, .off= 8.476455383920859113e-88 },
386 HP{.val=1.000000e-72, .off= 3.449543675455986564e-89 },
387 HP{.val=1.000000e-73, .off= 3.077238576654418974e-91 },
388 HP{.val=1.000000e-74, .off= 4.234998629903623140e-91 },
389 HP{.val=1.000000e-75, .off= 4.234998629903623412e-92 },
390 HP{.val=1.000000e-76, .off= 7.303182045714702338e-93 },
391 HP{.val=1.000000e-77, .off= 7.303182045714701699e-94 },
392 HP{.val=1.000000e-78, .off= 1.121271649074855759e-96 },
393 HP{.val=1.000000e-79, .off= 1.121271649074855863e-97 },
394 HP{.val=1.000000e-80, .off= 3.857468248661243988e-97 },
395 HP{.val=1.000000e-81, .off= 3.857468248661244248e-98 },
396 HP{.val=1.000000e-82, .off= 3.857468248661244410e-99 },
397 HP{.val=1.000000e-83, .off= -3.457651055545315679e-100 },
398 HP{.val=1.000000e-84, .off= -3.457651055545315933e-101 },
399 HP{.val=1.000000e-85, .off= 2.257285900866059216e-102 },
400 HP{.val=1.000000e-86, .off= -8.458220892405268345e-103 },
401 HP{.val=1.000000e-87, .off= -1.761029146610688867e-104 },
402 HP{.val=1.000000e-88, .off= 6.610460535632536565e-105 },
403 HP{.val=1.000000e-89, .off= -3.853901567171494935e-106 },
404 HP{.val=1.000000e-90, .off= 5.062493089968513723e-108 },
405 HP{.val=1.000000e-91, .off= -2.218844988608365240e-108 },
406 HP{.val=1.000000e-92, .off= 1.187522883398155383e-109 },
407 HP{.val=1.000000e-93, .off= 9.703442563414457296e-110 },
408 HP{.val=1.000000e-94, .off= 4.380992763404268896e-111 },
409 HP{.val=1.000000e-95, .off= 1.054461638397900823e-112 },
410 HP{.val=1.000000e-96, .off= 9.370789450913819736e-113 },
411 HP{.val=1.000000e-97, .off= -3.623472756142303998e-114 },
412 HP{.val=1.000000e-98, .off= 6.122223899149788839e-115 },
413 HP{.val=1.000000e-99, .off= -1.999189980260288281e-116 },
414 HP{.val=1.000000e-100, .off= -1.999189980260288281e-117 },
415 HP{.val=1.000000e-101, .off= -5.171617276904849634e-118 },
416 HP{.val=1.000000e-102, .off= 6.724985085512256320e-119 },
417 HP{.val=1.000000e-103, .off= 4.246526260008692213e-120 },
418 HP{.val=1.000000e-104, .off= 7.344599791888147003e-121 },
419 HP{.val=1.000000e-105, .off= 3.472007877038828407e-122 },
420 HP{.val=1.000000e-106, .off= 5.892377823819652194e-123 },
421 HP{.val=1.000000e-107, .off= -1.585470431324073925e-125 },
422 HP{.val=1.000000e-108, .off= -3.940375084977444795e-125 },
423 HP{.val=1.000000e-109, .off= 7.869099673288519908e-127 },
424 HP{.val=1.000000e-110, .off= -5.122196348054018581e-127 },
425 HP{.val=1.000000e-111, .off= -8.815387795168313713e-128 },
426 HP{.val=1.000000e-112, .off= 5.034080131510290214e-129 },
427 HP{.val=1.000000e-113, .off= 2.148774313452247863e-130 },
428 HP{.val=1.000000e-114, .off= -5.064490231692858416e-131 },
429 HP{.val=1.000000e-115, .off= -5.064490231692858166e-132 },
430 HP{.val=1.000000e-116, .off= 5.708726942017560559e-134 },
431 HP{.val=1.000000e-117, .off= -2.951229134482377772e-134 },
432 HP{.val=1.000000e-118, .off= 1.451398151372789513e-135 },
433 HP{.val=1.000000e-119, .off= -1.300243902286690040e-136 },
434 HP{.val=1.000000e-120, .off= 2.139308664787659449e-137 },
435 HP{.val=1.000000e-121, .off= 2.139308664787659329e-138 },
436 HP{.val=1.000000e-122, .off= -5.922142664292847471e-139 },
437 HP{.val=1.000000e-123, .off= -5.922142664292846912e-140 },
438 HP{.val=1.000000e-124, .off= 6.673875037395443799e-141 },
439 HP{.val=1.000000e-125, .off= -1.198636026159737932e-142 },
440 HP{.val=1.000000e-126, .off= 5.361789860136246995e-143 },
441 HP{.val=1.000000e-127, .off= -2.838742497733733936e-144 },
442 HP{.val=1.000000e-128, .off= -5.401408859568103261e-145 },
443 HP{.val=1.000000e-129, .off= 7.411922949603743011e-146 },
444 HP{.val=1.000000e-130, .off= -8.604741811861064385e-147 },
445 HP{.val=1.000000e-131, .off= 1.405673664054439890e-148 },
446 HP{.val=1.000000e-132, .off= 1.405673664054439933e-149 },
447 HP{.val=1.000000e-133, .off= -6.414963426504548053e-150 },
448 HP{.val=1.000000e-134, .off= -3.971014335704864578e-151 },
449 HP{.val=1.000000e-135, .off= -3.971014335704864748e-152 },
450 HP{.val=1.000000e-136, .off= -1.523438813303585576e-154 },
451 HP{.val=1.000000e-137, .off= 2.234325152653707766e-154 },
452 HP{.val=1.000000e-138, .off= -6.715683724786540160e-155 },
453 HP{.val=1.000000e-139, .off= -2.986513359186437306e-156 },
454 HP{.val=1.000000e-140, .off= 1.674949597813692102e-157 },
455 HP{.val=1.000000e-141, .off= -4.151879098436469092e-158 },
456 HP{.val=1.000000e-142, .off= -4.151879098436469295e-159 },
457 HP{.val=1.000000e-143, .off= 4.952540739454407825e-160 },
458 HP{.val=1.000000e-144, .off= 4.952540739454407667e-161 },
459 HP{.val=1.000000e-145, .off= 8.508954738630531443e-162 },
460 HP{.val=1.000000e-146, .off= -2.604839008794855481e-163 },
461 HP{.val=1.000000e-147, .off= 2.952057864917838382e-164 },
462 HP{.val=1.000000e-148, .off= 6.425118410988271757e-165 },
463 HP{.val=1.000000e-149, .off= 2.083792728400229858e-166 },
464 HP{.val=1.000000e-150, .off= -6.295358232172964237e-168 },
465 HP{.val=1.000000e-151, .off= 6.153785555826519421e-168 },
466 HP{.val=1.000000e-152, .off= -6.564942029880634994e-169 },
467 HP{.val=1.000000e-153, .off= -3.915207116191644540e-170 },
468 HP{.val=1.000000e-154, .off= 2.709130168030831503e-171 },
469 HP{.val=1.000000e-155, .off= -1.431080634608215966e-172 },
470 HP{.val=1.000000e-156, .off= -4.018712386257620994e-173 },
471 HP{.val=1.000000e-157, .off= 5.684906682427646782e-174 },
472 HP{.val=1.000000e-158, .off= -6.444617153428937489e-175 },
473 HP{.val=1.000000e-159, .off= 1.136335243981427681e-176 },
474 HP{.val=1.000000e-160, .off= 1.136335243981427725e-177 },
475 HP{.val=1.000000e-161, .off= -2.812077463003137395e-178 },
476 HP{.val=1.000000e-162, .off= 4.591196362592922204e-179 },
477 HP{.val=1.000000e-163, .off= 7.675893789924613703e-180 },
478 HP{.val=1.000000e-164, .off= 3.820022005759999543e-181 },
479 HP{.val=1.000000e-165, .off= -9.998177244457686588e-183 },
480 HP{.val=1.000000e-166, .off= -4.012217555824373639e-183 },
481 HP{.val=1.000000e-167, .off= -2.467177666011174334e-185 },
482 HP{.val=1.000000e-168, .off= -4.953592503130188139e-185 },
483 HP{.val=1.000000e-169, .off= -2.011795792799518887e-186 },
484 HP{.val=1.000000e-170, .off= 1.665450095113817423e-187 },
485 HP{.val=1.000000e-171, .off= 1.665450095113817487e-188 },
486 HP{.val=1.000000e-172, .off= -4.080246604750770577e-189 },
487 HP{.val=1.000000e-173, .off= -4.080246604750770677e-190 },
488 HP{.val=1.000000e-174, .off= 4.085789420184387951e-192 },
489 HP{.val=1.000000e-175, .off= 4.085789420184388146e-193 },
490 HP{.val=1.000000e-176, .off= 4.085789420184388146e-194 },
491 HP{.val=1.000000e-177, .off= 4.792197640035244894e-194 },
492 HP{.val=1.000000e-178, .off= 4.792197640035244742e-195 },
493 HP{.val=1.000000e-179, .off= -2.057206575616014662e-196 },
494 HP{.val=1.000000e-180, .off= -2.057206575616014662e-197 },
495 HP{.val=1.000000e-181, .off= -4.732755097354788053e-198 },
496 HP{.val=1.000000e-182, .off= -4.732755097354787867e-199 },
497 HP{.val=1.000000e-183, .off= -5.522105321379546765e-201 },
498 HP{.val=1.000000e-184, .off= -5.777891238658996019e-201 },
499 HP{.val=1.000000e-185, .off= 7.542096444923057046e-203 },
500 HP{.val=1.000000e-186, .off= 8.919335748431433483e-203 },
501 HP{.val=1.000000e-187, .off= -1.287071881492476028e-204 },
502 HP{.val=1.000000e-188, .off= 5.091932887209967018e-205 },
503 HP{.val=1.000000e-189, .off= -6.868701054107114024e-206 },
504 HP{.val=1.000000e-190, .off= -1.885103578558330118e-207 },
505 HP{.val=1.000000e-191, .off= -1.885103578558330205e-208 },
506 HP{.val=1.000000e-192, .off= -9.671974634103305058e-209 },
507 HP{.val=1.000000e-193, .off= -4.805180224387695640e-210 },
508 HP{.val=1.000000e-194, .off= -1.763433718315439838e-211 },
509 HP{.val=1.000000e-195, .off= -9.367799983496079132e-212 },
510 HP{.val=1.000000e-196, .off= -4.615071067758179837e-213 },
511 HP{.val=1.000000e-197, .off= 1.325840076914194777e-214 },
512 HP{.val=1.000000e-198, .off= 8.751979007754662425e-215 },
513 HP{.val=1.000000e-199, .off= 1.789973760091724198e-216 },
514 HP{.val=1.000000e-200, .off= 1.789973760091724077e-217 },
515 HP{.val=1.000000e-201, .off= 5.416018159916171171e-218 },
516 HP{.val=1.000000e-202, .off= -3.649092839644947067e-219 },
517 HP{.val=1.000000e-203, .off= -3.649092839644947067e-220 },
518 HP{.val=1.000000e-204, .off= -1.080338554413850956e-222 },
519 HP{.val=1.000000e-205, .off= -1.080338554413850841e-223 },
520 HP{.val=1.000000e-206, .off= -2.874486186850417807e-223 },
521 HP{.val=1.000000e-207, .off= 7.499710055933455072e-224 },
522 HP{.val=1.000000e-208, .off= -9.790617015372999087e-225 },
523 HP{.val=1.000000e-209, .off= -4.387389805589732612e-226 },
524 HP{.val=1.000000e-210, .off= -4.387389805589732612e-227 },
525 HP{.val=1.000000e-211, .off= -8.608661063232909897e-228 },
526 HP{.val=1.000000e-212, .off= 4.582811616902018972e-229 },
527 HP{.val=1.000000e-213, .off= 4.582811616902019155e-230 },
528 HP{.val=1.000000e-214, .off= 8.705146829444184930e-231 },
529 HP{.val=1.000000e-215, .off= -4.177150709750081830e-232 },
530 HP{.val=1.000000e-216, .off= -4.177150709750082366e-233 },
531 HP{.val=1.000000e-217, .off= -8.202868690748290237e-234 },
532 HP{.val=1.000000e-218, .off= -3.170721214500530119e-235 },
533 HP{.val=1.000000e-219, .off= -3.170721214500529857e-236 },
534 HP{.val=1.000000e-220, .off= 7.606440013180328441e-238 },
535 HP{.val=1.000000e-221, .off= -1.696459258568569049e-238 },
536 HP{.val=1.000000e-222, .off= -4.767838333426821244e-239 },
537 HP{.val=1.000000e-223, .off= 2.910609353718809138e-240 },
538 HP{.val=1.000000e-224, .off= -1.888420450747209784e-241 },
539 HP{.val=1.000000e-225, .off= 4.110366804835314035e-242 },
540 HP{.val=1.000000e-226, .off= 7.859608839574391006e-243 },
541 HP{.val=1.000000e-227, .off= 5.516332567862468419e-244 },
542 HP{.val=1.000000e-228, .off= -3.270953451057244613e-245 },
543 HP{.val=1.000000e-229, .off= -6.932322625607124670e-246 },
544 HP{.val=1.000000e-230, .off= -4.643966891513449762e-247 },
545 HP{.val=1.000000e-231, .off= 1.076922443720738305e-248 },
546 HP{.val=1.000000e-232, .off= -2.498633390800628939e-249 },
547 HP{.val=1.000000e-233, .off= 4.205533798926934891e-250 },
548 HP{.val=1.000000e-234, .off= 4.205533798926934891e-251 },
549 HP{.val=1.000000e-235, .off= 4.205533798926934697e-252 },
550 HP{.val=1.000000e-236, .off= -4.523850562697497656e-253 },
551 HP{.val=1.000000e-237, .off= 9.320146633177728298e-255 },
552 HP{.val=1.000000e-238, .off= 9.320146633177728062e-256 },
553 HP{.val=1.000000e-239, .off= -7.592774752331086440e-256 },
554 HP{.val=1.000000e-240, .off= 3.063212017229987840e-257 },
555 HP{.val=1.000000e-241, .off= 3.063212017229987562e-258 },
556 HP{.val=1.000000e-242, .off= 3.063212017229987562e-259 },
557 HP{.val=1.000000e-243, .off= 4.616527473176159842e-261 },
558 HP{.val=1.000000e-244, .off= 6.965550922098544975e-261 },
559 HP{.val=1.000000e-245, .off= 6.965550922098544749e-262 },
560 HP{.val=1.000000e-246, .off= 4.424965697574744679e-263 },
561 HP{.val=1.000000e-247, .off= -1.926497363734756420e-264 },
562 HP{.val=1.000000e-248, .off= 2.043167049583681740e-265 },
563 HP{.val=1.000000e-249, .off= -5.399953725388390154e-266 },
564 HP{.val=1.000000e-250, .off= -5.399953725388389982e-267 },
565 HP{.val=1.000000e-251, .off= -1.523328321757102663e-268 },
566 HP{.val=1.000000e-252, .off= 5.745344310051561161e-269 },
567 HP{.val=1.000000e-253, .off= -6.369110076296211879e-270 },
568 HP{.val=1.000000e-254, .off= 8.773957906638504842e-271 },
569 HP{.val=1.000000e-255, .off= -6.904595826956931908e-273 },
570 HP{.val=1.000000e-256, .off= 2.267170882721243669e-273 },
571 HP{.val=1.000000e-257, .off= 2.267170882721243669e-274 },
572 HP{.val=1.000000e-258, .off= 4.577819683828225398e-275 },
573 HP{.val=1.000000e-259, .off= -6.975424321706684210e-276 },
574 HP{.val=1.000000e-260, .off= 3.855741933482293648e-277 },
575 HP{.val=1.000000e-261, .off= 1.599248963651256552e-278 },
576 HP{.val=1.000000e-262, .off= -1.221367248637539543e-279 },
577 HP{.val=1.000000e-263, .off= -1.221367248637539494e-280 },
578 HP{.val=1.000000e-264, .off= -1.221367248637539647e-281 },
579 HP{.val=1.000000e-265, .off= 1.533140771175737943e-282 },
580 HP{.val=1.000000e-266, .off= 1.533140771175737895e-283 },
581 HP{.val=1.000000e-267, .off= 1.533140771175738074e-284 },
582 HP{.val=1.000000e-268, .off= 4.223090009274641634e-285 },
583 HP{.val=1.000000e-269, .off= 4.223090009274641634e-286 },
584 HP{.val=1.000000e-270, .off= -4.183001359784432924e-287 },
585 HP{.val=1.000000e-271, .off= 3.697709298708449474e-288 },
586 HP{.val=1.000000e-272, .off= 6.981338739747150474e-289 },
587 HP{.val=1.000000e-273, .off= -9.436808465446354751e-290 },
588 HP{.val=1.000000e-274, .off= 3.389869038611071740e-291 },
589 HP{.val=1.000000e-275, .off= 6.596538414625427829e-292 },
590 HP{.val=1.000000e-276, .off= -9.436808465446354618e-293 },
591 HP{.val=1.000000e-277, .off= 3.089243784609725523e-294 },
592 HP{.val=1.000000e-278, .off= 6.220756847123745836e-295 },
593 HP{.val=1.000000e-279, .off= -5.522417137303829470e-296 },
594 HP{.val=1.000000e-280, .off= 4.263561183052483059e-297 },
595 HP{.val=1.000000e-281, .off= -1.852675267170212272e-298 },
596 HP{.val=1.000000e-282, .off= -1.852675267170212378e-299 },
597 HP{.val=1.000000e-283, .off= 5.314789322934508480e-300 },
598 HP{.val=1.000000e-284, .off= -3.644541414696392675e-301 },
599 HP{.val=1.000000e-285, .off= -7.377595888709267777e-302 },
600 HP{.val=1.000000e-286, .off= -5.044436842451220838e-303 },
601 HP{.val=1.000000e-287, .off= -2.127988034628661760e-304 },
602 HP{.val=1.000000e-288, .off= -5.773549044406860911e-305 },
603 HP{.val=1.000000e-289, .off= -1.216597782184112068e-306 },
604 HP{.val=1.000000e-290, .off= -6.912786859962547924e-307 },
605 HP{.val=1.000000e-291, .off= 3.767567660872018813e-308 },
6 HP{ .val = 1.000000e+308, .off = -1.097906362944045488e+291 },
7 HP{ .val = 1.000000e+307, .off = 1.396894023974354241e+290 },
8 HP{ .val = 1.000000e+306, .off = -1.721606459673645508e+289 },
9 HP{ .val = 1.000000e+305, .off = 6.074644749446353973e+288 },
10 HP{ .val = 1.000000e+304, .off = 6.074644749446353567e+287 },
11 HP{ .val = 1.000000e+303, .off = -1.617650767864564452e+284 },
12 HP{ .val = 1.000000e+302, .off = -7.629703079084895055e+285 },
13 HP{ .val = 1.000000e+301, .off = -5.250476025520442286e+284 },
14 HP{ .val = 1.000000e+300, .off = -5.250476025520441956e+283 },
15 HP{ .val = 1.000000e+299, .off = -5.250476025520441750e+282 },
16 HP{ .val = 1.000000e+298, .off = 4.043379652465702264e+281 },
17 HP{ .val = 1.000000e+297, .off = -1.765280146275637946e+280 },
18 HP{ .val = 1.000000e+296, .off = 1.865132227937699609e+279 },
19 HP{ .val = 1.000000e+295, .off = 1.865132227937699609e+278 },
20 HP{ .val = 1.000000e+294, .off = -6.643646774124810287e+277 },
21 HP{ .val = 1.000000e+293, .off = 7.537651562646039934e+276 },
22 HP{ .val = 1.000000e+292, .off = -1.325659897835741608e+275 },
23 HP{ .val = 1.000000e+291, .off = 4.213909764965371606e+274 },
24 HP{ .val = 1.000000e+290, .off = -6.172783352786715670e+273 },
25 HP{ .val = 1.000000e+289, .off = -6.172783352786715670e+272 },
26 HP{ .val = 1.000000e+288, .off = -7.630473539575035471e+270 },
27 HP{ .val = 1.000000e+287, .off = -7.525217352494018700e+270 },
28 HP{ .val = 1.000000e+286, .off = -3.298861103408696612e+269 },
29 HP{ .val = 1.000000e+285, .off = 1.984084207947955778e+268 },
30 HP{ .val = 1.000000e+284, .off = -7.921438250845767591e+267 },
31 HP{ .val = 1.000000e+283, .off = 4.460464822646386735e+266 },
32 HP{ .val = 1.000000e+282, .off = -3.278224598286209647e+265 },
33 HP{ .val = 1.000000e+281, .off = -3.278224598286209737e+264 },
34 HP{ .val = 1.000000e+280, .off = -3.278224598286209961e+263 },
35 HP{ .val = 1.000000e+279, .off = -5.797329227496039232e+262 },
36 HP{ .val = 1.000000e+278, .off = 3.649313132040821498e+261 },
37 HP{ .val = 1.000000e+277, .off = -2.867878510995372374e+259 },
38 HP{ .val = 1.000000e+276, .off = -5.206914080024985409e+259 },
39 HP{ .val = 1.000000e+275, .off = 4.018322599210230404e+258 },
40 HP{ .val = 1.000000e+274, .off = 7.862171215558236495e+257 },
41 HP{ .val = 1.000000e+273, .off = 5.459765830340732821e+256 },
42 HP{ .val = 1.000000e+272, .off = -6.552261095746788047e+255 },
43 HP{ .val = 1.000000e+271, .off = 4.709014147460262298e+254 },
44 HP{ .val = 1.000000e+270, .off = -4.675381888545612729e+253 },
45 HP{ .val = 1.000000e+269, .off = -4.675381888545612892e+252 },
46 HP{ .val = 1.000000e+268, .off = 2.656177514583977380e+251 },
47 HP{ .val = 1.000000e+267, .off = 2.656177514583977190e+250 },
48 HP{ .val = 1.000000e+266, .off = -3.071603269111014892e+249 },
49 HP{ .val = 1.000000e+265, .off = -6.651466258920385440e+248 },
50 HP{ .val = 1.000000e+264, .off = -4.414051890289528972e+247 },
51 HP{ .val = 1.000000e+263, .off = -1.617283929500958387e+246 },
52 HP{ .val = 1.000000e+262, .off = -1.617283929500958241e+245 },
53 HP{ .val = 1.000000e+261, .off = 7.122615947963323868e+244 },
54 HP{ .val = 1.000000e+260, .off = -6.533477610574617382e+243 },
55 HP{ .val = 1.000000e+259, .off = 7.122615947963323982e+242 },
56 HP{ .val = 1.000000e+258, .off = -5.679971763165996225e+241 },
57 HP{ .val = 1.000000e+257, .off = -3.012765990014054219e+240 },
58 HP{ .val = 1.000000e+256, .off = -3.012765990014054219e+239 },
59 HP{ .val = 1.000000e+255, .off = 1.154743030535854616e+238 },
60 HP{ .val = 1.000000e+254, .off = 6.364129306223240767e+237 },
61 HP{ .val = 1.000000e+253, .off = 6.364129306223241129e+236 },
62 HP{ .val = 1.000000e+252, .off = -9.915202805299840595e+235 },
63 HP{ .val = 1.000000e+251, .off = -4.827911520448877980e+234 },
64 HP{ .val = 1.000000e+250, .off = 7.890316691678530146e+233 },
65 HP{ .val = 1.000000e+249, .off = 7.890316691678529484e+232 },
66 HP{ .val = 1.000000e+248, .off = -4.529828046727141859e+231 },
67 HP{ .val = 1.000000e+247, .off = 4.785280507077111924e+230 },
68 HP{ .val = 1.000000e+246, .off = -6.858605185178205305e+229 },
69 HP{ .val = 1.000000e+245, .off = -4.432795665958347728e+228 },
70 HP{ .val = 1.000000e+244, .off = -7.465057564983169531e+227 },
71 HP{ .val = 1.000000e+243, .off = -7.465057564983169741e+226 },
72 HP{ .val = 1.000000e+242, .off = -5.096102956370027445e+225 },
73 HP{ .val = 1.000000e+241, .off = -5.096102956370026952e+224 },
74 HP{ .val = 1.000000e+240, .off = -1.394611380411992474e+223 },
75 HP{ .val = 1.000000e+239, .off = 9.188208545617793960e+221 },
76 HP{ .val = 1.000000e+238, .off = -4.864759732872650359e+221 },
77 HP{ .val = 1.000000e+237, .off = 5.979453868566904629e+220 },
78 HP{ .val = 1.000000e+236, .off = -5.316601966265964857e+219 },
79 HP{ .val = 1.000000e+235, .off = -5.316601966265964701e+218 },
80 HP{ .val = 1.000000e+234, .off = -1.786584517880693123e+217 },
81 HP{ .val = 1.000000e+233, .off = 2.625937292600896716e+216 },
82 HP{ .val = 1.000000e+232, .off = -5.647541102052084079e+215 },
83 HP{ .val = 1.000000e+231, .off = -5.647541102052083888e+214 },
84 HP{ .val = 1.000000e+230, .off = -9.956644432600511943e+213 },
85 HP{ .val = 1.000000e+229, .off = 8.161138937705571862e+211 },
86 HP{ .val = 1.000000e+228, .off = 7.549087847752475275e+211 },
87 HP{ .val = 1.000000e+227, .off = -9.283347037202319948e+210 },
88 HP{ .val = 1.000000e+226, .off = 3.866992716668613820e+209 },
89 HP{ .val = 1.000000e+225, .off = 7.154577655136347262e+208 },
90 HP{ .val = 1.000000e+224, .off = 3.045096482051680688e+207 },
91 HP{ .val = 1.000000e+223, .off = -4.660180717482069567e+206 },
92 HP{ .val = 1.000000e+222, .off = -4.660180717482070101e+205 },
93 HP{ .val = 1.000000e+221, .off = -4.660180717482069544e+204 },
94 HP{ .val = 1.000000e+220, .off = 3.562757926310489022e+202 },
95 HP{ .val = 1.000000e+219, .off = 3.491561111451748149e+202 },
96 HP{ .val = 1.000000e+218, .off = -8.265758834125874135e+201 },
97 HP{ .val = 1.000000e+217, .off = 3.981449442517482365e+200 },
98 HP{ .val = 1.000000e+216, .off = -2.142154695804195936e+199 },
99 HP{ .val = 1.000000e+215, .off = 9.339603063548950188e+198 },
100 HP{ .val = 1.000000e+214, .off = 4.555537330485139746e+197 },
101 HP{ .val = 1.000000e+213, .off = 1.565496247320257804e+196 },
102 HP{ .val = 1.000000e+212, .off = 9.040598955232462036e+195 },
103 HP{ .val = 1.000000e+211, .off = 4.368659762787334780e+194 },
104 HP{ .val = 1.000000e+210, .off = 7.288621758065539072e+193 },
105 HP{ .val = 1.000000e+209, .off = -7.311188218325485628e+192 },
106 HP{ .val = 1.000000e+208, .off = 1.813693016918905189e+191 },
107 HP{ .val = 1.000000e+207, .off = -3.889357755108838992e+190 },
108 HP{ .val = 1.000000e+206, .off = -3.889357755108838992e+189 },
109 HP{ .val = 1.000000e+205, .off = -1.661603547285501360e+188 },
110 HP{ .val = 1.000000e+204, .off = 1.123089212493670643e+187 },
111 HP{ .val = 1.000000e+203, .off = 1.123089212493670643e+186 },
112 HP{ .val = 1.000000e+202, .off = 9.825254086803583029e+185 },
113 HP{ .val = 1.000000e+201, .off = -3.771878529305654999e+184 },
114 HP{ .val = 1.000000e+200, .off = 3.026687778748963675e+183 },
115 HP{ .val = 1.000000e+199, .off = -9.720624048853446693e+182 },
116 HP{ .val = 1.000000e+198, .off = -1.753554156601940139e+181 },
117 HP{ .val = 1.000000e+197, .off = 4.885670753607648963e+180 },
118 HP{ .val = 1.000000e+196, .off = 4.885670753607648963e+179 },
119 HP{ .val = 1.000000e+195, .off = 2.292223523057028076e+178 },
120 HP{ .val = 1.000000e+194, .off = 5.534032561245303825e+177 },
121 HP{ .val = 1.000000e+193, .off = -6.622751331960730683e+176 },
122 HP{ .val = 1.000000e+192, .off = -4.090088020876139692e+175 },
123 HP{ .val = 1.000000e+191, .off = -7.255917159731877552e+174 },
124 HP{ .val = 1.000000e+190, .off = -7.255917159731877992e+173 },
125 HP{ .val = 1.000000e+189, .off = -2.309309130269787104e+172 },
126 HP{ .val = 1.000000e+188, .off = -2.309309130269787019e+171 },
127 HP{ .val = 1.000000e+187, .off = 9.284303438781988230e+170 },
128 HP{ .val = 1.000000e+186, .off = 2.038295583124628364e+169 },
129 HP{ .val = 1.000000e+185, .off = 2.038295583124628532e+168 },
130 HP{ .val = 1.000000e+184, .off = -1.735666841696912925e+167 },
131 HP{ .val = 1.000000e+183, .off = 5.340512704843477241e+166 },
132 HP{ .val = 1.000000e+182, .off = -6.453119872723839321e+165 },
133 HP{ .val = 1.000000e+181, .off = 8.288920849235306587e+164 },
134 HP{ .val = 1.000000e+180, .off = -9.248546019891598293e+162 },
135 HP{ .val = 1.000000e+179, .off = 1.954450226518486016e+162 },
136 HP{ .val = 1.000000e+178, .off = -5.243811844750628197e+161 },
137 HP{ .val = 1.000000e+177, .off = -7.448980502074320639e+159 },
138 HP{ .val = 1.000000e+176, .off = -7.448980502074319858e+158 },
139 HP{ .val = 1.000000e+175, .off = 6.284654753766312753e+158 },
140 HP{ .val = 1.000000e+174, .off = -6.895756753684458388e+157 },
141 HP{ .val = 1.000000e+173, .off = -1.403918625579970616e+156 },
142 HP{ .val = 1.000000e+172, .off = -8.268716285710580522e+155 },
143 HP{ .val = 1.000000e+171, .off = 4.602779327034313170e+154 },
144 HP{ .val = 1.000000e+170, .off = -3.441905430931244940e+153 },
145 HP{ .val = 1.000000e+169, .off = 6.613950516525702884e+152 },
146 HP{ .val = 1.000000e+168, .off = 6.613950516525702652e+151 },
147 HP{ .val = 1.000000e+167, .off = -3.860899428741951187e+150 },
148 HP{ .val = 1.000000e+166, .off = 5.959272394946474605e+149 },
149 HP{ .val = 1.000000e+165, .off = 1.005101065481665103e+149 },
150 HP{ .val = 1.000000e+164, .off = -1.783349948587918355e+146 },
151 HP{ .val = 1.000000e+163, .off = 6.215006036188360099e+146 },
152 HP{ .val = 1.000000e+162, .off = 6.215006036188360099e+145 },
153 HP{ .val = 1.000000e+161, .off = -3.774589324822814903e+144 },
154 HP{ .val = 1.000000e+160, .off = -6.528407745068226929e+142 },
155 HP{ .val = 1.000000e+159, .off = 7.151530601283157561e+142 },
156 HP{ .val = 1.000000e+158, .off = 4.712664546348788765e+141 },
157 HP{ .val = 1.000000e+157, .off = 1.664081977680827856e+140 },
158 HP{ .val = 1.000000e+156, .off = 1.664081977680827750e+139 },
159 HP{ .val = 1.000000e+155, .off = -7.176231540910168265e+137 },
160 HP{ .val = 1.000000e+154, .off = -3.694754568805822650e+137 },
161 HP{ .val = 1.000000e+153, .off = 2.665969958768462622e+134 },
162 HP{ .val = 1.000000e+152, .off = -4.625108135904199522e+135 },
163 HP{ .val = 1.000000e+151, .off = -1.717753238721771919e+134 },
164 HP{ .val = 1.000000e+150, .off = 1.916440382756262433e+133 },
165 HP{ .val = 1.000000e+149, .off = -4.897672657515052040e+132 },
166 HP{ .val = 1.000000e+148, .off = -4.897672657515052198e+131 },
167 HP{ .val = 1.000000e+147, .off = 2.200361759434233991e+130 },
168 HP{ .val = 1.000000e+146, .off = 6.636633270027537273e+129 },
169 HP{ .val = 1.000000e+145, .off = 1.091293881785907977e+128 },
170 HP{ .val = 1.000000e+144, .off = -2.374543235865110597e+127 },
171 HP{ .val = 1.000000e+143, .off = -2.374543235865110537e+126 },
172 HP{ .val = 1.000000e+142, .off = -5.082228484029969099e+125 },
173 HP{ .val = 1.000000e+141, .off = -1.697621923823895943e+124 },
174 HP{ .val = 1.000000e+140, .off = -5.928380124081487212e+123 },
175 HP{ .val = 1.000000e+139, .off = -3.284156248920492522e+122 },
176 HP{ .val = 1.000000e+138, .off = -3.284156248920492706e+121 },
177 HP{ .val = 1.000000e+137, .off = -3.284156248920492476e+120 },
178 HP{ .val = 1.000000e+136, .off = -5.866406127007401066e+119 },
179 HP{ .val = 1.000000e+135, .off = 3.817030915818506056e+118 },
180 HP{ .val = 1.000000e+134, .off = 7.851796350329300951e+117 },
181 HP{ .val = 1.000000e+133, .off = -2.235117235947686077e+116 },
182 HP{ .val = 1.000000e+132, .off = 9.170432597638723691e+114 },
183 HP{ .val = 1.000000e+131, .off = 8.797444499042767883e+114 },
184 HP{ .val = 1.000000e+130, .off = -5.978307824605161274e+113 },
185 HP{ .val = 1.000000e+129, .off = 1.782556435814758516e+111 },
186 HP{ .val = 1.000000e+128, .off = -7.517448691651820362e+111 },
187 HP{ .val = 1.000000e+127, .off = 4.507089332150205498e+110 },
188 HP{ .val = 1.000000e+126, .off = 7.513223838100711695e+109 },
189 HP{ .val = 1.000000e+125, .off = 7.513223838100712113e+108 },
190 HP{ .val = 1.000000e+124, .off = 5.164681255326878494e+107 },
191 HP{ .val = 1.000000e+123, .off = 2.229003026859587122e+106 },
192 HP{ .val = 1.000000e+122, .off = -1.440594758724527399e+105 },
193 HP{ .val = 1.000000e+121, .off = -3.734093374714598783e+104 },
194 HP{ .val = 1.000000e+120, .off = 1.999653165260579757e+103 },
195 HP{ .val = 1.000000e+119, .off = 5.583244752745066693e+102 },
196 HP{ .val = 1.000000e+118, .off = 3.343500010567262234e+101 },
197 HP{ .val = 1.000000e+117, .off = -5.055542772599503556e+100 },
198 HP{ .val = 1.000000e+116, .off = -1.555941612946684331e+99 },
199 HP{ .val = 1.000000e+115, .off = -1.555941612946684331e+98 },
200 HP{ .val = 1.000000e+114, .off = -1.555941612946684293e+97 },
201 HP{ .val = 1.000000e+113, .off = -1.555941612946684246e+96 },
202 HP{ .val = 1.000000e+112, .off = 6.988006530736955847e+95 },
203 HP{ .val = 1.000000e+111, .off = 4.318022735835818244e+94 },
204 HP{ .val = 1.000000e+110, .off = -2.356936751417025578e+93 },
205 HP{ .val = 1.000000e+109, .off = 1.814912928116001926e+92 },
206 HP{ .val = 1.000000e+108, .off = -3.399899171300282744e+91 },
207 HP{ .val = 1.000000e+107, .off = 3.118615952970072913e+90 },
208 HP{ .val = 1.000000e+106, .off = -9.103599905036843605e+89 },
209 HP{ .val = 1.000000e+105, .off = 6.174169917471802325e+88 },
210 HP{ .val = 1.000000e+104, .off = -1.915675085734668657e+86 },
211 HP{ .val = 1.000000e+103, .off = -1.915675085734668864e+85 },
212 HP{ .val = 1.000000e+102, .off = 2.295048673475466221e+85 },
213 HP{ .val = 1.000000e+101, .off = 2.295048673475466135e+84 },
214 HP{ .val = 1.000000e+100, .off = -1.590289110975991792e+83 },
215 HP{ .val = 1.000000e+99, .off = 3.266383119588331155e+82 },
216 HP{ .val = 1.000000e+98, .off = 2.309629754856292029e+80 },
217 HP{ .val = 1.000000e+97, .off = -7.357587384771124533e+80 },
218 HP{ .val = 1.000000e+96, .off = -4.986165397190889509e+79 },
219 HP{ .val = 1.000000e+95, .off = -2.021887912715594741e+78 },
220 HP{ .val = 1.000000e+94, .off = -2.021887912715594638e+77 },
221 HP{ .val = 1.000000e+93, .off = -4.337729697461918675e+76 },
222 HP{ .val = 1.000000e+92, .off = -4.337729697461918997e+75 },
223 HP{ .val = 1.000000e+91, .off = -7.956232486128049702e+74 },
224 HP{ .val = 1.000000e+90, .off = 3.351588728453609882e+73 },
225 HP{ .val = 1.000000e+89, .off = 5.246334248081951113e+71 },
226 HP{ .val = 1.000000e+88, .off = 4.058327554364963672e+71 },
227 HP{ .val = 1.000000e+87, .off = 4.058327554364963918e+70 },
228 HP{ .val = 1.000000e+86, .off = -1.463069523067487266e+69 },
229 HP{ .val = 1.000000e+85, .off = -1.463069523067487314e+68 },
230 HP{ .val = 1.000000e+84, .off = -5.776660989811589441e+67 },
231 HP{ .val = 1.000000e+83, .off = -3.080666323096525761e+66 },
232 HP{ .val = 1.000000e+82, .off = 3.659320343691134468e+65 },
233 HP{ .val = 1.000000e+81, .off = 7.871812010433421235e+64 },
234 HP{ .val = 1.000000e+80, .off = -2.660986470836727449e+61 },
235 HP{ .val = 1.000000e+79, .off = 3.264399249934044627e+62 },
236 HP{ .val = 1.000000e+78, .off = -8.493621433689703070e+60 },
237 HP{ .val = 1.000000e+77, .off = 1.721738727445414063e+60 },
238 HP{ .val = 1.000000e+76, .off = -4.706013449590547218e+59 },
239 HP{ .val = 1.000000e+75, .off = 7.346021882351880518e+58 },
240 HP{ .val = 1.000000e+74, .off = 4.835181188197207515e+57 },
241 HP{ .val = 1.000000e+73, .off = 1.696630320503867482e+56 },
242 HP{ .val = 1.000000e+72, .off = 5.619818905120542959e+55 },
243 HP{ .val = 1.000000e+71, .off = -4.188152556421145598e+54 },
244 HP{ .val = 1.000000e+70, .off = -7.253143638152923145e+53 },
245 HP{ .val = 1.000000e+69, .off = -7.253143638152923145e+52 },
246 HP{ .val = 1.000000e+68, .off = 4.719477774861832896e+51 },
247 HP{ .val = 1.000000e+67, .off = 1.726322421608144052e+50 },
248 HP{ .val = 1.000000e+66, .off = 5.467766613175255107e+49 },
249 HP{ .val = 1.000000e+65, .off = 7.909613737163661911e+47 },
250 HP{ .val = 1.000000e+64, .off = -2.132041900945439564e+47 },
251 HP{ .val = 1.000000e+63, .off = -5.785795994272697265e+46 },
252 HP{ .val = 1.000000e+62, .off = -3.502199685943161329e+45 },
253 HP{ .val = 1.000000e+61, .off = 5.061286470292598274e+44 },
254 HP{ .val = 1.000000e+60, .off = 5.061286470292598472e+43 },
255 HP{ .val = 1.000000e+59, .off = 2.831211950439536034e+42 },
256 HP{ .val = 1.000000e+58, .off = 5.618805100255863927e+41 },
257 HP{ .val = 1.000000e+57, .off = -4.834669211555366251e+40 },
258 HP{ .val = 1.000000e+56, .off = -9.190283508143378583e+39 },
259 HP{ .val = 1.000000e+55, .off = -1.023506702040855158e+38 },
260 HP{ .val = 1.000000e+54, .off = -7.829154040459624616e+37 },
261 HP{ .val = 1.000000e+53, .off = 6.779051325638372659e+35 },
262 HP{ .val = 1.000000e+52, .off = 6.779051325638372290e+34 },
263 HP{ .val = 1.000000e+51, .off = 6.779051325638371598e+33 },
264 HP{ .val = 1.000000e+50, .off = -7.629769841091887392e+33 },
265 HP{ .val = 1.000000e+49, .off = 5.350972305245182400e+32 },
266 HP{ .val = 1.000000e+48, .off = -4.384584304507619764e+31 },
267 HP{ .val = 1.000000e+47, .off = -4.384584304507619876e+30 },
268 HP{ .val = 1.000000e+46, .off = 6.860180964052978705e+28 },
269 HP{ .val = 1.000000e+45, .off = 7.024271097546444878e+28 },
270 HP{ .val = 1.000000e+44, .off = -8.821361405306422641e+27 },
271 HP{ .val = 1.000000e+43, .off = -1.393721169594140991e+26 },
272 HP{ .val = 1.000000e+42, .off = -4.488571267807591679e+25 },
273 HP{ .val = 1.000000e+41, .off = -6.200086450407783195e+23 },
274 HP{ .val = 1.000000e+40, .off = -3.037860284270036669e+23 },
275 HP{ .val = 1.000000e+39, .off = 6.029083362839682141e+22 },
276 HP{ .val = 1.000000e+38, .off = 2.251190176543965970e+21 },
277 HP{ .val = 1.000000e+37, .off = 4.612373417978788577e+20 },
278 HP{ .val = 1.000000e+36, .off = -4.242063737401796198e+19 },
279 HP{ .val = 1.000000e+35, .off = 3.136633892082024448e+18 },
280 HP{ .val = 1.000000e+34, .off = 5.442476901295718400e+17 },
281 HP{ .val = 1.000000e+33, .off = 5.442476901295718400e+16 },
282 HP{ .val = 1.000000e+32, .off = -5.366162204393472000e+15 },
283 HP{ .val = 1.000000e+31, .off = 3.641037050347520000e+14 },
284 HP{ .val = 1.000000e+30, .off = -1.988462483865600000e+13 },
285 HP{ .val = 1.000000e+29, .off = 8.566849142784000000e+12 },
286 HP{ .val = 1.000000e+28, .off = 4.168802631680000000e+11 },
287 HP{ .val = 1.000000e+27, .off = -1.328755507200000000e+10 },
288 HP{ .val = 1.000000e+26, .off = -4.764729344000000000e+09 },
289 HP{ .val = 1.000000e+25, .off = -9.059696640000000000e+08 },
290 HP{ .val = 1.000000e+24, .off = 1.677721600000000000e+07 },
291 HP{ .val = 1.000000e+23, .off = 8.388608000000000000e+06 },
292 HP{ .val = 1.000000e+22, .off = 0.000000000000000000e+00 },
293 HP{ .val = 1.000000e+21, .off = 0.000000000000000000e+00 },
294 HP{ .val = 1.000000e+20, .off = 0.000000000000000000e+00 },
295 HP{ .val = 1.000000e+19, .off = 0.000000000000000000e+00 },
296 HP{ .val = 1.000000e+18, .off = 0.000000000000000000e+00 },
297 HP{ .val = 1.000000e+17, .off = 0.000000000000000000e+00 },
298 HP{ .val = 1.000000e+16, .off = 0.000000000000000000e+00 },
299 HP{ .val = 1.000000e+15, .off = 0.000000000000000000e+00 },
300 HP{ .val = 1.000000e+14, .off = 0.000000000000000000e+00 },
301 HP{ .val = 1.000000e+13, .off = 0.000000000000000000e+00 },
302 HP{ .val = 1.000000e+12, .off = 0.000000000000000000e+00 },
303 HP{ .val = 1.000000e+11, .off = 0.000000000000000000e+00 },
304 HP{ .val = 1.000000e+10, .off = 0.000000000000000000e+00 },
305 HP{ .val = 1.000000e+09, .off = 0.000000000000000000e+00 },
306 HP{ .val = 1.000000e+08, .off = 0.000000000000000000e+00 },
307 HP{ .val = 1.000000e+07, .off = 0.000000000000000000e+00 },
308 HP{ .val = 1.000000e+06, .off = 0.000000000000000000e+00 },
309 HP{ .val = 1.000000e+05, .off = 0.000000000000000000e+00 },
310 HP{ .val = 1.000000e+04, .off = 0.000000000000000000e+00 },
311 HP{ .val = 1.000000e+03, .off = 0.000000000000000000e+00 },
312 HP{ .val = 1.000000e+02, .off = 0.000000000000000000e+00 },
313 HP{ .val = 1.000000e+01, .off = 0.000000000000000000e+00 },
314 HP{ .val = 1.000000e+00, .off = 0.000000000000000000e+00 },
315 HP{ .val = 1.000000e-01, .off = -5.551115123125783010e-18 },
316 HP{ .val = 1.000000e-02, .off = -2.081668171172168436e-19 },
317 HP{ .val = 1.000000e-03, .off = -2.081668171172168557e-20 },
318 HP{ .val = 1.000000e-04, .off = -4.792173602385929943e-21 },
319 HP{ .val = 1.000000e-05, .off = -8.180305391403130547e-22 },
320 HP{ .val = 1.000000e-06, .off = 4.525188817411374069e-23 },
321 HP{ .val = 1.000000e-07, .off = 4.525188817411373922e-24 },
322 HP{ .val = 1.000000e-08, .off = -2.092256083012847109e-25 },
323 HP{ .val = 1.000000e-09, .off = -6.228159145777985254e-26 },
324 HP{ .val = 1.000000e-10, .off = -3.643219731549774344e-27 },
325 HP{ .val = 1.000000e-11, .off = 6.050303071806019080e-28 },
326 HP{ .val = 1.000000e-12, .off = 2.011335237074438524e-29 },
327 HP{ .val = 1.000000e-13, .off = -3.037374556340037101e-30 },
328 HP{ .val = 1.000000e-14, .off = 1.180690645440101289e-32 },
329 HP{ .val = 1.000000e-15, .off = -7.770539987666107583e-32 },
330 HP{ .val = 1.000000e-16, .off = 2.090221327596539779e-33 },
331 HP{ .val = 1.000000e-17, .off = -7.154242405462192144e-34 },
332 HP{ .val = 1.000000e-18, .off = -7.154242405462192572e-35 },
333 HP{ .val = 1.000000e-19, .off = 2.475407316473986894e-36 },
334 HP{ .val = 1.000000e-20, .off = 5.484672854579042914e-37 },
335 HP{ .val = 1.000000e-21, .off = 9.246254777210362522e-38 },
336 HP{ .val = 1.000000e-22, .off = -4.859677432657087182e-39 },
337 HP{ .val = 1.000000e-23, .off = 3.956530198510069291e-40 },
338 HP{ .val = 1.000000e-24, .off = 7.629950044829717753e-41 },
339 HP{ .val = 1.000000e-25, .off = -3.849486974919183692e-42 },
340 HP{ .val = 1.000000e-26, .off = -3.849486974919184170e-43 },
341 HP{ .val = 1.000000e-27, .off = -3.849486974919184070e-44 },
342 HP{ .val = 1.000000e-28, .off = 2.876745653839937870e-45 },
343 HP{ .val = 1.000000e-29, .off = 5.679342582489572168e-46 },
344 HP{ .val = 1.000000e-30, .off = -8.333642060758598930e-47 },
345 HP{ .val = 1.000000e-31, .off = -8.333642060758597958e-48 },
346 HP{ .val = 1.000000e-32, .off = -5.596730997624190224e-49 },
347 HP{ .val = 1.000000e-33, .off = -5.596730997624190604e-50 },
348 HP{ .val = 1.000000e-34, .off = 7.232539610818348498e-51 },
349 HP{ .val = 1.000000e-35, .off = -7.857545194582380514e-53 },
350 HP{ .val = 1.000000e-36, .off = 5.896157255772251528e-53 },
351 HP{ .val = 1.000000e-37, .off = -6.632427322784915796e-54 },
352 HP{ .val = 1.000000e-38, .off = 3.808059826012723592e-55 },
353 HP{ .val = 1.000000e-39, .off = 7.070712060011985131e-56 },
354 HP{ .val = 1.000000e-40, .off = 7.070712060011985584e-57 },
355 HP{ .val = 1.000000e-41, .off = -5.761291134237854167e-59 },
356 HP{ .val = 1.000000e-42, .off = -3.762312935688689794e-59 },
357 HP{ .val = 1.000000e-43, .off = -7.745042713519821150e-60 },
358 HP{ .val = 1.000000e-44, .off = 4.700987842202462817e-61 },
359 HP{ .val = 1.000000e-45, .off = 1.589480203271891964e-62 },
360 HP{ .val = 1.000000e-46, .off = -2.299904345391321765e-63 },
361 HP{ .val = 1.000000e-47, .off = 2.561826340437695261e-64 },
362 HP{ .val = 1.000000e-48, .off = 2.561826340437695345e-65 },
363 HP{ .val = 1.000000e-49, .off = 6.360053438741614633e-66 },
364 HP{ .val = 1.000000e-50, .off = -7.616223705782342295e-68 },
365 HP{ .val = 1.000000e-51, .off = -7.616223705782343324e-69 },
366 HP{ .val = 1.000000e-52, .off = -7.616223705782342295e-70 },
367 HP{ .val = 1.000000e-53, .off = -3.079876214757872338e-70 },
368 HP{ .val = 1.000000e-54, .off = -3.079876214757872821e-71 },
369 HP{ .val = 1.000000e-55, .off = 5.423954167728123147e-73 },
370 HP{ .val = 1.000000e-56, .off = -3.985444122640543680e-73 },
371 HP{ .val = 1.000000e-57, .off = 4.504255013759498850e-74 },
372 HP{ .val = 1.000000e-58, .off = -2.570494266573869991e-75 },
373 HP{ .val = 1.000000e-59, .off = -2.570494266573869930e-76 },
374 HP{ .val = 1.000000e-60, .off = 2.956653608686574324e-77 },
375 HP{ .val = 1.000000e-61, .off = -3.952281235388981376e-78 },
376 HP{ .val = 1.000000e-62, .off = -3.952281235388981376e-79 },
377 HP{ .val = 1.000000e-63, .off = -6.651083908855995172e-80 },
378 HP{ .val = 1.000000e-64, .off = 3.469426116645307030e-81 },
379 HP{ .val = 1.000000e-65, .off = 7.686305293937516319e-82 },
380 HP{ .val = 1.000000e-66, .off = 2.415206322322254927e-83 },
381 HP{ .val = 1.000000e-67, .off = 5.709643179581793251e-84 },
382 HP{ .val = 1.000000e-68, .off = -6.644495035141475923e-85 },
383 HP{ .val = 1.000000e-69, .off = 3.650620143794581913e-86 },
384 HP{ .val = 1.000000e-70, .off = 4.333966503770636492e-88 },
385 HP{ .val = 1.000000e-71, .off = 8.476455383920859113e-88 },
386 HP{ .val = 1.000000e-72, .off = 3.449543675455986564e-89 },
387 HP{ .val = 1.000000e-73, .off = 3.077238576654418974e-91 },
388 HP{ .val = 1.000000e-74, .off = 4.234998629903623140e-91 },
389 HP{ .val = 1.000000e-75, .off = 4.234998629903623412e-92 },
390 HP{ .val = 1.000000e-76, .off = 7.303182045714702338e-93 },
391 HP{ .val = 1.000000e-77, .off = 7.303182045714701699e-94 },
392 HP{ .val = 1.000000e-78, .off = 1.121271649074855759e-96 },
393 HP{ .val = 1.000000e-79, .off = 1.121271649074855863e-97 },
394 HP{ .val = 1.000000e-80, .off = 3.857468248661243988e-97 },
395 HP{ .val = 1.000000e-81, .off = 3.857468248661244248e-98 },
396 HP{ .val = 1.000000e-82, .off = 3.857468248661244410e-99 },
397 HP{ .val = 1.000000e-83, .off = -3.457651055545315679e-100 },
398 HP{ .val = 1.000000e-84, .off = -3.457651055545315933e-101 },
399 HP{ .val = 1.000000e-85, .off = 2.257285900866059216e-102 },
400 HP{ .val = 1.000000e-86, .off = -8.458220892405268345e-103 },
401 HP{ .val = 1.000000e-87, .off = -1.761029146610688867e-104 },
402 HP{ .val = 1.000000e-88, .off = 6.610460535632536565e-105 },
403 HP{ .val = 1.000000e-89, .off = -3.853901567171494935e-106 },
404 HP{ .val = 1.000000e-90, .off = 5.062493089968513723e-108 },
405 HP{ .val = 1.000000e-91, .off = -2.218844988608365240e-108 },
406 HP{ .val = 1.000000e-92, .off = 1.187522883398155383e-109 },
407 HP{ .val = 1.000000e-93, .off = 9.703442563414457296e-110 },
408 HP{ .val = 1.000000e-94, .off = 4.380992763404268896e-111 },
409 HP{ .val = 1.000000e-95, .off = 1.054461638397900823e-112 },
410 HP{ .val = 1.000000e-96, .off = 9.370789450913819736e-113 },
411 HP{ .val = 1.000000e-97, .off = -3.623472756142303998e-114 },
412 HP{ .val = 1.000000e-98, .off = 6.122223899149788839e-115 },
413 HP{ .val = 1.000000e-99, .off = -1.999189980260288281e-116 },
414 HP{ .val = 1.000000e-100, .off = -1.999189980260288281e-117 },
415 HP{ .val = 1.000000e-101, .off = -5.171617276904849634e-118 },
416 HP{ .val = 1.000000e-102, .off = 6.724985085512256320e-119 },
417 HP{ .val = 1.000000e-103, .off = 4.246526260008692213e-120 },
418 HP{ .val = 1.000000e-104, .off = 7.344599791888147003e-121 },
419 HP{ .val = 1.000000e-105, .off = 3.472007877038828407e-122 },
420 HP{ .val = 1.000000e-106, .off = 5.892377823819652194e-123 },
421 HP{ .val = 1.000000e-107, .off = -1.585470431324073925e-125 },
422 HP{ .val = 1.000000e-108, .off = -3.940375084977444795e-125 },
423 HP{ .val = 1.000000e-109, .off = 7.869099673288519908e-127 },
424 HP{ .val = 1.000000e-110, .off = -5.122196348054018581e-127 },
425 HP{ .val = 1.000000e-111, .off = -8.815387795168313713e-128 },
426 HP{ .val = 1.000000e-112, .off = 5.034080131510290214e-129 },
427 HP{ .val = 1.000000e-113, .off = 2.148774313452247863e-130 },
428 HP{ .val = 1.000000e-114, .off = -5.064490231692858416e-131 },
429 HP{ .val = 1.000000e-115, .off = -5.064490231692858166e-132 },
430 HP{ .val = 1.000000e-116, .off = 5.708726942017560559e-134 },
431 HP{ .val = 1.000000e-117, .off = -2.951229134482377772e-134 },
432 HP{ .val = 1.000000e-118, .off = 1.451398151372789513e-135 },
433 HP{ .val = 1.000000e-119, .off = -1.300243902286690040e-136 },
434 HP{ .val = 1.000000e-120, .off = 2.139308664787659449e-137 },
435 HP{ .val = 1.000000e-121, .off = 2.139308664787659329e-138 },
436 HP{ .val = 1.000000e-122, .off = -5.922142664292847471e-139 },
437 HP{ .val = 1.000000e-123, .off = -5.922142664292846912e-140 },
438 HP{ .val = 1.000000e-124, .off = 6.673875037395443799e-141 },
439 HP{ .val = 1.000000e-125, .off = -1.198636026159737932e-142 },
440 HP{ .val = 1.000000e-126, .off = 5.361789860136246995e-143 },
441 HP{ .val = 1.000000e-127, .off = -2.838742497733733936e-144 },
442 HP{ .val = 1.000000e-128, .off = -5.401408859568103261e-145 },
443 HP{ .val = 1.000000e-129, .off = 7.411922949603743011e-146 },
444 HP{ .val = 1.000000e-130, .off = -8.604741811861064385e-147 },
445 HP{ .val = 1.000000e-131, .off = 1.405673664054439890e-148 },
446 HP{ .val = 1.000000e-132, .off = 1.405673664054439933e-149 },
447 HP{ .val = 1.000000e-133, .off = -6.414963426504548053e-150 },
448 HP{ .val = 1.000000e-134, .off = -3.971014335704864578e-151 },
449 HP{ .val = 1.000000e-135, .off = -3.971014335704864748e-152 },
450 HP{ .val = 1.000000e-136, .off = -1.523438813303585576e-154 },
451 HP{ .val = 1.000000e-137, .off = 2.234325152653707766e-154 },
452 HP{ .val = 1.000000e-138, .off = -6.715683724786540160e-155 },
453 HP{ .val = 1.000000e-139, .off = -2.986513359186437306e-156 },
454 HP{ .val = 1.000000e-140, .off = 1.674949597813692102e-157 },
455 HP{ .val = 1.000000e-141, .off = -4.151879098436469092e-158 },
456 HP{ .val = 1.000000e-142, .off = -4.151879098436469295e-159 },
457 HP{ .val = 1.000000e-143, .off = 4.952540739454407825e-160 },
458 HP{ .val = 1.000000e-144, .off = 4.952540739454407667e-161 },
459 HP{ .val = 1.000000e-145, .off = 8.508954738630531443e-162 },
460 HP{ .val = 1.000000e-146, .off = -2.604839008794855481e-163 },
461 HP{ .val = 1.000000e-147, .off = 2.952057864917838382e-164 },
462 HP{ .val = 1.000000e-148, .off = 6.425118410988271757e-165 },
463 HP{ .val = 1.000000e-149, .off = 2.083792728400229858e-166 },
464 HP{ .val = 1.000000e-150, .off = -6.295358232172964237e-168 },
465 HP{ .val = 1.000000e-151, .off = 6.153785555826519421e-168 },
466 HP{ .val = 1.000000e-152, .off = -6.564942029880634994e-169 },
467 HP{ .val = 1.000000e-153, .off = -3.915207116191644540e-170 },
468 HP{ .val = 1.000000e-154, .off = 2.709130168030831503e-171 },
469 HP{ .val = 1.000000e-155, .off = -1.431080634608215966e-172 },
470 HP{ .val = 1.000000e-156, .off = -4.018712386257620994e-173 },
471 HP{ .val = 1.000000e-157, .off = 5.684906682427646782e-174 },
472 HP{ .val = 1.000000e-158, .off = -6.444617153428937489e-175 },
473 HP{ .val = 1.000000e-159, .off = 1.136335243981427681e-176 },
474 HP{ .val = 1.000000e-160, .off = 1.136335243981427725e-177 },
475 HP{ .val = 1.000000e-161, .off = -2.812077463003137395e-178 },
476 HP{ .val = 1.000000e-162, .off = 4.591196362592922204e-179 },
477 HP{ .val = 1.000000e-163, .off = 7.675893789924613703e-180 },
478 HP{ .val = 1.000000e-164, .off = 3.820022005759999543e-181 },
479 HP{ .val = 1.000000e-165, .off = -9.998177244457686588e-183 },
480 HP{ .val = 1.000000e-166, .off = -4.012217555824373639e-183 },
481 HP{ .val = 1.000000e-167, .off = -2.467177666011174334e-185 },
482 HP{ .val = 1.000000e-168, .off = -4.953592503130188139e-185 },
483 HP{ .val = 1.000000e-169, .off = -2.011795792799518887e-186 },
484 HP{ .val = 1.000000e-170, .off = 1.665450095113817423e-187 },
485 HP{ .val = 1.000000e-171, .off = 1.665450095113817487e-188 },
486 HP{ .val = 1.000000e-172, .off = -4.080246604750770577e-189 },
487 HP{ .val = 1.000000e-173, .off = -4.080246604750770677e-190 },
488 HP{ .val = 1.000000e-174, .off = 4.085789420184387951e-192 },
489 HP{ .val = 1.000000e-175, .off = 4.085789420184388146e-193 },
490 HP{ .val = 1.000000e-176, .off = 4.085789420184388146e-194 },
491 HP{ .val = 1.000000e-177, .off = 4.792197640035244894e-194 },
492 HP{ .val = 1.000000e-178, .off = 4.792197640035244742e-195 },
493 HP{ .val = 1.000000e-179, .off = -2.057206575616014662e-196 },
494 HP{ .val = 1.000000e-180, .off = -2.057206575616014662e-197 },
495 HP{ .val = 1.000000e-181, .off = -4.732755097354788053e-198 },
496 HP{ .val = 1.000000e-182, .off = -4.732755097354787867e-199 },
497 HP{ .val = 1.000000e-183, .off = -5.522105321379546765e-201 },
498 HP{ .val = 1.000000e-184, .off = -5.777891238658996019e-201 },
499 HP{ .val = 1.000000e-185, .off = 7.542096444923057046e-203 },
500 HP{ .val = 1.000000e-186, .off = 8.919335748431433483e-203 },
501 HP{ .val = 1.000000e-187, .off = -1.287071881492476028e-204 },
502 HP{ .val = 1.000000e-188, .off = 5.091932887209967018e-205 },
503 HP{ .val = 1.000000e-189, .off = -6.868701054107114024e-206 },
504 HP{ .val = 1.000000e-190, .off = -1.885103578558330118e-207 },
505 HP{ .val = 1.000000e-191, .off = -1.885103578558330205e-208 },
506 HP{ .val = 1.000000e-192, .off = -9.671974634103305058e-209 },
507 HP{ .val = 1.000000e-193, .off = -4.805180224387695640e-210 },
508 HP{ .val = 1.000000e-194, .off = -1.763433718315439838e-211 },
509 HP{ .val = 1.000000e-195, .off = -9.367799983496079132e-212 },
510 HP{ .val = 1.000000e-196, .off = -4.615071067758179837e-213 },
511 HP{ .val = 1.000000e-197, .off = 1.325840076914194777e-214 },
512 HP{ .val = 1.000000e-198, .off = 8.751979007754662425e-215 },
513 HP{ .val = 1.000000e-199, .off = 1.789973760091724198e-216 },
514 HP{ .val = 1.000000e-200, .off = 1.789973760091724077e-217 },
515 HP{ .val = 1.000000e-201, .off = 5.416018159916171171e-218 },
516 HP{ .val = 1.000000e-202, .off = -3.649092839644947067e-219 },
517 HP{ .val = 1.000000e-203, .off = -3.649092839644947067e-220 },
518 HP{ .val = 1.000000e-204, .off = -1.080338554413850956e-222 },
519 HP{ .val = 1.000000e-205, .off = -1.080338554413850841e-223 },
520 HP{ .val = 1.000000e-206, .off = -2.874486186850417807e-223 },
521 HP{ .val = 1.000000e-207, .off = 7.499710055933455072e-224 },
522 HP{ .val = 1.000000e-208, .off = -9.790617015372999087e-225 },
523 HP{ .val = 1.000000e-209, .off = -4.387389805589732612e-226 },
524 HP{ .val = 1.000000e-210, .off = -4.387389805589732612e-227 },
525 HP{ .val = 1.000000e-211, .off = -8.608661063232909897e-228 },
526 HP{ .val = 1.000000e-212, .off = 4.582811616902018972e-229 },
527 HP{ .val = 1.000000e-213, .off = 4.582811616902019155e-230 },
528 HP{ .val = 1.000000e-214, .off = 8.705146829444184930e-231 },
529 HP{ .val = 1.000000e-215, .off = -4.177150709750081830e-232 },
530 HP{ .val = 1.000000e-216, .off = -4.177150709750082366e-233 },
531 HP{ .val = 1.000000e-217, .off = -8.202868690748290237e-234 },
532 HP{ .val = 1.000000e-218, .off = -3.170721214500530119e-235 },
533 HP{ .val = 1.000000e-219, .off = -3.170721214500529857e-236 },
534 HP{ .val = 1.000000e-220, .off = 7.606440013180328441e-238 },
535 HP{ .val = 1.000000e-221, .off = -1.696459258568569049e-238 },
536 HP{ .val = 1.000000e-222, .off = -4.767838333426821244e-239 },
537 HP{ .val = 1.000000e-223, .off = 2.910609353718809138e-240 },
538 HP{ .val = 1.000000e-224, .off = -1.888420450747209784e-241 },
539 HP{ .val = 1.000000e-225, .off = 4.110366804835314035e-242 },
540 HP{ .val = 1.000000e-226, .off = 7.859608839574391006e-243 },
541 HP{ .val = 1.000000e-227, .off = 5.516332567862468419e-244 },
542 HP{ .val = 1.000000e-228, .off = -3.270953451057244613e-245 },
543 HP{ .val = 1.000000e-229, .off = -6.932322625607124670e-246 },
544 HP{ .val = 1.000000e-230, .off = -4.643966891513449762e-247 },
545 HP{ .val = 1.000000e-231, .off = 1.076922443720738305e-248 },
546 HP{ .val = 1.000000e-232, .off = -2.498633390800628939e-249 },
547 HP{ .val = 1.000000e-233, .off = 4.205533798926934891e-250 },
548 HP{ .val = 1.000000e-234, .off = 4.205533798926934891e-251 },
549 HP{ .val = 1.000000e-235, .off = 4.205533798926934697e-252 },
550 HP{ .val = 1.000000e-236, .off = -4.523850562697497656e-253 },
551 HP{ .val = 1.000000e-237, .off = 9.320146633177728298e-255 },
552 HP{ .val = 1.000000e-238, .off = 9.320146633177728062e-256 },
553 HP{ .val = 1.000000e-239, .off = -7.592774752331086440e-256 },
554 HP{ .val = 1.000000e-240, .off = 3.063212017229987840e-257 },
555 HP{ .val = 1.000000e-241, .off = 3.063212017229987562e-258 },
556 HP{ .val = 1.000000e-242, .off = 3.063212017229987562e-259 },
557 HP{ .val = 1.000000e-243, .off = 4.616527473176159842e-261 },
558 HP{ .val = 1.000000e-244, .off = 6.965550922098544975e-261 },
559 HP{ .val = 1.000000e-245, .off = 6.965550922098544749e-262 },
560 HP{ .val = 1.000000e-246, .off = 4.424965697574744679e-263 },
561 HP{ .val = 1.000000e-247, .off = -1.926497363734756420e-264 },
562 HP{ .val = 1.000000e-248, .off = 2.043167049583681740e-265 },
563 HP{ .val = 1.000000e-249, .off = -5.399953725388390154e-266 },
564 HP{ .val = 1.000000e-250, .off = -5.399953725388389982e-267 },
565 HP{ .val = 1.000000e-251, .off = -1.523328321757102663e-268 },
566 HP{ .val = 1.000000e-252, .off = 5.745344310051561161e-269 },
567 HP{ .val = 1.000000e-253, .off = -6.369110076296211879e-270 },
568 HP{ .val = 1.000000e-254, .off = 8.773957906638504842e-271 },
569 HP{ .val = 1.000000e-255, .off = -6.904595826956931908e-273 },
570 HP{ .val = 1.000000e-256, .off = 2.267170882721243669e-273 },
571 HP{ .val = 1.000000e-257, .off = 2.267170882721243669e-274 },
572 HP{ .val = 1.000000e-258, .off = 4.577819683828225398e-275 },
573 HP{ .val = 1.000000e-259, .off = -6.975424321706684210e-276 },
574 HP{ .val = 1.000000e-260, .off = 3.855741933482293648e-277 },
575 HP{ .val = 1.000000e-261, .off = 1.599248963651256552e-278 },
576 HP{ .val = 1.000000e-262, .off = -1.221367248637539543e-279 },
577 HP{ .val = 1.000000e-263, .off = -1.221367248637539494e-280 },
578 HP{ .val = 1.000000e-264, .off = -1.221367248637539647e-281 },
579 HP{ .val = 1.000000e-265, .off = 1.533140771175737943e-282 },
580 HP{ .val = 1.000000e-266, .off = 1.533140771175737895e-283 },
581 HP{ .val = 1.000000e-267, .off = 1.533140771175738074e-284 },
582 HP{ .val = 1.000000e-268, .off = 4.223090009274641634e-285 },
583 HP{ .val = 1.000000e-269, .off = 4.223090009274641634e-286 },
584 HP{ .val = 1.000000e-270, .off = -4.183001359784432924e-287 },
585 HP{ .val = 1.000000e-271, .off = 3.697709298708449474e-288 },
586 HP{ .val = 1.000000e-272, .off = 6.981338739747150474e-289 },
587 HP{ .val = 1.000000e-273, .off = -9.436808465446354751e-290 },
588 HP{ .val = 1.000000e-274, .off = 3.389869038611071740e-291 },
589 HP{ .val = 1.000000e-275, .off = 6.596538414625427829e-292 },
590 HP{ .val = 1.000000e-276, .off = -9.436808465446354618e-293 },
591 HP{ .val = 1.000000e-277, .off = 3.089243784609725523e-294 },
592 HP{ .val = 1.000000e-278, .off = 6.220756847123745836e-295 },
593 HP{ .val = 1.000000e-279, .off = -5.522417137303829470e-296 },
594 HP{ .val = 1.000000e-280, .off = 4.263561183052483059e-297 },
595 HP{ .val = 1.000000e-281, .off = -1.852675267170212272e-298 },
596 HP{ .val = 1.000000e-282, .off = -1.852675267170212378e-299 },
597 HP{ .val = 1.000000e-283, .off = 5.314789322934508480e-300 },
598 HP{ .val = 1.000000e-284, .off = -3.644541414696392675e-301 },
599 HP{ .val = 1.000000e-285, .off = -7.377595888709267777e-302 },
600 HP{ .val = 1.000000e-286, .off = -5.044436842451220838e-303 },
601 HP{ .val = 1.000000e-287, .off = -2.127988034628661760e-304 },
602 HP{ .val = 1.000000e-288, .off = -5.773549044406860911e-305 },
603 HP{ .val = 1.000000e-289, .off = -1.216597782184112068e-306 },
604 HP{ .val = 1.000000e-290, .off = -6.912786859962547924e-307 },
605 HP{ .val = 1.000000e-291, .off = 3.767567660872018813e-308 },
606606};
std/fmt/index.zig+823-308
......@@ -4,36 +4,26 @@ const debug = std.debug;
44const assert = debug.assert;
55const mem = std.mem;
66const builtin = @import("builtin");
7const errol3 = @import("errol/index.zig").errol3;
7const errol = @import("errol/index.zig");
8const lossyCast = std.math.lossyCast;
89
910const max_int_digits = 65;
1011
11const State = enum { // TODO put inside format function and make sure the name and debug info is correct
12 Start,
13 OpenBrace,
14 CloseBrace,
15 Integer,
16 IntegerWidth,
17 Float,
18 FloatWidth,
19 Character,
20 Buf,
21 BufWidth,
22};
23
2412/// Renders fmt string with args, calling output with slices of bytes.
2513/// If `output` returns an error, the error is returned from `format` and
2614/// `output` is not called again.
27pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
28 comptime fmt: []const u8, args: ...) Errors!void
29{
15pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
16 const State = enum {
17 Start,
18 OpenBrace,
19 CloseBrace,
20 FormatString,
21 Pointer,
22 };
23
3024 comptime var start_index = 0;
3125 comptime var state = State.Start;
3226 comptime var next_arg = 0;
33 comptime var radix = 0;
34 comptime var uppercase = false;
35 comptime var width = 0;
36 comptime var width_start = 0;
3727
3828 inline for (fmt) |c, i| {
3929 switch (state) {
......@@ -42,8 +32,10 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
4232 if (start_index < i) {
4333 try output(context, fmt[start_index..i]);
4434 }
35 start_index = i;
4536 state = State.OpenBrace;
4637 },
38
4739 '}' => {
4840 if (start_index < i) {
4941 try output(context, fmt[start_index..i]);
......@@ -58,48 +50,15 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
5850 start_index = i;
5951 },
6052 '}' => {
61 try formatValue(args[next_arg], context, Errors, output);
53 try formatType(args[next_arg], fmt[0..0], context, Errors, output);
6254 next_arg += 1;
6355 state = State.Start;
6456 start_index = i + 1;
6557 },
66 'd' => {
67 radix = 10;
68 uppercase = false;
69 width = 0;
70 state = State.Integer;
71 },
72 'x' => {
73 radix = 16;
74 uppercase = false;
75 width = 0;
76 state = State.Integer;
77 },
78 'X' => {
79 radix = 16;
80 uppercase = true;
81 width = 0;
82 state = State.Integer;
83 },
84 'c' => {
85 state = State.Character;
58 '*' => state = State.Pointer,
59 else => {
60 state = State.FormatString;
8661 },
87 's' => {
88 state = State.Buf;
89 },'.' => {
90 state = State.Float;
91 },
92 else => @compileError("Unknown format character: " ++ []u8{c}),
93 },
94 State.Buf => switch (c) {
95 '}' => {
96 return output(context, args[next_arg]);
97 },
98 '0' ... '9' => {
99 width_start = i;
100 state = State.BufWidth;
101 },
102 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
10362 },
10463 State.CloseBrace => switch (c) {
10564 '}' => {
......@@ -108,73 +67,26 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
10867 },
10968 else => @compileError("Single '}' encountered in format string"),
11069 },
111 State.Integer => switch (c) {
112 '}' => {
113 try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
114 next_arg += 1;
115 state = State.Start;
116 start_index = i + 1;
117 },
118 '0' ... '9' => {
119 width_start = i;
120 state = State.IntegerWidth;
121 },
122 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
123 },
124 State.IntegerWidth => switch (c) {
125 '}' => {
126 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
127 try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
128 next_arg += 1;
129 state = State.Start;
130 start_index = i + 1;
131 },
132 '0' ... '9' => {},
133 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
134 },
135 State.Float => switch (c) {
136 '}' => {
137 try formatFloatDecimal(args[next_arg], 0, context, Errors, output);
138 next_arg += 1;
139 state = State.Start;
140 start_index = i + 1;
141 },
142 '0' ... '9' => {
143 width_start = i;
144 state = State.FloatWidth;
145 },
146 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
147 },
148 State.FloatWidth => switch (c) {
149 '}' => {
150 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
151 try formatFloatDecimal(args[next_arg], width, context, Errors, output);
152 next_arg += 1;
153 state = State.Start;
154 start_index = i + 1;
155 },
156 '0' ... '9' => {},
157 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
158 },
159 State.BufWidth => switch (c) {
70 State.FormatString => switch (c) {
16071 '}' => {
161 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
162 try formatBuf(args[next_arg], width, context, Errors, output);
72 const s = start_index + 1;
73 try formatType(args[next_arg], fmt[s..i], context, Errors, output);
16374 next_arg += 1;
16475 state = State.Start;
16576 start_index = i + 1;
16677 },
167 '0' ... '9' => {},
168 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
78 else => {},
16979 },
170 State.Character => switch (c) {
80 State.Pointer => switch (c) {
17181 '}' => {
172 try formatAsciiChar(args[next_arg], context, Errors, output);
82 try output(context, @typeName(@typeOf(args[next_arg]).Child));
83 try output(context, "@");
84 try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);
17385 next_arg += 1;
17486 state = State.Start;
17587 start_index = i + 1;
17688 },
177 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
89 else => @compileError("Unexpected format character after '*'"),
17890 },
17991 }
18092 }
......@@ -191,14 +103,21 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
191103 }
192104}
193105
194pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
106pub fn formatType(
107 value: var,
108 comptime fmt: []const u8,
109 context: var,
110 comptime Errors: type,
111 output: fn (@typeOf(context), []const u8) Errors!void,
112) Errors!void {
195113 const T = @typeOf(value);
196 switch (@typeId(T)) {
197 builtin.TypeId.Int => {
198 return formatInt(value, 10, false, 0, context, Errors, output);
199 },
200 builtin.TypeId.Float => {
201 return formatFloat(value, context, Errors, output);
114 if (T == error) {
115 try output(context, "error.");
116 return output(context, @errorName(value));
117 }
118 switch (@typeInfo(T)) {
119 builtin.TypeId.Int, builtin.TypeId.Float => {
120 return formatValue(value, fmt, context, Errors, output);
202121 },
203122 builtin.TypeId.Void => {
204123 return output(context, "void");
......@@ -206,138 +125,511 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
206125 builtin.TypeId.Bool => {
207126 return output(context, if (value) "true" else "false");
208127 },
209 builtin.TypeId.Nullable => {
128 builtin.TypeId.Optional => {
210129 if (value) |payload| {
211 return formatValue(payload, context, Errors, output);
130 return formatType(payload, fmt, context, Errors, output);
212131 } else {
213132 return output(context, "null");
214133 }
215134 },
216135 builtin.TypeId.ErrorUnion => {
217136 if (value) |payload| {
218 return formatValue(payload, context, Errors, output);
137 return formatType(payload, fmt, context, Errors, output);
219138 } else |err| {
220 return formatValue(err, context, Errors, output);
139 return formatType(err, fmt, context, Errors, output);
221140 }
222141 },
223142 builtin.TypeId.ErrorSet => {
224143 try output(context, "error.");
225144 return output(context, @errorName(value));
226145 },
227 builtin.TypeId.Pointer => {
228 if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
229 return output(context, (*value)[0..]);
230 } else {
146 builtin.TypeId.Promise => {
147 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
148 },
149 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
150 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
151 builtin.TypeId.Array => |info| {
152 if (info.child == u8) {
153 return formatText(value, fmt, context, Errors, output);
154 }
155 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
156 },
157 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
158 const has_cust_fmt = comptime cf: {
159 const info = @typeInfo(T.Child);
160 const defs = switch (info) {
161 builtin.TypeId.Struct => |s| s.defs,
162 builtin.TypeId.Union => |u| u.defs,
163 builtin.TypeId.Enum => |e| e.defs,
164 else => unreachable,
165 };
166
167 for (defs) |def| {
168 if (mem.eql(u8, def.name, "format")) {
169 break :cf true;
170 }
171 }
172 break :cf false;
173 };
174
175 if (has_cust_fmt) return value.format(fmt, context, Errors, output);
176 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
177 },
178 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
179 },
180 builtin.TypeInfo.Pointer.Size.Many => {
181 if (ptr_info.child == u8) {
182 if (fmt[0] == 's') {
183 const len = std.cstr.len(value);
184 return formatText(value[0..len], fmt, context, Errors, output);
185 }
186 }
231187 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
232 }
188 },
189 builtin.TypeInfo.Pointer.Size.Slice => {
190 const casted_value = ([]const u8)(value);
191 return output(context, casted_value);
192 },
233193 },
234 else => if (@canImplicitCast([]const u8, value)) {
235 const casted_value = ([]const u8)(value);
236 return output(context, casted_value);
237 } else {
238 @compileError("Unable to format type '" ++ @typeName(T) ++ "'");
194 builtin.TypeId.Array => |info| {
195 if (info.child == u8) {
196 return formatText(value, fmt, context, Errors, output);
197 }
198 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
239199 },
200 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
240201 }
241202}
242203
243pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
244 return output(context, (&c)[0..1]);
204fn formatValue(
205 value: var,
206 comptime fmt: []const u8,
207 context: var,
208 comptime Errors: type,
209 output: fn (@typeOf(context), []const u8) Errors!void,
210) Errors!void {
211 if (fmt.len > 0) {
212 if (fmt[0] == 'B') {
213 comptime var width: ?usize = null;
214 if (fmt.len > 1) {
215 if (fmt[1] == 'i') {
216 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
217 return formatBytes(value, width, 1024, context, Errors, output);
218 }
219 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
220 }
221 return formatBytes(value, width, 1000, context, Errors, output);
222 }
223 }
224
225 comptime var T = @typeOf(value);
226 switch (@typeId(T)) {
227 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
228 builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
229 else => unreachable,
230 }
231}
232
233pub fn formatIntValue(
234 value: var,
235 comptime fmt: []const u8,
236 context: var,
237 comptime Errors: type,
238 output: fn (@typeOf(context), []const u8) Errors!void,
239) Errors!void {
240 comptime var radix = 10;
241 comptime var uppercase = false;
242 comptime var width = 0;
243 if (fmt.len > 0) {
244 switch (fmt[0]) {
245 'c' => {
246 if (@typeOf(value) == u8) {
247 if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]});
248 return formatAsciiChar(value, context, Errors, output);
249 }
250 },
251 'b' => {
252 radix = 2;
253 uppercase = false;
254 width = 0;
255 },
256 'd' => {
257 radix = 10;
258 uppercase = false;
259 width = 0;
260 },
261 'x' => {
262 radix = 16;
263 uppercase = false;
264 width = 0;
265 },
266 'X' => {
267 radix = 16;
268 uppercase = true;
269 width = 0;
270 },
271 else => @compileError("Unknown format character: " ++ []u8{fmt[0]}),
272 }
273 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
274 }
275 return formatInt(value, radix, uppercase, width, context, Errors, output);
245276}
246277
247pub fn formatBuf(buf: []const u8, width: usize,
248 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
249{
278fn formatFloatValue(
279 value: var,
280 comptime fmt: []const u8,
281 context: var,
282 comptime Errors: type,
283 output: fn (@typeOf(context), []const u8) Errors!void,
284) Errors!void {
285 comptime var width: ?usize = null;
286 comptime var float_fmt = 'e';
287 if (fmt.len > 0) {
288 float_fmt = fmt[0];
289 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
290 }
291
292 switch (float_fmt) {
293 'e' => try formatFloatScientific(value, width, context, Errors, output),
294 '.' => try formatFloatDecimal(value, width, context, Errors, output),
295 else => @compileError("Unknown format character: " ++ []u8{float_fmt}),
296 }
297}
298
299pub fn formatText(
300 bytes: []const u8,
301 comptime fmt: []const u8,
302 context: var,
303 comptime Errors: type,
304 output: fn (@typeOf(context), []const u8) Errors!void,
305) Errors!void {
306 if (fmt.len > 0) {
307 if (fmt[0] == 's') {
308 comptime var width = 0;
309 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
310 return formatBuf(bytes, width, context, Errors, output);
311 } else @compileError("Unknown format character: " ++ []u8{fmt[0]});
312 }
313 return output(context, bytes);
314}
315
316pub fn formatAsciiChar(
317 c: u8,
318 context: var,
319 comptime Errors: type,
320 output: fn (@typeOf(context), []const u8) Errors!void,
321) Errors!void {
322 return output(context, (*[1]u8)(&c)[0..]);
323}
324
325pub fn formatBuf(
326 buf: []const u8,
327 width: usize,
328 context: var,
329 comptime Errors: type,
330 output: fn (@typeOf(context), []const u8) Errors!void,
331) Errors!void {
250332 try output(context, buf);
251333
252334 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
253335 const pad_byte: u8 = ' ';
254336 while (leftover_padding > 0) : (leftover_padding -= 1) {
255 try output(context, (&pad_byte)[0..1]);
337 try output(context, (*[1]u8)(&pad_byte)[0..1]);
256338 }
257339}
258340
259pub fn formatFloat(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
260 var x = f64(value);
341// Print a float in scientific notation to the specified precision. Null uses full precision.
342// It should be the case that every full precision, printed value can be re-parsed back to the
343// same type unambiguously.
344pub fn formatFloatScientific(
345 value: var,
346 maybe_precision: ?usize,
347 context: var,
348 comptime Errors: type,
349 output: fn (@typeOf(context), []const u8) Errors!void,
350) Errors!void {
351 var x = @floatCast(f64, value);
261352
262353 // Errol doesn't handle these special cases.
263 if (math.isNan(x)) {
264 return output(context, "NaN");
265 }
266354 if (math.signbit(x)) {
267355 try output(context, "-");
268356 x = -x;
269357 }
358
359 if (math.isNan(x)) {
360 return output(context, "nan");
361 }
270362 if (math.isPositiveInf(x)) {
271 return output(context, "Infinity");
363 return output(context, "inf");
272364 }
273365 if (x == 0.0) {
274 return output(context, "0.0");
366 try output(context, "0");
367
368 if (maybe_precision) |precision| {
369 if (precision != 0) {
370 try output(context, ".");
371 var i: usize = 0;
372 while (i < precision) : (i += 1) {
373 try output(context, "0");
374 }
375 }
376 } else {
377 try output(context, ".0");
378 }
379
380 try output(context, "e+00");
381 return;
275382 }
276383
277384 var buffer: [32]u8 = undefined;
278 const float_decimal = errol3(x, buffer[0..]);
279 try output(context, float_decimal.digits[0..1]);
280 try output(context, ".");
281 if (float_decimal.digits.len > 1) {
282 const num_digits = if (@typeOf(value) == f32)
283 math.min(usize(9), float_decimal.digits.len)
284 else
285 float_decimal.digits.len;
286 try output(context, float_decimal.digits[1 .. num_digits]);
385 var float_decimal = errol.errol3(x, buffer[0..]);
386
387 if (maybe_precision) |precision| {
388 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
389
390 try output(context, float_decimal.digits[0..1]);
391
392 // {e0} case prints no `.`
393 if (precision != 0) {
394 try output(context, ".");
395
396 var printed: usize = 0;
397 if (float_decimal.digits.len > 1) {
398 const num_digits = math.min(float_decimal.digits.len, precision + 1);
399 try output(context, float_decimal.digits[1..num_digits]);
400 printed += num_digits - 1;
401 }
402
403 while (printed < precision) : (printed += 1) {
404 try output(context, "0");
405 }
406 }
287407 } else {
288 try output(context, "0");
408 try output(context, float_decimal.digits[0..1]);
409 try output(context, ".");
410 if (float_decimal.digits.len > 1) {
411 const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
412
413 try output(context, float_decimal.digits[1..num_digits]);
414 } else {
415 try output(context, "0");
416 }
289417 }
290418
291 if (float_decimal.exp != 1) {
292 try output(context, "e");
293 try formatInt(float_decimal.exp - 1, 10, false, 0, context, Errors, output);
419 try output(context, "e");
420 const exp = float_decimal.exp - 1;
421
422 if (exp >= 0) {
423 try output(context, "+");
424 if (exp > -10 and exp < 10) {
425 try output(context, "0");
426 }
427 try formatInt(exp, 10, false, 0, context, Errors, output);
428 } else {
429 try output(context, "-");
430 if (exp > -10 and exp < 10) {
431 try output(context, "0");
432 }
433 try formatInt(-exp, 10, false, 0, context, Errors, output);
294434 }
295435}
296436
297pub fn formatFloatDecimal(value: var, precision: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
437// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
438// By default floats are printed at full precision (no rounding).
439pub fn formatFloatDecimal(
440 value: var,
441 maybe_precision: ?usize,
442 context: var,
443 comptime Errors: type,
444 output: fn (@typeOf(context), []const u8) Errors!void,
445) Errors!void {
298446 var x = f64(value);
299447
300448 // Errol doesn't handle these special cases.
301 if (math.isNan(x)) {
302 return output(context, "NaN");
303 }
304449 if (math.signbit(x)) {
305450 try output(context, "-");
306451 x = -x;
307452 }
453
454 if (math.isNan(x)) {
455 return output(context, "nan");
456 }
308457 if (math.isPositiveInf(x)) {
309 return output(context, "Infinity");
458 return output(context, "inf");
310459 }
311460 if (x == 0.0) {
312 return output(context, "0.0");
461 try output(context, "0");
462
463 if (maybe_precision) |precision| {
464 if (precision != 0) {
465 try output(context, ".");
466 var i: usize = 0;
467 while (i < precision) : (i += 1) {
468 try output(context, "0");
469 }
470 } else {
471 try output(context, ".0");
472 }
473 } else {
474 try output(context, "0");
475 }
476
477 return;
313478 }
314479
480 // non-special case, use errol3
315481 var buffer: [32]u8 = undefined;
316 const float_decimal = errol3(x, buffer[0..]);
317
318 const num_left_digits = if (float_decimal.exp > 0) usize(float_decimal.exp) else 1;
319
320 try output(context, float_decimal.digits[0 .. num_left_digits]);
321 try output(context, ".");
322 if (float_decimal.digits.len > 1) {
323 const num_valid_digtis = if (@typeOf(value) == f32) math.min(usize(7), float_decimal.digits.len)
324 else
325 float_decimal.digits.len;
326
327 const num_right_digits = if (precision != 0)
328 math.min(precision, (num_valid_digtis-num_left_digits))
329 else
330 num_valid_digtis - num_left_digits;
331 try output(context, float_decimal.digits[num_left_digits .. (num_left_digits + num_right_digits)]);
482 var float_decimal = errol.errol3(x, buffer[0..]);
483
484 if (maybe_precision) |precision| {
485 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
486
487 // exp < 0 means the leading is always 0 as errol result is normalized.
488 var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
489
490 // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
491 var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
492
493 if (num_digits_whole > 0) {
494 // We may have to zero pad, for instance 1e4 requires zero padding.
495 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
496
497 var i = num_digits_whole_no_pad;
498 while (i < num_digits_whole) : (i += 1) {
499 try output(context, "0");
500 }
501 } else {
502 try output(context, "0");
503 }
504
505 // {.0} special case doesn't want a trailing '.'
506 if (precision == 0) {
507 return;
508 }
509
510 try output(context, ".");
511
512 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
513 var printed: usize = 0;
514
515 // Zero-fill until we reach significant digits or run out of precision.
516 if (float_decimal.exp <= 0) {
517 const zero_digit_count = @intCast(usize, -float_decimal.exp);
518 const zeros_to_print = math.min(zero_digit_count, precision);
519
520 var i: usize = 0;
521 while (i < zeros_to_print) : (i += 1) {
522 try output(context, "0");
523 printed += 1;
524 }
525
526 if (printed >= precision) {
527 return;
528 }
529 }
530
531 // Remaining fractional portion, zero-padding if insufficient.
532 debug.assert(precision >= printed);
533 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
534 try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
535 return;
536 } else {
537 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
538 printed += float_decimal.digits.len - num_digits_whole_no_pad;
539
540 while (printed < precision) : (printed += 1) {
541 try output(context, "0");
542 }
543 }
332544 } else {
333 try output(context, "0");
545 // exp < 0 means the leading is always 0 as errol result is normalized.
546 var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
547
548 // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
549 var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
550
551 if (num_digits_whole > 0) {
552 // We may have to zero pad, for instance 1e4 requires zero padding.
553 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
554
555 var i = num_digits_whole_no_pad;
556 while (i < num_digits_whole) : (i += 1) {
557 try output(context, "0");
558 }
559 } else {
560 try output(context, "0");
561 }
562
563 // Omit `.` if no fractional portion
564 if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
565 return;
566 }
567
568 try output(context, ".");
569
570 // Zero-fill until we reach significant digits or run out of precision.
571 if (float_decimal.exp < 0) {
572 const zero_digit_count = @intCast(usize, -float_decimal.exp);
573
574 var i: usize = 0;
575 while (i < zero_digit_count) : (i += 1) {
576 try output(context, "0");
577 }
578 }
579
580 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
334581 }
335582}
336583
584pub fn formatBytes(
585 value: var,
586 width: ?usize,
587 comptime radix: usize,
588 context: var,
589 comptime Errors: type,
590 output: fn (@typeOf(context), []const u8) Errors!void,
591) Errors!void {
592 if (value == 0) {
593 return output(context, "0B");
594 }
595
596 const mags_si = " kMGTPEZY";
597 const mags_iec = " KMGTPEZY";
598 const magnitude = switch (radix) {
599 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
600 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
601 else => unreachable,
602 };
603 const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
604 const suffix = switch (radix) {
605 1000 => mags_si[magnitude],
606 1024 => mags_iec[magnitude],
607 else => unreachable,
608 };
609
610 try formatFloatDecimal(new_value, width, context, Errors, output);
337611
338pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
339 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
340{
612 if (suffix == ' ') {
613 return output(context, "B");
614 }
615
616 const buf = switch (radix) {
617 1000 => []u8{ suffix, 'B' },
618 1024 => []u8{ suffix, 'i', 'B' },
619 else => unreachable,
620 };
621 return output(context, buf);
622}
623
624pub fn formatInt(
625 value: var,
626 base: u8,
627 uppercase: bool,
628 width: usize,
629 context: var,
630 comptime Errors: type,
631 output: fn (@typeOf(context), []const u8) Errors!void,
632) Errors!void {
341633 if (@typeOf(value).is_signed) {
342634 return formatIntSigned(value, base, uppercase, width, context, Errors, output);
343635 } else {
......@@ -345,30 +637,42 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
345637 }
346638}
347639
348fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
349 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
350{
640fn formatIntSigned(
641 value: var,
642 base: u8,
643 uppercase: bool,
644 width: usize,
645 context: var,
646 comptime Errors: type,
647 output: fn (@typeOf(context), []const u8) Errors!void,
648) Errors!void {
351649 const uint = @IntType(false, @typeOf(value).bit_count);
352650 if (value < 0) {
353651 const minus_sign: u8 = '-';
354 try output(context, (&minus_sign)[0..1]);
355 const new_value = uint(-(value + 1)) + 1;
652 try output(context, (*[1]u8)(&minus_sign)[0..]);
653 const new_value = @intCast(uint, -(value + 1)) + 1;
356654 const new_width = if (width == 0) 0 else (width - 1);
357655 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
358656 } else if (width == 0) {
359 return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output);
657 return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
360658 } else {
361659 const plus_sign: u8 = '+';
362 try output(context, (&plus_sign)[0..1]);
363 const new_value = uint(value);
660 try output(context, (*[1]u8)(&plus_sign)[0..]);
661 const new_value = @intCast(uint, value);
364662 const new_width = if (width == 0) 0 else (width - 1);
365663 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
366664 }
367665}
368666
369fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
370 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
371{
667fn formatIntUnsigned(
668 value: var,
669 base: u8,
670 uppercase: bool,
671 width: usize,
672 context: var,
673 comptime Errors: type,
674 output: fn (@typeOf(context), []const u8) Errors!void,
675) Errors!void {
372676 // max_int_digits accounts for the minus sign. when printing an unsigned
373677 // number we don't need to do that.
374678 var buf: [max_int_digits - 1]u8 = undefined;
......@@ -378,10 +682,9 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
378682 while (true) {
379683 const digit = a % base;
380684 index -= 1;
381 buf[index] = digitToChar(u8(digit), uppercase);
685 buf[index] = digitToChar(@intCast(u8, digit), uppercase);
382686 a /= base;
383 if (a == 0)
384 break;
687 if (a == 0) break;
385688 }
386689
387690 const digits_buf = buf[index..];
......@@ -391,22 +694,21 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
391694 const zero_byte: u8 = '0';
392695 var leftover_padding = padding - index;
393696 while (true) {
394 try output(context, (&zero_byte)[0..1]);
697 try output(context, (*[1]u8)(&zero_byte)[0..]);
395698 leftover_padding -= 1;
396 if (leftover_padding == 0)
397 break;
699 if (leftover_padding == 0) break;
398700 }
399701 mem.set(u8, buf[0..index], '0');
400702 return output(context, buf);
401703 } else {
402 const padded_buf = buf[index - padding..];
704 const padded_buf = buf[index - padding ..];
403705 mem.set(u8, padded_buf[0..padding], '0');
404706 return output(context, padded_buf);
405707 }
406708}
407709
408710pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
409 var context = FormatIntBuf {
711 var context = FormatIntBuf{
410712 .out_buf = out_buf,
411713 .index = 0,
412714 };
......@@ -417,16 +719,14 @@ const FormatIntBuf = struct {
417719 out_buf: []u8,
418720 index: usize,
419721};
420fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
722fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
421723 mem.copy(u8, context.out_buf[context.index..], bytes);
422724 context.index += bytes.len;
423725}
424726
425727pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
426 if (!T.is_signed)
427 return parseUnsigned(T, buf, radix);
428 if (buf.len == 0)
429 return T(0);
728 if (!T.is_signed) return parseUnsigned(T, buf, radix);
729 if (buf.len == 0) return T(0);
430730 if (buf[0] == '-') {
431731 return math.negate(try parseUnsigned(T, buf[1..], radix));
432732 } else if (buf[0] == '+') {
......@@ -446,9 +746,10 @@ test "fmt.parseInt" {
446746 assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
447747}
448748
449const ParseUnsignedError = error {
749const ParseUnsignedError = error{
450750 /// The result cannot fit in the type specified
451751 Overflow,
752
452753 /// The input had a byte that was not a digit
453754 InvalidCharacter,
454755};
......@@ -467,22 +768,21 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
467768
468769pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
469770 const value = switch (c) {
470 '0' ... '9' => c - '0',
471 'A' ... 'Z' => c - 'A' + 10,
472 'a' ... 'z' => c - 'a' + 10,
771 '0'...'9' => c - '0',
772 'A'...'Z' => c - 'A' + 10,
773 'a'...'z' => c - 'a' + 10,
473774 else => return error.InvalidCharacter,
474775 };
475776
476 if (value >= radix)
477 return error.InvalidCharacter;
777 if (value >= radix) return error.InvalidCharacter;
478778
479779 return value;
480780}
481781
482782fn digitToChar(digit: u8, uppercase: bool) u8 {
483783 return switch (digit) {
484 0 ... 9 => digit + '0',
485 10 ... 35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
784 0...9 => digit + '0',
785 10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
486786 else => unreachable,
487787 };
488788}
......@@ -491,27 +791,31 @@ const BufPrintContext = struct {
491791 remaining: []u8,
492792};
493793
494fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
794fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
495795 if (context.remaining.len < bytes.len) return error.BufferTooSmall;
496796 mem.copy(u8, context.remaining, bytes);
497797 context.remaining = context.remaining[bytes.len..];
498798}
499799
500800pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
501 var context = BufPrintContext { .remaining = buf, };
801 var context = BufPrintContext{ .remaining = buf };
502802 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
503 return buf[0..buf.len - context.remaining.len];
803 return buf[0 .. buf.len - context.remaining.len];
504804}
505805
506pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {
806pub const AllocPrintError = error{OutOfMemory};
807
808pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) AllocPrintError![]u8 {
507809 var size: usize = 0;
508810 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
509811 const buf = try allocator.alloc(u8, size);
510 return bufPrint(buf, fmt, args);
812 return bufPrint(buf, fmt, args) catch |err| switch (err) {
813 error.BufferTooSmall => unreachable, // we just counted the size above
814 };
511815}
512816
513fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
514 *size += bytes.len;
817fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
818 size.* += bytes.len;
515819}
516820
517821test "buf print int" {
......@@ -552,117 +856,329 @@ test "parse unsigned comptime" {
552856
553857test "fmt.format" {
554858 {
555 var buf1: [32]u8 = undefined;
556859 const value: ?i32 = 1234;
557 const result = try bufPrint(buf1[0..], "nullable: {}\n", value);
558 assert(mem.eql(u8, result, "nullable: 1234\n"));
860 try testFmt("optional: 1234\n", "optional: {}\n", value);
559861 }
560862 {
561 var buf1: [32]u8 = undefined;
562863 const value: ?i32 = null;
563 const result = try bufPrint(buf1[0..], "nullable: {}\n", value);
564 assert(mem.eql(u8, result, "nullable: null\n"));
864 try testFmt("optional: null\n", "optional: {}\n", value);
565865 }
566866 {
567 var buf1: [32]u8 = undefined;
568867 const value: error!i32 = 1234;
569 const result = try bufPrint(buf1[0..], "error union: {}\n", value);
570 assert(mem.eql(u8, result, "error union: 1234\n"));
868 try testFmt("error union: 1234\n", "error union: {}\n", value);
571869 }
572870 {
573 var buf1: [32]u8 = undefined;
574871 const value: error!i32 = error.InvalidChar;
575 const result = try bufPrint(buf1[0..], "error union: {}\n", value);
576 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
872 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
577873 }
578874 {
579 var buf1: [32]u8 = undefined;
580875 const value: u3 = 0b101;
581 const result = try bufPrint(buf1[0..], "u3: {}\n", value);
582 assert(mem.eql(u8, result, "u3: 5\n"));
876 try testFmt("u3: 5\n", "u3: {}\n", value);
877 }
878 {
879 const value: u8 = 'a';
880 try testFmt("u8: a\n", "u8: {c}\n", value);
881 }
882 {
883 const value: u8 = 0b1100;
884 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
885 }
886 {
887 const value: [3]u8 = "abc";
888 try testFmt("array: abc\n", "array: {}\n", value);
889 try testFmt("array: abc\n", "array: {}\n", &value);
890
891 var buf: [100]u8 = undefined;
892 try testFmt(
893 try bufPrint(buf[0..], "array: [3]u8@{x}\n", @ptrToInt(&value)),
894 "array: {*}\n",
895 &value,
896 );
897 }
898 {
899 const value: []const u8 = "abc";
900 try testFmt("slice: abc\n", "slice: {}\n", value);
901 }
902 {
903 const value = @intToPtr(*i32, 0xdeadbeef);
904 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
905 try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
583906 }
907 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
908 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
909 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
910 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
911 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
912 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
584913 {
585 // Dummy field because of https://github.com/zig-lang/zig/issues/557.
914 // Dummy field because of https://github.com/ziglang/zig/issues/557.
586915 const Struct = struct {
587916 unused: u8,
588917 };
589918 var buf1: [32]u8 = undefined;
590 const value = Struct {
591 .unused = 42,
592 };
919 const value = Struct{ .unused = 42 };
593920 const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);
594921 assert(mem.startsWith(u8, result, "pointer: Struct@"));
595922 }
596
597 // TODO get these tests passing in release modes
598 // https://github.com/zig-lang/zig/issues/564
599 if (builtin.mode == builtin.Mode.Debug) {
600 {
601 var buf1: [32]u8 = undefined;
602 const value: f32 = 12.34;
603 const result = try bufPrint(buf1[0..], "f32: {}\n", value);
604 assert(mem.eql(u8, result, "f32: 1.23400001e1\n"));
605 }
606 {
607 var buf1: [32]u8 = undefined;
608 const value: f64 = -12.34e10;
609 const result = try bufPrint(buf1[0..], "f64: {}\n", value);
610 assert(mem.eql(u8, result, "f64: -1.234e11\n"));
611 }
612 {
613 var buf1: [32]u8 = undefined;
614 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
615 assert(mem.eql(u8, result, "f64: NaN\n"));
616 }
617 {
618 var buf1: [32]u8 = undefined;
619 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
620 assert(mem.eql(u8, result, "f64: Infinity\n"));
621 }
622 {
623 var buf1: [32]u8 = undefined;
624 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
625 assert(mem.eql(u8, result, "f64: -Infinity\n"));
626 }
627 {
628 var buf1: [32]u8 = undefined;
629 const value: f32 = 1.1234;
630 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
631 assert(mem.eql(u8, result, "f32: 1.1\n"));
632 }
633 {
634 var buf1: [32]u8 = undefined;
635 const value: f32 = 1234.567;
636 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
637 assert(mem.eql(u8, result, "f32: 1234.56\n"));
638 }
639 {
640 var buf1: [32]u8 = undefined;
641 const value: f32 = -11.1234;
642 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
643 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
644 // -11.12339... is truncated to -11.1233
645 assert(mem.eql(u8, result, "f32: -11.1233\n"));
646 }
647 {
648 var buf1: [32]u8 = undefined;
649 const value: f32 = 91.12345;
650 const result = try bufPrint(buf1[0..], "f32: {.}\n", value);
651 assert(mem.eql(u8, result, "f32: 91.12345\n"));
652 }
653 {
923 {
924 var buf1: [32]u8 = undefined;
925 const value: f32 = 1.34;
926 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
927 assert(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
928 }
929 {
930 var buf1: [32]u8 = undefined;
931 const value: f32 = 12.34;
932 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
933 assert(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
934 }
935 {
936 var buf1: [32]u8 = undefined;
937 const value: f64 = -12.34e10;
938 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
939 assert(mem.eql(u8, result, "f64: -1.234e+11\n"));
940 }
941 {
942 // This fails on release due to a minor rounding difference.
943 // --release-fast outputs 9.999960000000001e-40 vs. the expected.
944 if (builtin.mode == builtin.Mode.Debug) {
654945 var buf1: [32]u8 = undefined;
655 const value: f64 = 91.12345678901235;
656 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
657 assert(mem.eql(u8, result, "f64: 91.1234567890\n"));
946 const value: f64 = 9.999960e-40;
947 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
948 assert(mem.eql(u8, result, "f64: 9.99996e-40\n"));
658949 }
950 }
951 {
952 var buf1: [32]u8 = undefined;
953 const value: f64 = 1.409706e-42;
954 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
955 assert(mem.eql(u8, result, "f64: 1.40971e-42\n"));
956 }
957 {
958 var buf1: [32]u8 = undefined;
959 const value: f64 = @bitCast(f32, u32(814313563));
960 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
961 assert(mem.eql(u8, result, "f64: 1.00000e-09\n"));
962 }
963 {
964 var buf1: [32]u8 = undefined;
965 const value: f64 = @bitCast(f32, u32(1006632960));
966 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
967 assert(mem.eql(u8, result, "f64: 7.81250e-03\n"));
968 }
969 {
970 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
971 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
972 var buf1: [32]u8 = undefined;
973 const value: f64 = @bitCast(f32, u32(1203982400));
974 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
975 assert(mem.eql(u8, result, "f64: 1.00001e+05\n"));
976 }
977 {
978 var buf1: [32]u8 = undefined;
979 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
980 assert(mem.eql(u8, result, "f64: nan\n"));
981 }
982 {
983 var buf1: [32]u8 = undefined;
984 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
985 assert(mem.eql(u8, result, "f64: -nan\n"));
986 }
987 {
988 var buf1: [32]u8 = undefined;
989 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
990 assert(mem.eql(u8, result, "f64: inf\n"));
991 }
992 {
993 var buf1: [32]u8 = undefined;
994 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
995 assert(mem.eql(u8, result, "f64: -inf\n"));
996 }
997 {
998 var buf1: [64]u8 = undefined;
999 const value: f64 = 1.52314e+29;
1000 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
1001 assert(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
1002 }
1003 {
1004 var buf1: [32]u8 = undefined;
1005 const value: f32 = 1.1234;
1006 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
1007 assert(mem.eql(u8, result, "f32: 1.1\n"));
1008 }
1009 {
1010 var buf1: [32]u8 = undefined;
1011 const value: f32 = 1234.567;
1012 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
1013 assert(mem.eql(u8, result, "f32: 1234.57\n"));
1014 }
1015 {
1016 var buf1: [32]u8 = undefined;
1017 const value: f32 = -11.1234;
1018 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
1019 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1020 // -11.12339... is rounded back up to -11.1234
1021 assert(mem.eql(u8, result, "f32: -11.1234\n"));
1022 }
1023 {
1024 var buf1: [32]u8 = undefined;
1025 const value: f32 = 91.12345;
1026 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
1027 assert(mem.eql(u8, result, "f32: 91.12345\n"));
1028 }
1029 {
1030 var buf1: [32]u8 = undefined;
1031 const value: f64 = 91.12345678901235;
1032 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
1033 assert(mem.eql(u8, result, "f64: 91.1234567890\n"));
1034 }
1035 {
1036 var buf1: [32]u8 = undefined;
1037 const value: f64 = 0.0;
1038 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1039 assert(mem.eql(u8, result, "f64: 0.00000\n"));
1040 }
1041 {
1042 var buf1: [32]u8 = undefined;
1043 const value: f64 = 5.700;
1044 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
1045 assert(mem.eql(u8, result, "f64: 6\n"));
1046 }
1047 {
1048 var buf1: [32]u8 = undefined;
1049 const value: f64 = 9.999;
1050 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
1051 assert(mem.eql(u8, result, "f64: 10.0\n"));
1052 }
1053 {
1054 var buf1: [32]u8 = undefined;
1055 const value: f64 = 1.0;
1056 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
1057 assert(mem.eql(u8, result, "f64: 1.000\n"));
1058 }
1059 {
1060 var buf1: [32]u8 = undefined;
1061 const value: f64 = 0.0003;
1062 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
1063 assert(mem.eql(u8, result, "f64: 0.00030000\n"));
1064 }
1065 {
1066 var buf1: [32]u8 = undefined;
1067 const value: f64 = 1.40130e-45;
1068 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1069 assert(mem.eql(u8, result, "f64: 0.00000\n"));
1070 }
1071 {
1072 var buf1: [32]u8 = undefined;
1073 const value: f64 = 9.999960e-40;
1074 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1075 assert(mem.eql(u8, result, "f64: 0.00000\n"));
1076 }
1077 // libc checks
1078 {
1079 var buf1: [32]u8 = undefined;
1080 const value: f64 = f64(@bitCast(f32, u32(916964781)));
1081 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1082 assert(mem.eql(u8, result, "f64: 0.00001\n"));
1083 }
1084 {
1085 var buf1: [32]u8 = undefined;
1086 const value: f64 = f64(@bitCast(f32, u32(925353389)));
1087 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1088 assert(mem.eql(u8, result, "f64: 0.00001\n"));
1089 }
1090 {
1091 var buf1: [32]u8 = undefined;
1092 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
1093 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1094 assert(mem.eql(u8, result, "f64: 0.10000\n"));
1095 }
1096 {
1097 var buf1: [32]u8 = undefined;
1098 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
1099 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1100 assert(mem.eql(u8, result, "f64: 1.00000\n"));
1101 }
1102 {
1103 var buf1: [32]u8 = undefined;
1104 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
1105 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1106 assert(mem.eql(u8, result, "f64: 10.00000\n"));
1107 }
1108 // libc differences
1109 {
1110 var buf1: [32]u8 = undefined;
1111 // This is 0.015625 exactly according to gdb. We thus round down,
1112 // however glibc rounds up for some reason. This occurs for all
1113 // floats of the form x.yyyy25 on a precision point.
1114 const value: f64 = f64(@bitCast(f32, u32(1015021568)));
1115 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1116 assert(mem.eql(u8, result, "f64: 0.01563\n"));
1117 }
1118 // std-windows-x86_64-Debug-bare test case fails
1119 {
1120 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1121 // also rounds to 630 so I'm inclined to believe libc is not
1122 // optimal here.
1123 var buf1: [32]u8 = undefined;
1124 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
1125 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1126 assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1127 }
1128 //custom type format
1129 {
1130 const Vec2 = struct {
1131 const SelfType = this;
1132 x: f32,
1133 y: f32,
6591134
1135 pub fn format(
1136 self: *SelfType,
1137 comptime fmt: []const u8,
1138 context: var,
1139 comptime Errors: type,
1140 output: fn (@typeOf(context), []const u8) Errors!void,
1141 ) Errors!void {
1142 if (fmt.len > 0) {
1143 if (fmt.len > 1) unreachable;
1144 switch (fmt[0]) {
1145 //point format
1146 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1147 //dimension format
1148 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1149 else => unreachable,
1150 }
1151 }
1152 return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y);
1153 }
1154 };
1155
1156 var buf1: [32]u8 = undefined;
1157 var value = Vec2{
1158 .x = 10.2,
1159 .y = 2.22,
1160 };
1161 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1162 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
6601163 }
6611164}
6621165
1166fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
1167 var buf: [100]u8 = undefined;
1168 const result = try bufPrint(buf[0..], template, args);
1169 if (mem.eql(u8, result, expected)) return;
1170
1171 std.debug.warn("\n====== expected this output: =========\n");
1172 std.debug.warn("{}", expected);
1173 std.debug.warn("\n======== instead found this: =========\n");
1174 std.debug.warn("{}", result);
1175 std.debug.warn("\n======================================\n");
1176 return error.TestFailed;
1177}
1178
6631179pub fn trim(buf: []const u8) []const u8 {
6641180 var start: usize = 0;
665 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) { }
1181 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
6661182
6671183 var end: usize = buf.len;
6681184 while (true) {
......@@ -674,7 +1190,6 @@ pub fn trim(buf: []const u8) []const u8 {
6741190 }
6751191 }
6761192 break;
677
6781193 }
6791194 return buf[start..end];
6801195}
std/hash/adler.zig+8-13
......@@ -13,14 +13,12 @@ pub const Adler32 = struct {
1313 adler: u32,
1414
1515 pub fn init() Adler32 {
16 return Adler32 {
17 .adler = 1,
18 };
16 return Adler32{ .adler = 1 };
1917 }
2018
2119 // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
2220 // buffer inputs and should be much quicker.
23 pub fn update(self: &Adler32, input: []const u8) void {
21 pub fn update(self: *Adler32, input: []const u8) void {
2422 var s1 = self.adler & 0xffff;
2523 var s2 = (self.adler >> 16) & 0xffff;
2624
......@@ -33,8 +31,7 @@ pub const Adler32 = struct {
3331 if (s2 >= base) {
3432 s2 -= base;
3533 }
36 }
37 else if (input.len < 16) {
34 } else if (input.len < 16) {
3835 for (input) |b| {
3936 s1 +%= b;
4037 s2 +%= s1;
......@@ -44,8 +41,7 @@ pub const Adler32 = struct {
4441 }
4542
4643 s2 %= base;
47 }
48 else {
44 } else {
4945 var i: usize = 0;
5046 while (i + nmax <= input.len) : (i += nmax) {
5147 const n = nmax / 16; // note: 16 | nmax
......@@ -81,7 +77,7 @@ pub const Adler32 = struct {
8177 self.adler = s1 | (s2 << 16);
8278 }
8379
84 pub fn final(self: &Adler32) u32 {
80 pub fn final(self: *Adler32) u32 {
8581 return self.adler;
8682 }
8783
......@@ -98,15 +94,14 @@ test "adler32 sanity" {
9894}
9995
10096test "adler32 long" {
101 const long1 = []u8 {1} ** 1024;
97 const long1 = []u8{1} ** 1024;
10298 debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
10399
104 const long2 = []u8 {1} ** 1025;
100 const long2 = []u8{1} ** 1025;
105101 debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
106102}
107103
108104test "adler32 very long" {
109 const long = []u8 {1} ** 5553;
105 const long = []u8{1} ** 5553;
110106 debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
111107}
112
std/hash/crc.zig+23-24
......@@ -9,9 +9,9 @@ const std = @import("../index.zig");
99const debug = std.debug;
1010
1111pub const Polynomial = struct {
12 const IEEE = 0xedb88320;
12 const IEEE = 0xedb88320;
1313 const Castagnoli = 0x82f63b78;
14 const Koopman = 0xeb31d82e;
14 const Koopman = 0xeb31d82e;
1515};
1616
1717// IEEE is by far the most common CRC and so is aliased by default.
......@@ -26,21 +26,23 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
2626 var tables: [8][256]u32 = undefined;
2727
2828 for (tables[0]) |*e, i| {
29 var crc = u32(i);
30 var j: usize = 0; while (j < 8) : (j += 1) {
29 var crc = @intCast(u32, i);
30 var j: usize = 0;
31 while (j < 8) : (j += 1) {
3132 if (crc & 1 == 1) {
3233 crc = (crc >> 1) ^ poly;
3334 } else {
3435 crc = (crc >> 1);
3536 }
3637 }
37 *e = crc;
38 e.* = crc;
3839 }
3940
4041 var i: usize = 0;
4142 while (i < 256) : (i += 1) {
4243 var crc = tables[0][i];
43 var j: usize = 1; while (j < 8) : (j += 1) {
44 var j: usize = 1;
45 while (j < 8) : (j += 1) {
4446 const index = @truncate(u8, crc);
4547 crc = tables[0][index] ^ (crc >> 8);
4648 tables[j][i] = crc;
......@@ -53,19 +55,17 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
5355 crc: u32,
5456
5557 pub fn init() Self {
56 return Self {
57 .crc = 0xffffffff,
58 };
58 return Self{ .crc = 0xffffffff };
5959 }
6060
61 pub fn update(self: &Self, input: []const u8) void {
61 pub fn update(self: *Self, input: []const u8) void {
6262 var i: usize = 0;
6363 while (i + 8 <= input.len) : (i += 8) {
64 const p = input[i..i+8];
64 const p = input[i .. i + 8];
6565
6666 // Unrolling this way gives ~50Mb/s increase
67 self.crc ^= (u32(p[0]) << 0);
68 self.crc ^= (u32(p[1]) << 8);
67 self.crc ^= (u32(p[0]) << 0);
68 self.crc ^= (u32(p[1]) << 8);
6969 self.crc ^= (u32(p[2]) << 16);
7070 self.crc ^= (u32(p[3]) << 24);
7171
......@@ -76,8 +76,8 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
7676 lookup_tables[3][p[4]] ^
7777 lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
7878 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)];
79 lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
80 lookup_tables[7][@truncate(u8, self.crc >> 0)];
8181 }
8282
8383 while (i < input.len) : (i += 1) {
......@@ -86,7 +86,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
8686 }
8787 }
8888
89 pub fn final(self: &Self) u32 {
89 pub fn final(self: *Self) u32 {
9090 return ~self.crc;
9191 }
9292
......@@ -122,15 +122,16 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
122122 var table: [16]u32 = undefined;
123123
124124 for (table) |*e, i| {
125 var crc = u32(i * 16);
126 var j: usize = 0; while (j < 8) : (j += 1) {
125 var crc = @intCast(u32, i * 16);
126 var j: usize = 0;
127 while (j < 8) : (j += 1) {
127128 if (crc & 1 == 1) {
128129 crc = (crc >> 1) ^ poly;
129130 } else {
130131 crc = (crc >> 1);
131132 }
132133 }
133 *e = crc;
134 e.* = crc;
134135 }
135136
136137 break :block table;
......@@ -139,19 +140,17 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
139140 crc: u32,
140141
141142 pub fn init() Self {
142 return Self {
143 .crc = 0xffffffff,
144 };
143 return Self{ .crc = 0xffffffff };
145144 }
146145
147 pub fn update(self: &Self, input: []const u8) void {
146 pub fn update(self: *Self, input: []const u8) void {
148147 for (input) |b| {
149148 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 0))] ^ (self.crc >> 4);
150149 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 4))] ^ (self.crc >> 4);
151150 }
152151 }
153152
154 pub fn final(self: &Self) u32 {
153 pub fn final(self: *Self) u32 {
155154 return ~self.crc;
156155 }
157156
std/hash/fnv.zig+4-6
......@@ -7,7 +7,7 @@
77const std = @import("../index.zig");
88const debug = std.debug;
99
10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5);
10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);
1111pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
1212pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d);
1313
......@@ -18,19 +18,17 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
1818 value: T,
1919
2020 pub fn init() Self {
21 return Self {
22 .value = offset,
23 };
21 return Self{ .value = offset };
2422 }
2523
26 pub fn update(self: &Self, input: []const u8) void {
24 pub fn update(self: *Self, input: []const u8) void {
2725 for (input) |b| {
2826 self.value ^= b;
2927 self.value *%= prime;
3028 }
3129 }
3230
33 pub fn final(self: &Self) T {
31 pub fn final(self: *Self) T {
3432 return self.value;
3533 }
3634
std/hash/siphash.zig+11-11
......@@ -45,7 +45,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
4545 const k0 = mem.readInt(key[0..8], u64, Endian.Little);
4646 const k1 = mem.readInt(key[8..16], u64, Endian.Little);
4747
48 var d = Self {
48 var d = Self{
4949 .v0 = k0 ^ 0x736f6d6570736575,
5050 .v1 = k1 ^ 0x646f72616e646f6d,
5151 .v2 = k0 ^ 0x6c7967656e657261,
......@@ -63,7 +63,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
6363 return d;
6464 }
6565
66 pub fn update(d: &Self, b: []const u8) void {
66 pub fn update(d: *Self, b: []const u8) void {
6767 var off: usize = 0;
6868
6969 // Partial from previous.
......@@ -76,16 +76,16 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
7676
7777 // Full middle blocks.
7878 while (off + 8 <= b.len) : (off += 8) {
79 d.round(b[off..off + 8]);
79 d.round(b[off .. off + 8]);
8080 }
8181
8282 // Remainder for next pass.
8383 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
84 d.buf_len += u8(b[off..].len);
84 d.buf_len += @intCast(u8, b[off..].len);
8585 d.msg_len +%= @truncate(u8, b.len);
8686 }
8787
88 pub fn final(d: &Self) T {
88 pub fn final(d: *Self) T {
8989 // Padding
9090 mem.set(u8, d.buf[d.buf_len..], 0);
9191 d.buf[7] = d.msg_len;
......@@ -118,7 +118,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
118118 return (u128(b2) << 64) | b1;
119119 }
120120
121 fn round(d: &Self, b: []const u8) void {
121 fn round(d: *Self, b: []const u8) void {
122122 debug.assert(b.len == 8);
123123
124124 const m = mem.readInt(b[0..], u64, Endian.Little);
......@@ -132,7 +132,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
132132 d.v0 ^= m;
133133 }
134134
135 fn sipRound(d: &Self) void {
135 fn sipRound(d: *Self) void {
136136 d.v0 +%= d.v1;
137137 d.v1 = math.rotl(u64, d.v1, u64(13));
138138 d.v1 ^= d.v0;
......@@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
162162const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
163163
164164test "siphash64-2-4 sanity" {
165 const vectors = [][]const u8 {
165 const vectors = [][]const u8{
166166 "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
167167 "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
168168 "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
......@@ -233,7 +233,7 @@ test "siphash64-2-4 sanity" {
233233
234234 var buffer: [64]u8 = undefined;
235235 for (vectors) |vector, i| {
236 buffer[i] = u8(i);
236 buffer[i] = @intCast(u8, i);
237237
238238 const expected = mem.readInt(vector, u64, Endian.Little);
239239 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
......@@ -241,7 +241,7 @@ test "siphash64-2-4 sanity" {
241241}
242242
243243test "siphash128-2-4 sanity" {
244 const vectors = [][]const u8 {
244 const vectors = [][]const u8{
245245 "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
246246 "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
247247 "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
......@@ -312,7 +312,7 @@ test "siphash128-2-4 sanity" {
312312
313313 var buffer: [64]u8 = undefined;
314314 for (vectors) |vector, i| {
315 buffer[i] = u8(i);
315 buffer[i] = @intCast(u8, i);
316316
317317 const expected = mem.readInt(vector, u128, Endian.Little);
318318 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
std/hash_map.zig+129-65
......@@ -9,15 +9,12 @@ const builtin = @import("builtin");
99const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;
1010const debug_u32 = if (want_modification_safety) u32 else void;
1111
12pub fn HashMap(comptime K: type, comptime V: type,
13 comptime hash: fn(key: K)u32,
14 comptime eql: fn(a: K, b: K)bool) type
15{
12pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u32, comptime eql: fn (a: K, b: K) bool) type {
1613 return struct {
1714 entries: []Entry,
1815 size: usize,
1916 max_distance_from_start_index: usize,
20 allocator: &Allocator,
17 allocator: *Allocator,
2118 // this is used to detect bugs where a hashtable is edited while an iterator is running.
2219 modification_count: debug_u32,
2320
......@@ -31,7 +28,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
3128 };
3229
3330 pub const Iterator = struct {
34 hm: &const Self,
31 hm: *const Self,
3532 // how many items have we returned
3633 count: usize,
3734 // iterator through the entry array
......@@ -39,7 +36,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
3936 // used to detect concurrent modification
4037 initial_modification_count: debug_u32,
4138
42 pub fn next(it: &Iterator) ?&Entry {
39 pub fn next(it: *Iterator) ?*Entry {
4340 if (want_modification_safety) {
4441 assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification
4542 }
......@@ -54,10 +51,18 @@ pub fn HashMap(comptime K: type, comptime V: type,
5451 }
5552 unreachable; // no next item
5653 }
54
55 // Reset the iterator to the initial index
56 pub fn reset(it: *Iterator) void {
57 it.count = 0;
58 it.index = 0;
59 // Resetting the modification count too
60 it.initial_modification_count = it.hm.modification_count;
61 }
5762 };
5863
59 pub fn init(allocator: &Allocator) Self {
60 return Self {
64 pub fn init(allocator: *Allocator) Self {
65 return Self{
6166 .entries = []Entry{},
6267 .allocator = allocator,
6368 .size = 0,
......@@ -66,11 +71,11 @@ pub fn HashMap(comptime K: type, comptime V: type,
6671 };
6772 }
6873
69 pub fn deinit(hm: &Self) void {
74 pub fn deinit(hm: *const Self) void {
7075 hm.allocator.free(hm.entries);
7176 }
7277
73 pub fn clear(hm: &Self) void {
78 pub fn clear(hm: *Self) void {
7479 for (hm.entries) |*entry| {
7580 entry.used = false;
7681 }
......@@ -79,8 +84,12 @@ pub fn HashMap(comptime K: type, comptime V: type,
7984 hm.incrementModificationCount();
8085 }
8186
87 pub fn count(hm: *const Self) usize {
88 return hm.size;
89 }
90
8291 /// Returns the value that was already there.
83 pub fn put(hm: &Self, key: K, value: &const V) !?V {
92 pub fn put(hm: *Self, key: K, value: *const V) !?V {
8493 if (hm.entries.len == 0) {
8594 try hm.initCapacity(16);
8695 }
......@@ -102,49 +111,51 @@ pub fn HashMap(comptime K: type, comptime V: type,
102111 return hm.internalPut(key, value);
103112 }
104113
105 pub fn get(hm: &Self, key: K) ?&Entry {
114 pub fn get(hm: *const Self, key: K) ?*Entry {
106115 if (hm.entries.len == 0) {
107116 return null;
108117 }
109118 return hm.internalGet(key);
110119 }
111120
112 pub fn contains(hm: &Self, key: K) bool {
121 pub fn contains(hm: *const Self, key: K) bool {
113122 return hm.get(key) != null;
114123 }
115124
116 pub fn remove(hm: &Self, key: K) ?&Entry {
125 pub fn remove(hm: *Self, key: K) ?*Entry {
117126 if (hm.entries.len == 0) return null;
118127 hm.incrementModificationCount();
119128 const start_index = hm.keyToIndex(key);
120 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
121 const index = (start_index + roll_over) % hm.entries.len;
122 var entry = &hm.entries[index];
123
124 if (!entry.used)
125 return null;
126
127 if (!eql(entry.key, key)) continue;
128
129 while (roll_over < hm.entries.len) : (roll_over += 1) {
130 const next_index = (start_index + roll_over + 1) % hm.entries.len;
131 const next_entry = &hm.entries[next_index];
132 if (!next_entry.used or next_entry.distance_from_start_index == 0) {
133 entry.used = false;
134 hm.size -= 1;
135 return entry;
129 {
130 var roll_over: usize = 0;
131 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
132 const index = (start_index + roll_over) % hm.entries.len;
133 var entry = &hm.entries[index];
134
135 if (!entry.used) return null;
136
137 if (!eql(entry.key, key)) continue;
138
139 while (roll_over < hm.entries.len) : (roll_over += 1) {
140 const next_index = (start_index + roll_over + 1) % hm.entries.len;
141 const next_entry = &hm.entries[next_index];
142 if (!next_entry.used or next_entry.distance_from_start_index == 0) {
143 entry.used = false;
144 hm.size -= 1;
145 return entry;
146 }
147 entry.* = next_entry.*;
148 entry.distance_from_start_index -= 1;
149 entry = next_entry;
136150 }
137 *entry = *next_entry;
138 entry.distance_from_start_index -= 1;
139 entry = next_entry;
151 unreachable; // shifting everything in the table
140152 }
141 unreachable; // shifting everything in the table
142 }}
153 }
143154 return null;
144155 }
145156
146 pub fn iterator(hm: &const Self) Iterator {
147 return Iterator {
157 pub fn iterator(hm: *const Self) Iterator {
158 return Iterator{
148159 .hm = hm,
149160 .count = 0,
150161 .index = 0,
......@@ -152,7 +163,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
152163 };
153164 }
154165
155 fn initCapacity(hm: &Self, capacity: usize) !void {
166 fn initCapacity(hm: *Self, capacity: usize) !void {
156167 hm.entries = try hm.allocator.alloc(Entry, capacity);
157168 hm.size = 0;
158169 hm.max_distance_from_start_index = 0;
......@@ -161,30 +172,32 @@ pub fn HashMap(comptime K: type, comptime V: type,
161172 }
162173 }
163174
164 fn incrementModificationCount(hm: &Self) void {
175 fn incrementModificationCount(hm: *Self) void {
165176 if (want_modification_safety) {
166177 hm.modification_count +%= 1;
167178 }
168179 }
169180
170181 /// Returns the value that was already there.
171 fn internalPut(hm: &Self, orig_key: K, orig_value: &const V) ?V {
182 fn internalPut(hm: *Self, orig_key: K, orig_value: *const V) ?V {
172183 var key = orig_key;
173 var value = *orig_value;
184 var value = orig_value.*;
174185 const start_index = hm.keyToIndex(key);
175186 var roll_over: usize = 0;
176187 var distance_from_start_index: usize = 0;
177 while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) {
188 while (roll_over < hm.entries.len) : ({
189 roll_over += 1;
190 distance_from_start_index += 1;
191 }) {
178192 const index = (start_index + roll_over) % hm.entries.len;
179193 const entry = &hm.entries[index];
180194
181195 if (entry.used and !eql(entry.key, key)) {
182196 if (entry.distance_from_start_index < distance_from_start_index) {
183197 // robin hood to the rescue
184 const tmp = *entry;
185 hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,
186 distance_from_start_index);
187 *entry = Entry {
198 const tmp = entry.*;
199 hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index, distance_from_start_index);
200 entry.* = Entry{
188201 .used = true,
189202 .distance_from_start_index = distance_from_start_index,
190203 .key = key,
......@@ -207,7 +220,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
207220 }
208221
209222 hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);
210 *entry = Entry {
223 entry.* = Entry{
211224 .used = true,
212225 .distance_from_start_index = distance_from_start_index,
213226 .key = key,
......@@ -218,19 +231,22 @@ pub fn HashMap(comptime K: type, comptime V: type,
218231 unreachable; // put into a full map
219232 }
220233
221 fn internalGet(hm: &Self, key: K) ?&Entry {
234 fn internalGet(hm: *const Self, key: K) ?*Entry {
222235 const start_index = hm.keyToIndex(key);
223 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
224 const index = (start_index + roll_over) % hm.entries.len;
225 const entry = &hm.entries[index];
226
227 if (!entry.used) return null;
228 if (eql(entry.key, key)) return entry;
229 }}
236 {
237 var roll_over: usize = 0;
238 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
239 const index = (start_index + roll_over) % hm.entries.len;
240 const entry = &hm.entries[index];
241
242 if (!entry.used) return null;
243 if (eql(entry.key, key)) return entry;
244 }
245 }
230246 return null;
231247 }
232248
233 fn keyToIndex(hm: &Self, key: K) usize {
249 fn keyToIndex(hm: *const Self, key: K) usize {
234250 return usize(hash(key)) % hm.entries.len;
235251 }
236252 };
......@@ -243,21 +259,69 @@ test "basic hash map usage" {
243259 var map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
244260 defer map.deinit();
245261
246 assert((map.put(1, 11) catch unreachable) == null);
247 assert((map.put(2, 22) catch unreachable) == null);
248 assert((map.put(3, 33) catch unreachable) == null);
249 assert((map.put(4, 44) catch unreachable) == null);
250 assert((map.put(5, 55) catch unreachable) == null);
262 assert((try map.put(1, 11)) == null);
263 assert((try map.put(2, 22)) == null);
264 assert((try map.put(3, 33)) == null);
265 assert((try map.put(4, 44)) == null);
266 assert((try map.put(5, 55)) == null);
251267
252 assert(??(map.put(5, 66) catch unreachable) == 55);
253 assert(??(map.put(5, 55) catch unreachable) == 66);
268 assert((try map.put(5, 66)).? == 55);
269 assert((try map.put(5, 55)).? == 66);
254270
255 assert((??map.get(2)).value == 22);
271 assert(map.contains(2));
272 assert(map.get(2).?.value == 22);
256273 _ = map.remove(2);
257274 assert(map.remove(2) == null);
258275 assert(map.get(2) == null);
259276}
260277
278test "iterator hash map" {
279 var direct_allocator = std.heap.DirectAllocator.init();
280 defer direct_allocator.deinit();
281
282 var reset_map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
283 defer reset_map.deinit();
284
285 assert((try reset_map.put(1, 11)) == null);
286 assert((try reset_map.put(2, 22)) == null);
287 assert((try reset_map.put(3, 33)) == null);
288
289 var keys = []i32{
290 1,
291 2,
292 3,
293 };
294 var values = []i32{
295 11,
296 22,
297 33,
298 };
299
300 var it = reset_map.iterator();
301 var count: usize = 0;
302 while (it.next()) |next| {
303 assert(next.key == keys[count]);
304 assert(next.value == values[count]);
305 count += 1;
306 }
307
308 assert(count == 3);
309 assert(it.next() == null);
310 it.reset();
311 count = 0;
312 while (it.next()) |next| {
313 assert(next.key == keys[count]);
314 assert(next.value == values[count]);
315 count += 1;
316 if (count == 2) break;
317 }
318
319 it.reset();
320 var entry = it.next().?;
321 assert(entry.key == keys[0]);
322 assert(entry.value == values[0]);
323}
324
261325fn hash_i32(x: i32) u32 {
262326 return @bitCast(u32, x);
263327}
std/heap.zig+309-77
......@@ -10,24 +10,21 @@ const c = std.c;
1010const Allocator = mem.Allocator;
1111
1212pub const c_allocator = &c_allocator_state;
13var c_allocator_state = Allocator {
13var c_allocator_state = Allocator{
1414 .allocFn = cAlloc,
1515 .reallocFn = cRealloc,
1616 .freeFn = cFree,
1717};
1818
19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
19fn cAlloc(self: *Allocator, n: usize, alignment: u29) ![]u8 {
2020 assert(alignment <= @alignOf(c_longdouble));
21 return if (c.malloc(n)) |buf|
22 @ptrCast(&u8, buf)[0..n]
23 else
24 error.OutOfMemory;
21 return if (c.malloc(n)) |buf| @ptrCast([*]u8, buf)[0..n] else error.OutOfMemory;
2522}
2623
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
28 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
24fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
25 const old_ptr = @ptrCast(*c_void, old_mem.ptr);
2926 if (c.realloc(old_ptr, new_size)) |buf| {
30 return @ptrCast(&u8, buf)[0..new_size];
27 return @ptrCast([*]u8, buf)[0..new_size];
3128 } else if (new_size <= old_mem.len) {
3229 return old_mem[0..new_size];
3330 } else {
......@@ -35,28 +32,22 @@ fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![
3532 }
3633}
3734
38fn cFree(self: &Allocator, old_mem: []u8) void {
39 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
35fn cFree(self: *Allocator, old_mem: []u8) void {
36 const old_ptr = @ptrCast(*c_void, old_mem.ptr);
4037 c.free(old_ptr);
4138}
4239
4340/// This allocator makes a syscall directly for every allocation and free.
41/// Thread-safe and lock-free.
4442pub const DirectAllocator = struct {
4543 allocator: Allocator,
4644 heap_handle: ?HeapHandle,
4745
4846 const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
4947
50 //pub const canary_bytes = []u8 {48, 239, 128, 46, 18, 49, 147, 9, 195, 59, 203, 3, 245, 54, 9, 122};
51 //pub const want_safety = switch (builtin.mode) {
52 // builtin.Mode.Debug => true,
53 // builtin.Mode.ReleaseSafe => true,
54 // else => false,
55 //};
56
5748 pub fn init() DirectAllocator {
58 return DirectAllocator {
59 .allocator = Allocator {
49 return DirectAllocator{
50 .allocator = Allocator{
6051 .allocFn = alloc,
6152 .reallocFn = realloc,
6253 .freeFn = free,
......@@ -65,7 +56,7 @@ pub const DirectAllocator = struct {
6556 };
6657 }
6758
68 pub fn deinit(self: &DirectAllocator) void {
59 pub fn deinit(self: *DirectAllocator) void {
6960 switch (builtin.os) {
7061 Os.windows => if (self.heap_handle) |heap_handle| {
7162 _ = os.windows.HeapDestroy(heap_handle);
......@@ -74,41 +65,58 @@ pub const DirectAllocator = struct {
7465 }
7566 }
7667
77 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
68 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
7869 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
7970
8071 switch (builtin.os) {
8172 Os.linux, Os.macosx, Os.ios => {
82 assert(alignment <= os.page_size);
8373 const p = os.posix;
84 const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE,
85 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
86 if (addr == p.MAP_FAILED) {
87 return error.OutOfMemory;
88 }
89 return @intToPtr(&u8, addr)[0..n];
74 const alloc_size = if (alignment <= os.page_size) n else n + alignment;
75 const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
76 if (addr == p.MAP_FAILED) return error.OutOfMemory;
77 if (alloc_size == n) return @intToPtr([*]u8, addr)[0..n];
78
79 const aligned_addr = (addr & ~usize(alignment - 1)) + alignment;
80
81 // We can unmap the unused portions of our mmap, but we must only
82 // pass munmap bytes that exist outside our allocated pages or it
83 // will happily eat us too.
84
85 // Since alignment > page_size, we are by definition on a page boundary.
86 const unused_start = addr;
87 const unused_len = aligned_addr - 1 - unused_start;
88
89 const err = p.munmap(unused_start, unused_len);
90 assert(p.getErrno(err) == 0);
91
92 // It is impossible that there is an unoccupied page at the top of our
93 // mmap.
94
95 return @intToPtr([*]u8, aligned_addr)[0..n];
9096 },
9197 Os.windows => {
9298 const amt = n + alignment + @sizeOf(usize);
93 const heap_handle = self.heap_handle ?? blk: {
94 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
95 self.heap_handle = hh;
96 break :blk hh;
99 const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst);
100 const heap_handle = optional_heap_handle orelse blk: {
101 const hh = os.windows.HeapCreate(0, amt, 0) orelse return error.OutOfMemory;
102 const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh;
103 _ = os.windows.HeapDestroy(hh);
104 break :blk other_hh.?; // can't be null because of the cmpxchg
97105 };
98 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) ?? return error.OutOfMemory;
106 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
99107 const root_addr = @ptrToInt(ptr);
100108 const rem = @rem(root_addr, alignment);
101109 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
102110 const adjusted_addr = root_addr + march_forward_bytes;
103111 const record_addr = adjusted_addr + n;
104 *@intToPtr(&align(1) usize, record_addr) = root_addr;
105 return @intToPtr(&u8, adjusted_addr)[0..n];
112 @intToPtr(*align(1) usize, record_addr).* = root_addr;
113 return @intToPtr([*]u8, adjusted_addr)[0..n];
106114 },
107115 else => @compileError("Unsupported OS"),
108116 }
109117 }
110118
111 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
119 fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
112120 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
113121
114122 switch (builtin.os) {
......@@ -120,7 +128,7 @@ pub const DirectAllocator = struct {
120128 const rem = @rem(new_addr_end, os.page_size);
121129 const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem);
122130 if (old_addr_end > new_addr_end_rounded) {
123 _ = os.posix.munmap(@intToPtr(&u8, new_addr_end_rounded), old_addr_end - new_addr_end_rounded);
131 _ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded);
124132 }
125133 return old_mem[0..new_size];
126134 }
......@@ -132,13 +140,13 @@ pub const DirectAllocator = struct {
132140 Os.windows => {
133141 const old_adjusted_addr = @ptrToInt(old_mem.ptr);
134142 const old_record_addr = old_adjusted_addr + old_mem.len;
135 const root_addr = *@intToPtr(&align(1) usize, old_record_addr);
136 const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);
143 const root_addr = @intToPtr(*align(1) usize, old_record_addr).*;
144 const old_ptr = @intToPtr(*c_void, root_addr);
137145 const amt = new_size + alignment + @sizeOf(usize);
138 const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
146 const new_ptr = os.windows.HeapReAlloc(self.heap_handle.?, 0, old_ptr, amt) orelse blk: {
139147 if (new_size > old_mem.len) return error.OutOfMemory;
140148 const new_record_addr = old_record_addr - new_size + old_mem.len;
141 *@intToPtr(&align(1) usize, new_record_addr) = root_addr;
149 @intToPtr(*align(1) usize, new_record_addr).* = root_addr;
142150 return old_mem[0..new_size];
143151 };
144152 const offset = old_adjusted_addr - root_addr;
......@@ -146,25 +154,25 @@ pub const DirectAllocator = struct {
146154 const new_adjusted_addr = new_root_addr + offset;
147155 assert(new_adjusted_addr % alignment == 0);
148156 const new_record_addr = new_adjusted_addr + new_size;
149 *@intToPtr(&align(1) usize, new_record_addr) = new_root_addr;
150 return @intToPtr(&u8, new_adjusted_addr)[0..new_size];
157 @intToPtr(*align(1) usize, new_record_addr).* = new_root_addr;
158 return @intToPtr([*]u8, new_adjusted_addr)[0..new_size];
151159 },
152160 else => @compileError("Unsupported OS"),
153161 }
154162 }
155163
156 fn free(allocator: &Allocator, bytes: []u8) void {
164 fn free(allocator: *Allocator, bytes: []u8) void {
157165 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
158166
159167 switch (builtin.os) {
160168 Os.linux, Os.macosx, Os.ios => {
161 _ = os.posix.munmap(bytes.ptr, bytes.len);
169 _ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);
162170 },
163171 Os.windows => {
164172 const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
165 const root_addr = *@intToPtr(&align(1) usize, record_addr);
166 const ptr = @intToPtr(os.windows.LPVOID, root_addr);
167 _ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
173 const root_addr = @intToPtr(*align(1) usize, record_addr).*;
174 const ptr = @intToPtr(*c_void, root_addr);
175 _ = os.windows.HeapFree(self.heap_handle.?, 0, ptr);
168176 },
169177 else => @compileError("Unsupported OS"),
170178 }
......@@ -176,15 +184,15 @@ pub const DirectAllocator = struct {
176184pub const ArenaAllocator = struct {
177185 pub allocator: Allocator,
178186
179 child_allocator: &Allocator,
187 child_allocator: *Allocator,
180188 buffer_list: std.LinkedList([]u8),
181189 end_index: usize,
182190
183191 const BufNode = std.LinkedList([]u8).Node;
184192
185 pub fn init(child_allocator: &Allocator) ArenaAllocator {
186 return ArenaAllocator {
187 .allocator = Allocator {
193 pub fn init(child_allocator: *Allocator) ArenaAllocator {
194 return ArenaAllocator{
195 .allocator = Allocator{
188196 .allocFn = alloc,
189197 .reallocFn = realloc,
190198 .freeFn = free,
......@@ -195,7 +203,7 @@ pub const ArenaAllocator = struct {
195203 };
196204 }
197205
198 pub fn deinit(self: &ArenaAllocator) void {
206 pub fn deinit(self: *ArenaAllocator) void {
199207 var it = self.buffer_list.first;
200208 while (it) |node| {
201209 // this has to occur before the free because the free frees node
......@@ -205,7 +213,7 @@ pub const ArenaAllocator = struct {
205213 }
206214 }
207215
208 fn createNode(self: &ArenaAllocator, prev_len: usize, minimum_size: usize) !&BufNode {
216 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {
209217 const actual_min_size = minimum_size + @sizeOf(BufNode);
210218 var len = prev_len;
211219 while (true) {
......@@ -214,9 +222,9 @@ pub const ArenaAllocator = struct {
214222 if (len >= actual_min_size) break;
215223 }
216224 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
217 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
225 const buf_node_slice = @bytesToSlice(BufNode, buf[0..@sizeOf(BufNode)]);
218226 const buf_node = &buf_node_slice[0];
219 *buf_node = BufNode {
227 buf_node.* = BufNode{
220228 .data = buf,
221229 .prev = null,
222230 .next = null,
......@@ -226,7 +234,7 @@ pub const ArenaAllocator = struct {
226234 return buf_node;
227235 }
228236
229 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
237 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
230238 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
231239
232240 var cur_node = if (self.buffer_list.last) |last_node| last_node else try self.createNode(0, n + alignment);
......@@ -241,13 +249,13 @@ pub const ArenaAllocator = struct {
241249 cur_node = try self.createNode(cur_buf.len, n + alignment);
242250 continue;
243251 }
244 const result = cur_buf[adjusted_index .. new_end_index];
252 const result = cur_buf[adjusted_index..new_end_index];
245253 self.end_index = new_end_index;
246254 return result;
247255 }
248256 }
249257
250 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
258 fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
251259 if (new_size <= old_mem.len) {
252260 return old_mem[0..new_size];
253261 } else {
......@@ -257,7 +265,7 @@ pub const ArenaAllocator = struct {
257265 }
258266 }
259267
260 fn free(allocator: &Allocator, bytes: []u8) void { }
268 fn free(allocator: *Allocator, bytes: []u8) void {}
261269};
262270
263271pub const FixedBufferAllocator = struct {
......@@ -266,8 +274,8 @@ pub const FixedBufferAllocator = struct {
266274 buffer: []u8,
267275
268276 pub fn init(buffer: []u8) FixedBufferAllocator {
269 return FixedBufferAllocator {
270 .allocator = Allocator {
277 return FixedBufferAllocator{
278 .allocator = Allocator{
271279 .allocFn = alloc,
272280 .reallocFn = realloc,
273281 .freeFn = free,
......@@ -277,9 +285,9 @@ pub const FixedBufferAllocator = struct {
277285 };
278286 }
279287
280 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
288 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
281289 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
282 const addr = @ptrToInt(&self.buffer[self.end_index]);
290 const addr = @ptrToInt(self.buffer.ptr) + self.end_index;
283291 const rem = @rem(addr, alignment);
284292 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
285293 const adjusted_index = self.end_index + march_forward_bytes;
......@@ -287,13 +295,69 @@ pub const FixedBufferAllocator = struct {
287295 if (new_end_index > self.buffer.len) {
288296 return error.OutOfMemory;
289297 }
290 const result = self.buffer[adjusted_index .. new_end_index];
298 const result = self.buffer[adjusted_index..new_end_index];
291299 self.end_index = new_end_index;
292300
293301 return result;
294302 }
295303
296 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
304 fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
305 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
306 assert(old_mem.len <= self.end_index);
307 if (new_size <= old_mem.len) {
308 return old_mem[0..new_size];
309 } else if (old_mem.ptr == self.buffer.ptr + self.end_index - old_mem.len) {
310 const start_index = self.end_index - old_mem.len;
311 const new_end_index = start_index + new_size;
312 if (new_end_index > self.buffer.len) return error.OutOfMemory;
313 const result = self.buffer[start_index..new_end_index];
314 self.end_index = new_end_index;
315 return result;
316 } else {
317 const result = try alloc(allocator, new_size, alignment);
318 mem.copy(u8, result, old_mem);
319 return result;
320 }
321 }
322
323 fn free(allocator: *Allocator, bytes: []u8) void {}
324};
325
326/// lock free
327pub const ThreadSafeFixedBufferAllocator = struct {
328 allocator: Allocator,
329 end_index: usize,
330 buffer: []u8,
331
332 pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {
333 return ThreadSafeFixedBufferAllocator{
334 .allocator = Allocator{
335 .allocFn = alloc,
336 .reallocFn = realloc,
337 .freeFn = free,
338 },
339 .buffer = buffer,
340 .end_index = 0,
341 };
342 }
343
344 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
345 const self = @fieldParentPtr(ThreadSafeFixedBufferAllocator, "allocator", allocator);
346 var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst);
347 while (true) {
348 const addr = @ptrToInt(self.buffer.ptr) + end_index;
349 const rem = @rem(addr, alignment);
350 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
351 const adjusted_index = end_index + march_forward_bytes;
352 const new_end_index = adjusted_index + n;
353 if (new_end_index > self.buffer.len) {
354 return error.OutOfMemory;
355 }
356 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse return self.buffer[adjusted_index..new_end_index];
357 }
358 }
359
360 fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
297361 if (new_size <= old_mem.len) {
298362 return old_mem[0..new_size];
299363 } else {
......@@ -303,10 +367,75 @@ pub const FixedBufferAllocator = struct {
303367 }
304368 }
305369
306 fn free(allocator: &Allocator, bytes: []u8) void { }
370 fn free(allocator: *Allocator, bytes: []u8) void {}
307371};
308372
373pub fn stackFallback(comptime size: usize, fallback_allocator: *Allocator) StackFallbackAllocator(size) {
374 return StackFallbackAllocator(size){
375 .buffer = undefined,
376 .fallback_allocator = fallback_allocator,
377 .fixed_buffer_allocator = undefined,
378 .allocator = Allocator{
379 .allocFn = StackFallbackAllocator(size).alloc,
380 .reallocFn = StackFallbackAllocator(size).realloc,
381 .freeFn = StackFallbackAllocator(size).free,
382 },
383 };
384}
385
386pub fn StackFallbackAllocator(comptime size: usize) type {
387 return struct {
388 const Self = this;
389
390 buffer: [size]u8,
391 allocator: Allocator,
392 fallback_allocator: *Allocator,
393 fixed_buffer_allocator: FixedBufferAllocator,
394
395 pub fn get(self: *Self) *Allocator {
396 self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]);
397 return &self.allocator;
398 }
399
400 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
401 const self = @fieldParentPtr(Self, "allocator", allocator);
402 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator.allocator, n, alignment) catch
403 self.fallback_allocator.allocFn(self.fallback_allocator, n, alignment);
404 }
405
406 fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
407 const self = @fieldParentPtr(Self, "allocator", allocator);
408 const in_buffer = @ptrToInt(old_mem.ptr) >= @ptrToInt(&self.buffer) and
409 @ptrToInt(old_mem.ptr) < @ptrToInt(&self.buffer) + self.buffer.len;
410 if (in_buffer) {
411 return FixedBufferAllocator.realloc(
412 &self.fixed_buffer_allocator.allocator,
413 old_mem,
414 new_size,
415 alignment,
416 ) catch {
417 const result = try self.fallback_allocator.allocFn(
418 self.fallback_allocator,
419 new_size,
420 alignment,
421 );
422 mem.copy(u8, result, old_mem);
423 return result;
424 };
425 }
426 return self.fallback_allocator.reallocFn(self.fallback_allocator, old_mem, new_size, alignment);
427 }
309428
429 fn free(allocator: *Allocator, bytes: []u8) void {
430 const self = @fieldParentPtr(Self, "allocator", allocator);
431 const in_buffer = @ptrToInt(bytes.ptr) >= @ptrToInt(&self.buffer) and
432 @ptrToInt(bytes.ptr) < @ptrToInt(&self.buffer) + self.buffer.len;
433 if (!in_buffer) {
434 return self.fallback_allocator.freeFn(self.fallback_allocator, bytes);
435 }
436 }
437 };
438}
310439
311440test "c_allocator" {
312441 if (builtin.link_libc) {
......@@ -322,6 +451,8 @@ test "DirectAllocator" {
322451
323452 const allocator = &direct_allocator.allocator;
324453 try testAllocator(allocator);
454 try testAllocatorAligned(allocator, 16);
455 try testAllocatorLargeAlignment(allocator);
325456}
326457
327458test "ArenaAllocator" {
......@@ -332,6 +463,8 @@ test "ArenaAllocator" {
332463 defer arena_allocator.deinit();
333464
334465 try testAllocator(&arena_allocator.allocator);
466 try testAllocatorAligned(&arena_allocator.allocator, 16);
467 try testAllocatorLargeAlignment(&arena_allocator.allocator);
335468}
336469
337470var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;
......@@ -339,24 +472,123 @@ test "FixedBufferAllocator" {
339472 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
340473
341474 try testAllocator(&fixed_buffer_allocator.allocator);
475 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);
476 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
342477}
343478
344fn testAllocator(allocator: &mem.Allocator) !void {
345 var slice = try allocator.alloc(&i32, 100);
479test "FixedBufferAllocator Reuse memory on realloc" {
480 var small_fixed_buffer: [10]u8 = undefined;
481 // check if we re-use the memory
482 {
483 var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]);
484
485 var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 5);
486 assert(slice0.len == 5);
487 var slice1 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 10);
488 assert(slice1.ptr == slice0.ptr);
489 assert(slice1.len == 10);
490 debug.assertError(fixed_buffer_allocator.allocator.realloc(u8, slice1, 11), error.OutOfMemory);
491 }
492 // check that we don't re-use the memory if it's not the most recent block
493 {
494 var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]);
495
496 var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 2);
497 slice0[0] = 1;
498 slice0[1] = 2;
499 var slice1 = try fixed_buffer_allocator.allocator.alloc(u8, 2);
500 var slice2 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 4);
501 assert(slice0.ptr != slice2.ptr);
502 assert(slice1.ptr != slice2.ptr);
503 assert(slice2[0] == 1);
504 assert(slice2[1] == 2);
505 }
506}
507
508test "ThreadSafeFixedBufferAllocator" {
509 var fixed_buffer_allocator = ThreadSafeFixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
510
511 try testAllocator(&fixed_buffer_allocator.allocator);
512 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);
513 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
514}
346515
516fn testAllocator(allocator: *mem.Allocator) !void {
517 var slice = try allocator.alloc(*i32, 100);
518 assert(slice.len == 100);
347519 for (slice) |*item, i| {
348 *item = try allocator.create(i32);
349 **item = i32(i);
520 item.* = try allocator.create(@intCast(i32, i));
350521 }
351522
352 for (slice) |item, i| {
523 slice = try allocator.realloc(*i32, slice, 20000);
524 assert(slice.len == 20000);
525
526 for (slice[0..100]) |item, i| {
527 assert(item.* == @intCast(i32, i));
353528 allocator.destroy(item);
354529 }
355530
356 slice = try allocator.realloc(&i32, slice, 20000);
357 slice = try allocator.realloc(&i32, slice, 50);
358 slice = try allocator.realloc(&i32, slice, 25);
359 slice = try allocator.realloc(&i32, slice, 10);
531 slice = try allocator.realloc(*i32, slice, 50);
532 assert(slice.len == 50);
533 slice = try allocator.realloc(*i32, slice, 25);
534 assert(slice.len == 25);
535 slice = try allocator.realloc(*i32, slice, 0);
536 assert(slice.len == 0);
537 slice = try allocator.realloc(*i32, slice, 10);
538 assert(slice.len == 10);
539
540 allocator.free(slice);
541}
542
543fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !void {
544 // initial
545 var slice = try allocator.alignedAlloc(u8, alignment, 10);
546 assert(slice.len == 10);
547 // grow
548 slice = try allocator.alignedRealloc(u8, alignment, slice, 100);
549 assert(slice.len == 100);
550 // shrink
551 slice = try allocator.alignedRealloc(u8, alignment, slice, 10);
552 assert(slice.len == 10);
553 // go to zero
554 slice = try allocator.alignedRealloc(u8, alignment, slice, 0);
555 assert(slice.len == 0);
556 // realloc from zero
557 slice = try allocator.alignedRealloc(u8, alignment, slice, 100);
558 assert(slice.len == 100);
559 // shrink with shrink
560 slice = allocator.alignedShrink(u8, alignment, slice, 10);
561 assert(slice.len == 10);
562 // shrink to zero
563 slice = allocator.alignedShrink(u8, alignment, slice, 0);
564 assert(slice.len == 0);
565}
566
567fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void {
568 //Maybe a platform's page_size is actually the same as or
569 // very near usize?
570 if (os.page_size << 2 > @maxValue(usize)) return;
571
572 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
573 const large_align = u29(os.page_size << 2);
574
575 var align_mask: usize = undefined;
576 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
577
578 var slice = try allocator.allocFn(allocator, 500, large_align);
579 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
580
581 slice = try allocator.reallocFn(allocator, slice, 100, large_align);
582 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
583
584 slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
585 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
586
587 slice = try allocator.reallocFn(allocator, slice, 10, large_align);
588 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
589
590 slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
591 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
360592
361593 allocator.free(slice);
362594}
std/index.zig+10
......@@ -7,7 +7,10 @@ pub const BufferOutStream = @import("buffer.zig").BufferOutStream;
77pub const HashMap = @import("hash_map.zig").HashMap;
88pub const LinkedList = @import("linked_list.zig").LinkedList;
99pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;
10pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
11pub const DynLib = @import("dynamic_library.zig").DynLib;
1012
13pub const atomic = @import("atomic/index.zig");
1114pub const base64 = @import("base64.zig");
1215pub const build = @import("build.zig");
1316pub const c = @import("c/index.zig");
......@@ -22,6 +25,7 @@ pub const fmt = @import("fmt/index.zig");
2225pub const hash = @import("hash/index.zig");
2326pub const heap = @import("heap.zig");
2427pub const io = @import("io.zig");
28pub const json = @import("json.zig");
2529pub const macho = @import("macho.zig");
2630pub const math = @import("math/index.zig");
2731pub const mem = @import("mem.zig");
......@@ -32,14 +36,18 @@ pub const sort = @import("sort.zig");
3236pub const unicode = @import("unicode.zig");
3337pub const zig = @import("zig/index.zig");
3438
39pub const lazyInit = @import("lazy_init.zig").lazyInit;
40
3541test "std" {
3642 // run tests from these
43 _ = @import("atomic/index.zig");
3744 _ = @import("array_list.zig");
3845 _ = @import("buf_map.zig");
3946 _ = @import("buf_set.zig");
4047 _ = @import("buffer.zig");
4148 _ = @import("hash_map.zig");
4249 _ = @import("linked_list.zig");
50 _ = @import("segmented_list.zig");
4351
4452 _ = @import("base64.zig");
4553 _ = @import("build.zig");
......@@ -54,6 +62,7 @@ test "std" {
5462 _ = @import("fmt/index.zig");
5563 _ = @import("hash/index.zig");
5664 _ = @import("io.zig");
65 _ = @import("json.zig");
5766 _ = @import("macho.zig");
5867 _ = @import("math/index.zig");
5968 _ = @import("mem.zig");
......@@ -64,4 +73,5 @@ test "std" {
6473 _ = @import("sort.zig");
6574 _ = @import("unicode.zig");
6675 _ = @import("zig/index.zig");
76 _ = @import("lazy_init.zig");
6777}
std/io.zig+233-94
......@@ -18,53 +18,36 @@ const is_windows = builtin.os == builtin.Os.windows;
1818const GetStdIoErrs = os.WindowsGetStdHandleErrs;
1919
2020pub fn getStdErr() GetStdIoErrs!File {
21 const handle = if (is_windows)
22 try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE)
23 else if (is_posix)
24 os.posix.STDERR_FILENO
25 else
26 unreachable;
21 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
2722 return File.openHandle(handle);
2823}
2924
3025pub fn getStdOut() GetStdIoErrs!File {
31 const handle = if (is_windows)
32 try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE)
33 else if (is_posix)
34 os.posix.STDOUT_FILENO
35 else
36 unreachable;
26 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
3727 return File.openHandle(handle);
3828}
3929
4030pub fn getStdIn() GetStdIoErrs!File {
41 const handle = if (is_windows)
42 try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE)
43 else if (is_posix)
44 os.posix.STDIN_FILENO
45 else
46 unreachable;
31 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
4732 return File.openHandle(handle);
4833}
4934
5035/// Implementation of InStream trait for File
5136pub const FileInStream = struct {
52 file: &File,
37 file: *File,
5338 stream: Stream,
5439
5540 pub const Error = @typeOf(File.read).ReturnType.ErrorSet;
5641 pub const Stream = InStream(Error);
5742
58 pub fn init(file: &File) FileInStream {
59 return FileInStream {
43 pub fn init(file: *File) FileInStream {
44 return FileInStream{
6045 .file = file,
61 .stream = Stream {
62 .readFn = readFn,
63 },
46 .stream = Stream{ .readFn = readFn },
6447 };
6548 }
6649
67 fn readFn(in_stream: &Stream, buffer: []u8) Error!usize {
50 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
6851 const self = @fieldParentPtr(FileInStream, "stream", in_stream);
6952 return self.file.read(buffer);
7053 }
......@@ -72,22 +55,20 @@ pub const FileInStream = struct {
7255
7356/// Implementation of OutStream trait for File
7457pub const FileOutStream = struct {
75 file: &File,
58 file: *File,
7659 stream: Stream,
7760
7861 pub const Error = File.WriteError;
7962 pub const Stream = OutStream(Error);
8063
81 pub fn init(file: &File) FileOutStream {
82 return FileOutStream {
64 pub fn init(file: *File) FileOutStream {
65 return FileOutStream{
8366 .file = file,
84 .stream = Stream {
85 .writeFn = writeFn,
86 },
67 .stream = Stream{ .writeFn = writeFn },
8768 };
8869 }
8970
90 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
71 fn writeFn(out_stream: *Stream, bytes: []const u8) !void {
9172 const self = @fieldParentPtr(FileOutStream, "stream", out_stream);
9273 return self.file.write(bytes);
9374 }
......@@ -101,12 +82,12 @@ pub fn InStream(comptime ReadError: type) type {
10182 /// Return the number of bytes read. If the number read is smaller than buf.len, it
10283 /// means the stream reached the end. Reaching the end of a stream is not an error
10384 /// condition.
104 readFn: fn(self: &Self, buffer: []u8) Error!usize,
85 readFn: fn (self: *Self, buffer: []u8) Error!usize,
10586
10687 /// Replaces `buffer` contents by reading from the stream until it is finished.
10788 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
10889 /// the contents read from the stream are lost.
109 pub fn readAllBuffer(self: &Self, buffer: &Buffer, max_size: usize) !void {
90 pub fn readAllBuffer(self: *Self, buffer: *Buffer, max_size: usize) !void {
11091 try buffer.resize(0);
11192
11293 var actual_buf_len: usize = 0;
......@@ -121,8 +102,7 @@ pub fn InStream(comptime ReadError: type) type {
121102 }
122103
123104 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
124 if (new_buf_size == actual_buf_len)
125 return error.StreamTooLong;
105 if (new_buf_size == actual_buf_len) return error.StreamTooLong;
126106 try buffer.resize(new_buf_size);
127107 }
128108 }
......@@ -131,7 +111,7 @@ pub fn InStream(comptime ReadError: type) type {
131111 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
132112 /// Caller owns returned memory.
133113 /// If this function returns an error, the contents from the stream read so far are lost.
134 pub fn readAllAlloc(self: &Self, allocator: &mem.Allocator, max_size: usize) ![]u8 {
114 pub fn readAllAlloc(self: *Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
135115 var buf = Buffer.initNull(allocator);
136116 defer buf.deinit();
137117
......@@ -143,7 +123,7 @@ pub fn InStream(comptime ReadError: type) type {
143123 /// Does not include the delimiter in the result.
144124 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
145125 /// read from the stream so far are lost.
146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
126 pub fn readUntilDelimiterBuffer(self: *Self, buffer: *Buffer, delimiter: u8, max_size: usize) !void {
147127 try buffer.resize(0);
148128
149129 while (true) {
......@@ -165,9 +145,7 @@ pub fn InStream(comptime ReadError: type) type {
165145 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
166146 /// Caller owns returned memory.
167147 /// If this function returns an error, the contents from the stream read so far are lost.
168 pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator,
169 delimiter: u8, max_size: usize) ![]u8
170 {
148 pub fn readUntilDelimiterAlloc(self: *Self, allocator: *mem.Allocator, delimiter: u8, max_size: usize) ![]u8 {
171149 var buf = Buffer.initNull(allocator);
172150 defer buf.deinit();
173151
......@@ -178,43 +156,43 @@ pub fn InStream(comptime ReadError: type) type {
178156 /// Returns the number of bytes read. If the number read is smaller than buf.len, it
179157 /// means the stream reached the end. Reaching the end of a stream is not an error
180158 /// condition.
181 pub fn read(self: &Self, buffer: []u8) !usize {
159 pub fn read(self: *Self, buffer: []u8) !usize {
182160 return self.readFn(self, buffer);
183161 }
184162
185163 /// Same as `read` but end of stream returns `error.EndOfStream`.
186 pub fn readNoEof(self: &Self, buf: []u8) !void {
164 pub fn readNoEof(self: *Self, buf: []u8) !void {
187165 const amt_read = try self.read(buf);
188166 if (amt_read < buf.len) return error.EndOfStream;
189167 }
190168
191169 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
192 pub fn readByte(self: &Self) !u8 {
170 pub fn readByte(self: *Self) !u8 {
193171 var result: [1]u8 = undefined;
194172 try self.readNoEof(result[0..]);
195173 return result[0];
196174 }
197175
198176 /// Same as `readByte` except the returned byte is signed.
199 pub fn readByteSigned(self: &Self) !i8 {
177 pub fn readByteSigned(self: *Self) !i8 {
200178 return @bitCast(i8, try self.readByte());
201179 }
202180
203 pub fn readIntLe(self: &Self, comptime T: type) !T {
181 pub fn readIntLe(self: *Self, comptime T: type) !T {
204182 return self.readInt(builtin.Endian.Little, T);
205183 }
206184
207 pub fn readIntBe(self: &Self, comptime T: type) !T {
185 pub fn readIntBe(self: *Self, comptime T: type) !T {
208186 return self.readInt(builtin.Endian.Big, T);
209187 }
210188
211 pub fn readInt(self: &Self, endian: builtin.Endian, comptime T: type) !T {
189 pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
212190 var bytes: [@sizeOf(T)]u8 = undefined;
213191 try self.readNoEof(bytes[0..]);
214192 return mem.readInt(bytes, T, endian);
215193 }
216194
217 pub fn readVarInt(self: &Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
195 pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
218196 assert(size <= @sizeOf(T));
219197 assert(size <= 8);
220198 var input_buf: [8]u8 = undefined;
......@@ -222,6 +200,13 @@ pub fn InStream(comptime ReadError: type) type {
222200 try self.readNoEof(input_slice);
223201 return mem.readInt(input_slice, T, endian);
224202 }
203
204 pub fn skipBytes(self: *Self, num_bytes: usize) !void {
205 var i: usize = 0;
206 while (i < num_bytes) : (i += 1) {
207 _ = try self.readByte();
208 }
209 }
225210 };
226211}
227212
......@@ -230,45 +215,64 @@ pub fn OutStream(comptime WriteError: type) type {
230215 const Self = this;
231216 pub const Error = WriteError;
232217
233 writeFn: fn(self: &Self, bytes: []const u8) Error!void,
218 writeFn: fn (self: *Self, bytes: []const u8) Error!void,
234219
235 pub fn print(self: &Self, comptime format: []const u8, args: ...) !void {
220 pub fn print(self: *Self, comptime format: []const u8, args: ...) !void {
236221 return std.fmt.format(self, Error, self.writeFn, format, args);
237222 }
238223
239 pub fn write(self: &Self, bytes: []const u8) !void {
224 pub fn write(self: *Self, bytes: []const u8) !void {
240225 return self.writeFn(self, bytes);
241226 }
242227
243 pub fn writeByte(self: &Self, byte: u8) !void {
244 const slice = (&byte)[0..1];
228 pub fn writeByte(self: *Self, byte: u8) !void {
229 const slice = (*[1]u8)(&byte)[0..];
245230 return self.writeFn(self, slice);
246231 }
247232
248 pub fn writeByteNTimes(self: &Self, byte: u8, n: usize) !void {
249 const slice = (&byte)[0..1];
233 pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) !void {
234 const slice = (*[1]u8)(&byte)[0..];
250235 var i: usize = 0;
251236 while (i < n) : (i += 1) {
252237 try self.writeFn(self, slice);
253238 }
254239 }
240
241 pub fn writeIntLe(self: *Self, comptime T: type, value: T) !void {
242 return self.writeInt(builtin.Endian.Little, T, value);
243 }
244
245 pub fn writeIntBe(self: *Self, comptime T: type, value: T) !void {
246 return self.writeInt(builtin.Endian.Big, T, value);
247 }
248
249 pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) !void {
250 var bytes: [@sizeOf(T)]u8 = undefined;
251 mem.writeInt(bytes[0..], value, endian);
252 return self.writeFn(self, bytes);
253 }
255254 };
256255}
257256
258257/// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
259pub fn writeFile(allocator: &mem.Allocator, path: []const u8, data: []const u8) !void {
258pub fn writeFile(allocator: *mem.Allocator, path: []const u8, data: []const u8) !void {
260259 var file = try File.openWrite(allocator, path);
261260 defer file.close();
262261 try file.write(data);
263262}
264263
265264/// On success, caller owns returned buffer.
266pub fn readFileAlloc(allocator: &mem.Allocator, path: []const u8) ![]u8 {
265pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
266 return readFileAllocAligned(allocator, path, @alignOf(u8));
267}
268
269/// On success, caller owns returned buffer.
270pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptime A: u29) ![]align(A) u8 {
267271 var file = try File.openRead(allocator, path);
268272 defer file.close();
269273
270274 const size = try file.getEndPos();
271 const buf = try allocator.alloc(u8, size);
275 const buf = try allocator.alignedAlloc(u8, A, size);
272276 errdefer allocator.free(buf);
273277
274278 var adapter = FileInStream.init(&file);
......@@ -283,18 +287,18 @@ pub fn BufferedInStream(comptime Error: type) type {
283287pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
284288 return struct {
285289 const Self = this;
286 const Stream = InStream(Error);
290 const Stream = InStream(Error);
287291
288292 pub stream: Stream,
289293
290 unbuffered_in_stream: &Stream,
294 unbuffered_in_stream: *Stream,
291295
292296 buffer: [buffer_size]u8,
293297 start_index: usize,
294298 end_index: usize,
295299
296 pub fn init(unbuffered_in_stream: &Stream) Self {
297 return Self {
300 pub fn init(unbuffered_in_stream: *Stream) Self {
301 return Self{
298302 .unbuffered_in_stream = unbuffered_in_stream,
299303 .buffer = undefined,
300304
......@@ -305,13 +309,11 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
305309 .start_index = buffer_size,
306310 .end_index = buffer_size,
307311
308 .stream = Stream {
309 .readFn = readFn,
310 },
312 .stream = Stream{ .readFn = readFn },
311313 };
312314 }
313315
314 fn readFn(in_stream: &Stream, dest: []u8) !usize {
316 fn readFn(in_stream: *Stream, dest: []u8) !usize {
315317 const self = @fieldParentPtr(Self, "stream", in_stream);
316318
317319 var dest_index: usize = 0;
......@@ -350,6 +352,150 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
350352 };
351353}
352354
355/// Creates a stream which supports 'un-reading' data, so that it can be read again.
356/// This makes look-ahead style parsing much easier.
357pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type {
358 return struct {
359 const Self = this;
360 pub const Error = InStreamError;
361 pub const Stream = InStream(Error);
362
363 pub stream: Stream,
364 base: *Stream,
365
366 // Right now the look-ahead space is statically allocated, but a version with dynamic allocation
367 // is not too difficult to derive from this.
368 buffer: [buffer_size]u8,
369 index: usize,
370 at_end: bool,
371
372 pub fn init(base: *Stream) Self {
373 return Self{
374 .base = base,
375 .buffer = undefined,
376 .index = 0,
377 .at_end = false,
378 .stream = Stream{ .readFn = readFn },
379 };
380 }
381
382 pub fn putBackByte(self: *Self, byte: u8) void {
383 self.buffer[self.index] = byte;
384 self.index += 1;
385 }
386
387 pub fn putBack(self: *Self, bytes: []const u8) void {
388 var pos = bytes.len;
389 while (pos != 0) {
390 pos -= 1;
391 self.putBackByte(bytes[pos]);
392 }
393 }
394
395 fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
396 const self = @fieldParentPtr(Self, "stream", in_stream);
397
398 // copy over anything putBack()'d
399 var pos: usize = 0;
400 while (pos < dest.len and self.index != 0) {
401 dest[pos] = self.buffer[self.index - 1];
402 self.index -= 1;
403 pos += 1;
404 }
405
406 if (pos == dest.len or self.at_end) {
407 return pos;
408 }
409
410 // ask the backing stream for more
411 const left = dest.len - pos;
412 const read = try self.base.read(dest[pos..]);
413 assert(read <= left);
414
415 self.at_end = (read < left);
416 return pos + read;
417 }
418
419 };
420}
421
422pub const SliceInStream = struct {
423 const Self = this;
424 pub const Error = error { };
425 pub const Stream = InStream(Error);
426
427 pub stream: Stream,
428
429 pos: usize,
430 slice: []const u8,
431
432 pub fn init(slice: []const u8) Self {
433 return Self{
434 .slice = slice,
435 .pos = 0,
436 .stream = Stream{ .readFn = readFn },
437 };
438 }
439
440 fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
441 const self = @fieldParentPtr(Self, "stream", in_stream);
442 const size = math.min(dest.len, self.slice.len - self.pos);
443 const end = self.pos + size;
444
445 mem.copy(u8, dest[0..size], self.slice[self.pos..end]);
446 self.pos = end;
447
448 return size;
449 }
450};
451
452/// This is a simple OutStream that writes to a slice, and returns an error
453/// when it runs out of space.
454pub const SliceOutStream = struct {
455 pub const Error = error{OutOfSpace};
456 pub const Stream = OutStream(Error);
457
458 pub stream: Stream,
459
460 pos: usize,
461 slice: []u8,
462
463 pub fn init(slice: []u8) SliceOutStream {
464 return SliceOutStream{
465 .slice = slice,
466 .pos = 0,
467 .stream = Stream{ .writeFn = writeFn },
468 };
469 }
470
471 pub fn getWritten(self: *const SliceOutStream) []const u8 {
472 return self.slice[0..self.pos];
473 }
474
475 pub fn reset(self: *SliceOutStream) void {
476 self.pos = 0;
477 }
478
479 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
480 const self = @fieldParentPtr(SliceOutStream, "stream", out_stream);
481
482 assert(self.pos <= self.slice.len);
483
484 const n =
485 if (self.pos + bytes.len <= self.slice.len)
486 bytes.len
487 else
488 self.slice.len - self.pos;
489
490 std.mem.copy(u8, self.slice[self.pos..self.pos + n], bytes[0..n]);
491 self.pos += n;
492
493 if (n < bytes.len) {
494 return Error.OutOfSpace;
495 }
496 }
497};
498
353499pub fn BufferedOutStream(comptime Error: type) type {
354500 return BufferedOutStreamCustom(os.page_size, Error);
355501}
......@@ -362,28 +508,26 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
362508
363509 pub stream: Stream,
364510
365 unbuffered_out_stream: &Stream,
511 unbuffered_out_stream: *Stream,
366512
367513 buffer: [buffer_size]u8,
368514 index: usize,
369515
370 pub fn init(unbuffered_out_stream: &Stream) Self {
371 return Self {
516 pub fn init(unbuffered_out_stream: *Stream) Self {
517 return Self{
372518 .unbuffered_out_stream = unbuffered_out_stream,
373519 .buffer = undefined,
374520 .index = 0,
375 .stream = Stream {
376 .writeFn = writeFn,
377 },
521 .stream = Stream{ .writeFn = writeFn },
378522 };
379523 }
380524
381 pub fn flush(self: &Self) !void {
525 pub fn flush(self: *Self) !void {
382526 try self.unbuffered_out_stream.write(self.buffer[0..self.index]);
383527 self.index = 0;
384528 }
385529
386 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
530 fn writeFn(out_stream: *Stream, bytes: []const u8) !void {
387531 const self = @fieldParentPtr(Self, "stream", out_stream);
388532
389533 if (bytes.len >= self.buffer.len) {
......@@ -395,7 +539,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
395539 while (src_index < bytes.len) {
396540 const dest_space_left = self.buffer.len - self.index;
397541 const copy_amt = math.min(dest_space_left, bytes.len - src_index);
398 mem.copy(u8, self.buffer[self.index..], bytes[src_index..src_index + copy_amt]);
542 mem.copy(u8, self.buffer[self.index..], bytes[src_index .. src_index + copy_amt]);
399543 self.index += copy_amt;
400544 assert(self.index <= self.buffer.len);
401545 if (self.index == self.buffer.len) {
......@@ -409,43 +553,38 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
409553
410554/// Implementation of OutStream trait for Buffer
411555pub const BufferOutStream = struct {
412 buffer: &Buffer,
556 buffer: *Buffer,
413557 stream: Stream,
414558
415559 pub const Error = error{OutOfMemory};
416560 pub const Stream = OutStream(Error);
417561
418 pub fn init(buffer: &Buffer) BufferOutStream {
419 return BufferOutStream {
562 pub fn init(buffer: *Buffer) BufferOutStream {
563 return BufferOutStream{
420564 .buffer = buffer,
421 .stream = Stream {
422 .writeFn = writeFn,
423 },
565 .stream = Stream{ .writeFn = writeFn },
424566 };
425567 }
426568
427 fn writeFn(out_stream: &Stream, bytes: []const u8) !void {
569 fn writeFn(out_stream: *Stream, bytes: []const u8) !void {
428570 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
429571 return self.buffer.append(bytes);
430572 }
431573};
432574
433
434575pub const BufferedAtomicFile = struct {
435576 atomic_file: os.AtomicFile,
436577 file_stream: FileOutStream,
437578 buffered_stream: BufferedOutStream(FileOutStream.Error),
438579
439 pub fn create(allocator: &mem.Allocator, dest_path: []const u8) !&BufferedAtomicFile {
580 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
440581 // TODO with well defined copy elision we don't need this allocation
441 var self = try allocator.create(BufferedAtomicFile);
442 errdefer allocator.destroy(self);
443
444 *self = BufferedAtomicFile {
582 var self = try allocator.create(BufferedAtomicFile{
445583 .atomic_file = undefined,
446584 .file_stream = undefined,
447585 .buffered_stream = undefined,
448 };
586 });
587 errdefer allocator.destroy(self);
449588
450589 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.default_file_mode);
451590 errdefer self.atomic_file.deinit();
......@@ -456,18 +595,18 @@ pub const BufferedAtomicFile = struct {
456595 }
457596
458597 /// always call destroy, even after successful finish()
459 pub fn destroy(self: &BufferedAtomicFile) void {
598 pub fn destroy(self: *BufferedAtomicFile) void {
460599 const allocator = self.atomic_file.allocator;
461600 self.atomic_file.deinit();
462601 allocator.destroy(self);
463602 }
464603
465 pub fn finish(self: &BufferedAtomicFile) !void {
604 pub fn finish(self: *BufferedAtomicFile) !void {
466605 try self.buffered_stream.flush();
467606 try self.atomic_file.finish();
468607 }
469608
470 pub fn stream(self: &BufferedAtomicFile) &OutStream(FileOutStream.Error) {
609 pub fn stream(self: *BufferedAtomicFile) *OutStream(FileOutStream.Error) {
471610 return &self.buffered_stream.stream;
472611 }
473612};
......@@ -489,7 +628,7 @@ pub fn readLine(buf: []u8) !usize {
489628 '\r' => {
490629 // trash the following \n
491630 _ = stream.readByte() catch return error.EndOfFile;
492 return index;
631 return index;
493632 },
494633 '\n' => return index,
495634 else => {
std/io_test.zig+90-2
......@@ -1,13 +1,16 @@
11const std = @import("index.zig");
22const io = std.io;
3const allocator = std.debug.global_allocator;
43const DefaultPrng = std.rand.DefaultPrng;
54const assert = std.debug.assert;
5const assertError = std.debug.assertError;
66const mem = std.mem;
77const os = std.os;
88const builtin = @import("builtin");
99
1010test "write a file, read it, then delete it" {
11 var raw_bytes: [200 * 1024]u8 = undefined;
12 var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;
13
1114 var data: [1024]u8 = undefined;
1215 var prng = DefaultPrng.init(1234);
1316 prng.random.bytes(data[0..]);
......@@ -39,8 +42,93 @@ test "write a file, read it, then delete it" {
3942 defer allocator.free(contents);
4043
4144 assert(mem.eql(u8, contents[0.."begin".len], "begin"));
42 assert(mem.eql(u8, contents["begin".len..contents.len - "end".len], data));
45 assert(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));
4346 assert(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
4447 }
4548 try os.deleteFile(allocator, tmp_file_name);
4649}
50
51test "BufferOutStream" {
52 var bytes: [100]u8 = undefined;
53 var allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
54
55 var buffer = try std.Buffer.initSize(allocator, 0);
56 var buf_stream = &std.io.BufferOutStream.init(&buffer).stream;
57
58 const x: i32 = 42;
59 const y: i32 = 1234;
60 try buf_stream.print("x: {}\ny: {}\n", x, y);
61
62 assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n"));
63}
64
65test "SliceInStream" {
66 const bytes = []const u8 { 1, 2, 3, 4, 5, 6, 7 };
67 var ss = io.SliceInStream.init(bytes);
68
69 var dest: [4]u8 = undefined;
70
71 var read = try ss.stream.read(dest[0..4]);
72 assert(read == 4);
73 assert(mem.eql(u8, dest[0..4], bytes[0..4]));
74
75 read = try ss.stream.read(dest[0..4]);
76 assert(read == 3);
77 assert(mem.eql(u8, dest[0..3], bytes[4..7]));
78
79 read = try ss.stream.read(dest[0..4]);
80 assert(read == 0);
81}
82
83test "PeekStream" {
84 const bytes = []const u8 { 1, 2, 3, 4, 5, 6, 7, 8 };
85 var ss = io.SliceInStream.init(bytes);
86 var ps = io.PeekStream(2, io.SliceInStream.Error).init(&ss.stream);
87
88 var dest: [4]u8 = undefined;
89
90 ps.putBackByte(9);
91 ps.putBackByte(10);
92
93 var read = try ps.stream.read(dest[0..4]);
94 assert(read == 4);
95 assert(dest[0] == 10);
96 assert(dest[1] == 9);
97 assert(mem.eql(u8, dest[2..4], bytes[0..2]));
98
99 read = try ps.stream.read(dest[0..4]);
100 assert(read == 4);
101 assert(mem.eql(u8, dest[0..4], bytes[2..6]));
102
103 read = try ps.stream.read(dest[0..4]);
104 assert(read == 2);
105 assert(mem.eql(u8, dest[0..2], bytes[6..8]));
106
107 ps.putBackByte(11);
108 ps.putBackByte(12);
109
110 read = try ps.stream.read(dest[0..4]);
111 assert(read == 2);
112 assert(dest[0] == 12);
113 assert(dest[1] == 11);
114}
115
116test "SliceOutStream" {
117 var buffer: [10]u8 = undefined;
118 var ss = io.SliceOutStream.init(buffer[0..]);
119
120 try ss.stream.write("Hello");
121 assert(mem.eql(u8, ss.getWritten(), "Hello"));
122
123 try ss.stream.write("world");
124 assert(mem.eql(u8, ss.getWritten(), "Helloworld"));
125
126 assertError(ss.stream.write("!"), error.OutOfSpace);
127 assert(mem.eql(u8, ss.getWritten(), "Helloworld"));
128
129 ss.reset();
130 assert(ss.getWritten().len == 0);
131
132 assertError(ss.stream.write("Hello world!"), error.OutOfSpace);
133 assert(mem.eql(u8, ss.getWritten(), "Hello worl"));
134}
std/json.zig created+1389
......@@ -0,0 +1,1389 @@
1// JSON parser conforming to RFC8259.
2//
3// https://tools.ietf.org/html/rfc8259
4
5const std = @import("index.zig");
6const debug = std.debug;
7const mem = std.mem;
8
9// A single token slice into the parent string.
10//
11// Use `token.slice()` on the input at the current position to get the current slice.
12pub const Token = struct {
13 id: Id,
14 // How many bytes do we skip before counting
15 offset: u1,
16 // Whether string contains a \uXXXX sequence and cannot be zero-copied
17 string_has_escape: bool,
18 // Whether number is simple and can be represented by an integer (i.e. no `.` or `e`)
19 number_is_integer: bool,
20 // How many bytes from the current position behind the start of this token is.
21 count: usize,
22
23 pub const Id = enum {
24 ObjectBegin,
25 ObjectEnd,
26 ArrayBegin,
27 ArrayEnd,
28 String,
29 Number,
30 True,
31 False,
32 Null,
33 };
34
35 pub fn init(id: Id, count: usize, offset: u1) Token {
36 return Token{
37 .id = id,
38 .offset = offset,
39 .string_has_escape = false,
40 .number_is_integer = true,
41 .count = count,
42 };
43 }
44
45 pub fn initString(count: usize, has_unicode_escape: bool) Token {
46 return Token{
47 .id = Id.String,
48 .offset = 0,
49 .string_has_escape = has_unicode_escape,
50 .number_is_integer = true,
51 .count = count,
52 };
53 }
54
55 pub fn initNumber(count: usize, number_is_integer: bool) Token {
56 return Token{
57 .id = Id.Number,
58 .offset = 0,
59 .string_has_escape = false,
60 .number_is_integer = number_is_integer,
61 .count = count,
62 };
63 }
64
65 // A marker token is a zero-length
66 pub fn initMarker(id: Id) Token {
67 return Token{
68 .id = id,
69 .offset = 0,
70 .string_has_escape = false,
71 .number_is_integer = true,
72 .count = 0,
73 };
74 }
75
76 // Slice into the underlying input string.
77 pub fn slice(self: *const Token, input: []const u8, i: usize) []const u8 {
78 return input[i + self.offset - self.count .. i + self.offset];
79 }
80};
81
82// A small streaming JSON parser. This accepts input one byte at a time and returns tokens as
83// they are encountered. No copies or allocations are performed during parsing and the entire
84// parsing state requires ~40-50 bytes of stack space.
85//
86// Conforms strictly to RFC8529.
87//
88// For a non-byte based wrapper, consider using TokenStream instead.
89pub const StreamingParser = struct {
90 // Current state
91 state: State,
92 // How many bytes we have counted for the current token
93 count: usize,
94 // What state to follow after parsing a string (either property or value string)
95 after_string_state: State,
96 // What state to follow after parsing a value (either top-level or value end)
97 after_value_state: State,
98 // If we stopped now, would the complete parsed string to now be a valid json string
99 complete: bool,
100 // Current token flags to pass through to the next generated, see Token.
101 string_has_escape: bool,
102 number_is_integer: bool,
103
104 // Bit-stack for nested object/map literals (max 255 nestings).
105 stack: u256,
106 stack_used: u8,
107
108 const object_bit = 0;
109 const array_bit = 1;
110 const max_stack_size = @maxValue(u8);
111
112 pub fn init() StreamingParser {
113 var p: StreamingParser = undefined;
114 p.reset();
115 return p;
116 }
117
118 pub fn reset(p: *StreamingParser) void {
119 p.state = State.TopLevelBegin;
120 p.count = 0;
121 // Set before ever read in main transition function
122 p.after_string_state = undefined;
123 p.after_value_state = State.ValueEnd; // handle end of values normally
124 p.stack = 0;
125 p.stack_used = 0;
126 p.complete = false;
127 p.string_has_escape = false;
128 p.number_is_integer = true;
129 }
130
131 pub const State = enum {
132 // These must be first with these explicit values as we rely on them for indexing the
133 // bit-stack directly and avoiding a branch.
134 ObjectSeparator = 0,
135 ValueEnd = 1,
136
137 TopLevelBegin,
138 TopLevelEnd,
139
140 ValueBegin,
141 ValueBeginNoClosing,
142
143 String,
144 StringUtf8Byte3,
145 StringUtf8Byte2,
146 StringUtf8Byte1,
147 StringEscapeCharacter,
148 StringEscapeHexUnicode4,
149 StringEscapeHexUnicode3,
150 StringEscapeHexUnicode2,
151 StringEscapeHexUnicode1,
152
153 Number,
154 NumberMaybeDotOrExponent,
155 NumberMaybeDigitOrDotOrExponent,
156 NumberFractionalRequired,
157 NumberFractional,
158 NumberMaybeExponent,
159 NumberExponent,
160 NumberExponentDigitsRequired,
161 NumberExponentDigits,
162
163 TrueLiteral1,
164 TrueLiteral2,
165 TrueLiteral3,
166
167 FalseLiteral1,
168 FalseLiteral2,
169 FalseLiteral3,
170 FalseLiteral4,
171
172 NullLiteral1,
173 NullLiteral2,
174 NullLiteral3,
175
176 // Only call this function to generate array/object final state.
177 pub fn fromInt(x: var) State {
178 debug.assert(x == 0 or x == 1);
179 const T = @TagType(State);
180 return @intToEnum(State, @intCast(T, x));
181 }
182 };
183
184 pub const Error = error{
185 InvalidTopLevel,
186 TooManyNestedItems,
187 TooManyClosingItems,
188 InvalidValueBegin,
189 InvalidValueEnd,
190 UnbalancedBrackets,
191 UnbalancedBraces,
192 UnexpectedClosingBracket,
193 UnexpectedClosingBrace,
194 InvalidNumber,
195 InvalidSeparator,
196 InvalidLiteral,
197 InvalidEscapeCharacter,
198 InvalidUnicodeHexSymbol,
199 InvalidUtf8Byte,
200 InvalidTopLevelTrailing,
201 InvalidControlCharacter,
202 };
203
204 // Give another byte to the parser and obtain any new tokens. This may (rarely) return two
205 // tokens. token2 is always null if token1 is null.
206 //
207 // There is currently no error recovery on a bad stream.
208 pub fn feed(p: *StreamingParser, c: u8, token1: *?Token, token2: *?Token) Error!void {
209 token1.* = null;
210 token2.* = null;
211 p.count += 1;
212
213 // unlikely
214 if (try p.transition(c, token1)) {
215 _ = try p.transition(c, token2);
216 }
217 }
218
219 // Perform a single transition on the state machine and return any possible token.
220 fn transition(p: *StreamingParser, c: u8, token: *?Token) Error!bool {
221 switch (p.state) {
222 State.TopLevelBegin => switch (c) {
223 '{' => {
224 p.stack <<= 1;
225 p.stack |= object_bit;
226 p.stack_used += 1;
227
228 p.state = State.ValueBegin;
229 p.after_string_state = State.ObjectSeparator;
230
231 token.* = Token.initMarker(Token.Id.ObjectBegin);
232 },
233 '[' => {
234 p.stack <<= 1;
235 p.stack |= array_bit;
236 p.stack_used += 1;
237
238 p.state = State.ValueBegin;
239 p.after_string_state = State.ValueEnd;
240
241 token.* = Token.initMarker(Token.Id.ArrayBegin);
242 },
243 '-' => {
244 p.number_is_integer = true;
245 p.state = State.Number;
246 p.after_value_state = State.TopLevelEnd;
247 p.count = 0;
248 },
249 '0' => {
250 p.number_is_integer = true;
251 p.state = State.NumberMaybeDotOrExponent;
252 p.after_value_state = State.TopLevelEnd;
253 p.count = 0;
254 },
255 '1'...'9' => {
256 p.number_is_integer = true;
257 p.state = State.NumberMaybeDigitOrDotOrExponent;
258 p.after_value_state = State.TopLevelEnd;
259 p.count = 0;
260 },
261 '"' => {
262 p.state = State.String;
263 p.after_value_state = State.TopLevelEnd;
264 // We don't actually need the following since after_value_state should override.
265 p.after_string_state = State.ValueEnd;
266 p.string_has_escape = false;
267 p.count = 0;
268 },
269 't' => {
270 p.state = State.TrueLiteral1;
271 p.after_value_state = State.TopLevelEnd;
272 p.count = 0;
273 },
274 'f' => {
275 p.state = State.FalseLiteral1;
276 p.after_value_state = State.TopLevelEnd;
277 p.count = 0;
278 },
279 'n' => {
280 p.state = State.NullLiteral1;
281 p.after_value_state = State.TopLevelEnd;
282 p.count = 0;
283 },
284 0x09, 0x0A, 0x0D, 0x20 => {
285 // whitespace
286 },
287 else => {
288 return error.InvalidTopLevel;
289 },
290 },
291
292 State.TopLevelEnd => switch (c) {
293 0x09, 0x0A, 0x0D, 0x20 => {
294 // whitespace
295 },
296 else => {
297 return error.InvalidTopLevelTrailing;
298 },
299 },
300
301 State.ValueBegin => switch (c) {
302 // NOTE: These are shared in ValueEnd as well, think we can reorder states to
303 // be a bit clearer and avoid this duplication.
304 '}' => {
305 // unlikely
306 if (p.stack & 1 != object_bit) {
307 return error.UnexpectedClosingBracket;
308 }
309 if (p.stack_used == 0) {
310 return error.TooManyClosingItems;
311 }
312
313 p.state = State.ValueBegin;
314 p.after_string_state = State.fromInt(p.stack & 1);
315
316 p.stack >>= 1;
317 p.stack_used -= 1;
318
319 switch (p.stack_used) {
320 0 => {
321 p.complete = true;
322 p.state = State.TopLevelEnd;
323 },
324 else => {
325 p.state = State.ValueEnd;
326 },
327 }
328
329 token.* = Token.initMarker(Token.Id.ObjectEnd);
330 },
331 ']' => {
332 if (p.stack & 1 != array_bit) {
333 return error.UnexpectedClosingBrace;
334 }
335 if (p.stack_used == 0) {
336 return error.TooManyClosingItems;
337 }
338
339 p.state = State.ValueBegin;
340 p.after_string_state = State.fromInt(p.stack & 1);
341
342 p.stack >>= 1;
343 p.stack_used -= 1;
344
345 switch (p.stack_used) {
346 0 => {
347 p.complete = true;
348 p.state = State.TopLevelEnd;
349 },
350 else => {
351 p.state = State.ValueEnd;
352 },
353 }
354
355 token.* = Token.initMarker(Token.Id.ArrayEnd);
356 },
357 '{' => {
358 if (p.stack_used == max_stack_size) {
359 return error.TooManyNestedItems;
360 }
361
362 p.stack <<= 1;
363 p.stack |= object_bit;
364 p.stack_used += 1;
365
366 p.state = State.ValueBegin;
367 p.after_string_state = State.ObjectSeparator;
368
369 token.* = Token.initMarker(Token.Id.ObjectBegin);
370 },
371 '[' => {
372 if (p.stack_used == max_stack_size) {
373 return error.TooManyNestedItems;
374 }
375
376 p.stack <<= 1;
377 p.stack |= array_bit;
378 p.stack_used += 1;
379
380 p.state = State.ValueBegin;
381 p.after_string_state = State.ValueEnd;
382
383 token.* = Token.initMarker(Token.Id.ArrayBegin);
384 },
385 '-' => {
386 p.state = State.Number;
387 p.count = 0;
388 },
389 '0' => {
390 p.state = State.NumberMaybeDotOrExponent;
391 p.count = 0;
392 },
393 '1'...'9' => {
394 p.state = State.NumberMaybeDigitOrDotOrExponent;
395 p.count = 0;
396 },
397 '"' => {
398 p.state = State.String;
399 p.count = 0;
400 },
401 't' => {
402 p.state = State.TrueLiteral1;
403 p.count = 0;
404 },
405 'f' => {
406 p.state = State.FalseLiteral1;
407 p.count = 0;
408 },
409 'n' => {
410 p.state = State.NullLiteral1;
411 p.count = 0;
412 },
413 0x09, 0x0A, 0x0D, 0x20 => {
414 // whitespace
415 },
416 else => {
417 return error.InvalidValueBegin;
418 },
419 },
420
421 // TODO: A bit of duplication here and in the following state, redo.
422 State.ValueBeginNoClosing => switch (c) {
423 '{' => {
424 if (p.stack_used == max_stack_size) {
425 return error.TooManyNestedItems;
426 }
427
428 p.stack <<= 1;
429 p.stack |= object_bit;
430 p.stack_used += 1;
431
432 p.state = State.ValueBegin;
433 p.after_string_state = State.ObjectSeparator;
434
435 token.* = Token.initMarker(Token.Id.ObjectBegin);
436 },
437 '[' => {
438 if (p.stack_used == max_stack_size) {
439 return error.TooManyNestedItems;
440 }
441
442 p.stack <<= 1;
443 p.stack |= array_bit;
444 p.stack_used += 1;
445
446 p.state = State.ValueBegin;
447 p.after_string_state = State.ValueEnd;
448
449 token.* = Token.initMarker(Token.Id.ArrayBegin);
450 },
451 '-' => {
452 p.state = State.Number;
453 p.count = 0;
454 },
455 '0' => {
456 p.state = State.NumberMaybeDotOrExponent;
457 p.count = 0;
458 },
459 '1'...'9' => {
460 p.state = State.NumberMaybeDigitOrDotOrExponent;
461 p.count = 0;
462 },
463 '"' => {
464 p.state = State.String;
465 p.count = 0;
466 },
467 't' => {
468 p.state = State.TrueLiteral1;
469 p.count = 0;
470 },
471 'f' => {
472 p.state = State.FalseLiteral1;
473 p.count = 0;
474 },
475 'n' => {
476 p.state = State.NullLiteral1;
477 p.count = 0;
478 },
479 0x09, 0x0A, 0x0D, 0x20 => {
480 // whitespace
481 },
482 else => {
483 return error.InvalidValueBegin;
484 },
485 },
486
487 State.ValueEnd => switch (c) {
488 ',' => {
489 p.after_string_state = State.fromInt(p.stack & 1);
490 p.state = State.ValueBeginNoClosing;
491 },
492 ']' => {
493 if (p.stack_used == 0) {
494 return error.UnbalancedBrackets;
495 }
496
497 p.state = State.ValueEnd;
498 p.after_string_state = State.fromInt(p.stack & 1);
499
500 p.stack >>= 1;
501 p.stack_used -= 1;
502
503 if (p.stack_used == 0) {
504 p.complete = true;
505 p.state = State.TopLevelEnd;
506 }
507
508 token.* = Token.initMarker(Token.Id.ArrayEnd);
509 },
510 '}' => {
511 if (p.stack_used == 0) {
512 return error.UnbalancedBraces;
513 }
514
515 p.state = State.ValueEnd;
516 p.after_string_state = State.fromInt(p.stack & 1);
517
518 p.stack >>= 1;
519 p.stack_used -= 1;
520
521 if (p.stack_used == 0) {
522 p.complete = true;
523 p.state = State.TopLevelEnd;
524 }
525
526 token.* = Token.initMarker(Token.Id.ObjectEnd);
527 },
528 0x09, 0x0A, 0x0D, 0x20 => {
529 // whitespace
530 },
531 else => {
532 return error.InvalidValueEnd;
533 },
534 },
535
536 State.ObjectSeparator => switch (c) {
537 ':' => {
538 p.state = State.ValueBegin;
539 p.after_string_state = State.ValueEnd;
540 },
541 0x09, 0x0A, 0x0D, 0x20 => {
542 // whitespace
543 },
544 else => {
545 return error.InvalidSeparator;
546 },
547 },
548
549 State.String => switch (c) {
550 0x00...0x1F => {
551 return error.InvalidControlCharacter;
552 },
553 '"' => {
554 p.state = p.after_string_state;
555 if (p.after_value_state == State.TopLevelEnd) {
556 p.state = State.TopLevelEnd;
557 p.complete = true;
558 }
559
560 token.* = Token.initString(p.count - 1, p.string_has_escape);
561 },
562 '\\' => {
563 p.state = State.StringEscapeCharacter;
564 },
565 0x20, 0x21, 0x23...0x5B, 0x5D...0x7F => {
566 // non-control ascii
567 },
568 0xC0...0xDF => {
569 p.state = State.StringUtf8Byte1;
570 },
571 0xE0...0xEF => {
572 p.state = State.StringUtf8Byte2;
573 },
574 0xF0...0xFF => {
575 p.state = State.StringUtf8Byte3;
576 },
577 else => {
578 return error.InvalidUtf8Byte;
579 },
580 },
581
582 State.StringUtf8Byte3 => switch (c >> 6) {
583 0b10 => p.state = State.StringUtf8Byte2,
584 else => return error.InvalidUtf8Byte,
585 },
586
587 State.StringUtf8Byte2 => switch (c >> 6) {
588 0b10 => p.state = State.StringUtf8Byte1,
589 else => return error.InvalidUtf8Byte,
590 },
591
592 State.StringUtf8Byte1 => switch (c >> 6) {
593 0b10 => p.state = State.String,
594 else => return error.InvalidUtf8Byte,
595 },
596
597 State.StringEscapeCharacter => switch (c) {
598 // NOTE: '/' is allowed as an escaped character but it also is allowed
599 // as unescaped according to the RFC. There is a reported errata which suggests
600 // removing the non-escaped variant but it makes more sense to simply disallow
601 // it as an escape code here.
602 //
603 // The current JSONTestSuite tests rely on both of this behaviour being present
604 // however, so we default to the status quo where both are accepted until this
605 // is further clarified.
606 '"', '\\', '/', 'b', 'f', 'n', 'r', 't' => {
607 p.string_has_escape = true;
608 p.state = State.String;
609 },
610 'u' => {
611 p.string_has_escape = true;
612 p.state = State.StringEscapeHexUnicode4;
613 },
614 else => {
615 return error.InvalidEscapeCharacter;
616 },
617 },
618
619 State.StringEscapeHexUnicode4 => switch (c) {
620 '0'...'9', 'A'...'F', 'a'...'f' => {
621 p.state = State.StringEscapeHexUnicode3;
622 },
623 else => return error.InvalidUnicodeHexSymbol,
624 },
625
626 State.StringEscapeHexUnicode3 => switch (c) {
627 '0'...'9', 'A'...'F', 'a'...'f' => {
628 p.state = State.StringEscapeHexUnicode2;
629 },
630 else => return error.InvalidUnicodeHexSymbol,
631 },
632
633 State.StringEscapeHexUnicode2 => switch (c) {
634 '0'...'9', 'A'...'F', 'a'...'f' => {
635 p.state = State.StringEscapeHexUnicode1;
636 },
637 else => return error.InvalidUnicodeHexSymbol,
638 },
639
640 State.StringEscapeHexUnicode1 => switch (c) {
641 '0'...'9', 'A'...'F', 'a'...'f' => {
642 p.state = State.String;
643 },
644 else => return error.InvalidUnicodeHexSymbol,
645 },
646
647 State.Number => {
648 p.complete = p.after_value_state == State.TopLevelEnd;
649 switch (c) {
650 '0' => {
651 p.state = State.NumberMaybeDotOrExponent;
652 },
653 '1'...'9' => {
654 p.state = State.NumberMaybeDigitOrDotOrExponent;
655 },
656 else => {
657 return error.InvalidNumber;
658 },
659 }
660 },
661
662 State.NumberMaybeDotOrExponent => {
663 p.complete = p.after_value_state == State.TopLevelEnd;
664 switch (c) {
665 '.' => {
666 p.number_is_integer = false;
667 p.state = State.NumberFractionalRequired;
668 },
669 'e', 'E' => {
670 p.number_is_integer = false;
671 p.state = State.NumberExponent;
672 },
673 else => {
674 p.state = p.after_value_state;
675 token.* = Token.initNumber(p.count, p.number_is_integer);
676 return true;
677 },
678 }
679 },
680
681 State.NumberMaybeDigitOrDotOrExponent => {
682 p.complete = p.after_value_state == State.TopLevelEnd;
683 switch (c) {
684 '.' => {
685 p.number_is_integer = false;
686 p.state = State.NumberFractionalRequired;
687 },
688 'e', 'E' => {
689 p.number_is_integer = false;
690 p.state = State.NumberExponent;
691 },
692 '0'...'9' => {
693 // another digit
694 },
695 else => {
696 p.state = p.after_value_state;
697 token.* = Token.initNumber(p.count, p.number_is_integer);
698 return true;
699 },
700 }
701 },
702
703 State.NumberFractionalRequired => {
704 p.complete = p.after_value_state == State.TopLevelEnd;
705 switch (c) {
706 '0'...'9' => {
707 p.state = State.NumberFractional;
708 },
709 else => {
710 return error.InvalidNumber;
711 },
712 }
713 },
714
715 State.NumberFractional => {
716 p.complete = p.after_value_state == State.TopLevelEnd;
717 switch (c) {
718 '0'...'9' => {
719 // another digit
720 },
721 'e', 'E' => {
722 p.number_is_integer = false;
723 p.state = State.NumberExponent;
724 },
725 else => {
726 p.state = p.after_value_state;
727 token.* = Token.initNumber(p.count, p.number_is_integer);
728 return true;
729 },
730 }
731 },
732
733 State.NumberMaybeExponent => {
734 p.complete = p.after_value_state == State.TopLevelEnd;
735 switch (c) {
736 'e', 'E' => {
737 p.number_is_integer = false;
738 p.state = State.NumberExponent;
739 },
740 else => {
741 p.state = p.after_value_state;
742 token.* = Token.initNumber(p.count, p.number_is_integer);
743 return true;
744 },
745 }
746 },
747
748 State.NumberExponent => switch (c) {
749 '-', '+' => {
750 p.complete = false;
751 p.state = State.NumberExponentDigitsRequired;
752 },
753 '0'...'9' => {
754 p.complete = p.after_value_state == State.TopLevelEnd;
755 p.state = State.NumberExponentDigits;
756 },
757 else => {
758 return error.InvalidNumber;
759 },
760 },
761
762 State.NumberExponentDigitsRequired => switch (c) {
763 '0'...'9' => {
764 p.complete = p.after_value_state == State.TopLevelEnd;
765 p.state = State.NumberExponentDigits;
766 },
767 else => {
768 return error.InvalidNumber;
769 },
770 },
771
772 State.NumberExponentDigits => {
773 p.complete = p.after_value_state == State.TopLevelEnd;
774 switch (c) {
775 '0'...'9' => {
776 // another digit
777 },
778 else => {
779 p.state = p.after_value_state;
780 token.* = Token.initNumber(p.count, p.number_is_integer);
781 return true;
782 },
783 }
784 },
785
786 State.TrueLiteral1 => switch (c) {
787 'r' => p.state = State.TrueLiteral2,
788 else => return error.InvalidLiteral,
789 },
790
791 State.TrueLiteral2 => switch (c) {
792 'u' => p.state = State.TrueLiteral3,
793 else => return error.InvalidLiteral,
794 },
795
796 State.TrueLiteral3 => switch (c) {
797 'e' => {
798 p.state = p.after_value_state;
799 p.complete = p.state == State.TopLevelEnd;
800 token.* = Token.init(Token.Id.True, p.count + 1, 1);
801 },
802 else => {
803 return error.InvalidLiteral;
804 },
805 },
806
807 State.FalseLiteral1 => switch (c) {
808 'a' => p.state = State.FalseLiteral2,
809 else => return error.InvalidLiteral,
810 },
811
812 State.FalseLiteral2 => switch (c) {
813 'l' => p.state = State.FalseLiteral3,
814 else => return error.InvalidLiteral,
815 },
816
817 State.FalseLiteral3 => switch (c) {
818 's' => p.state = State.FalseLiteral4,
819 else => return error.InvalidLiteral,
820 },
821
822 State.FalseLiteral4 => switch (c) {
823 'e' => {
824 p.state = p.after_value_state;
825 p.complete = p.state == State.TopLevelEnd;
826 token.* = Token.init(Token.Id.False, p.count + 1, 1);
827 },
828 else => {
829 return error.InvalidLiteral;
830 },
831 },
832
833 State.NullLiteral1 => switch (c) {
834 'u' => p.state = State.NullLiteral2,
835 else => return error.InvalidLiteral,
836 },
837
838 State.NullLiteral2 => switch (c) {
839 'l' => p.state = State.NullLiteral3,
840 else => return error.InvalidLiteral,
841 },
842
843 State.NullLiteral3 => switch (c) {
844 'l' => {
845 p.state = p.after_value_state;
846 p.complete = p.state == State.TopLevelEnd;
847 token.* = Token.init(Token.Id.Null, p.count + 1, 1);
848 },
849 else => {
850 return error.InvalidLiteral;
851 },
852 },
853 }
854
855 return false;
856 }
857};
858
859// A small wrapper over a StreamingParser for full slices. Returns a stream of json Tokens.
860pub const TokenStream = struct {
861 i: usize,
862 slice: []const u8,
863 parser: StreamingParser,
864 token: ?Token,
865
866 pub fn init(slice: []const u8) TokenStream {
867 return TokenStream{
868 .i = 0,
869 .slice = slice,
870 .parser = StreamingParser.init(),
871 .token = null,
872 };
873 }
874
875 pub fn next(self: *TokenStream) !?Token {
876 if (self.token) |token| {
877 self.token = null;
878 return token;
879 }
880
881 var t1: ?Token = undefined;
882 var t2: ?Token = undefined;
883
884 while (self.i < self.slice.len) {
885 try self.parser.feed(self.slice[self.i], &t1, &t2);
886 self.i += 1;
887
888 if (t1) |token| {
889 self.token = t2;
890 return token;
891 }
892 }
893
894 if (self.i > self.slice.len) {
895 try self.parser.feed(' ', &t1, &t2);
896 self.i += 1;
897
898 if (t1) |token| {
899 return token;
900 }
901 }
902
903 return null;
904 }
905};
906
907fn checkNext(p: *TokenStream, id: Token.Id) void {
908 const token = (p.next() catch unreachable).?;
909 debug.assert(token.id == id);
910}
911
912test "token" {
913 const s =
914 \\{
915 \\ "Image": {
916 \\ "Width": 800,
917 \\ "Height": 600,
918 \\ "Title": "View from 15th Floor",
919 \\ "Thumbnail": {
920 \\ "Url": "http://www.example.com/image/481989943",
921 \\ "Height": 125,
922 \\ "Width": 100
923 \\ },
924 \\ "Animated" : false,
925 \\ "IDs": [116, 943, 234, 38793]
926 \\ }
927 \\}
928 ;
929
930 var p = TokenStream.init(s);
931
932 checkNext(&p, Token.Id.ObjectBegin);
933 checkNext(&p, Token.Id.String); // Image
934 checkNext(&p, Token.Id.ObjectBegin);
935 checkNext(&p, Token.Id.String); // Width
936 checkNext(&p, Token.Id.Number);
937 checkNext(&p, Token.Id.String); // Height
938 checkNext(&p, Token.Id.Number);
939 checkNext(&p, Token.Id.String); // Title
940 checkNext(&p, Token.Id.String);
941 checkNext(&p, Token.Id.String); // Thumbnail
942 checkNext(&p, Token.Id.ObjectBegin);
943 checkNext(&p, Token.Id.String); // Url
944 checkNext(&p, Token.Id.String);
945 checkNext(&p, Token.Id.String); // Height
946 checkNext(&p, Token.Id.Number);
947 checkNext(&p, Token.Id.String); // Width
948 checkNext(&p, Token.Id.Number);
949 checkNext(&p, Token.Id.ObjectEnd);
950 checkNext(&p, Token.Id.String); // Animated
951 checkNext(&p, Token.Id.False);
952 checkNext(&p, Token.Id.String); // IDs
953 checkNext(&p, Token.Id.ArrayBegin);
954 checkNext(&p, Token.Id.Number);
955 checkNext(&p, Token.Id.Number);
956 checkNext(&p, Token.Id.Number);
957 checkNext(&p, Token.Id.Number);
958 checkNext(&p, Token.Id.ArrayEnd);
959 checkNext(&p, Token.Id.ObjectEnd);
960 checkNext(&p, Token.Id.ObjectEnd);
961
962 debug.assert((try p.next()) == null);
963}
964
965// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
966// be able to decode the string even if this returns true.
967pub fn validate(s: []const u8) bool {
968 var p = StreamingParser.init();
969
970 for (s) |c, i| {
971 var token1: ?Token = undefined;
972 var token2: ?Token = undefined;
973
974 p.feed(c, &token1, &token2) catch |err| {
975 return false;
976 };
977 }
978
979 return p.complete;
980}
981
982test "json validate" {
983 debug.assert(validate("{}"));
984}
985
986const Allocator = std.mem.Allocator;
987const ArenaAllocator = std.heap.ArenaAllocator;
988const ArrayList = std.ArrayList;
989const HashMap = std.HashMap;
990
991pub const ValueTree = struct {
992 arena: ArenaAllocator,
993 root: Value,
994
995 pub fn deinit(self: *ValueTree) void {
996 self.arena.deinit();
997 }
998};
999
1000pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8);
1001
1002pub const Value = union(enum) {
1003 Null,
1004 Bool: bool,
1005 Integer: i64,
1006 Float: f64,
1007 String: []const u8,
1008 Array: ArrayList(Value),
1009 Object: ObjectMap,
1010
1011 pub fn dump(self: *const Value) void {
1012 switch (self.*) {
1013 Value.Null => {
1014 debug.warn("null");
1015 },
1016 Value.Bool => |inner| {
1017 debug.warn("{}", inner);
1018 },
1019 Value.Integer => |inner| {
1020 debug.warn("{}", inner);
1021 },
1022 Value.Float => |inner| {
1023 debug.warn("{.5}", inner);
1024 },
1025 Value.String => |inner| {
1026 debug.warn("\"{}\"", inner);
1027 },
1028 Value.Array => |inner| {
1029 var not_first = false;
1030 debug.warn("[");
1031 for (inner.toSliceConst()) |value| {
1032 if (not_first) {
1033 debug.warn(",");
1034 }
1035 not_first = true;
1036 value.dump();
1037 }
1038 debug.warn("]");
1039 },
1040 Value.Object => |inner| {
1041 var not_first = false;
1042 debug.warn("{{");
1043 var it = inner.iterator();
1044
1045 while (it.next()) |entry| {
1046 if (not_first) {
1047 debug.warn(",");
1048 }
1049 not_first = true;
1050 debug.warn("\"{}\":", entry.key);
1051 entry.value.dump();
1052 }
1053 debug.warn("}}");
1054 },
1055 }
1056 }
1057
1058 pub fn dumpIndent(self: *const Value, indent: usize) void {
1059 if (indent == 0) {
1060 self.dump();
1061 } else {
1062 self.dumpIndentLevel(indent, 0);
1063 }
1064 }
1065
1066 fn dumpIndentLevel(self: *const Value, indent: usize, level: usize) void {
1067 switch (self.*) {
1068 Value.Null => {
1069 debug.warn("null");
1070 },
1071 Value.Bool => |inner| {
1072 debug.warn("{}", inner);
1073 },
1074 Value.Integer => |inner| {
1075 debug.warn("{}", inner);
1076 },
1077 Value.Float => |inner| {
1078 debug.warn("{.5}", inner);
1079 },
1080 Value.String => |inner| {
1081 debug.warn("\"{}\"", inner);
1082 },
1083 Value.Array => |inner| {
1084 var not_first = false;
1085 debug.warn("[\n");
1086
1087 for (inner.toSliceConst()) |value| {
1088 if (not_first) {
1089 debug.warn(",\n");
1090 }
1091 not_first = true;
1092 padSpace(level + indent);
1093 value.dumpIndentLevel(indent, level + indent);
1094 }
1095 debug.warn("\n");
1096 padSpace(level);
1097 debug.warn("]");
1098 },
1099 Value.Object => |inner| {
1100 var not_first = false;
1101 debug.warn("{{\n");
1102 var it = inner.iterator();
1103
1104 while (it.next()) |entry| {
1105 if (not_first) {
1106 debug.warn(",\n");
1107 }
1108 not_first = true;
1109 padSpace(level + indent);
1110 debug.warn("\"{}\": ", entry.key);
1111 entry.value.dumpIndentLevel(indent, level + indent);
1112 }
1113 debug.warn("\n");
1114 padSpace(level);
1115 debug.warn("}}");
1116 },
1117 }
1118 }
1119
1120 fn padSpace(indent: usize) void {
1121 var i: usize = 0;
1122 while (i < indent) : (i += 1) {
1123 debug.warn(" ");
1124 }
1125 }
1126};
1127
1128// A non-stream JSON parser which constructs a tree of Value's.
1129pub const Parser = struct {
1130 allocator: *Allocator,
1131 state: State,
1132 copy_strings: bool,
1133 // Stores parent nodes and un-combined Values.
1134 stack: ArrayList(Value),
1135
1136 const State = enum {
1137 ObjectKey,
1138 ObjectValue,
1139 ArrayValue,
1140 Simple,
1141 };
1142
1143 pub fn init(allocator: *Allocator, copy_strings: bool) Parser {
1144 return Parser{
1145 .allocator = allocator,
1146 .state = State.Simple,
1147 .copy_strings = copy_strings,
1148 .stack = ArrayList(Value).init(allocator),
1149 };
1150 }
1151
1152 pub fn deinit(p: *Parser) void {
1153 p.stack.deinit();
1154 }
1155
1156 pub fn reset(p: *Parser) void {
1157 p.state = State.Simple;
1158 p.stack.shrink(0);
1159 }
1160
1161 pub fn parse(p: *Parser, input: []const u8) !ValueTree {
1162 var s = TokenStream.init(input);
1163
1164 var arena = ArenaAllocator.init(p.allocator);
1165 errdefer arena.deinit();
1166
1167 while (try s.next()) |token| {
1168 try p.transition(&arena.allocator, input, s.i - 1, token);
1169 }
1170
1171 debug.assert(p.stack.len == 1);
1172
1173 return ValueTree{
1174 .arena = arena,
1175 .root = p.stack.at(0),
1176 };
1177 }
1178
1179 // Even though p.allocator exists, we take an explicit allocator so that allocation state
1180 // can be cleaned up on error correctly during a `parse` on call.
1181 fn transition(p: *Parser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void {
1182 switch (p.state) {
1183 State.ObjectKey => switch (token.id) {
1184 Token.Id.ObjectEnd => {
1185 if (p.stack.len == 1) {
1186 return;
1187 }
1188
1189 var value = p.stack.pop();
1190 try p.pushToParent(value);
1191 },
1192 Token.Id.String => {
1193 try p.stack.append(try p.parseString(allocator, token, input, i));
1194 p.state = State.ObjectValue;
1195 },
1196 else => {
1197 unreachable;
1198 },
1199 },
1200 State.ObjectValue => {
1201 var object = &p.stack.items[p.stack.len - 2].Object;
1202 var key = p.stack.items[p.stack.len - 1].String;
1203
1204 switch (token.id) {
1205 Token.Id.ObjectBegin => {
1206 try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
1207 p.state = State.ObjectKey;
1208 },
1209 Token.Id.ArrayBegin => {
1210 try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
1211 p.state = State.ArrayValue;
1212 },
1213 Token.Id.String => {
1214 _ = try object.put(key, try p.parseString(allocator, token, input, i));
1215 _ = p.stack.pop();
1216 p.state = State.ObjectKey;
1217 },
1218 Token.Id.Number => {
1219 _ = try object.put(key, try p.parseNumber(token, input, i));
1220 _ = p.stack.pop();
1221 p.state = State.ObjectKey;
1222 },
1223 Token.Id.True => {
1224 _ = try object.put(key, Value{ .Bool = true });
1225 _ = p.stack.pop();
1226 p.state = State.ObjectKey;
1227 },
1228 Token.Id.False => {
1229 _ = try object.put(key, Value{ .Bool = false });
1230 _ = p.stack.pop();
1231 p.state = State.ObjectKey;
1232 },
1233 Token.Id.Null => {
1234 _ = try object.put(key, Value.Null);
1235 _ = p.stack.pop();
1236 p.state = State.ObjectKey;
1237 },
1238 Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
1239 unreachable;
1240 },
1241 }
1242 },
1243 State.ArrayValue => {
1244 var array = &p.stack.items[p.stack.len - 1].Array;
1245
1246 switch (token.id) {
1247 Token.Id.ArrayEnd => {
1248 if (p.stack.len == 1) {
1249 return;
1250 }
1251
1252 var value = p.stack.pop();
1253 try p.pushToParent(value);
1254 },
1255 Token.Id.ObjectBegin => {
1256 try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
1257 p.state = State.ObjectKey;
1258 },
1259 Token.Id.ArrayBegin => {
1260 try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
1261 p.state = State.ArrayValue;
1262 },
1263 Token.Id.String => {
1264 try array.append(try p.parseString(allocator, token, input, i));
1265 },
1266 Token.Id.Number => {
1267 try array.append(try p.parseNumber(token, input, i));
1268 },
1269 Token.Id.True => {
1270 try array.append(Value{ .Bool = true });
1271 },
1272 Token.Id.False => {
1273 try array.append(Value{ .Bool = false });
1274 },
1275 Token.Id.Null => {
1276 try array.append(Value.Null);
1277 },
1278 Token.Id.ObjectEnd => {
1279 unreachable;
1280 },
1281 }
1282 },
1283 State.Simple => switch (token.id) {
1284 Token.Id.ObjectBegin => {
1285 try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
1286 p.state = State.ObjectKey;
1287 },
1288 Token.Id.ArrayBegin => {
1289 try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
1290 p.state = State.ArrayValue;
1291 },
1292 Token.Id.String => {
1293 try p.stack.append(try p.parseString(allocator, token, input, i));
1294 },
1295 Token.Id.Number => {
1296 try p.stack.append(try p.parseNumber(token, input, i));
1297 },
1298 Token.Id.True => {
1299 try p.stack.append(Value{ .Bool = true });
1300 },
1301 Token.Id.False => {
1302 try p.stack.append(Value{ .Bool = false });
1303 },
1304 Token.Id.Null => {
1305 try p.stack.append(Value.Null);
1306 },
1307 Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
1308 unreachable;
1309 },
1310 },
1311 }
1312 }
1313
1314 fn pushToParent(p: *Parser, value: *const Value) !void {
1315 switch (p.stack.at(p.stack.len - 1)) {
1316 // Object Parent -> [ ..., object, <key>, value ]
1317 Value.String => |key| {
1318 _ = p.stack.pop();
1319
1320 var object = &p.stack.items[p.stack.len - 1].Object;
1321 _ = try object.put(key, value);
1322 p.state = State.ObjectKey;
1323 },
1324 // Array Parent -> [ ..., <array>, value ]
1325 Value.Array => |*array| {
1326 try array.append(value.*);
1327 p.state = State.ArrayValue;
1328 },
1329 else => {
1330 unreachable;
1331 },
1332 }
1333 }
1334
1335 fn parseString(p: *Parser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value {
1336 // TODO: We don't strictly have to copy values which do not contain any escape
1337 // characters if flagged with the option.
1338 const slice = token.slice(input, i);
1339 return Value{ .String = try mem.dupe(p.allocator, u8, slice) };
1340 }
1341
1342 fn parseNumber(p: *Parser, token: *const Token, input: []const u8, i: usize) !Value {
1343 return if (token.number_is_integer)
1344 Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
1345 else
1346 @panic("TODO: fmt.parseFloat not yet implemented");
1347 }
1348};
1349
1350test "json parser dynamic" {
1351 var p = Parser.init(debug.global_allocator, false);
1352 defer p.deinit();
1353
1354 const s =
1355 \\{
1356 \\ "Image": {
1357 \\ "Width": 800,
1358 \\ "Height": 600,
1359 \\ "Title": "View from 15th Floor",
1360 \\ "Thumbnail": {
1361 \\ "Url": "http://www.example.com/image/481989943",
1362 \\ "Height": 125,
1363 \\ "Width": 100
1364 \\ },
1365 \\ "Animated" : false,
1366 \\ "IDs": [116, 943, 234, 38793]
1367 \\ }
1368 \\}
1369 ;
1370
1371 var tree = try p.parse(s);
1372 defer tree.deinit();
1373
1374 var root = tree.root;
1375
1376 var image = root.Object.get("Image").?.value;
1377
1378 const width = image.Object.get("Width").?.value;
1379 debug.assert(width.Integer == 800);
1380
1381 const height = image.Object.get("Height").?.value;
1382 debug.assert(height.Integer == 600);
1383
1384 const title = image.Object.get("Title").?.value;
1385 debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
1386
1387 const animated = image.Object.get("Animated").?.value;
1388 debug.assert(animated.Bool == false);
1389}
std/json_test.zig created+1904
......@@ -0,0 +1,1904 @@
1// RFC 8529 conformance tests.
2//
3// Tests are taken from https://github.com/nst/JSONTestSuite
4// Read also http://seriot.ch/parsing_json.php for a good overview.
5
6const std = @import("index.zig");
7
8fn ok(comptime s: []const u8) void {
9 std.debug.assert(std.json.validate(s));
10}
11
12fn err(comptime s: []const u8) void {
13 std.debug.assert(!std.json.validate(s));
14}
15
16fn any(comptime s: []const u8) void {
17 std.debug.assert(true);
18}
19
20////////////////////////////////////////////////////////////////////////////////////////////////////
21//
22// Additional tests not part of test JSONTestSuite.
23
24test "y_trailing_comma_after_empty" {
25 ok(
26 \\{"1":[],"2":{},"3":"4"}
27 );
28}
29
30////////////////////////////////////////////////////////////////////////////////////////////////////
31
32test "y_array_arraysWithSpaces" {
33 ok(
34 \\[[] ]
35 );
36}
37
38test "y_array_empty" {
39 ok(
40 \\[]
41 );
42}
43
44test "y_array_empty-string" {
45 ok(
46 \\[""]
47 );
48}
49
50test "y_array_ending_with_newline" {
51 ok(
52 \\["a"]
53 );
54}
55
56test "y_array_false" {
57 ok(
58 \\[false]
59 );
60}
61
62test "y_array_heterogeneous" {
63 ok(
64 \\[null, 1, "1", {}]
65 );
66}
67
68test "y_array_null" {
69 ok(
70 \\[null]
71 );
72}
73
74test "y_array_with_1_and_newline" {
75 ok(
76 \\[1
77 \\]
78 );
79}
80
81test "y_array_with_leading_space" {
82 ok(
83 \\ [1]
84 );
85}
86
87test "y_array_with_several_null" {
88 ok(
89 \\[1,null,null,null,2]
90 );
91}
92
93test "y_array_with_trailing_space" {
94 ok("[2] ");
95}
96
97test "y_number_0e+1" {
98 ok(
99 \\[0e+1]
100 );
101}
102
103test "y_number_0e1" {
104 ok(
105 \\[0e1]
106 );
107}
108
109test "y_number_after_space" {
110 ok(
111 \\[ 4]
112 );
113}
114
115test "y_number_double_close_to_zero" {
116 ok(
117 \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]
118 );
119}
120
121test "y_number_int_with_exp" {
122 ok(
123 \\[20e1]
124 );
125}
126
127test "y_number" {
128 ok(
129 \\[123e65]
130 );
131}
132
133test "y_number_minus_zero" {
134 ok(
135 \\[-0]
136 );
137}
138
139test "y_number_negative_int" {
140 ok(
141 \\[-123]
142 );
143}
144
145test "y_number_negative_one" {
146 ok(
147 \\[-1]
148 );
149}
150
151test "y_number_negative_zero" {
152 ok(
153 \\[-0]
154 );
155}
156
157test "y_number_real_capital_e" {
158 ok(
159 \\[1E22]
160 );
161}
162
163test "y_number_real_capital_e_neg_exp" {
164 ok(
165 \\[1E-2]
166 );
167}
168
169test "y_number_real_capital_e_pos_exp" {
170 ok(
171 \\[1E+2]
172 );
173}
174
175test "y_number_real_exponent" {
176 ok(
177 \\[123e45]
178 );
179}
180
181test "y_number_real_fraction_exponent" {
182 ok(
183 \\[123.456e78]
184 );
185}
186
187test "y_number_real_neg_exp" {
188 ok(
189 \\[1e-2]
190 );
191}
192
193test "y_number_real_pos_exponent" {
194 ok(
195 \\[1e+2]
196 );
197}
198
199test "y_number_simple_int" {
200 ok(
201 \\[123]
202 );
203}
204
205test "y_number_simple_real" {
206 ok(
207 \\[123.456789]
208 );
209}
210
211test "y_object_basic" {
212 ok(
213 \\{"asd":"sdf"}
214 );
215}
216
217test "y_object_duplicated_key_and_value" {
218 ok(
219 \\{"a":"b","a":"b"}
220 );
221}
222
223test "y_object_duplicated_key" {
224 ok(
225 \\{"a":"b","a":"c"}
226 );
227}
228
229test "y_object_empty" {
230 ok(
231 \\{}
232 );
233}
234
235test "y_object_empty_key" {
236 ok(
237 \\{"":0}
238 );
239}
240
241test "y_object_escaped_null_in_key" {
242 ok(
243 \\{"foo\u0000bar": 42}
244 );
245}
246
247test "y_object_extreme_numbers" {
248 ok(
249 \\{ "min": -1.0e+28, "max": 1.0e+28 }
250 );
251}
252
253test "y_object" {
254 ok(
255 \\{"asd":"sdf", "dfg":"fgh"}
256 );
257}
258
259test "y_object_long_strings" {
260 ok(
261 \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
262 );
263}
264
265test "y_object_simple" {
266 ok(
267 \\{"a":[]}
268 );
269}
270
271test "y_object_string_unicode" {
272 ok(
273 \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }
274 );
275}
276
277test "y_object_with_newlines" {
278 ok(
279 \\{
280 \\"a": "b"
281 \\}
282 );
283}
284
285test "y_string_1_2_3_bytes_UTF-8_sequences" {
286 ok(
287 \\["\u0060\u012a\u12AB"]
288 );
289}
290
291test "y_string_accepted_surrogate_pair" {
292 ok(
293 \\["\uD801\udc37"]
294 );
295}
296
297test "y_string_accepted_surrogate_pairs" {
298 ok(
299 \\["\ud83d\ude39\ud83d\udc8d"]
300 );
301}
302
303test "y_string_allowed_escapes" {
304 ok(
305 \\["\"\\\/\b\f\n\r\t"]
306 );
307}
308
309test "y_string_backslash_and_u_escaped_zero" {
310 ok(
311 \\["\\u0000"]
312 );
313}
314
315test "y_string_backslash_doublequotes" {
316 ok(
317 \\["\""]
318 );
319}
320
321test "y_string_comments" {
322 ok(
323 \\["a/*b*/c/*d//e"]
324 );
325}
326
327test "y_string_double_escape_a" {
328 ok(
329 \\["\\a"]
330 );
331}
332
333test "y_string_double_escape_n" {
334 ok(
335 \\["\\n"]
336 );
337}
338
339test "y_string_escaped_control_character" {
340 ok(
341 \\["\u0012"]
342 );
343}
344
345test "y_string_escaped_noncharacter" {
346 ok(
347 \\["\uFFFF"]
348 );
349}
350
351test "y_string_in_array" {
352 ok(
353 \\["asd"]
354 );
355}
356
357test "y_string_in_array_with_leading_space" {
358 ok(
359 \\[ "asd"]
360 );
361}
362
363test "y_string_last_surrogates_1_and_2" {
364 ok(
365 \\["\uDBFF\uDFFF"]
366 );
367}
368
369test "y_string_nbsp_uescaped" {
370 ok(
371 \\["new\u00A0line"]
372 );
373}
374
375test "y_string_nonCharacterInUTF-8_U+10FFFF" {
376 ok(
377 \\["􏿿"]
378 );
379}
380
381test "y_string_nonCharacterInUTF-8_U+FFFF" {
382 ok(
383 \\["￿"]
384 );
385}
386
387test "y_string_null_escape" {
388 ok(
389 \\["\u0000"]
390 );
391}
392
393test "y_string_one-byte-utf-8" {
394 ok(
395 \\["\u002c"]
396 );
397}
398
399test "y_string_pi" {
400 ok(
401 \\["π"]
402 );
403}
404
405test "y_string_reservedCharacterInUTF-8_U+1BFFF" {
406 ok(
407 \\["𛿿"]
408 );
409}
410
411test "y_string_simple_ascii" {
412 ok(
413 \\["asd "]
414 );
415}
416
417test "y_string_space" {
418 ok(
419 \\" "
420 );
421}
422
423test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" {
424 ok(
425 \\["\uD834\uDd1e"]
426 );
427}
428
429test "y_string_three-byte-utf-8" {
430 ok(
431 \\["\u0821"]
432 );
433}
434
435test "y_string_two-byte-utf-8" {
436 ok(
437 \\["\u0123"]
438 );
439}
440
441test "y_string_u+2028_line_sep" {
442 ok("[\"\xe2\x80\xa8\"]");
443}
444
445test "y_string_u+2029_par_sep" {
446 ok("[\"\xe2\x80\xa9\"]");
447}
448
449test "y_string_uescaped_newline" {
450 ok(
451 \\["new\u000Aline"]
452 );
453}
454
455test "y_string_uEscape" {
456 ok(
457 \\["\u0061\u30af\u30EA\u30b9"]
458 );
459}
460
461test "y_string_unescaped_char_delete" {
462 ok("[\"\x7f\"]");
463}
464
465test "y_string_unicode_2" {
466 ok(
467 \\["⍂㈴⍂"]
468 );
469}
470
471test "y_string_unicodeEscapedBackslash" {
472 ok(
473 \\["\u005C"]
474 );
475}
476
477test "y_string_unicode_escaped_double_quote" {
478 ok(
479 \\["\u0022"]
480 );
481}
482
483test "y_string_unicode" {
484 ok(
485 \\["\uA66D"]
486 );
487}
488
489test "y_string_unicode_U+10FFFE_nonchar" {
490 ok(
491 \\["\uDBFF\uDFFE"]
492 );
493}
494
495test "y_string_unicode_U+1FFFE_nonchar" {
496 ok(
497 \\["\uD83F\uDFFE"]
498 );
499}
500
501test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" {
502 ok(
503 \\["\u200B"]
504 );
505}
506
507test "y_string_unicode_U+2064_invisible_plus" {
508 ok(
509 \\["\u2064"]
510 );
511}
512
513test "y_string_unicode_U+FDD0_nonchar" {
514 ok(
515 \\["\uFDD0"]
516 );
517}
518
519test "y_string_unicode_U+FFFE_nonchar" {
520 ok(
521 \\["\uFFFE"]
522 );
523}
524
525test "y_string_utf8" {
526 ok(
527 \\["€𝄞"]
528 );
529}
530
531test "y_string_with_del_character" {
532 ok("[\"a\x7fa\"]");
533}
534
535test "y_structure_lonely_false" {
536 ok(
537 \\false
538 );
539}
540
541test "y_structure_lonely_int" {
542 ok(
543 \\42
544 );
545}
546
547test "y_structure_lonely_negative_real" {
548 ok(
549 \\-0.1
550 );
551}
552
553test "y_structure_lonely_null" {
554 ok(
555 \\null
556 );
557}
558
559test "y_structure_lonely_string" {
560 ok(
561 \\"asd"
562 );
563}
564
565test "y_structure_lonely_true" {
566 ok(
567 \\true
568 );
569}
570
571test "y_structure_string_empty" {
572 ok(
573 \\""
574 );
575}
576
577test "y_structure_trailing_newline" {
578 ok(
579 \\["a"]
580 );
581}
582
583test "y_structure_true_in_array" {
584 ok(
585 \\[true]
586 );
587}
588
589test "y_structure_whitespace_array" {
590 ok(" [] ");
591}
592
593////////////////////////////////////////////////////////////////////////////////////////////////////
594
595test "n_array_1_true_without_comma" {
596 err(
597 \\[1 true]
598 );
599}
600
601test "n_array_a_invalid_utf8" {
602 err(
603 \\[aå]
604 );
605}
606
607test "n_array_colon_instead_of_comma" {
608 err(
609 \\["": 1]
610 );
611}
612
613test "n_array_comma_after_close" {
614 //err(
615 // \\[""],
616 //);
617}
618
619test "n_array_comma_and_number" {
620 err(
621 \\[,1]
622 );
623}
624
625test "n_array_double_comma" {
626 err(
627 \\[1,,2]
628 );
629}
630
631test "n_array_double_extra_comma" {
632 err(
633 \\["x",,]
634 );
635}
636
637test "n_array_extra_close" {
638 err(
639 \\["x"]]
640 );
641}
642
643test "n_array_extra_comma" {
644 //err(
645 // \\["",]
646 //);
647}
648
649test "n_array_incomplete_invalid_value" {
650 err(
651 \\[x
652 );
653}
654
655test "n_array_incomplete" {
656 err(
657 \\["x"
658 );
659}
660
661test "n_array_inner_array_no_comma" {
662 err(
663 \\[3[4]]
664 );
665}
666
667test "n_array_invalid_utf8" {
668 err(
669 \\[ÿ]
670 );
671}
672
673test "n_array_items_separated_by_semicolon" {
674 err(
675 \\[1:2]
676 );
677}
678
679test "n_array_just_comma" {
680 err(
681 \\[,]
682 );
683}
684
685test "n_array_just_minus" {
686 err(
687 \\[-]
688 );
689}
690
691test "n_array_missing_value" {
692 err(
693 \\[ , ""]
694 );
695}
696
697test "n_array_newlines_unclosed" {
698 err(
699 \\["a",
700 \\4
701 \\,1,
702 );
703}
704
705test "n_array_number_and_comma" {
706 err(
707 \\[1,]
708 );
709}
710
711test "n_array_number_and_several_commas" {
712 err(
713 \\[1,,]
714 );
715}
716
717test "n_array_spaces_vertical_tab_formfeed" {
718 err("[\"\x0aa\"\\f]");
719}
720
721test "n_array_star_inside" {
722 err(
723 \\[*]
724 );
725}
726
727test "n_array_unclosed" {
728 err(
729 \\[""
730 );
731}
732
733test "n_array_unclosed_trailing_comma" {
734 err(
735 \\[1,
736 );
737}
738
739test "n_array_unclosed_with_new_lines" {
740 err(
741 \\[1,
742 \\1
743 \\,1
744 );
745}
746
747test "n_array_unclosed_with_object_inside" {
748 err(
749 \\[{}
750 );
751}
752
753test "n_incomplete_false" {
754 err(
755 \\[fals]
756 );
757}
758
759test "n_incomplete_null" {
760 err(
761 \\[nul]
762 );
763}
764
765test "n_incomplete_true" {
766 err(
767 \\[tru]
768 );
769}
770
771test "n_multidigit_number_then_00" {
772 err("123\x00");
773}
774
775test "n_number_0.1.2" {
776 err(
777 \\[0.1.2]
778 );
779}
780
781test "n_number_-01" {
782 err(
783 \\[-01]
784 );
785}
786
787test "n_number_0.3e" {
788 err(
789 \\[0.3e]
790 );
791}
792
793test "n_number_0.3e+" {
794 err(
795 \\[0.3e+]
796 );
797}
798
799test "n_number_0_capital_E" {
800 err(
801 \\[0E]
802 );
803}
804
805test "n_number_0_capital_E+" {
806 err(
807 \\[0E+]
808 );
809}
810
811test "n_number_0.e1" {
812 err(
813 \\[0.e1]
814 );
815}
816
817test "n_number_0e" {
818 err(
819 \\[0e]
820 );
821}
822
823test "n_number_0e+" {
824 err(
825 \\[0e+]
826 );
827}
828
829test "n_number_1_000" {
830 err(
831 \\[1 000.0]
832 );
833}
834
835test "n_number_1.0e-" {
836 err(
837 \\[1.0e-]
838 );
839}
840
841test "n_number_1.0e" {
842 err(
843 \\[1.0e]
844 );
845}
846
847test "n_number_1.0e+" {
848 err(
849 \\[1.0e+]
850 );
851}
852
853test "n_number_-1.0." {
854 err(
855 \\[-1.0.]
856 );
857}
858
859test "n_number_1eE2" {
860 err(
861 \\[1eE2]
862 );
863}
864
865test "n_number_.-1" {
866 err(
867 \\[.-1]
868 );
869}
870
871test "n_number_+1" {
872 err(
873 \\[+1]
874 );
875}
876
877test "n_number_.2e-3" {
878 err(
879 \\[.2e-3]
880 );
881}
882
883test "n_number_2.e-3" {
884 err(
885 \\[2.e-3]
886 );
887}
888
889test "n_number_2.e+3" {
890 err(
891 \\[2.e+3]
892 );
893}
894
895test "n_number_2.e3" {
896 err(
897 \\[2.e3]
898 );
899}
900
901test "n_number_-2." {
902 err(
903 \\[-2.]
904 );
905}
906
907test "n_number_9.e+" {
908 err(
909 \\[9.e+]
910 );
911}
912
913test "n_number_expression" {
914 err(
915 \\[1+2]
916 );
917}
918
919test "n_number_hex_1_digit" {
920 err(
921 \\[0x1]
922 );
923}
924
925test "n_number_hex_2_digits" {
926 err(
927 \\[0x42]
928 );
929}
930
931test "n_number_infinity" {
932 err(
933 \\[Infinity]
934 );
935}
936
937test "n_number_+Inf" {
938 err(
939 \\[+Inf]
940 );
941}
942
943test "n_number_Inf" {
944 err(
945 \\[Inf]
946 );
947}
948
949test "n_number_invalid+-" {
950 err(
951 \\[0e+-1]
952 );
953}
954
955test "n_number_invalid-negative-real" {
956 err(
957 \\[-123.123foo]
958 );
959}
960
961test "n_number_invalid-utf-8-in-bigger-int" {
962 err(
963 \\[123å]
964 );
965}
966
967test "n_number_invalid-utf-8-in-exponent" {
968 err(
969 \\[1e1å]
970 );
971}
972
973test "n_number_invalid-utf-8-in-int" {
974 err(
975 \\[0å]
976 );
977}
978
979test "n_number_++" {
980 err(
981 \\[++1234]
982 );
983}
984
985test "n_number_minus_infinity" {
986 err(
987 \\[-Infinity]
988 );
989}
990
991test "n_number_minus_sign_with_trailing_garbage" {
992 err(
993 \\[-foo]
994 );
995}
996
997test "n_number_minus_space_1" {
998 err(
999 \\[- 1]
1000 );
1001}
1002
1003test "n_number_-NaN" {
1004 err(
1005 \\[-NaN]
1006 );
1007}
1008
1009test "n_number_NaN" {
1010 err(
1011 \\[NaN]
1012 );
1013}
1014
1015test "n_number_neg_int_starting_with_zero" {
1016 err(
1017 \\[-012]
1018 );
1019}
1020
1021test "n_number_neg_real_without_int_part" {
1022 err(
1023 \\[-.123]
1024 );
1025}
1026
1027test "n_number_neg_with_garbage_at_end" {
1028 err(
1029 \\[-1x]
1030 );
1031}
1032
1033test "n_number_real_garbage_after_e" {
1034 err(
1035 \\[1ea]
1036 );
1037}
1038
1039test "n_number_real_with_invalid_utf8_after_e" {
1040 err(
1041 \\[1eå]
1042 );
1043}
1044
1045test "n_number_real_without_fractional_part" {
1046 err(
1047 \\[1.]
1048 );
1049}
1050
1051test "n_number_starting_with_dot" {
1052 err(
1053 \\[.123]
1054 );
1055}
1056
1057test "n_number_U+FF11_fullwidth_digit_one" {
1058 err(
1059 \\[1]
1060 );
1061}
1062
1063test "n_number_with_alpha_char" {
1064 err(
1065 \\[1.8011670033376514H-308]
1066 );
1067}
1068
1069test "n_number_with_alpha" {
1070 err(
1071 \\[1.2a-3]
1072 );
1073}
1074
1075test "n_number_with_leading_zero" {
1076 err(
1077 \\[012]
1078 );
1079}
1080
1081test "n_object_bad_value" {
1082 err(
1083 \\["x", truth]
1084 );
1085}
1086
1087test "n_object_bracket_key" {
1088 err(
1089 \\{[: "x"}
1090 );
1091}
1092
1093test "n_object_comma_instead_of_colon" {
1094 err(
1095 \\{"x", null}
1096 );
1097}
1098
1099test "n_object_double_colon" {
1100 err(
1101 \\{"x"::"b"}
1102 );
1103}
1104
1105test "n_object_emoji" {
1106 err(
1107 \\{🇨🇭}
1108 );
1109}
1110
1111test "n_object_garbage_at_end" {
1112 err(
1113 \\{"a":"a" 123}
1114 );
1115}
1116
1117test "n_object_key_with_single_quotes" {
1118 err(
1119 \\{key: 'value'}
1120 );
1121}
1122
1123test "n_object_lone_continuation_byte_in_key_and_trailing_comma" {
1124 err(
1125 \\{"¹":"0",}
1126 );
1127}
1128
1129test "n_object_missing_colon" {
1130 err(
1131 \\{"a" b}
1132 );
1133}
1134
1135test "n_object_missing_key" {
1136 err(
1137 \\{:"b"}
1138 );
1139}
1140
1141test "n_object_missing_semicolon" {
1142 err(
1143 \\{"a" "b"}
1144 );
1145}
1146
1147test "n_object_missing_value" {
1148 err(
1149 \\{"a":
1150 );
1151}
1152
1153test "n_object_no-colon" {
1154 err(
1155 \\{"a"
1156 );
1157}
1158
1159test "n_object_non_string_key_but_huge_number_instead" {
1160 err(
1161 \\{9999E9999:1}
1162 );
1163}
1164
1165test "n_object_non_string_key" {
1166 err(
1167 \\{1:1}
1168 );
1169}
1170
1171test "n_object_repeated_null_null" {
1172 err(
1173 \\{null:null,null:null}
1174 );
1175}
1176
1177test "n_object_several_trailing_commas" {
1178 err(
1179 \\{"id":0,,,,,}
1180 );
1181}
1182
1183test "n_object_single_quote" {
1184 err(
1185 \\{'a':0}
1186 );
1187}
1188
1189test "n_object_trailing_comma" {
1190 err(
1191 \\{"id":0,}
1192 );
1193}
1194
1195test "n_object_trailing_comment" {
1196 err(
1197 \\{"a":"b"}/**/
1198 );
1199}
1200
1201test "n_object_trailing_comment_open" {
1202 err(
1203 \\{"a":"b"}/**//
1204 );
1205}
1206
1207test "n_object_trailing_comment_slash_open_incomplete" {
1208 err(
1209 \\{"a":"b"}/
1210 );
1211}
1212
1213test "n_object_trailing_comment_slash_open" {
1214 err(
1215 \\{"a":"b"}//
1216 );
1217}
1218
1219test "n_object_two_commas_in_a_row" {
1220 err(
1221 \\{"a":"b",,"c":"d"}
1222 );
1223}
1224
1225test "n_object_unquoted_key" {
1226 err(
1227 \\{a: "b"}
1228 );
1229}
1230
1231test "n_object_unterminated-value" {
1232 err(
1233 \\{"a":"a
1234 );
1235}
1236
1237test "n_object_with_single_string" {
1238 err(
1239 \\{ "foo" : "bar", "a" }
1240 );
1241}
1242
1243test "n_object_with_trailing_garbage" {
1244 err(
1245 \\{"a":"b"}#
1246 );
1247}
1248
1249test "n_single_space" {
1250 err(" ");
1251}
1252
1253test "n_string_1_surrogate_then_escape" {
1254 err(
1255 \\["\uD800\"]
1256 );
1257}
1258
1259test "n_string_1_surrogate_then_escape_u1" {
1260 err(
1261 \\["\uD800\u1"]
1262 );
1263}
1264
1265test "n_string_1_surrogate_then_escape_u1x" {
1266 err(
1267 \\["\uD800\u1x"]
1268 );
1269}
1270
1271test "n_string_1_surrogate_then_escape_u" {
1272 err(
1273 \\["\uD800\u"]
1274 );
1275}
1276
1277test "n_string_accentuated_char_no_quotes" {
1278 err(
1279 \\[é]
1280 );
1281}
1282
1283test "n_string_backslash_00" {
1284 err("[\"\x00\"]");
1285}
1286
1287test "n_string_escaped_backslash_bad" {
1288 err(
1289 \\["\\\"]
1290 );
1291}
1292
1293test "n_string_escaped_ctrl_char_tab" {
1294 err("\x5b\x22\x5c\x09\x22\x5d");
1295}
1296
1297test "n_string_escaped_emoji" {
1298 err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]");
1299}
1300
1301test "n_string_escape_x" {
1302 err(
1303 \\["\x00"]
1304 );
1305}
1306
1307test "n_string_incomplete_escaped_character" {
1308 err(
1309 \\["\u00A"]
1310 );
1311}
1312
1313test "n_string_incomplete_escape" {
1314 err(
1315 \\["\"]
1316 );
1317}
1318
1319test "n_string_incomplete_surrogate_escape_invalid" {
1320 err(
1321 \\["\uD800\uD800\x"]
1322 );
1323}
1324
1325test "n_string_incomplete_surrogate" {
1326 err(
1327 \\["\uD834\uDd"]
1328 );
1329}
1330
1331test "n_string_invalid_backslash_esc" {
1332 err(
1333 \\["\a"]
1334 );
1335}
1336
1337test "n_string_invalid_unicode_escape" {
1338 err(
1339 \\["\uqqqq"]
1340 );
1341}
1342
1343test "n_string_invalid_utf8_after_escape" {
1344 err("[\"\\\x75\xc3\xa5\"]");
1345}
1346
1347test "n_string_invalid-utf-8-in-escape" {
1348 err(
1349 \\["\uå"]
1350 );
1351}
1352
1353test "n_string_leading_uescaped_thinspace" {
1354 err(
1355 \\[\u0020"asd"]
1356 );
1357}
1358
1359test "n_string_no_quotes_with_bad_escape" {
1360 err(
1361 \\[\n]
1362 );
1363}
1364
1365test "n_string_single_doublequote" {
1366 err(
1367 \\"
1368 );
1369}
1370
1371test "n_string_single_quote" {
1372 err(
1373 \\['single quote']
1374 );
1375}
1376
1377test "n_string_single_string_no_double_quotes" {
1378 err(
1379 \\abc
1380 );
1381}
1382
1383test "n_string_start_escape_unclosed" {
1384 err(
1385 \\["\
1386 );
1387}
1388
1389test "n_string_unescaped_crtl_char" {
1390 err("[\"a\x00a\"]");
1391}
1392
1393test "n_string_unescaped_newline" {
1394 err(
1395 \\["new
1396 \\line"]
1397 );
1398}
1399
1400test "n_string_unescaped_tab" {
1401 err("[\"\t\"]");
1402}
1403
1404test "n_string_unicode_CapitalU" {
1405 err(
1406 \\"\UA66D"
1407 );
1408}
1409
1410test "n_string_with_trailing_garbage" {
1411 err(
1412 \\""x
1413 );
1414}
1415
1416test "n_structure_100000_opening_arrays" {
1417 err("[" ** 100000);
1418}
1419
1420test "n_structure_angle_bracket_." {
1421 err(
1422 \\<.>
1423 );
1424}
1425
1426test "n_structure_angle_bracket_null" {
1427 err(
1428 \\[<null>]
1429 );
1430}
1431
1432test "n_structure_array_trailing_garbage" {
1433 err(
1434 \\[1]x
1435 );
1436}
1437
1438test "n_structure_array_with_extra_array_close" {
1439 err(
1440 \\[1]]
1441 );
1442}
1443
1444test "n_structure_array_with_unclosed_string" {
1445 err(
1446 \\["asd]
1447 );
1448}
1449
1450test "n_structure_ascii-unicode-identifier" {
1451 err(
1452 \\aå
1453 );
1454}
1455
1456test "n_structure_capitalized_True" {
1457 err(
1458 \\[True]
1459 );
1460}
1461
1462test "n_structure_close_unopened_array" {
1463 err(
1464 \\1]
1465 );
1466}
1467
1468test "n_structure_comma_instead_of_closing_brace" {
1469 err(
1470 \\{"x": true,
1471 );
1472}
1473
1474test "n_structure_double_array" {
1475 err(
1476 \\[][]
1477 );
1478}
1479
1480test "n_structure_end_array" {
1481 err(
1482 \\]
1483 );
1484}
1485
1486test "n_structure_incomplete_UTF8_BOM" {
1487 err(
1488 \\ï»{}
1489 );
1490}
1491
1492test "n_structure_lone-invalid-utf-8" {
1493 err(
1494 \\å
1495 );
1496}
1497
1498test "n_structure_lone-open-bracket" {
1499 err(
1500 \\[
1501 );
1502}
1503
1504test "n_structure_no_data" {
1505 err(
1506 \\
1507 );
1508}
1509
1510test "n_structure_null-byte-outside-string" {
1511 err("[\x00]");
1512}
1513
1514test "n_structure_number_with_trailing_garbage" {
1515 err(
1516 \\2@
1517 );
1518}
1519
1520test "n_structure_object_followed_by_closing_object" {
1521 err(
1522 \\{}}
1523 );
1524}
1525
1526test "n_structure_object_unclosed_no_value" {
1527 err(
1528 \\{"":
1529 );
1530}
1531
1532test "n_structure_object_with_comment" {
1533 err(
1534 \\{"a":/*comment*/"b"}
1535 );
1536}
1537
1538test "n_structure_object_with_trailing_garbage" {
1539 err(
1540 \\{"a": true} "x"
1541 );
1542}
1543
1544test "n_structure_open_array_apostrophe" {
1545 err(
1546 \\['
1547 );
1548}
1549
1550test "n_structure_open_array_comma" {
1551 err(
1552 \\[,
1553 );
1554}
1555
1556test "n_structure_open_array_object" {
1557 err("[{\"\":" ** 50000);
1558}
1559
1560test "n_structure_open_array_open_object" {
1561 err(
1562 \\[{
1563 );
1564}
1565
1566test "n_structure_open_array_open_string" {
1567 err(
1568 \\["a
1569 );
1570}
1571
1572test "n_structure_open_array_string" {
1573 err(
1574 \\["a"
1575 );
1576}
1577
1578test "n_structure_open_object_close_array" {
1579 err(
1580 \\{]
1581 );
1582}
1583
1584test "n_structure_open_object_comma" {
1585 err(
1586 \\{,
1587 );
1588}
1589
1590test "n_structure_open_object" {
1591 err(
1592 \\{
1593 );
1594}
1595
1596test "n_structure_open_object_open_array" {
1597 err(
1598 \\{[
1599 );
1600}
1601
1602test "n_structure_open_object_open_string" {
1603 err(
1604 \\{"a
1605 );
1606}
1607
1608test "n_structure_open_object_string_with_apostrophes" {
1609 err(
1610 \\{'a'
1611 );
1612}
1613
1614test "n_structure_open_open" {
1615 err(
1616 \\["\{["\{["\{["\{
1617 );
1618}
1619
1620test "n_structure_single_eacute" {
1621 err(
1622 \\é
1623 );
1624}
1625
1626test "n_structure_single_star" {
1627 err(
1628 \\*
1629 );
1630}
1631
1632test "n_structure_trailing_#" {
1633 err(
1634 \\{"a":"b"}#{}
1635 );
1636}
1637
1638test "n_structure_U+2060_word_joined" {
1639 err(
1640 \\[⁠]
1641 );
1642}
1643
1644test "n_structure_uescaped_LF_before_string" {
1645 err(
1646 \\[\u000A""]
1647 );
1648}
1649
1650test "n_structure_unclosed_array" {
1651 err(
1652 \\[1
1653 );
1654}
1655
1656test "n_structure_unclosed_array_partial_null" {
1657 err(
1658 \\[ false, nul
1659 );
1660}
1661
1662test "n_structure_unclosed_array_unfinished_false" {
1663 err(
1664 \\[ true, fals
1665 );
1666}
1667
1668test "n_structure_unclosed_array_unfinished_true" {
1669 err(
1670 \\[ false, tru
1671 );
1672}
1673
1674test "n_structure_unclosed_object" {
1675 err(
1676 \\{"asd":"asd"
1677 );
1678}
1679
1680test "n_structure_unicode-identifier" {
1681 err(
1682 \\Ã¥
1683 );
1684}
1685
1686test "n_structure_UTF8_BOM_no_data" {
1687 err(
1688 \\
1689 );
1690}
1691
1692test "n_structure_whitespace_formfeed" {
1693 err("[\x0c]");
1694}
1695
1696test "n_structure_whitespace_U+2060_word_joiner" {
1697 err(
1698 \\[⁠]
1699 );
1700}
1701
1702////////////////////////////////////////////////////////////////////////////////////////////////////
1703
1704test "i_number_double_huge_neg_exp" {
1705 any(
1706 \\[123.456e-789]
1707 );
1708}
1709
1710test "i_number_huge_exp" {
1711 any(
1712 \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]
1713 );
1714}
1715
1716test "i_number_neg_int_huge_exp" {
1717 any(
1718 \\[-1e+9999]
1719 );
1720}
1721
1722test "i_number_pos_double_huge_exp" {
1723 any(
1724 \\[1.5e+9999]
1725 );
1726}
1727
1728test "i_number_real_neg_overflow" {
1729 any(
1730 \\[-123123e100000]
1731 );
1732}
1733
1734test "i_number_real_pos_overflow" {
1735 any(
1736 \\[123123e100000]
1737 );
1738}
1739
1740test "i_number_real_underflow" {
1741 any(
1742 \\[123e-10000000]
1743 );
1744}
1745
1746test "i_number_too_big_neg_int" {
1747 any(
1748 \\[-123123123123123123123123123123]
1749 );
1750}
1751
1752test "i_number_too_big_pos_int" {
1753 any(
1754 \\[100000000000000000000]
1755 );
1756}
1757
1758test "i_number_very_big_negative_int" {
1759 any(
1760 \\[-237462374673276894279832749832423479823246327846]
1761 );
1762}
1763
1764test "i_object_key_lone_2nd_surrogate" {
1765 any(
1766 \\{"\uDFAA":0}
1767 );
1768}
1769
1770test "i_string_1st_surrogate_but_2nd_missing" {
1771 any(
1772 \\["\uDADA"]
1773 );
1774}
1775
1776test "i_string_1st_valid_surrogate_2nd_invalid" {
1777 any(
1778 \\["\uD888\u1234"]
1779 );
1780}
1781
1782test "i_string_incomplete_surrogate_and_escape_valid" {
1783 any(
1784 \\["\uD800\n"]
1785 );
1786}
1787
1788test "i_string_incomplete_surrogate_pair" {
1789 any(
1790 \\["\uDd1ea"]
1791 );
1792}
1793
1794test "i_string_incomplete_surrogates_escape_valid" {
1795 any(
1796 \\["\uD800\uD800\n"]
1797 );
1798}
1799
1800test "i_string_invalid_lonely_surrogate" {
1801 any(
1802 \\["\ud800"]
1803 );
1804}
1805
1806test "i_string_invalid_surrogate" {
1807 any(
1808 \\["\ud800abc"]
1809 );
1810}
1811
1812test "i_string_invalid_utf-8" {
1813 any(
1814 \\["ÿ"]
1815 );
1816}
1817
1818test "i_string_inverted_surrogates_U+1D11E" {
1819 any(
1820 \\["\uDd1e\uD834"]
1821 );
1822}
1823
1824test "i_string_iso_latin_1" {
1825 any(
1826 \\["é"]
1827 );
1828}
1829
1830test "i_string_lone_second_surrogate" {
1831 any(
1832 \\["\uDFAA"]
1833 );
1834}
1835
1836test "i_string_lone_utf8_continuation_byte" {
1837 any(
1838 \\[""]
1839 );
1840}
1841
1842test "i_string_not_in_unicode_range" {
1843 any(
1844 \\["ô¿¿¿"]
1845 );
1846}
1847
1848test "i_string_overlong_sequence_2_bytes" {
1849 any(
1850 \\["À¯"]
1851 );
1852}
1853
1854test "i_string_overlong_sequence_6_bytes" {
1855 any(
1856 \\["üƒ¿¿¿¿"]
1857 );
1858}
1859
1860test "i_string_overlong_sequence_6_bytes_null" {
1861 any(
1862 \\["ü€€€€€"]
1863 );
1864}
1865
1866test "i_string_truncated-utf-8" {
1867 any(
1868 \\["àÿ"]
1869 );
1870}
1871
1872test "i_string_utf16BE_no_BOM" {
1873 any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d");
1874}
1875
1876test "i_string_utf16LE_no_BOM" {
1877 any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00");
1878}
1879
1880test "i_string_UTF-16LE_with_BOM" {
1881 any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00");
1882}
1883
1884test "i_string_UTF-8_invalid_sequence" {
1885 any(
1886 \\["日шú"]
1887 );
1888}
1889
1890test "i_string_UTF8_surrogate_U+D800" {
1891 any(
1892 \\["í €"]
1893 );
1894}
1895
1896test "i_structure_500_nested_arrays" {
1897 any(("[" ** 500) ++ ("]" ** 500));
1898}
1899
1900test "i_structure_UTF-8_BOM_empty_object" {
1901 any(
1902 \\{}
1903 );
1904}
std/lazy_init.zig created+85
......@@ -0,0 +1,85 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const AtomicRmwOp = builtin.AtomicRmwOp;
5const AtomicOrder = builtin.AtomicOrder;
6
7/// Thread-safe initialization of global data.
8/// TODO use a mutex instead of a spinlock
9pub fn lazyInit(comptime T: type) LazyInit(T) {
10 return LazyInit(T){
11 .data = undefined,
12 .state = 0,
13 };
14}
15
16fn LazyInit(comptime T: type) type {
17 return struct {
18 state: u8, // TODO make this an enum
19 data: Data,
20
21 const Self = this;
22
23 // TODO this isn't working for void, investigate and then remove this special case
24 const Data = if (@sizeOf(T) == 0) u8 else T;
25 const Ptr = if (T == void) void else *T;
26
27 /// Returns a usable pointer to the initialized data,
28 /// or returns null, indicating that the caller should
29 /// perform the initialization and then call resolve().
30 pub fn get(self: *Self) ?Ptr {
31 while (true) {
32 var state = @cmpxchgWeak(u8, &self.state, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;
33 switch (state) {
34 0 => continue,
35 1 => {
36 // TODO mutex instead of a spinlock
37 continue;
38 },
39 2 => {
40 if (@sizeOf(T) == 0) {
41 return T(undefined);
42 } else {
43 return &self.data;
44 }
45 },
46 else => unreachable,
47 }
48 }
49 }
50
51 pub fn resolve(self: *Self) void {
52 const prev = @atomicRmw(u8, &self.state, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);
53 assert(prev == 1); // resolve() called twice
54 }
55 };
56}
57
58var global_number = lazyInit(i32);
59
60test "std.lazyInit" {
61 if (global_number.get()) |_| @panic("bad") else {
62 global_number.data = 1234;
63 global_number.resolve();
64 }
65 if (global_number.get()) |x| {
66 assert(x.* == 1234);
67 } else {
68 @panic("bad");
69 }
70 if (global_number.get()) |x| {
71 assert(x.* == 1234);
72 } else {
73 @panic("bad");
74 }
75}
76
77var global_void = lazyInit(void);
78
79test "std.lazyInit(void)" {
80 if (global_void.get()) |_| @panic("bad") else {
81 global_void.resolve();
82 }
83 assert(global_void.get() != null);
84 assert(global_void.get() != null);
85}
std/linked_list.zig+73-58
......@@ -21,15 +21,15 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
2121
2222 /// Node inside the linked list wrapping the actual data.
2323 pub const Node = struct {
24 prev: ?&Node,
25 next: ?&Node,
24 prev: ?*Node,
25 next: ?*Node,
2626 data: T,
2727
28 pub fn init(value: &const T) Node {
29 return Node {
28 pub fn init(value: *const T) Node {
29 return Node{
3030 .prev = null,
3131 .next = null,
32 .data = *value,
32 .data = value.*,
3333 };
3434 }
3535
......@@ -38,25 +38,25 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
3838 return Node.init({});
3939 }
4040
41 pub fn toData(node: &Node) &ParentType {
41 pub fn toData(node: *Node) *ParentType {
4242 comptime assert(isIntrusive());
4343 return @fieldParentPtr(ParentType, field_name, node);
4444 }
4545 };
4646
47 first: ?&Node,
48 last: ?&Node,
49 len: usize,
47 first: ?*Node,
48 last: ?*Node,
49 len: usize,
5050
5151 /// Initialize a linked list.
5252 ///
5353 /// Returns:
5454 /// An empty linked list.
5555 pub fn init() Self {
56 return Self {
56 return Self{
5757 .first = null,
58 .last = null,
59 .len = 0,
58 .last = null,
59 .len = 0,
6060 };
6161 }
6262
......@@ -69,7 +69,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
6969 /// Arguments:
7070 /// node: Pointer to a node in the list.
7171 /// new_node: Pointer to the new node to insert.
72 pub fn insertAfter(list: &Self, node: &Node, new_node: &Node) void {
72 pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void {
7373 new_node.prev = node;
7474 if (node.next) |next_node| {
7575 // Intermediate node.
......@@ -90,7 +90,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
9090 /// Arguments:
9191 /// node: Pointer to a node in the list.
9292 /// new_node: Pointer to the new node to insert.
93 pub fn insertBefore(list: &Self, node: &Node, new_node: &Node) void {
93 pub fn insertBefore(list: *Self, node: *Node, new_node: *Node) void {
9494 new_node.next = node;
9595 if (node.prev) |prev_node| {
9696 // Intermediate node.
......@@ -110,7 +110,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
110110 ///
111111 /// Arguments:
112112 /// new_node: Pointer to the new node to insert.
113 pub fn append(list: &Self, new_node: &Node) void {
113 pub fn append(list: *Self, new_node: *Node) void {
114114 if (list.last) |last| {
115115 // Insert after last.
116116 list.insertAfter(last, new_node);
......@@ -124,14 +124,14 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
124124 ///
125125 /// Arguments:
126126 /// new_node: Pointer to the new node to insert.
127 pub fn prepend(list: &Self, new_node: &Node) void {
127 pub fn prepend(list: *Self, new_node: *Node) void {
128128 if (list.first) |first| {
129129 // Insert before first.
130130 list.insertBefore(first, new_node);
131131 } else {
132132 // Empty list.
133133 list.first = new_node;
134 list.last = new_node;
134 list.last = new_node;
135135 new_node.prev = null;
136136 new_node.next = null;
137137
......@@ -143,7 +143,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
143143 ///
144144 /// Arguments:
145145 /// node: Pointer to the node to be removed.
146 pub fn remove(list: &Self, node: &Node) void {
146 pub fn remove(list: *Self, node: *Node) void {
147147 if (node.prev) |prev_node| {
148148 // Intermediate node.
149149 prev_node.next = node.next;
......@@ -168,8 +168,8 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
168168 ///
169169 /// Returns:
170170 /// A pointer to the last node in the list.
171 pub fn pop(list: &Self) ?&Node {
172 const last = list.last ?? return null;
171 pub fn pop(list: *Self) ?*Node {
172 const last = list.last orelse return null;
173173 list.remove(last);
174174 return last;
175175 }
......@@ -178,8 +178,8 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
178178 ///
179179 /// Returns:
180180 /// A pointer to the first node in the list.
181 pub fn popFirst(list: &Self) ?&Node {
182 const first = list.first ?? return null;
181 pub fn popFirst(list: *Self) ?*Node {
182 const first = list.first orelse return null;
183183 list.remove(first);
184184 return first;
185185 }
......@@ -191,9 +191,9 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
191191 ///
192192 /// Returns:
193193 /// A pointer to the new node.
194 pub fn allocateNode(list: &Self, allocator: &Allocator) !&Node {
194 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
195195 comptime assert(!isIntrusive());
196 return allocator.create(Node);
196 return allocator.create(Node(undefined));
197197 }
198198
199199 /// Deallocate a node.
......@@ -201,7 +201,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
201201 /// Arguments:
202202 /// node: Pointer to the node to deallocate.
203203 /// allocator: Dynamic memory allocator.
204 pub fn destroyNode(list: &Self, node: &Node, allocator: &Allocator) void {
204 pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void {
205205 comptime assert(!isIntrusive());
206206 allocator.destroy(node);
207207 }
......@@ -214,10 +214,10 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
214214 ///
215215 /// Returns:
216216 /// A pointer to the new node.
217 pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) !&Node {
217 pub fn createNode(list: *Self, data: *const T, allocator: *Allocator) !*Node {
218218 comptime assert(!isIntrusive());
219219 var node = try list.allocateNode(allocator);
220 *node = Node.init(data);
220 node.* = Node.init(data);
221221 return node;
222222 }
223223 };
......@@ -227,11 +227,11 @@ test "basic linked list test" {
227227 const allocator = debug.global_allocator;
228228 var list = LinkedList(u32).init();
229229
230 var one = try list.createNode(1, allocator);
231 var two = try list.createNode(2, allocator);
230 var one = try list.createNode(1, allocator);
231 var two = try list.createNode(2, allocator);
232232 var three = try list.createNode(3, allocator);
233 var four = try list.createNode(4, allocator);
234 var five = try list.createNode(5, allocator);
233 var four = try list.createNode(4, allocator);
234 var five = try list.createNode(5, allocator);
235235 defer {
236236 list.destroyNode(one, allocator);
237237 list.destroyNode(two, allocator);
......@@ -240,11 +240,11 @@ test "basic linked list test" {
240240 list.destroyNode(five, allocator);
241241 }
242242
243 list.append(two); // {2}
244 list.append(five); // {2, 5}
245 list.prepend(one); // {1, 2, 5}
246 list.insertBefore(five, four); // {1, 2, 4, 5}
247 list.insertAfter(two, three); // {1, 2, 3, 4, 5}
243 list.append(two); // {2}
244 list.append(five); // {2, 5}
245 list.prepend(one); // {1, 2, 5}
246 list.insertBefore(five, four); // {1, 2, 4, 5}
247 list.insertAfter(two, three); // {1, 2, 3, 4, 5}
248248
249249 // Traverse forwards.
250250 {
......@@ -266,13 +266,13 @@ test "basic linked list test" {
266266 }
267267 }
268268
269 var first = list.popFirst(); // {2, 3, 4, 5}
270 var last = list.pop(); // {2, 3, 4}
271 list.remove(three); // {2, 4}
269 var first = list.popFirst(); // {2, 3, 4, 5}
270 var last = list.pop(); // {2, 3, 4}
271 list.remove(three); // {2, 4}
272272
273 assert ((??list.first).data == 2);
274 assert ((??list.last ).data == 4);
275 assert (list.len == 2);
273 assert(list.first.?.data == 2);
274 assert(list.last.?.data == 4);
275 assert(list.len == 2);
276276}
277277
278278const ElementList = IntrusiveLinkedList(Element, "link");
......@@ -285,17 +285,32 @@ test "basic intrusive linked list test" {
285285 const allocator = debug.global_allocator;
286286 var list = ElementList.init();
287287
288 var one = Element { .value = 1, .link = ElementList.Node.initIntrusive() };
289 var two = Element { .value = 2, .link = ElementList.Node.initIntrusive() };
290 var three = Element { .value = 3, .link = ElementList.Node.initIntrusive() };
291 var four = Element { .value = 4, .link = ElementList.Node.initIntrusive() };
292 var five = Element { .value = 5, .link = ElementList.Node.initIntrusive() };
288 var one = Element{
289 .value = 1,
290 .link = ElementList.Node.initIntrusive(),
291 };
292 var two = Element{
293 .value = 2,
294 .link = ElementList.Node.initIntrusive(),
295 };
296 var three = Element{
297 .value = 3,
298 .link = ElementList.Node.initIntrusive(),
299 };
300 var four = Element{
301 .value = 4,
302 .link = ElementList.Node.initIntrusive(),
303 };
304 var five = Element{
305 .value = 5,
306 .link = ElementList.Node.initIntrusive(),
307 };
293308
294 list.append(&two.link); // {2}
295 list.append(&five.link); // {2, 5}
296 list.prepend(&one.link); // {1, 2, 5}
297 list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}
298 list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}
309 list.append(&two.link); // {2}
310 list.append(&five.link); // {2, 5}
311 list.prepend(&one.link); // {1, 2, 5}
312 list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}
313 list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}
299314
300315 // Traverse forwards.
301316 {
......@@ -317,11 +332,11 @@ test "basic intrusive linked list test" {
317332 }
318333 }
319334
320 var first = list.popFirst(); // {2, 3, 4, 5}
321 var last = list.pop(); // {2, 3, 4}
322 list.remove(&three.link); // {2, 4}
335 var first = list.popFirst(); // {2, 3, 4, 5}
336 var last = list.pop(); // {2, 3, 4}
337 list.remove(&three.link); // {2, 4}
323338
324 assert ((??list.first).toData().value == 2);
325 assert ((??list.last ).toData().value == 4);
326 assert (list.len == 2);
339 assert(list.first.?.toData().value == 2);
340 assert(list.last.?.toData().value == 4);
341 assert(list.len == 2);
327342}
std/macho.zig+23-21
......@@ -42,13 +42,13 @@ pub const Symbol = struct {
4242 name: []const u8,
4343 address: u64,
4444
45 fn addressLessThan(lhs: &const Symbol, rhs: &const Symbol) bool {
45 fn addressLessThan(lhs: Symbol, rhs: Symbol) bool {
4646 return lhs.address < rhs.address;
4747 }
4848};
4949
5050pub const SymbolTable = struct {
51 allocator: &mem.Allocator,
51 allocator: *mem.Allocator,
5252 symbols: []const Symbol,
5353 strings: []const u8,
5454
......@@ -56,17 +56,17 @@ pub const SymbolTable = struct {
5656 // Ideally we'd use _mh_execute_header because it's always at 0x100000000
5757 // in the image but as it's located in a different section than executable
5858 // code, its displacement is different.
59 pub fn deinit(self: &SymbolTable) void {
59 pub fn deinit(self: *SymbolTable) void {
6060 self.allocator.free(self.symbols);
61 self.symbols = []const Symbol {};
61 self.symbols = []const Symbol{};
6262
6363 self.allocator.free(self.strings);
64 self.strings = []const u8 {};
64 self.strings = []const u8{};
6565 }
6666
67 pub fn search(self: &const SymbolTable, address: usize) ?&const Symbol {
67 pub fn search(self: *const SymbolTable, address: usize) ?*const Symbol {
6868 var min: usize = 0;
69 var max: usize = self.symbols.len - 1; // Exclude sentinel.
69 var max: usize = self.symbols.len - 1; // Exclude sentinel.
7070 while (min < max) {
7171 const mid = min + (max - min) / 2;
7272 const curr = &self.symbols[mid];
......@@ -83,7 +83,7 @@ pub const SymbolTable = struct {
8383 }
8484};
8585
86pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable {
86pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable {
8787 var file = in.file;
8888 try file.seekTo(0);
8989
......@@ -118,10 +118,11 @@ pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable
118118 try in.stream.readNoEof(strings);
119119
120120 var nsyms: usize = 0;
121 for (syms) |sym| if (isSymbol(sym)) nsyms += 1;
121 for (syms) |sym|
122 if (isSymbol(sym)) nsyms += 1;
122123 if (nsyms == 0) return error.MissingDebugInfo;
123124
124 var symbols = try allocator.alloc(Symbol, nsyms + 1); // Room for sentinel.
125 var symbols = try allocator.alloc(Symbol, nsyms + 1); // Room for sentinel.
125126 errdefer allocator.free(symbols);
126127
127128 var pie_slide: usize = 0;
......@@ -129,10 +130,10 @@ pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable
129130 for (syms) |sym| {
130131 if (!isSymbol(sym)) continue;
131132 const start = sym.n_strx;
132 const end = ??mem.indexOfScalarPos(u8, strings, start, 0);
133 const end = mem.indexOfScalarPos(u8, strings, start, 0).?;
133134 const name = strings[start..end];
134135 const address = sym.n_value;
135 symbols[nsym] = Symbol { .name = name, .address = address };
136 symbols[nsym] = Symbol{ .name = name, .address = address };
136137 nsym += 1;
137138 if (is_pie and mem.eql(u8, name, "_SymbolTable_deinit")) {
138139 pie_slide = @ptrToInt(SymbolTable.deinit) - address;
......@@ -140,31 +141,32 @@ pub fn loadSymbols(allocator: &mem.Allocator, in: &io.FileInStream) !SymbolTable
140141 }
141142
142143 // Effectively a no-op, lld emits symbols in ascending order.
143 std.sort.insertionSort(Symbol, symbols[0..nsyms], Symbol.addressLessThan);
144 std.sort.sort(Symbol, symbols[0..nsyms], Symbol.addressLessThan);
144145
145146 // Insert the sentinel. Since we don't know where the last function ends,
146147 // we arbitrarily limit it to the start address + 4 KB.
147148 const top = symbols[nsyms - 1].address + 4096;
148 symbols[nsyms] = Symbol { .name = "", .address = top };
149 symbols[nsyms] = Symbol{ .name = "", .address = top };
149150
150151 if (pie_slide != 0) {
151 for (symbols) |*symbol| symbol.address += pie_slide;
152 for (symbols) |*symbol|
153 symbol.address += pie_slide;
152154 }
153155
154 return SymbolTable {
156 return SymbolTable{
155157 .allocator = allocator,
156158 .symbols = symbols,
157159 .strings = strings,
158160 };
159161}
160162
161fn readNoEof(in: &io.FileInStream, comptime T: type, result: []T) !void {
162 return in.stream.readNoEof(([]u8)(result));
163fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
164 return in.stream.readNoEof(@sliceToBytes(result));
163165}
164fn readOneNoEof(in: &io.FileInStream, comptime T: type, result: &T) !void {
165 return readNoEof(in, T, result[0..1]);
166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {
167 return readNoEof(in, T, (*[1]T)(result)[0..]);
166168}
167169
168fn isSymbol(sym: &const Nlist64) bool {
170fn isSymbol(sym: *const Nlist64) bool {
169171 return sym.n_value != 0 and sym.n_desc == 0;
170172}
std/math/acos.zig+9-9
......@@ -16,7 +16,7 @@ pub fn acos(x: var) @typeOf(x) {
1616}
1717
1818fn r32(z: f32) f32 {
19 const pS0 = 1.6666586697e-01;
19 const pS0 = 1.6666586697e-01;
2020 const pS1 = -4.2743422091e-02;
2121 const pS2 = -8.6563630030e-03;
2222 const qS1 = -7.0662963390e-01;
......@@ -74,16 +74,16 @@ fn acos32(x: f32) f32 {
7474}
7575
7676fn r64(z: f64) f64 {
77 const pS0: f64 = 1.66666666666666657415e-01;
77 const pS0: f64 = 1.66666666666666657415e-01;
7878 const pS1: f64 = -3.25565818622400915405e-01;
79 const pS2: f64 = 2.01212532134862925881e-01;
79 const pS2: f64 = 2.01212532134862925881e-01;
8080 const pS3: f64 = -4.00555345006794114027e-02;
81 const pS4: f64 = 7.91534994289814532176e-04;
82 const pS5: f64 = 3.47933107596021167570e-05;
81 const pS4: f64 = 7.91534994289814532176e-04;
82 const pS5: f64 = 3.47933107596021167570e-05;
8383 const qS1: f64 = -2.40339491173441421878e+00;
84 const qS2: f64 = 2.02094576023350569471e+00;
84 const qS2: f64 = 2.02094576023350569471e+00;
8585 const qS3: f64 = -6.88283971605453293030e-01;
86 const qS4: f64 = 7.70381505559019352791e-02;
86 const qS4: f64 = 7.70381505559019352791e-02;
8787
8888 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
8989 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
......@@ -95,12 +95,12 @@ fn acos64(x: f64) f64 {
9595 const pio2_lo: f64 = 6.12323399573676603587e-17;
9696
9797 const ux = @bitCast(u64, x);
98 const hx = u32(ux >> 32);
98 const hx = @intCast(u32, ux >> 32);
9999 const ix = hx & 0x7FFFFFFF;
100100
101101 // |x| >= 1 or nan
102102 if (ix >= 0x3FF00000) {
103 const lx = u32(ux & 0xFFFFFFFF);
103 const lx = @intCast(u32, ux & 0xFFFFFFFF);
104104
105105 // acos(1) = 0, acos(-1) = pi
106106 if ((ix - 0x3FF00000) | lx == 0) {
std/math/asin.zig+11-11
......@@ -17,7 +17,7 @@ pub fn asin(x: var) @typeOf(x) {
1717}
1818
1919fn r32(z: f32) f32 {
20 const pS0 = 1.6666586697e-01;
20 const pS0 = 1.6666586697e-01;
2121 const pS1 = -4.2743422091e-02;
2222 const pS2 = -8.6563630030e-03;
2323 const qS1 = -7.0662963390e-01;
......@@ -37,9 +37,9 @@ fn asin32(x: f32) f32 {
3737 if (ix >= 0x3F800000) {
3838 // |x| >= 1
3939 if (ix == 0x3F800000) {
40 return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact
40 return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact
4141 } else {
42 return math.nan(f32); // asin(|x| > 1) is nan
42 return math.nan(f32); // asin(|x| > 1) is nan
4343 }
4444 }
4545
......@@ -66,16 +66,16 @@ fn asin32(x: f32) f32 {
6666}
6767
6868fn r64(z: f64) f64 {
69 const pS0: f64 = 1.66666666666666657415e-01;
69 const pS0: f64 = 1.66666666666666657415e-01;
7070 const pS1: f64 = -3.25565818622400915405e-01;
71 const pS2: f64 = 2.01212532134862925881e-01;
71 const pS2: f64 = 2.01212532134862925881e-01;
7272 const pS3: f64 = -4.00555345006794114027e-02;
73 const pS4: f64 = 7.91534994289814532176e-04;
74 const pS5: f64 = 3.47933107596021167570e-05;
73 const pS4: f64 = 7.91534994289814532176e-04;
74 const pS5: f64 = 3.47933107596021167570e-05;
7575 const qS1: f64 = -2.40339491173441421878e+00;
76 const qS2: f64 = 2.02094576023350569471e+00;
76 const qS2: f64 = 2.02094576023350569471e+00;
7777 const qS3: f64 = -6.88283971605453293030e-01;
78 const qS4: f64 = 7.70381505559019352791e-02;
78 const qS4: f64 = 7.70381505559019352791e-02;
7979
8080 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
8181 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
......@@ -87,12 +87,12 @@ fn asin64(x: f64) f64 {
8787 const pio2_lo: f64 = 6.12323399573676603587e-17;
8888
8989 const ux = @bitCast(u64, x);
90 const hx = u32(ux >> 32);
90 const hx = @intCast(u32, ux >> 32);
9191 const ix = hx & 0x7FFFFFFF;
9292
9393 // |x| >= 1 or nan
9494 if (ix >= 0x3FF00000) {
95 const lx = u32(ux & 0xFFFFFFFF);
95 const lx = @intCast(u32, ux & 0xFFFFFFFF);
9696
9797 // asin(1) = +-pi/2 with inexact
9898 if ((ix - 0x3FF00000) | lx == 0) {
std/math/atan.zig+17-19
......@@ -17,25 +17,25 @@ pub fn atan(x: var) @typeOf(x) {
1717}
1818
1919fn atan32(x_: f32) f32 {
20 const atanhi = []const f32 {
20 const atanhi = []const f32{
2121 4.6364760399e-01, // atan(0.5)hi
2222 7.8539812565e-01, // atan(1.0)hi
2323 9.8279368877e-01, // atan(1.5)hi
2424 1.5707962513e+00, // atan(inf)hi
2525 };
2626
27 const atanlo = []const f32 {
27 const atanlo = []const f32{
2828 5.0121582440e-09, // atan(0.5)lo
2929 3.7748947079e-08, // atan(1.0)lo
3030 3.4473217170e-08, // atan(1.5)lo
3131 7.5497894159e-08, // atan(inf)lo
3232 };
3333
34 const aT = []const f32 {
34 const aT = []const f32{
3535 3.3333328366e-01,
36 -1.9999158382e-01,
36 -1.9999158382e-01,
3737 1.4253635705e-01,
38 -1.0648017377e-01,
38 -1.0648017377e-01,
3939 6.1687607318e-02,
4040 };
4141
......@@ -80,8 +80,7 @@ fn atan32(x_: f32) f32 {
8080 id = 1;
8181 x = (x - 1.0) / (x + 1.0);
8282 }
83 }
84 else {
83 } else {
8584 // |x| < 2.4375
8685 if (ix < 0x401C0000) {
8786 id = 2;
......@@ -109,37 +108,37 @@ fn atan32(x_: f32) f32 {
109108}
110109
111110fn atan64(x_: f64) f64 {
112 const atanhi = []const f64 {
111 const atanhi = []const f64{
113112 4.63647609000806093515e-01, // atan(0.5)hi
114113 7.85398163397448278999e-01, // atan(1.0)hi
115114 9.82793723247329054082e-01, // atan(1.5)hi
116115 1.57079632679489655800e+00, // atan(inf)hi
117116 };
118117
119 const atanlo = []const f64 {
118 const atanlo = []const f64{
120119 2.26987774529616870924e-17, // atan(0.5)lo
121120 3.06161699786838301793e-17, // atan(1.0)lo
122121 1.39033110312309984516e-17, // atan(1.5)lo
123122 6.12323399573676603587e-17, // atan(inf)lo
124123 };
125124
126 const aT = []const f64 {
125 const aT = []const f64{
127126 3.33333333333329318027e-01,
128 -1.99999999998764832476e-01,
127 -1.99999999998764832476e-01,
129128 1.42857142725034663711e-01,
130 -1.11111104054623557880e-01,
129 -1.11111104054623557880e-01,
131130 9.09088713343650656196e-02,
132 -7.69187620504482999495e-02,
131 -7.69187620504482999495e-02,
133132 6.66107313738753120669e-02,
134 -5.83357013379057348645e-02,
133 -5.83357013379057348645e-02,
135134 4.97687799461593236017e-02,
136 -3.65315727442169155270e-02,
135 -3.65315727442169155270e-02,
137136 1.62858201153657823623e-02,
138137 };
139138
140139 var x = x_;
141140 var ux = @bitCast(u64, x);
142 var ix = u32(ux >> 32);
141 var ix = @intCast(u32, ux >> 32);
143142 const sign = ix >> 31;
144143 ix &= 0x7FFFFFFF;
145144
......@@ -160,7 +159,7 @@ fn atan64(x_: f64) f64 {
160159 // |x| < 2^(-27)
161160 if (ix < 0x3E400000) {
162161 if (ix < 0x00100000) {
163 math.forceEval(f32(x));
162 math.forceEval(@floatCast(f32, x));
164163 }
165164 return x;
166165 }
......@@ -179,8 +178,7 @@ fn atan64(x_: f64) f64 {
179178 id = 1;
180179 x = (x - 1.0) / (x + 1.0);
181180 }
182 }
183 else {
181 } else {
184182 // |x| < 2.4375
185183 if (ix < 0x40038000) {
186184 id = 2;
std/math/atan2.zig+36-36
......@@ -31,7 +31,7 @@ pub fn atan2(comptime T: type, x: T, y: T) T {
3131}
3232
3333fn atan2_32(y: f32, x: f32) f32 {
34 const pi: f32 = 3.1415927410e+00;
34 const pi: f32 = 3.1415927410e+00;
3535 const pi_lo: f32 = -8.7422776573e-08;
3636
3737 if (math.isNan(x) or math.isNan(y)) {
......@@ -53,9 +53,9 @@ fn atan2_32(y: f32, x: f32) f32 {
5353
5454 if (iy == 0) {
5555 switch (m) {
56 0, 1 => return y, // atan(+-0, +...)
57 2 => return pi, // atan(+0, -...)
58 3 => return -pi, // atan(-0, -...)
56 0, 1 => return y, // atan(+-0, +...)
57 2 => return pi, // atan(+0, -...)
58 3 => return -pi, // atan(-0, -...)
5959 else => unreachable,
6060 }
6161 }
......@@ -71,18 +71,18 @@ fn atan2_32(y: f32, x: f32) f32 {
7171 if (ix == 0x7F800000) {
7272 if (iy == 0x7F800000) {
7373 switch (m) {
74 0 => return pi / 4, // atan(+inf, +inf)
75 1 => return -pi / 4, // atan(-inf, +inf)
76 2 => return 3*pi / 4, // atan(+inf, -inf)
77 3 => return -3*pi / 4, // atan(-inf, -inf)
74 0 => return pi / 4, // atan(+inf, +inf)
75 1 => return -pi / 4, // atan(-inf, +inf)
76 2 => return 3 * pi / 4, // atan(+inf, -inf)
77 3 => return -3 * pi / 4, // atan(-inf, -inf)
7878 else => unreachable,
7979 }
8080 } else {
8181 switch (m) {
82 0 => return 0.0, // atan(+..., +inf)
83 1 => return -0.0, // atan(-..., +inf)
84 2 => return pi, // atan(+..., -inf)
85 3 => return -pi, // atan(-...f, -inf)
82 0 => return 0.0, // atan(+..., +inf)
83 1 => return -0.0, // atan(-..., +inf)
84 2 => return pi, // atan(+..., -inf)
85 3 => return -pi, // atan(-...f, -inf)
8686 else => unreachable,
8787 }
8888 }
......@@ -107,16 +107,16 @@ fn atan2_32(y: f32, x: f32) f32 {
107107 };
108108
109109 switch (m) {
110 0 => return z, // atan(+, +)
111 1 => return -z, // atan(-, +)
112 2 => return pi - (z - pi_lo), // atan(+, -)
113 3 => return (z - pi_lo) - pi, // atan(-, -)
110 0 => return z, // atan(+, +)
111 1 => return -z, // atan(-, +)
112 2 => return pi - (z - pi_lo), // atan(+, -)
113 3 => return (z - pi_lo) - pi, // atan(-, -)
114114 else => unreachable,
115115 }
116116}
117117
118118fn atan2_64(y: f64, x: f64) f64 {
119 const pi: f64 = 3.1415926535897931160E+00;
119 const pi: f64 = 3.1415926535897931160E+00;
120120 const pi_lo: f64 = 1.2246467991473531772E-16;
121121
122122 if (math.isNan(x) or math.isNan(y)) {
......@@ -124,12 +124,12 @@ fn atan2_64(y: f64, x: f64) f64 {
124124 }
125125
126126 var ux = @bitCast(u64, x);
127 var ix = u32(ux >> 32);
128 var lx = u32(ux & 0xFFFFFFFF);
127 var ix = @intCast(u32, ux >> 32);
128 var lx = @intCast(u32, ux & 0xFFFFFFFF);
129129
130130 var uy = @bitCast(u64, y);
131 var iy = u32(uy >> 32);
132 var ly = u32(uy & 0xFFFFFFFF);
131 var iy = @intCast(u32, uy >> 32);
132 var ly = @intCast(u32, uy & 0xFFFFFFFF);
133133
134134 // x = 1.0
135135 if ((ix -% 0x3FF00000) | lx == 0) {
......@@ -143,9 +143,9 @@ fn atan2_64(y: f64, x: f64) f64 {
143143
144144 if (iy | ly == 0) {
145145 switch (m) {
146 0, 1 => return y, // atan(+-0, +...)
147 2 => return pi, // atan(+0, -...)
148 3 => return -pi, // atan(-0, -...)
146 0, 1 => return y, // atan(+-0, +...)
147 2 => return pi, // atan(+0, -...)
148 3 => return -pi, // atan(-0, -...)
149149 else => unreachable,
150150 }
151151 }
......@@ -161,18 +161,18 @@ fn atan2_64(y: f64, x: f64) f64 {
161161 if (ix == 0x7FF00000) {
162162 if (iy == 0x7FF00000) {
163163 switch (m) {
164 0 => return pi / 4, // atan(+inf, +inf)
165 1 => return -pi / 4, // atan(-inf, +inf)
166 2 => return 3*pi / 4, // atan(+inf, -inf)
167 3 => return -3*pi / 4, // atan(-inf, -inf)
164 0 => return pi / 4, // atan(+inf, +inf)
165 1 => return -pi / 4, // atan(-inf, +inf)
166 2 => return 3 * pi / 4, // atan(+inf, -inf)
167 3 => return -3 * pi / 4, // atan(-inf, -inf)
168168 else => unreachable,
169169 }
170170 } else {
171171 switch (m) {
172 0 => return 0.0, // atan(+..., +inf)
173 1 => return -0.0, // atan(-..., +inf)
174 2 => return pi, // atan(+..., -inf)
175 3 => return -pi, // atan(-...f, -inf)
172 0 => return 0.0, // atan(+..., +inf)
173 1 => return -0.0, // atan(-..., +inf)
174 2 => return pi, // atan(+..., -inf)
175 3 => return -pi, // atan(-...f, -inf)
176176 else => unreachable,
177177 }
178178 }
......@@ -197,10 +197,10 @@ fn atan2_64(y: f64, x: f64) f64 {
197197 };
198198
199199 switch (m) {
200 0 => return z, // atan(+, +)
201 1 => return -z, // atan(-, +)
202 2 => return pi - (z - pi_lo), // atan(+, -)
203 3 => return (z - pi_lo) - pi, // atan(-, -)
200 0 => return z, // atan(+, +)
201 1 => return -z, // atan(-, +)
202 2 => return pi - (z - pi_lo), // atan(+, -)
203 3 => return (z - pi_lo) - pi, // atan(-, -)
204204 else => unreachable,
205205 }
206206}
std/math/atanh.zig+1-1
......@@ -62,7 +62,7 @@ fn atanh_64(x: f64) f64 {
6262 if (e < 0x3FF - 32) {
6363 // underflow
6464 if (e == 0) {
65 math.forceEval(f32(y));
65 math.forceEval(@floatCast(f32, y));
6666 }
6767 }
6868 // |x| < 0.5
std/math/big/index.zig created+5
......@@ -0,0 +1,5 @@
1pub use @import("int.zig");
2
3test "math.big" {
4 _ = @import("int.zig");
5}
std/math/big/int.zig created+2103
......@@ -0,0 +1,2103 @@
1const std = @import("../../index.zig");
2const builtin = @import("builtin");
3const debug = std.debug;
4const math = std.math;
5const mem = std.mem;
6const Allocator = mem.Allocator;
7const ArrayList = std.ArrayList;
8
9const TypeId = builtin.TypeId;
10
11pub const Limb = usize;
12pub const DoubleLimb = @IntType(false, 2 * Limb.bit_count);
13pub const Log2Limb = math.Log2Int(Limb);
14
15comptime {
16 debug.assert(math.floorPowerOfTwo(usize, Limb.bit_count) == Limb.bit_count);
17 debug.assert(Limb.bit_count <= 64); // u128 set is unsupported
18 debug.assert(Limb.is_signed == false);
19}
20
21pub const Int = struct {
22 allocator: *Allocator,
23 positive: bool,
24 // - little-endian ordered
25 // - len >= 1 always
26 // - zero value -> len == 1 with limbs[0] == 0
27 limbs: []Limb,
28 len: usize,
29
30 const default_capacity = 4;
31
32 pub fn init(allocator: *Allocator) !Int {
33 return try Int.initCapacity(allocator, default_capacity);
34 }
35
36 pub fn initSet(allocator: *Allocator, value: var) !Int {
37 var s = try Int.init(allocator);
38 try s.set(value);
39 return s;
40 }
41
42 pub fn initCapacity(allocator: *Allocator, capacity: usize) !Int {
43 return Int{
44 .allocator = allocator,
45 .positive = true,
46 .limbs = block: {
47 var limbs = try allocator.alloc(Limb, math.max(default_capacity, capacity));
48 limbs[0] = 0;
49 break :block limbs;
50 },
51 .len = 1,
52 };
53 }
54
55 pub fn ensureCapacity(self: *Int, capacity: usize) !void {
56 if (capacity <= self.limbs.len) {
57 return;
58 }
59
60 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
61 }
62
63 pub fn deinit(self: *Int) void {
64 self.allocator.free(self.limbs);
65 self.* = undefined;
66 }
67
68 pub fn clone(other: Int) !Int {
69 return Int{
70 .allocator = other.allocator,
71 .positive = other.positive,
72 .limbs = block: {
73 var limbs = try other.allocator.alloc(Limb, other.len);
74 mem.copy(Limb, limbs[0..], other.limbs[0..other.len]);
75 break :block limbs;
76 },
77 .len = other.len,
78 };
79 }
80
81 pub fn copy(self: *Int, other: Int) !void {
82 if (self == &other) {
83 return;
84 }
85
86 self.positive = other.positive;
87 try self.ensureCapacity(other.len);
88 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len]);
89 self.len = other.len;
90 }
91
92 pub fn swap(self: *Int, other: *Int) void {
93 mem.swap(Int, self, other);
94 }
95
96 pub fn dump(self: Int) void {
97 for (self.limbs) |limb| {
98 debug.warn("{x} ", limb);
99 }
100 debug.warn("\n");
101 }
102
103 pub fn negate(r: *Int) void {
104 r.positive = !r.positive;
105 }
106
107 pub fn abs(r: *Int) void {
108 r.positive = true;
109 }
110
111 pub fn isOdd(r: Int) bool {
112 return r.limbs[0] & 1 != 0;
113 }
114
115 pub fn isEven(r: Int) bool {
116 return !r.isOdd();
117 }
118
119 // Returns the number of bits required to represent the absolute value of self.
120 fn bitCountAbs(self: Int) usize {
121 return (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
122 }
123
124 // Returns the number of bits required to represent the integer in twos-complement form.
125 //
126 // If the integer is negative the value returned is the number of bits needed by a signed
127 // integer to represent the value. If positive the value is the number of bits for an
128 // unsigned integer. Any unsigned integer will fit in the signed integer with bitcount
129 // one greater than the returned value.
130 //
131 // e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7.
132 fn bitCountTwosComp(self: Int) usize {
133 var bits = self.bitCountAbs();
134
135 // If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos
136 // complement requires one less bit.
137 if (!self.positive) block: {
138 bits += 1;
139
140 if (@popCount(self.limbs[self.len - 1]) == 1) {
141 for (self.limbs[0 .. self.len - 1]) |limb| {
142 if (@popCount(limb) != 0) {
143 break :block;
144 }
145 }
146
147 bits -= 1;
148 }
149 }
150
151 return bits;
152 }
153
154 pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool {
155 if (self.eqZero()) {
156 return true;
157 }
158 if (!is_signed and !self.positive) {
159 return false;
160 }
161
162 const req_bits = self.bitCountTwosComp() + @boolToInt(self.positive and is_signed);
163 return bit_count >= req_bits;
164 }
165
166 pub fn fits(self: Int, comptime T: type) bool {
167 return self.fitsInTwosComp(T.is_signed, T.bit_count);
168 }
169
170 // Returns the approximate size of the integer in the given base. Negative values accomodate for
171 // the minus sign. This is used for determining the number of characters needed to print the
172 // value. It is inexact and will exceed the given value by 1-2 digits.
173 pub fn sizeInBase(self: Int, base: usize) usize {
174 const bit_count = usize(@boolToInt(!self.positive)) + self.bitCountAbs();
175 return (bit_count / math.log2(base)) + 1;
176 }
177
178 pub fn set(self: *Int, value: var) Allocator.Error!void {
179 const T = @typeOf(value);
180
181 switch (@typeInfo(T)) {
182 TypeId.Int => |info| {
183 const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
184
185 try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb));
186 self.positive = value >= 0;
187 self.len = 0;
188
189 var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value);
190
191 if (info.bits <= Limb.bit_count) {
192 self.limbs[0] = Limb(w_value);
193 self.len = 1;
194 } else {
195 var i: usize = 0;
196 while (w_value != 0) : (i += 1) {
197 self.limbs[i] = @truncate(Limb, w_value);
198 self.len += 1;
199
200 // TODO: shift == 64 at compile-time fails. Fails on u128 limbs.
201 w_value >>= Limb.bit_count / 2;
202 w_value >>= Limb.bit_count / 2;
203 }
204 }
205 },
206 TypeId.ComptimeInt => {
207 comptime var w_value = if (value < 0) -value else value;
208
209 const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1;
210 try self.ensureCapacity(req_limbs);
211
212 self.positive = value >= 0;
213 self.len = req_limbs;
214
215 if (w_value <= @maxValue(Limb)) {
216 self.limbs[0] = w_value;
217 } else {
218 const mask = (1 << Limb.bit_count) - 1;
219
220 comptime var i = 0;
221 inline while (w_value != 0) : (i += 1) {
222 self.limbs[i] = w_value & mask;
223
224 w_value >>= Limb.bit_count / 2;
225 w_value >>= Limb.bit_count / 2;
226 }
227 }
228 },
229 else => {
230 @compileError("cannot set Int using type " ++ @typeName(T));
231 },
232 }
233 }
234
235 pub const ConvertError = error{
236 NegativeIntoUnsigned,
237 TargetTooSmall,
238 };
239
240 pub fn to(self: Int, comptime T: type) ConvertError!T {
241 switch (@typeId(T)) {
242 TypeId.Int => {
243 const UT = @IntType(false, T.bit_count);
244
245 if (self.bitCountTwosComp() > T.bit_count) {
246 return error.TargetTooSmall;
247 }
248
249 var r: UT = 0;
250
251 if (@sizeOf(UT) <= @sizeOf(Limb)) {
252 r = @intCast(UT, self.limbs[0]);
253 } else {
254 for (self.limbs[0..self.len]) |_, ri| {
255 const limb = self.limbs[self.len - ri - 1];
256 r <<= Limb.bit_count;
257 r |= limb;
258 }
259 }
260
261 if (!T.is_signed) {
262 return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned;
263 } else {
264 if (self.positive) {
265 return @intCast(T, r);
266 } else {
267 if (math.cast(T, r)) |ok| {
268 return -ok;
269 } else |_| {
270 return @minValue(T);
271 }
272 }
273 }
274 },
275 else => {
276 @compileError("cannot convert Int to type " ++ @typeName(T));
277 },
278 }
279 }
280
281 fn charToDigit(ch: u8, base: u8) !u8 {
282 const d = switch (ch) {
283 '0'...'9' => ch - '0',
284 'a'...'f' => (ch - 'a') + 0xa,
285 else => return error.InvalidCharForDigit,
286 };
287
288 return if (d < base) d else return error.DigitTooLargeForBase;
289 }
290
291 fn digitToChar(d: u8, base: u8) !u8 {
292 if (d >= base) {
293 return error.DigitTooLargeForBase;
294 }
295
296 return switch (d) {
297 0...9 => '0' + d,
298 0xa...0xf => ('a' - 0xa) + d,
299 else => unreachable,
300 };
301 }
302
303 pub fn setString(self: *Int, base: u8, value: []const u8) !void {
304 if (base < 2 or base > 16) {
305 return error.InvalidBase;
306 }
307
308 var i: usize = 0;
309 var positive = true;
310 if (value.len > 0 and value[0] == '-') {
311 positive = false;
312 i += 1;
313 }
314
315 // TODO values less than limb size should guarantee non allocating
316 var base_buffer: [512]u8 = undefined;
317 const base_al = &std.heap.FixedBufferAllocator.init(base_buffer[0..]).allocator;
318 const base_ap = try Int.initSet(base_al, base);
319
320 var d_buffer: [512]u8 = undefined;
321 var d_fba = std.heap.FixedBufferAllocator.init(d_buffer[0..]);
322 const d_al = &d_fba.allocator;
323
324 try self.set(0);
325 for (value[i..]) |ch| {
326 const d = try charToDigit(ch, base);
327 d_fba.end_index = 0;
328 const d_ap = try Int.initSet(d_al, d);
329
330 try self.mul(self.*, base_ap);
331 try self.add(self.*, d_ap);
332 }
333 self.positive = positive;
334 }
335
336 /// TODO make this call format instead of the other way around
337 pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
338 if (base < 2 or base > 16) {
339 return error.InvalidBase;
340 }
341
342 var digits = ArrayList(u8).init(allocator);
343 try digits.ensureCapacity(self.sizeInBase(base) + 1);
344 defer digits.deinit();
345
346 if (self.eqZero()) {
347 try digits.append('0');
348 return digits.toOwnedSlice();
349 }
350
351 // Power of two: can do a single pass and use masks to extract digits.
352 if (base & (base - 1) == 0) {
353 const base_shift = math.log2_int(Limb, base);
354
355 for (self.limbs[0..self.len]) |limb| {
356 var shift: usize = 0;
357 while (shift < Limb.bit_count) : (shift += base_shift) {
358 const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & Limb(base - 1));
359 const ch = try digitToChar(r, base);
360 try digits.append(ch);
361 }
362 }
363
364 while (true) {
365 // always will have a non-zero digit somewhere
366 const c = digits.pop();
367 if (c != '0') {
368 digits.append(c) catch unreachable;
369 break;
370 }
371 }
372 } // Non power-of-two: batch divisions per word size.
373 else {
374 const digits_per_limb = math.log(Limb, base, @maxValue(Limb));
375 var limb_base: Limb = 1;
376 var j: usize = 0;
377 while (j < digits_per_limb) : (j += 1) {
378 limb_base *= base;
379 }
380
381 var q = try self.clone();
382 q.positive = true;
383 var r = try Int.init(allocator);
384 var b = try Int.initSet(allocator, limb_base);
385
386 while (q.len >= 2) {
387 try Int.divTrunc(&q, &r, q, b);
388
389 var r_word = r.limbs[0];
390 var i: usize = 0;
391 while (i < digits_per_limb) : (i += 1) {
392 const ch = try digitToChar(@intCast(u8, r_word % base), base);
393 r_word /= base;
394 try digits.append(ch);
395 }
396 }
397
398 {
399 debug.assert(q.len == 1);
400
401 var r_word = q.limbs[0];
402 while (r_word != 0) {
403 const ch = try digitToChar(@intCast(u8, r_word % base), base);
404 r_word /= base;
405 try digits.append(ch);
406 }
407 }
408 }
409
410 if (!self.positive) {
411 try digits.append('-');
412 }
413
414 var s = digits.toOwnedSlice();
415 mem.reverse(u8, s);
416 return s;
417 }
418
419 /// for the std lib format function
420 /// TODO make this non-allocating
421 pub fn format(
422 self: Int,
423 comptime fmt: []const u8,
424 context: var,
425 comptime FmtError: type,
426 output: fn (@typeOf(context), []const u8) FmtError!void,
427 ) FmtError!void {
428 // TODO look at fmt and support other bases
429 const str = self.toString(self.allocator, 10) catch @panic("TODO make this non allocating");
430 defer self.allocator.free(str);
431 return output(context, str);
432 }
433
434 // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
435 pub fn cmpAbs(a: Int, b: Int) i8 {
436 if (a.len < b.len) {
437 return -1;
438 }
439 if (a.len > b.len) {
440 return 1;
441 }
442
443 var i: usize = a.len - 1;
444 while (i != 0) : (i -= 1) {
445 if (a.limbs[i] != b.limbs[i]) {
446 break;
447 }
448 }
449
450 if (a.limbs[i] < b.limbs[i]) {
451 return -1;
452 } else if (a.limbs[i] > b.limbs[i]) {
453 return 1;
454 } else {
455 return 0;
456 }
457 }
458
459 // returns -1, 0, 1 if a < b, a == b or a > b respectively.
460 pub fn cmp(a: Int, b: Int) i8 {
461 if (a.positive != b.positive) {
462 return if (a.positive) i8(1) else -1;
463 } else {
464 const r = cmpAbs(a, b);
465 return if (a.positive) r else -r;
466 }
467 }
468
469 // if a == 0
470 pub fn eqZero(a: Int) bool {
471 return a.len == 1 and a.limbs[0] == 0;
472 }
473
474 // if |a| == |b|
475 pub fn eqAbs(a: Int, b: Int) bool {
476 return cmpAbs(a, b) == 0;
477 }
478
479 // if a == b
480 pub fn eq(a: Int, b: Int) bool {
481 return cmp(a, b) == 0;
482 }
483
484 // Normalize for a possible single carry digit.
485 //
486 // [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
487 // [1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]
488 // [0] -> [0]
489 fn norm1(r: *Int, length: usize) void {
490 debug.assert(length > 0);
491 debug.assert(length <= r.limbs.len);
492
493 if (r.limbs[length - 1] == 0) {
494 r.len = if (length > 1) length - 1 else 1;
495 } else {
496 r.len = length;
497 }
498 }
499
500 // Normalize a possible sequence of leading zeros.
501 //
502 // [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
503 // [1, 2, 0, 0, 0] -> [1, 2]
504 // [0, 0, 0, 0, 0] -> [0]
505 fn normN(r: *Int, length: usize) void {
506 debug.assert(length > 0);
507 debug.assert(length <= r.limbs.len);
508
509 var j = length;
510 while (j > 0) : (j -= 1) {
511 if (r.limbs[j - 1] != 0) {
512 break;
513 }
514 }
515
516 // Handle zero
517 r.len = if (j != 0) j else 1;
518 }
519
520 // r = a + b
521 pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void {
522 if (a.eqZero()) {
523 try r.copy(b);
524 return;
525 } else if (b.eqZero()) {
526 try r.copy(a);
527 return;
528 }
529
530 if (a.positive != b.positive) {
531 if (a.positive) {
532 // (a) + (-b) => a - b
533 const bp = Int{
534 .allocator = undefined,
535 .positive = true,
536 .limbs = b.limbs,
537 .len = b.len,
538 };
539 try r.sub(a, bp);
540 } else {
541 // (-a) + (b) => b - a
542 const ap = Int{
543 .allocator = undefined,
544 .positive = true,
545 .limbs = a.limbs,
546 .len = a.len,
547 };
548 try r.sub(b, ap);
549 }
550 } else {
551 if (a.len >= b.len) {
552 try r.ensureCapacity(a.len + 1);
553 lladd(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
554 r.norm1(a.len + 1);
555 } else {
556 try r.ensureCapacity(b.len + 1);
557 lladd(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
558 r.norm1(b.len + 1);
559 }
560
561 r.positive = a.positive;
562 }
563 }
564
565 // Knuth 4.3.1, Algorithm A.
566 fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void {
567 @setRuntimeSafety(false);
568 debug.assert(a.len != 0 and b.len != 0);
569 debug.assert(a.len >= b.len);
570 debug.assert(r.len >= a.len + 1);
571
572 var i: usize = 0;
573 var carry: Limb = 0;
574
575 while (i < b.len) : (i += 1) {
576 var c: Limb = 0;
577 c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));
578 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
579 carry = c;
580 }
581
582 while (i < a.len) : (i += 1) {
583 carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i]));
584 }
585
586 r[i] = carry;
587 }
588
589 // r = a - b
590 pub fn sub(r: *Int, a: Int, b: Int) !void {
591 if (a.positive != b.positive) {
592 if (a.positive) {
593 // (a) - (-b) => a + b
594 const bp = Int{
595 .allocator = undefined,
596 .positive = true,
597 .limbs = b.limbs,
598 .len = b.len,
599 };
600 try r.add(a, bp);
601 } else {
602 // (-a) - (b) => -(a + b)
603 const ap = Int{
604 .allocator = undefined,
605 .positive = true,
606 .limbs = a.limbs,
607 .len = a.len,
608 };
609 try r.add(ap, b);
610 r.positive = false;
611 }
612 } else {
613 if (a.positive) {
614 // (a) - (b) => a - b
615 if (a.cmp(b) >= 0) {
616 try r.ensureCapacity(a.len + 1);
617 llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
618 r.normN(a.len);
619 r.positive = true;
620 } else {
621 try r.ensureCapacity(b.len + 1);
622 llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
623 r.normN(b.len);
624 r.positive = false;
625 }
626 } else {
627 // (-a) - (-b) => -(a - b)
628 if (a.cmp(b) < 0) {
629 try r.ensureCapacity(a.len + 1);
630 llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
631 r.normN(a.len);
632 r.positive = false;
633 } else {
634 try r.ensureCapacity(b.len + 1);
635 llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
636 r.normN(b.len);
637 r.positive = true;
638 }
639 }
640 }
641 }
642
643 // Knuth 4.3.1, Algorithm S.
644 fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void {
645 @setRuntimeSafety(false);
646 debug.assert(a.len != 0 and b.len != 0);
647 debug.assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1]));
648 debug.assert(r.len >= a.len);
649
650 var i: usize = 0;
651 var borrow: Limb = 0;
652
653 while (i < b.len) : (i += 1) {
654 var c: Limb = 0;
655 c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));
656 c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));
657 borrow = c;
658 }
659
660 while (i < a.len) : (i += 1) {
661 borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i]));
662 }
663
664 debug.assert(borrow == 0);
665 }
666
667 // rma = a * b
668 //
669 // For greatest efficiency, ensure rma does not alias a or b.
670 pub fn mul(rma: *Int, a: Int, b: Int) !void {
671 var r = rma;
672 var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr;
673
674 var sr: Int = undefined;
675 if (aliased) {
676 sr = try Int.initCapacity(rma.allocator, a.len + b.len);
677 r = &sr;
678 aliased = true;
679 }
680 defer if (aliased) {
681 rma.swap(r);
682 r.deinit();
683 };
684
685 try r.ensureCapacity(a.len + b.len);
686
687 if (a.len >= b.len) {
688 llmul(r.limbs, a.limbs[0..a.len], b.limbs[0..b.len]);
689 } else {
690 llmul(r.limbs, b.limbs[0..b.len], a.limbs[0..a.len]);
691 }
692
693 r.positive = a.positive == b.positive;
694 r.normN(a.len + b.len);
695 }
696
697 // a + b * c + *carry, sets carry to the overflow bits
698 pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
699 var r1: Limb = undefined;
700
701 // r1 = a + *carry
702 const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));
703
704 // r2 = b * c
705 //
706 // We still use a DoubleLimb here since the @mulWithOverflow builtin does not
707 // return the carry and lower bits separately so we would need to perform this
708 // anyway to get the carry bits. The branch on the overflow case costs more than
709 // just computing them unconditionally and splitting.
710 //
711 // This could be a single x86 mul instruction, which stores the carry/lower in rdx:rax.
712 const bc = DoubleLimb(b) * DoubleLimb(c);
713 const r2 = @truncate(Limb, bc);
714 const c2 = @truncate(Limb, bc >> Limb.bit_count);
715
716 // r1 = r1 + r2
717 const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));
718
719 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
720 // c2 is at least <= @maxValue(Limb) - 2.
721 carry.* = c1 + c2 + c3;
722
723 return r1;
724 }
725
726 // Knuth 4.3.1, Algorithm M.
727 //
728 // r MUST NOT alias any of a or b.
729 fn llmul(r: []Limb, a: []const Limb, b: []const Limb) void {
730 @setRuntimeSafety(false);
731 debug.assert(a.len >= b.len);
732 debug.assert(r.len >= a.len + b.len);
733
734 mem.set(Limb, r[0 .. a.len + b.len], 0);
735
736 var i: usize = 0;
737 while (i < a.len) : (i += 1) {
738 var carry: Limb = 0;
739 var j: usize = 0;
740 while (j < b.len) : (j += 1) {
741 r[i + j] = @inlineCall(addMulLimbWithCarry, r[i + j], a[i], b[j], &carry);
742 }
743 r[i + j] = carry;
744 }
745 }
746
747 pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void {
748 try div(q, r, a, b);
749
750 // Trunc -> Floor.
751 if (!q.positive) {
752 // TODO values less than limb size should guarantee non allocating
753 var one_buffer: [512]u8 = undefined;
754 const one_al = &std.heap.FixedBufferAllocator.init(one_buffer[0..]).allocator;
755 const one_ap = try Int.initSet(one_al, 1);
756
757 try q.sub(q.*, one_ap);
758 try r.add(q.*, one_ap);
759 }
760 r.positive = b.positive;
761 }
762
763 pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void {
764 try div(q, r, a, b);
765 r.positive = a.positive;
766 }
767
768 // Truncates by default.
769 fn div(quo: *Int, rem: *Int, a: Int, b: Int) !void {
770 if (b.eqZero()) {
771 @panic("division by zero");
772 }
773 if (quo == rem) {
774 @panic("quo and rem cannot be same variable");
775 }
776
777 if (a.cmpAbs(b) < 0) {
778 // quo may alias a so handle rem first
779 try rem.copy(a);
780 rem.positive = a.positive == b.positive;
781
782 quo.positive = true;
783 quo.len = 1;
784 quo.limbs[0] = 0;
785 return;
786 }
787
788 if (b.len == 1) {
789 try quo.ensureCapacity(a.len);
790
791 lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[0..a.len], b.limbs[0]);
792 quo.norm1(a.len);
793 quo.positive = a.positive == b.positive;
794
795 rem.len = 1;
796 rem.positive = true;
797 } else {
798 // x and y are modified during division
799 var x = try a.clone();
800 defer x.deinit();
801
802 var y = try b.clone();
803 defer y.deinit();
804
805 // x may grow one limb during normalization
806 try quo.ensureCapacity(a.len + y.len);
807 try divN(quo.allocator, quo, rem, &x, &y);
808
809 quo.positive = a.positive == b.positive;
810 }
811 }
812
813 // Knuth 4.3.1, Exercise 16.
814 fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void {
815 @setRuntimeSafety(false);
816 debug.assert(a.len > 1 or a[0] >= b);
817 debug.assert(quo.len >= a.len);
818
819 rem.* = 0;
820 for (a) |_, ri| {
821 const i = a.len - ri - 1;
822 const pdiv = ((DoubleLimb(rem.*) << Limb.bit_count) | a[i]);
823
824 if (pdiv == 0) {
825 quo[i] = 0;
826 rem.* = 0;
827 } else if (pdiv < b) {
828 quo[i] = 0;
829 rem.* = @truncate(Limb, pdiv);
830 } else if (pdiv == b) {
831 quo[i] = 1;
832 rem.* = 0;
833 } else {
834 quo[i] = @truncate(Limb, @divTrunc(pdiv, b));
835 rem.* = @truncate(Limb, pdiv - (quo[i] *% b));
836 }
837 }
838 }
839
840 // Handbook of Applied Cryptography, 14.20
841 //
842 // x = qy + r where 0 <= r < y
843 fn divN(allocator: *Allocator, q: *Int, r: *Int, x: *Int, y: *Int) !void {
844 debug.assert(y.len >= 2);
845 debug.assert(x.len >= y.len);
846 debug.assert(q.limbs.len >= x.len + y.len - 1);
847 debug.assert(default_capacity >= 3); // see 3.2
848
849 var tmp = try Int.init(allocator);
850 defer tmp.deinit();
851
852 // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set)
853 const norm_shift = @clz(y.limbs[y.len - 1]);
854 try x.shiftLeft(x.*, norm_shift);
855 try y.shiftLeft(y.*, norm_shift);
856
857 const n = x.len - 1;
858 const t = y.len - 1;
859
860 // 1.
861 q.len = n - t + 1;
862 mem.set(Limb, q.limbs[0..q.len], 0);
863
864 // 2.
865 try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
866 while (x.cmp(tmp) >= 0) {
867 q.limbs[n - t] += 1;
868 try x.sub(x.*, tmp);
869 }
870
871 // 3.
872 var i = n;
873 while (i > t) : (i -= 1) {
874 // 3.1
875 if (x.limbs[i] == y.limbs[t]) {
876 q.limbs[i - t - 1] = @maxValue(Limb);
877 } else {
878 const num = (DoubleLimb(x.limbs[i]) << Limb.bit_count) | DoubleLimb(x.limbs[i - 1]);
879 const z = @intCast(Limb, num / DoubleLimb(y.limbs[t]));
880 q.limbs[i - t - 1] = if (z > @maxValue(Limb)) @maxValue(Limb) else Limb(z);
881 }
882
883 // 3.2
884 tmp.limbs[0] = if (i >= 2) x.limbs[i - 2] else 0;
885 tmp.limbs[1] = if (i >= 1) x.limbs[i - 1] else 0;
886 tmp.limbs[2] = x.limbs[i];
887 tmp.normN(3);
888
889 while (true) {
890 // 2x1 limb multiplication unrolled against single-limb q[i-t-1]
891 var carry: Limb = 0;
892 r.limbs[0] = addMulLimbWithCarry(0, if (t >= 1) y.limbs[t - 1] else 0, q.limbs[i - t - 1], &carry);
893 r.limbs[1] = addMulLimbWithCarry(0, y.limbs[t], q.limbs[i - t - 1], &carry);
894 r.limbs[2] = carry;
895 r.normN(3);
896
897 if (r.cmpAbs(tmp) <= 0) {
898 break;
899 }
900
901 q.limbs[i - t - 1] -= 1;
902 }
903
904 // 3.3
905 try tmp.set(q.limbs[i - t - 1]);
906 try tmp.mul(tmp, y.*);
907 try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1));
908 try x.sub(x.*, tmp);
909
910 if (!x.positive) {
911 try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1));
912 try x.add(x.*, tmp);
913 q.limbs[i - t - 1] -= 1;
914 }
915 }
916
917 // Denormalize
918 q.normN(q.len);
919
920 try r.shiftRight(x.*, norm_shift);
921 r.normN(r.len);
922 }
923
924 // r = a << shift, in other words, r = a * 2^shift
925 pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void {
926 try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
927 llshl(r.limbs[0..], a.limbs[0..a.len], shift);
928 r.norm1(a.len + (shift / Limb.bit_count) + 1);
929 r.positive = a.positive;
930 }
931
932 fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
933 @setRuntimeSafety(false);
934 debug.assert(a.len >= 1);
935 debug.assert(r.len >= a.len + (shift / Limb.bit_count) + 1);
936
937 const limb_shift = shift / Limb.bit_count + 1;
938 const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count);
939
940 var carry: Limb = 0;
941 var i: usize = 0;
942 while (i < a.len) : (i += 1) {
943 const src_i = a.len - i - 1;
944 const dst_i = src_i + limb_shift;
945
946 const src_digit = a[src_i];
947 r[dst_i] = carry | @inlineCall(math.shr, Limb, src_digit, Limb.bit_count - @intCast(Limb, interior_limb_shift));
948 carry = (src_digit << interior_limb_shift);
949 }
950
951 r[limb_shift - 1] = carry;
952 mem.set(Limb, r[0 .. limb_shift - 1], 0);
953 }
954
955 // r = a >> shift
956 pub fn shiftRight(r: *Int, a: Int, shift: usize) !void {
957 if (a.len <= shift / Limb.bit_count) {
958 r.len = 1;
959 r.limbs[0] = 0;
960 r.positive = true;
961 return;
962 }
963
964 try r.ensureCapacity(a.len - (shift / Limb.bit_count));
965 const r_len = llshr(r.limbs[0..], a.limbs[0..a.len], shift);
966 r.len = a.len - (shift / Limb.bit_count);
967 r.positive = a.positive;
968 }
969
970 fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
971 @setRuntimeSafety(false);
972 debug.assert(a.len >= 1);
973 debug.assert(r.len >= a.len - (shift / Limb.bit_count));
974
975 const limb_shift = shift / Limb.bit_count;
976 const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count);
977
978 var carry: Limb = 0;
979 var i: usize = 0;
980 while (i < a.len - limb_shift) : (i += 1) {
981 const src_i = a.len - i - 1;
982 const dst_i = src_i - limb_shift;
983
984 const src_digit = a[src_i];
985 r[dst_i] = carry | (src_digit >> interior_limb_shift);
986 carry = @inlineCall(math.shl, Limb, src_digit, Limb.bit_count - @intCast(Limb, interior_limb_shift));
987 }
988 }
989
990 // r = a | b
991 pub fn bitOr(r: *Int, a: Int, b: Int) !void {
992 if (a.len > b.len) {
993 try r.ensureCapacity(a.len);
994 llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
995 r.len = a.len;
996 } else {
997 try r.ensureCapacity(b.len);
998 llor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
999 r.len = b.len;
1000 }
1001 }
1002
1003 fn llor(r: []Limb, a: []const Limb, b: []const Limb) void {
1004 @setRuntimeSafety(false);
1005 debug.assert(r.len >= a.len);
1006 debug.assert(a.len >= b.len);
1007
1008 var i: usize = 0;
1009 while (i < b.len) : (i += 1) {
1010 r[i] = a[i] | b[i];
1011 }
1012 while (i < a.len) : (i += 1) {
1013 r[i] = a[i];
1014 }
1015 }
1016
1017 // r = a & b
1018 pub fn bitAnd(r: *Int, a: Int, b: Int) !void {
1019 if (a.len > b.len) {
1020 try r.ensureCapacity(b.len);
1021 lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1022 r.normN(b.len);
1023 } else {
1024 try r.ensureCapacity(a.len);
1025 lland(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1026 r.normN(a.len);
1027 }
1028 }
1029
1030 fn lland(r: []Limb, a: []const Limb, b: []const Limb) void {
1031 @setRuntimeSafety(false);
1032 debug.assert(r.len >= b.len);
1033 debug.assert(a.len >= b.len);
1034
1035 var i: usize = 0;
1036 while (i < b.len) : (i += 1) {
1037 r[i] = a[i] & b[i];
1038 }
1039 }
1040
1041 // r = a ^ b
1042 pub fn bitXor(r: *Int, a: Int, b: Int) !void {
1043 if (a.len > b.len) {
1044 try r.ensureCapacity(a.len);
1045 llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1046 r.normN(a.len);
1047 } else {
1048 try r.ensureCapacity(b.len);
1049 llxor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1050 r.normN(b.len);
1051 }
1052 }
1053
1054 fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void {
1055 @setRuntimeSafety(false);
1056 debug.assert(r.len >= a.len);
1057 debug.assert(a.len >= b.len);
1058
1059 var i: usize = 0;
1060 while (i < b.len) : (i += 1) {
1061 r[i] = a[i] ^ b[i];
1062 }
1063 while (i < a.len) : (i += 1) {
1064 r[i] = a[i];
1065 }
1066 }
1067};
1068
1069// NOTE: All the following tests assume the max machine-word will be 64-bit.
1070//
1071// They will still run on larger than this and should pass, but the multi-limb code-paths
1072// may be untested in some cases.
1073
1074const al = debug.global_allocator;
1075
1076test "big.int comptime_int set" {
1077 comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
1078 var a = try Int.initSet(al, s);
1079
1080 const s_limb_count = 128 / Limb.bit_count;
1081
1082 comptime var i: usize = 0;
1083 inline while (i < s_limb_count) : (i += 1) {
1084 const result = Limb(s & @maxValue(Limb));
1085 s >>= Limb.bit_count / 2;
1086 s >>= Limb.bit_count / 2;
1087 debug.assert(a.limbs[i] == result);
1088 }
1089}
1090
1091test "big.int comptime_int set negative" {
1092 var a = try Int.initSet(al, -10);
1093
1094 debug.assert(a.limbs[0] == 10);
1095 debug.assert(a.positive == false);
1096}
1097
1098test "big.int int set unaligned small" {
1099 var a = try Int.initSet(al, u7(45));
1100
1101 debug.assert(a.limbs[0] == 45);
1102 debug.assert(a.positive == true);
1103}
1104
1105test "big.int comptime_int to" {
1106 const a = try Int.initSet(al, 0xefffffff00000001eeeeeeefaaaaaaab);
1107
1108 debug.assert((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab);
1109}
1110
1111test "big.int sub-limb to" {
1112 const a = try Int.initSet(al, 10);
1113
1114 debug.assert((try a.to(u8)) == 10);
1115}
1116
1117test "big.int to target too small error" {
1118 const a = try Int.initSet(al, 0xffffffff);
1119
1120 if (a.to(u8)) |_| {
1121 unreachable;
1122 } else |err| {
1123 debug.assert(err == error.TargetTooSmall);
1124 }
1125}
1126
1127test "big.int norm1" {
1128 var a = try Int.init(al);
1129 try a.ensureCapacity(8);
1130
1131 a.limbs[0] = 1;
1132 a.limbs[1] = 2;
1133 a.limbs[2] = 3;
1134 a.limbs[3] = 0;
1135 a.norm1(4);
1136 debug.assert(a.len == 3);
1137
1138 a.limbs[0] = 1;
1139 a.limbs[1] = 2;
1140 a.limbs[2] = 3;
1141 a.norm1(3);
1142 debug.assert(a.len == 3);
1143
1144 a.limbs[0] = 0;
1145 a.limbs[1] = 0;
1146 a.norm1(2);
1147 debug.assert(a.len == 1);
1148
1149 a.limbs[0] = 0;
1150 a.norm1(1);
1151 debug.assert(a.len == 1);
1152}
1153
1154test "big.int normN" {
1155 var a = try Int.init(al);
1156 try a.ensureCapacity(8);
1157
1158 a.limbs[0] = 1;
1159 a.limbs[1] = 2;
1160 a.limbs[2] = 0;
1161 a.limbs[3] = 0;
1162 a.normN(4);
1163 debug.assert(a.len == 2);
1164
1165 a.limbs[0] = 1;
1166 a.limbs[1] = 2;
1167 a.limbs[2] = 3;
1168 a.normN(3);
1169 debug.assert(a.len == 3);
1170
1171 a.limbs[0] = 0;
1172 a.limbs[1] = 0;
1173 a.limbs[2] = 0;
1174 a.limbs[3] = 0;
1175 a.normN(4);
1176 debug.assert(a.len == 1);
1177
1178 a.limbs[0] = 0;
1179 a.normN(1);
1180 debug.assert(a.len == 1);
1181}
1182
1183test "big.int parity" {
1184 var a = try Int.init(al);
1185 try a.set(0);
1186 debug.assert(a.isEven());
1187 debug.assert(!a.isOdd());
1188
1189 try a.set(7);
1190 debug.assert(!a.isEven());
1191 debug.assert(a.isOdd());
1192}
1193
1194test "big.int bitcount + sizeInBase" {
1195 var a = try Int.init(al);
1196
1197 try a.set(0b100);
1198 debug.assert(a.bitCountAbs() == 3);
1199 debug.assert(a.sizeInBase(2) >= 3);
1200 debug.assert(a.sizeInBase(10) >= 1);
1201
1202 a.negate();
1203 debug.assert(a.bitCountAbs() == 3);
1204 debug.assert(a.sizeInBase(2) >= 4);
1205 debug.assert(a.sizeInBase(10) >= 2);
1206
1207 try a.set(0xffffffff);
1208 debug.assert(a.bitCountAbs() == 32);
1209 debug.assert(a.sizeInBase(2) >= 32);
1210 debug.assert(a.sizeInBase(10) >= 10);
1211
1212 try a.shiftLeft(a, 5000);
1213 debug.assert(a.bitCountAbs() == 5032);
1214 debug.assert(a.sizeInBase(2) >= 5032);
1215 a.positive = false;
1216
1217 debug.assert(a.bitCountAbs() == 5032);
1218 debug.assert(a.sizeInBase(2) >= 5033);
1219}
1220
1221test "big.int bitcount/to" {
1222 var a = try Int.init(al);
1223
1224 try a.set(0);
1225 debug.assert(a.bitCountTwosComp() == 0);
1226
1227 // TODO: stack smashing
1228 // debug.assert((try a.to(u0)) == 0);
1229 // TODO: sigsegv
1230 // debug.assert((try a.to(i0)) == 0);
1231
1232 try a.set(-1);
1233 debug.assert(a.bitCountTwosComp() == 1);
1234 debug.assert((try a.to(i1)) == -1);
1235
1236 try a.set(-8);
1237 debug.assert(a.bitCountTwosComp() == 4);
1238 debug.assert((try a.to(i4)) == -8);
1239
1240 try a.set(127);
1241 debug.assert(a.bitCountTwosComp() == 7);
1242 debug.assert((try a.to(u7)) == 127);
1243
1244 try a.set(-128);
1245 debug.assert(a.bitCountTwosComp() == 8);
1246 debug.assert((try a.to(i8)) == -128);
1247
1248 try a.set(-129);
1249 debug.assert(a.bitCountTwosComp() == 9);
1250 debug.assert((try a.to(i9)) == -129);
1251}
1252
1253test "big.int fits" {
1254 var a = try Int.init(al);
1255
1256 try a.set(0);
1257 debug.assert(a.fits(u0));
1258 debug.assert(a.fits(i0));
1259
1260 try a.set(255);
1261 debug.assert(!a.fits(u0));
1262 debug.assert(!a.fits(u1));
1263 debug.assert(!a.fits(i8));
1264 debug.assert(a.fits(u8));
1265 debug.assert(a.fits(u9));
1266 debug.assert(a.fits(i9));
1267
1268 try a.set(-128);
1269 debug.assert(!a.fits(i7));
1270 debug.assert(a.fits(i8));
1271 debug.assert(a.fits(i9));
1272 debug.assert(!a.fits(u9));
1273
1274 try a.set(0x1ffffffffeeeeeeee);
1275 debug.assert(!a.fits(u32));
1276 debug.assert(!a.fits(u64));
1277 debug.assert(a.fits(u65));
1278}
1279
1280test "big.int string set" {
1281 var a = try Int.init(al);
1282 try a.setString(10, "120317241209124781241290847124");
1283
1284 debug.assert((try a.to(u128)) == 120317241209124781241290847124);
1285}
1286
1287test "big.int string negative" {
1288 var a = try Int.init(al);
1289 try a.setString(10, "-1023");
1290 debug.assert((try a.to(i32)) == -1023);
1291}
1292
1293test "big.int string set bad char error" {
1294 var a = try Int.init(al);
1295 a.setString(10, "x") catch |err| debug.assert(err == error.InvalidCharForDigit);
1296}
1297
1298test "big.int string set bad base error" {
1299 var a = try Int.init(al);
1300 a.setString(45, "10") catch |err| debug.assert(err == error.InvalidBase);
1301}
1302
1303test "big.int string to" {
1304 const a = try Int.initSet(al, 120317241209124781241290847124);
1305
1306 const as = try a.toString(al, 10);
1307 const es = "120317241209124781241290847124";
1308
1309 debug.assert(mem.eql(u8, as, es));
1310}
1311
1312test "big.int string to base base error" {
1313 const a = try Int.initSet(al, 0xffffffff);
1314
1315 if (a.toString(al, 45)) |_| {
1316 unreachable;
1317 } else |err| {
1318 debug.assert(err == error.InvalidBase);
1319 }
1320}
1321
1322test "big.int string to base 2" {
1323 const a = try Int.initSet(al, -0b1011);
1324
1325 const as = try a.toString(al, 2);
1326 const es = "-1011";
1327
1328 debug.assert(mem.eql(u8, as, es));
1329}
1330
1331test "big.int string to base 16" {
1332 const a = try Int.initSet(al, 0xefffffff00000001eeeeeeefaaaaaaab);
1333
1334 const as = try a.toString(al, 16);
1335 const es = "efffffff00000001eeeeeeefaaaaaaab";
1336
1337 debug.assert(mem.eql(u8, as, es));
1338}
1339
1340test "big.int neg string to" {
1341 const a = try Int.initSet(al, -123907434);
1342
1343 const as = try a.toString(al, 10);
1344 const es = "-123907434";
1345
1346 debug.assert(mem.eql(u8, as, es));
1347}
1348
1349test "big.int zero string to" {
1350 const a = try Int.initSet(al, 0);
1351
1352 const as = try a.toString(al, 10);
1353 const es = "0";
1354
1355 debug.assert(mem.eql(u8, as, es));
1356}
1357
1358test "big.int clone" {
1359 var a = try Int.initSet(al, 1234);
1360 const b = try a.clone();
1361
1362 debug.assert((try a.to(u32)) == 1234);
1363 debug.assert((try b.to(u32)) == 1234);
1364
1365 try a.set(77);
1366 debug.assert((try a.to(u32)) == 77);
1367 debug.assert((try b.to(u32)) == 1234);
1368}
1369
1370test "big.int swap" {
1371 var a = try Int.initSet(al, 1234);
1372 var b = try Int.initSet(al, 5678);
1373
1374 debug.assert((try a.to(u32)) == 1234);
1375 debug.assert((try b.to(u32)) == 5678);
1376
1377 a.swap(&b);
1378
1379 debug.assert((try a.to(u32)) == 5678);
1380 debug.assert((try b.to(u32)) == 1234);
1381}
1382
1383test "big.int to negative" {
1384 var a = try Int.initSet(al, -10);
1385
1386 debug.assert((try a.to(i32)) == -10);
1387}
1388
1389test "big.int compare" {
1390 var a = try Int.initSet(al, -11);
1391 var b = try Int.initSet(al, 10);
1392
1393 debug.assert(a.cmpAbs(b) == 1);
1394 debug.assert(a.cmp(b) == -1);
1395}
1396
1397test "big.int compare similar" {
1398 var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee);
1399 var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef);
1400
1401 debug.assert(a.cmpAbs(b) == -1);
1402 debug.assert(b.cmpAbs(a) == 1);
1403}
1404
1405test "big.int compare different limb size" {
1406 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1407 var b = try Int.initSet(al, 1);
1408
1409 debug.assert(a.cmpAbs(b) == 1);
1410 debug.assert(b.cmpAbs(a) == -1);
1411}
1412
1413test "big.int compare multi-limb" {
1414 var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
1415 var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
1416
1417 debug.assert(a.cmpAbs(b) == 1);
1418 debug.assert(a.cmp(b) == -1);
1419}
1420
1421test "big.int equality" {
1422 var a = try Int.initSet(al, 0xffffffff1);
1423 var b = try Int.initSet(al, -0xffffffff1);
1424
1425 debug.assert(a.eqAbs(b));
1426 debug.assert(!a.eq(b));
1427}
1428
1429test "big.int abs" {
1430 var a = try Int.initSet(al, -5);
1431
1432 a.abs();
1433 debug.assert((try a.to(u32)) == 5);
1434
1435 a.abs();
1436 debug.assert((try a.to(u32)) == 5);
1437}
1438
1439test "big.int negate" {
1440 var a = try Int.initSet(al, 5);
1441
1442 a.negate();
1443 debug.assert((try a.to(i32)) == -5);
1444
1445 a.negate();
1446 debug.assert((try a.to(i32)) == 5);
1447}
1448
1449test "big.int add single-single" {
1450 var a = try Int.initSet(al, 50);
1451 var b = try Int.initSet(al, 5);
1452
1453 var c = try Int.init(al);
1454 try c.add(a, b);
1455
1456 debug.assert((try c.to(u32)) == 55);
1457}
1458
1459test "big.int add multi-single" {
1460 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1461 var b = try Int.initSet(al, 1);
1462
1463 var c = try Int.init(al);
1464
1465 try c.add(a, b);
1466 debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
1467
1468 try c.add(b, a);
1469 debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
1470}
1471
1472test "big.int add multi-multi" {
1473 const op1 = 0xefefefef7f7f7f7f;
1474 const op2 = 0xfefefefe9f9f9f9f;
1475 var a = try Int.initSet(al, op1);
1476 var b = try Int.initSet(al, op2);
1477
1478 var c = try Int.init(al);
1479 try c.add(a, b);
1480
1481 debug.assert((try c.to(u128)) == op1 + op2);
1482}
1483
1484test "big.int add zero-zero" {
1485 var a = try Int.initSet(al, 0);
1486 var b = try Int.initSet(al, 0);
1487
1488 var c = try Int.init(al);
1489 try c.add(a, b);
1490
1491 debug.assert((try c.to(u32)) == 0);
1492}
1493
1494test "big.int add alias multi-limb nonzero-zero" {
1495 const op1 = 0xffffffff777777771;
1496 var a = try Int.initSet(al, op1);
1497 var b = try Int.initSet(al, 0);
1498
1499 try a.add(a, b);
1500
1501 debug.assert((try a.to(u128)) == op1);
1502}
1503
1504test "big.int add sign" {
1505 var a = try Int.init(al);
1506
1507 const one = try Int.initSet(al, 1);
1508 const two = try Int.initSet(al, 2);
1509 const neg_one = try Int.initSet(al, -1);
1510 const neg_two = try Int.initSet(al, -2);
1511
1512 try a.add(one, two);
1513 debug.assert((try a.to(i32)) == 3);
1514
1515 try a.add(neg_one, two);
1516 debug.assert((try a.to(i32)) == 1);
1517
1518 try a.add(one, neg_two);
1519 debug.assert((try a.to(i32)) == -1);
1520
1521 try a.add(neg_one, neg_two);
1522 debug.assert((try a.to(i32)) == -3);
1523}
1524
1525test "big.int sub single-single" {
1526 var a = try Int.initSet(al, 50);
1527 var b = try Int.initSet(al, 5);
1528
1529 var c = try Int.init(al);
1530 try c.sub(a, b);
1531
1532 debug.assert((try c.to(u32)) == 45);
1533}
1534
1535test "big.int sub multi-single" {
1536 var a = try Int.initSet(al, @maxValue(Limb) + 1);
1537 var b = try Int.initSet(al, 1);
1538
1539 var c = try Int.init(al);
1540 try c.sub(a, b);
1541
1542 debug.assert((try c.to(Limb)) == @maxValue(Limb));
1543}
1544
1545test "big.int sub multi-multi" {
1546 const op1 = 0xefefefefefefefefefefefef;
1547 const op2 = 0xabababababababababababab;
1548
1549 var a = try Int.initSet(al, op1);
1550 var b = try Int.initSet(al, op2);
1551
1552 var c = try Int.init(al);
1553 try c.sub(a, b);
1554
1555 debug.assert((try c.to(u128)) == op1 - op2);
1556}
1557
1558test "big.int sub equal" {
1559 var a = try Int.initSet(al, 0x11efefefefefefefefefefefef);
1560 var b = try Int.initSet(al, 0x11efefefefefefefefefefefef);
1561
1562 var c = try Int.init(al);
1563 try c.sub(a, b);
1564
1565 debug.assert((try c.to(u32)) == 0);
1566}
1567
1568test "big.int sub sign" {
1569 var a = try Int.init(al);
1570
1571 const one = try Int.initSet(al, 1);
1572 const two = try Int.initSet(al, 2);
1573 const neg_one = try Int.initSet(al, -1);
1574 const neg_two = try Int.initSet(al, -2);
1575
1576 try a.sub(one, two);
1577 debug.assert((try a.to(i32)) == -1);
1578
1579 try a.sub(neg_one, two);
1580 debug.assert((try a.to(i32)) == -3);
1581
1582 try a.sub(one, neg_two);
1583 debug.assert((try a.to(i32)) == 3);
1584
1585 try a.sub(neg_one, neg_two);
1586 debug.assert((try a.to(i32)) == 1);
1587
1588 try a.sub(neg_two, neg_one);
1589 debug.assert((try a.to(i32)) == -1);
1590}
1591
1592test "big.int mul single-single" {
1593 var a = try Int.initSet(al, 50);
1594 var b = try Int.initSet(al, 5);
1595
1596 var c = try Int.init(al);
1597 try c.mul(a, b);
1598
1599 debug.assert((try c.to(u64)) == 250);
1600}
1601
1602test "big.int mul multi-single" {
1603 var a = try Int.initSet(al, @maxValue(Limb));
1604 var b = try Int.initSet(al, 2);
1605
1606 var c = try Int.init(al);
1607 try c.mul(a, b);
1608
1609 debug.assert((try c.to(DoubleLimb)) == 2 * @maxValue(Limb));
1610}
1611
1612test "big.int mul multi-multi" {
1613 const op1 = 0x998888efefefefefefefef;
1614 const op2 = 0x333000abababababababab;
1615 var a = try Int.initSet(al, op1);
1616 var b = try Int.initSet(al, op2);
1617
1618 var c = try Int.init(al);
1619 try c.mul(a, b);
1620
1621 debug.assert((try c.to(u256)) == op1 * op2);
1622}
1623
1624test "big.int mul alias r with a" {
1625 var a = try Int.initSet(al, @maxValue(Limb));
1626 var b = try Int.initSet(al, 2);
1627
1628 try a.mul(a, b);
1629
1630 debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
1631}
1632
1633test "big.int mul alias r with b" {
1634 var a = try Int.initSet(al, @maxValue(Limb));
1635 var b = try Int.initSet(al, 2);
1636
1637 try a.mul(b, a);
1638
1639 debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
1640}
1641
1642test "big.int mul alias r with a and b" {
1643 var a = try Int.initSet(al, @maxValue(Limb));
1644
1645 try a.mul(a, a);
1646
1647 debug.assert((try a.to(DoubleLimb)) == @maxValue(Limb) * @maxValue(Limb));
1648}
1649
1650test "big.int mul a*0" {
1651 var a = try Int.initSet(al, 0xefefefefefefefef);
1652 var b = try Int.initSet(al, 0);
1653
1654 var c = try Int.init(al);
1655 try c.mul(a, b);
1656
1657 debug.assert((try c.to(u32)) == 0);
1658}
1659
1660test "big.int mul 0*0" {
1661 var a = try Int.initSet(al, 0);
1662 var b = try Int.initSet(al, 0);
1663
1664 var c = try Int.init(al);
1665 try c.mul(a, b);
1666
1667 debug.assert((try c.to(u32)) == 0);
1668}
1669
1670test "big.int div single-single no rem" {
1671 var a = try Int.initSet(al, 50);
1672 var b = try Int.initSet(al, 5);
1673
1674 var q = try Int.init(al);
1675 var r = try Int.init(al);
1676 try Int.divTrunc(&q, &r, a, b);
1677
1678 debug.assert((try q.to(u32)) == 10);
1679 debug.assert((try r.to(u32)) == 0);
1680}
1681
1682test "big.int div single-single with rem" {
1683 var a = try Int.initSet(al, 49);
1684 var b = try Int.initSet(al, 5);
1685
1686 var q = try Int.init(al);
1687 var r = try Int.init(al);
1688 try Int.divTrunc(&q, &r, a, b);
1689
1690 debug.assert((try q.to(u32)) == 9);
1691 debug.assert((try r.to(u32)) == 4);
1692}
1693
1694test "big.int div multi-single no rem" {
1695 const op1 = 0xffffeeeeddddcccc;
1696 const op2 = 34;
1697
1698 var a = try Int.initSet(al, op1);
1699 var b = try Int.initSet(al, op2);
1700
1701 var q = try Int.init(al);
1702 var r = try Int.init(al);
1703 try Int.divTrunc(&q, &r, a, b);
1704
1705 debug.assert((try q.to(u64)) == op1 / op2);
1706 debug.assert((try r.to(u64)) == 0);
1707}
1708
1709test "big.int div multi-single with rem" {
1710 const op1 = 0xffffeeeeddddcccf;
1711 const op2 = 34;
1712
1713 var a = try Int.initSet(al, op1);
1714 var b = try Int.initSet(al, op2);
1715
1716 var q = try Int.init(al);
1717 var r = try Int.init(al);
1718 try Int.divTrunc(&q, &r, a, b);
1719
1720 debug.assert((try q.to(u64)) == op1 / op2);
1721 debug.assert((try r.to(u64)) == 3);
1722}
1723
1724test "big.int div multi>2-single" {
1725 const op1 = 0xfefefefefefefefefefefefefefefefe;
1726 const op2 = 0xefab8;
1727
1728 var a = try Int.initSet(al, op1);
1729 var b = try Int.initSet(al, op2);
1730
1731 var q = try Int.init(al);
1732 var r = try Int.init(al);
1733 try Int.divTrunc(&q, &r, a, b);
1734
1735 debug.assert((try q.to(u128)) == op1 / op2);
1736 debug.assert((try r.to(u32)) == 0x3e4e);
1737}
1738
1739test "big.int div single-single q < r" {
1740 var a = try Int.initSet(al, 0x0078f432);
1741 var b = try Int.initSet(al, 0x01000000);
1742
1743 var q = try Int.init(al);
1744 var r = try Int.init(al);
1745 try Int.divTrunc(&q, &r, a, b);
1746
1747 debug.assert((try q.to(u64)) == 0);
1748 debug.assert((try r.to(u64)) == 0x0078f432);
1749}
1750
1751test "big.int div single-single q == r" {
1752 var a = try Int.initSet(al, 10);
1753 var b = try Int.initSet(al, 10);
1754
1755 var q = try Int.init(al);
1756 var r = try Int.init(al);
1757 try Int.divTrunc(&q, &r, a, b);
1758
1759 debug.assert((try q.to(u64)) == 1);
1760 debug.assert((try r.to(u64)) == 0);
1761}
1762
1763test "big.int div q=0 alias" {
1764 var a = try Int.initSet(al, 3);
1765 var b = try Int.initSet(al, 10);
1766
1767 try Int.divTrunc(&a, &b, a, b);
1768
1769 debug.assert((try a.to(u64)) == 0);
1770 debug.assert((try b.to(u64)) == 3);
1771}
1772
1773test "big.int div multi-multi q < r" {
1774 const op1 = 0x1ffffffff0078f432;
1775 const op2 = 0x1ffffffff01000000;
1776 var a = try Int.initSet(al, op1);
1777 var b = try Int.initSet(al, op2);
1778
1779 var q = try Int.init(al);
1780 var r = try Int.init(al);
1781 try Int.divTrunc(&q, &r, a, b);
1782
1783 debug.assert((try q.to(u128)) == 0);
1784 debug.assert((try r.to(u128)) == op1);
1785}
1786
1787test "big.int div trunc single-single +/+" {
1788 const u: i32 = 5;
1789 const v: i32 = 3;
1790
1791 var a = try Int.initSet(al, u);
1792 var b = try Int.initSet(al, v);
1793
1794 var q = try Int.init(al);
1795 var r = try Int.init(al);
1796 try Int.divTrunc(&q, &r, a, b);
1797
1798 // n = q * d + r
1799 // 5 = 1 * 3 + 2
1800 const eq = @divTrunc(u, v);
1801 const er = @mod(u, v);
1802
1803 debug.assert((try q.to(i32)) == eq);
1804 debug.assert((try r.to(i32)) == er);
1805}
1806
1807test "big.int div trunc single-single -/+" {
1808 const u: i32 = -5;
1809 const v: i32 = 3;
1810
1811 var a = try Int.initSet(al, u);
1812 var b = try Int.initSet(al, v);
1813
1814 var q = try Int.init(al);
1815 var r = try Int.init(al);
1816 try Int.divTrunc(&q, &r, a, b);
1817
1818 // n = q * d + r
1819 // -5 = 1 * -3 - 2
1820 const eq = -1;
1821 const er = -2;
1822
1823 debug.assert((try q.to(i32)) == eq);
1824 debug.assert((try r.to(i32)) == er);
1825}
1826
1827test "big.int div trunc single-single +/-" {
1828 const u: i32 = 5;
1829 const v: i32 = -3;
1830
1831 var a = try Int.initSet(al, u);
1832 var b = try Int.initSet(al, v);
1833
1834 var q = try Int.init(al);
1835 var r = try Int.init(al);
1836 try Int.divTrunc(&q, &r, a, b);
1837
1838 // n = q * d + r
1839 // 5 = -1 * -3 + 2
1840 const eq = -1;
1841 const er = 2;
1842
1843 debug.assert((try q.to(i32)) == eq);
1844 debug.assert((try r.to(i32)) == er);
1845}
1846
1847test "big.int div trunc single-single -/-" {
1848 const u: i32 = -5;
1849 const v: i32 = -3;
1850
1851 var a = try Int.initSet(al, u);
1852 var b = try Int.initSet(al, v);
1853
1854 var q = try Int.init(al);
1855 var r = try Int.init(al);
1856 try Int.divTrunc(&q, &r, a, b);
1857
1858 // n = q * d + r
1859 // -5 = 1 * -3 - 2
1860 const eq = 1;
1861 const er = -2;
1862
1863 debug.assert((try q.to(i32)) == eq);
1864 debug.assert((try r.to(i32)) == er);
1865}
1866
1867test "big.int div floor single-single +/+" {
1868 const u: i32 = 5;
1869 const v: i32 = 3;
1870
1871 var a = try Int.initSet(al, u);
1872 var b = try Int.initSet(al, v);
1873
1874 var q = try Int.init(al);
1875 var r = try Int.init(al);
1876 try Int.divFloor(&q, &r, a, b);
1877
1878 // n = q * d + r
1879 // 5 = 1 * 3 + 2
1880 const eq = 1;
1881 const er = 2;
1882
1883 debug.assert((try q.to(i32)) == eq);
1884 debug.assert((try r.to(i32)) == er);
1885}
1886
1887test "big.int div floor single-single -/+" {
1888 const u: i32 = -5;
1889 const v: i32 = 3;
1890
1891 var a = try Int.initSet(al, u);
1892 var b = try Int.initSet(al, v);
1893
1894 var q = try Int.init(al);
1895 var r = try Int.init(al);
1896 try Int.divFloor(&q, &r, a, b);
1897
1898 // n = q * d + r
1899 // -5 = -2 * 3 + 1
1900 const eq = -2;
1901 const er = 1;
1902
1903 debug.assert((try q.to(i32)) == eq);
1904 debug.assert((try r.to(i32)) == er);
1905}
1906
1907test "big.int div floor single-single +/-" {
1908 const u: i32 = 5;
1909 const v: i32 = -3;
1910
1911 var a = try Int.initSet(al, u);
1912 var b = try Int.initSet(al, v);
1913
1914 var q = try Int.init(al);
1915 var r = try Int.init(al);
1916 try Int.divFloor(&q, &r, a, b);
1917
1918 // n = q * d + r
1919 // 5 = -2 * -3 - 1
1920 const eq = -2;
1921 const er = -1;
1922
1923 debug.assert((try q.to(i32)) == eq);
1924 debug.assert((try r.to(i32)) == er);
1925}
1926
1927test "big.int div floor single-single -/-" {
1928 const u: i32 = -5;
1929 const v: i32 = -3;
1930
1931 var a = try Int.initSet(al, u);
1932 var b = try Int.initSet(al, v);
1933
1934 var q = try Int.init(al);
1935 var r = try Int.init(al);
1936 try Int.divFloor(&q, &r, a, b);
1937
1938 // n = q * d + r
1939 // -5 = 2 * -3 + 1
1940 const eq = 1;
1941 const er = -2;
1942
1943 debug.assert((try q.to(i32)) == eq);
1944 debug.assert((try r.to(i32)) == er);
1945}
1946
1947test "big.int div multi-multi with rem" {
1948 var a = try Int.initSet(al, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999);
1949 var b = try Int.initSet(al, 0x99990000111122223333);
1950
1951 var q = try Int.init(al);
1952 var r = try Int.init(al);
1953 try Int.divTrunc(&q, &r, a, b);
1954
1955 debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
1956 debug.assert((try r.to(u128)) == 0x28de0acacd806823638);
1957}
1958
1959test "big.int div multi-multi no rem" {
1960 var a = try Int.initSet(al, 0x8888999911110000ffffeeeedb4fec200ee3a4286361);
1961 var b = try Int.initSet(al, 0x99990000111122223333);
1962
1963 var q = try Int.init(al);
1964 var r = try Int.init(al);
1965 try Int.divTrunc(&q, &r, a, b);
1966
1967 debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
1968 debug.assert((try r.to(u128)) == 0);
1969}
1970
1971test "big.int div multi-multi (2 branch)" {
1972 var a = try Int.initSet(al, 0x866666665555555588888887777777761111111111111111);
1973 var b = try Int.initSet(al, 0x86666666555555554444444433333333);
1974
1975 var q = try Int.init(al);
1976 var r = try Int.init(al);
1977 try Int.divTrunc(&q, &r, a, b);
1978
1979 debug.assert((try q.to(u128)) == 0x10000000000000000);
1980 debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111);
1981}
1982
1983test "big.int div multi-multi (3.1/3.3 branch)" {
1984 var a = try Int.initSet(al, 0x11111111111111111111111111111111111111111111111111111111111111);
1985 var b = try Int.initSet(al, 0x1111111111111111111111111111111111111111171);
1986
1987 var q = try Int.init(al);
1988 var r = try Int.init(al);
1989 try Int.divTrunc(&q, &r, a, b);
1990
1991 debug.assert((try q.to(u128)) == 0xfffffffffffffffffff);
1992 debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
1993}
1994
1995test "big.int shift-right single" {
1996 var a = try Int.initSet(al, 0xffff0000);
1997 try a.shiftRight(a, 16);
1998
1999 debug.assert((try a.to(u32)) == 0xffff);
2000}
2001
2002test "big.int shift-right multi" {
2003 var a = try Int.initSet(al, 0xffff0000eeee1111dddd2222cccc3333);
2004 try a.shiftRight(a, 67);
2005
2006 debug.assert((try a.to(u64)) == 0x1fffe0001dddc222);
2007}
2008
2009test "big.int shift-left single" {
2010 var a = try Int.initSet(al, 0xffff);
2011 try a.shiftLeft(a, 16);
2012
2013 debug.assert((try a.to(u64)) == 0xffff0000);
2014}
2015
2016test "big.int shift-left multi" {
2017 var a = try Int.initSet(al, 0x1fffe0001dddc222);
2018 try a.shiftLeft(a, 67);
2019
2020 debug.assert((try a.to(u128)) == 0xffff0000eeee11100000000000000000);
2021}
2022
2023test "big.int shift-right negative" {
2024 var a = try Int.init(al);
2025
2026 try a.shiftRight(try Int.initSet(al, -20), 2);
2027 debug.assert((try a.to(i32)) == -20 >> 2);
2028
2029 try a.shiftRight(try Int.initSet(al, -5), 10);
2030 debug.assert((try a.to(i32)) == -5 >> 10);
2031}
2032
2033test "big.int shift-left negative" {
2034 var a = try Int.init(al);
2035
2036 try a.shiftRight(try Int.initSet(al, -10), 1232);
2037 debug.assert((try a.to(i32)) == -10 >> 1232);
2038}
2039
2040test "big.int bitwise and simple" {
2041 var a = try Int.initSet(al, 0xffffffff11111111);
2042 var b = try Int.initSet(al, 0xeeeeeeee22222222);
2043
2044 try a.bitAnd(a, b);
2045
2046 debug.assert((try a.to(u64)) == 0xeeeeeeee00000000);
2047}
2048
2049test "big.int bitwise and multi-limb" {
2050 var a = try Int.initSet(al, @maxValue(Limb) + 1);
2051 var b = try Int.initSet(al, @maxValue(Limb));
2052
2053 try a.bitAnd(a, b);
2054
2055 debug.assert((try a.to(u128)) == 0);
2056}
2057
2058test "big.int bitwise xor simple" {
2059 var a = try Int.initSet(al, 0xffffffff11111111);
2060 var b = try Int.initSet(al, 0xeeeeeeee22222222);
2061
2062 try a.bitXor(a, b);
2063
2064 debug.assert((try a.to(u64)) == 0x1111111133333333);
2065}
2066
2067test "big.int bitwise xor multi-limb" {
2068 var a = try Int.initSet(al, @maxValue(Limb) + 1);
2069 var b = try Int.initSet(al, @maxValue(Limb));
2070
2071 try a.bitXor(a, b);
2072
2073 debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) ^ @maxValue(Limb));
2074}
2075
2076test "big.int bitwise or simple" {
2077 var a = try Int.initSet(al, 0xffffffff11111111);
2078 var b = try Int.initSet(al, 0xeeeeeeee22222222);
2079
2080 try a.bitOr(a, b);
2081
2082 debug.assert((try a.to(u64)) == 0xffffffff33333333);
2083}
2084
2085test "big.int bitwise or multi-limb" {
2086 var a = try Int.initSet(al, @maxValue(Limb) + 1);
2087 var b = try Int.initSet(al, @maxValue(Limb));
2088
2089 try a.bitOr(a, b);
2090
2091 // TODO: big.int.cpp or is wrong on multi-limb.
2092 debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) + @maxValue(Limb));
2093}
2094
2095test "big.int var args" {
2096 var a = try Int.initSet(al, 5);
2097
2098 try a.add(a, try Int.initSet(al, 6));
2099 debug.assert((try a.to(u64)) == 11);
2100
2101 debug.assert(a.cmp(try Int.initSet(al, 11)) == 0);
2102 debug.assert(a.cmp(try Int.initSet(al, 14)) <= 0);
2103}
std/math/cbrt.zig+8-8
......@@ -54,22 +54,22 @@ fn cbrt32(x: f32) f32 {
5454 r = t * t * t;
5555 t = t * (f64(x) + x + r) / (x + r + r);
5656
57 return f32(t);
57 return @floatCast(f32, t);
5858}
5959
6060fn cbrt64(x: f64) f64 {
61 const B1: u32 = 715094163; // (1023 - 1023 / 3 - 0.03306235651 * 2^20
62 const B2: u32 = 696219795; // (1023 - 1023 / 3 - 54 / 3 - 0.03306235651 * 2^20
61 const B1: u32 = 715094163; // (1023 - 1023 / 3 - 0.03306235651 * 2^20
62 const B2: u32 = 696219795; // (1023 - 1023 / 3 - 54 / 3 - 0.03306235651 * 2^20
6363
6464 // |1 / cbrt(x) - p(x)| < 2^(23.5)
65 const P0: f64 = 1.87595182427177009643;
65 const P0: f64 = 1.87595182427177009643;
6666 const P1: f64 = -1.88497979543377169875;
67 const P2: f64 = 1.621429720105354466140;
67 const P2: f64 = 1.621429720105354466140;
6868 const P3: f64 = -0.758397934778766047437;
69 const P4: f64 = 0.145996192886612446982;
69 const P4: f64 = 0.145996192886612446982;
7070
7171 var u = @bitCast(u64, x);
72 var hx = u32(u >> 32) & 0x7FFFFFFF;
72 var hx = @intCast(u32, u >> 32) & 0x7FFFFFFF;
7373
7474 // cbrt(nan, inf) = itself
7575 if (hx >= 0x7FF00000) {
......@@ -79,7 +79,7 @@ fn cbrt64(x: f64) f64 {
7979 // cbrt to ~5bits
8080 if (hx < 0x00100000) {
8181 u = @bitCast(u64, x * 0x1.0p54);
82 hx = u32(u >> 32) & 0x7FFFFFFF;
82 hx = @intCast(u32, u >> 32) & 0x7FFFFFFF;
8383
8484 // cbrt(0) is itself
8585 if (hx == 0) {
std/math/ceil.zig+4-4
......@@ -20,7 +20,7 @@ pub fn ceil(x: var) @typeOf(x) {
2020
2121fn ceil32(x: f32) f32 {
2222 var u = @bitCast(u32, x);
23 var e = i32((u >> 23) & 0xFF) - 0x7F;
23 var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
2424 var m: u32 = undefined;
2525
2626 // TODO: Shouldn't need this explicit check.
......@@ -31,7 +31,7 @@ fn ceil32(x: f32) f32 {
3131 if (e >= 23) {
3232 return x;
3333 } else if (e >= 0) {
34 m = u32(0x007FFFFF) >> u5(e);
34 m = u32(0x007FFFFF) >> @intCast(u5, e);
3535 if (u & m == 0) {
3636 return x;
3737 }
......@@ -56,7 +56,7 @@ fn ceil64(x: f64) f64 {
5656 const e = (u >> 52) & 0x7FF;
5757 var y: f64 = undefined;
5858
59 if (e >= 0x3FF+52 or x == 0) {
59 if (e >= 0x3FF + 52 or x == 0) {
6060 return x;
6161 }
6262
......@@ -68,7 +68,7 @@ fn ceil64(x: f64) f64 {
6868 y = x + math.f64_toint - math.f64_toint - x;
6969 }
7070
71 if (e <= 0x3FF-1) {
71 if (e <= 0x3FF - 1) {
7272 math.forceEval(y);
7373 if (u >> 63 != 0) {
7474 return -0.0;
std/math/complex/abs.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn abs(z: var) @typeOf(z.re) {
8 const T = @typeOf(z.re);
9 return math.hypot(T, z.re, z.im);
10}
11
12const epsilon = 0.0001;
13
14test "complex.cabs" {
15 const a = Complex(f32).new(5, 3);
16 const c = abs(a);
17 debug.assert(math.approxEq(f32, c, 5.83095, epsilon));
18}
std/math/complex/acos.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn acos(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = cmath.asin(z);
10 return Complex(T).new(T(math.pi) / 2 - q.re, -q.im);
11}
12
13const epsilon = 0.0001;
14
15test "complex.cacos" {
16 const a = Complex(f32).new(5, 3);
17 const c = acos(a);
18
19 debug.assert(math.approxEq(f32, c.re, 0.546975, epsilon));
20 debug.assert(math.approxEq(f32, c.im, -2.452914, epsilon));
21}
std/math/complex/acosh.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn acosh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = cmath.acos(z);
10 return Complex(T).new(-q.im, q.re);
11}
12
13const epsilon = 0.0001;
14
15test "complex.cacosh" {
16 const a = Complex(f32).new(5, 3);
17 const c = acosh(a);
18
19 debug.assert(math.approxEq(f32, c.re, 2.452914, epsilon));
20 debug.assert(math.approxEq(f32, c.im, 0.546975, epsilon));
21}
std/math/complex/arg.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn arg(z: var) @typeOf(z.re) {
8 const T = @typeOf(z.re);
9 return math.atan2(T, z.im, z.re);
10}
11
12const epsilon = 0.0001;
13
14test "complex.carg" {
15 const a = Complex(f32).new(5, 3);
16 const c = arg(a);
17 debug.assert(math.approxEq(f32, c, 0.540420, epsilon));
18}
std/math/complex/asin.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn asin(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const x = z.re;
10 const y = z.im;
11
12 const p = Complex(T).new(1.0 - (x - y) * (x + y), -2.0 * x * y);
13 const q = Complex(T).new(-y, x);
14 const r = cmath.log(q.add(cmath.sqrt(p)));
15
16 return Complex(T).new(r.im, -r.re);
17}
18
19const epsilon = 0.0001;
20
21test "complex.casin" {
22 const a = Complex(f32).new(5, 3);
23 const c = asin(a);
24
25 debug.assert(math.approxEq(f32, c.re, 1.023822, epsilon));
26 debug.assert(math.approxEq(f32, c.im, 2.452914, epsilon));
27}
std/math/complex/asinh.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn asinh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = Complex(T).new(-z.im, z.re);
10 const r = cmath.asin(q);
11 return Complex(T).new(r.im, -r.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.casinh" {
17 const a = Complex(f32).new(5, 3);
18 const c = asinh(a);
19
20 debug.assert(math.approxEq(f32, c.re, 2.459831, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 0.533999, epsilon));
22}
std/math/complex/atan.zig created+130
......@@ -0,0 +1,130 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn atan(z: var) @typeOf(z) {
8 const T = @typeOf(z.re);
9 return switch (T) {
10 f32 => atan32(z),
11 f64 => atan64(z),
12 else => @compileError("atan not implemented for " ++ @typeName(z)),
13 };
14}
15
16fn redupif32(x: f32) f32 {
17 const DP1 = 3.140625;
18 const DP2 = 9.67502593994140625e-4;
19 const DP3 = 1.509957990978376432e-7;
20
21 var t = x / math.pi;
22 if (t >= 0.0) {
23 t += 0.5;
24 } else {
25 t -= 0.5;
26 }
27
28 const u = @intToFloat(f32, @floatToInt(i32, t));
29 return ((x - u * DP1) - u * DP2) - t * DP3;
30}
31
32fn atan32(z: Complex(f32)) Complex(f32) {
33 const maxnum = 1.0e38;
34
35 const x = z.re;
36 const y = z.im;
37
38 if ((x == 0.0) and (y > 1.0)) {
39 // overflow
40 return Complex(f32).new(maxnum, maxnum);
41 }
42
43 const x2 = x * x;
44 var a = 1.0 - x2 - (y * y);
45 if (a == 0.0) {
46 // overflow
47 return Complex(f32).new(maxnum, maxnum);
48 }
49
50 var t = 0.5 * math.atan2(f32, 2.0 * x, a);
51 var w = redupif32(t);
52
53 t = y - 1.0;
54 a = x2 + t * t;
55 if (a == 0.0) {
56 // overflow
57 return Complex(f32).new(maxnum, maxnum);
58 }
59
60 t = y + 1.0;
61 a = (x2 + (t * t)) / a;
62 return Complex(f32).new(w, 0.25 * math.ln(a));
63}
64
65fn redupif64(x: f64) f64 {
66 const DP1 = 3.14159265160560607910;
67 const DP2 = 1.98418714791870343106e-9;
68 const DP3 = 1.14423774522196636802e-17;
69
70 var t = x / math.pi;
71 if (t >= 0.0) {
72 t += 0.5;
73 } else {
74 t -= 0.5;
75 }
76
77 const u = @intToFloat(f64, @floatToInt(i64, t));
78 return ((x - u * DP1) - u * DP2) - t * DP3;
79}
80
81fn atan64(z: Complex(f64)) Complex(f64) {
82 const maxnum = 1.0e308;
83
84 const x = z.re;
85 const y = z.im;
86
87 if ((x == 0.0) and (y > 1.0)) {
88 // overflow
89 return Complex(f64).new(maxnum, maxnum);
90 }
91
92 const x2 = x * x;
93 var a = 1.0 - x2 - (y * y);
94 if (a == 0.0) {
95 // overflow
96 return Complex(f64).new(maxnum, maxnum);
97 }
98
99 var t = 0.5 * math.atan2(f64, 2.0 * x, a);
100 var w = redupif64(t);
101
102 t = y - 1.0;
103 a = x2 + t * t;
104 if (a == 0.0) {
105 // overflow
106 return Complex(f64).new(maxnum, maxnum);
107 }
108
109 t = y + 1.0;
110 a = (x2 + (t * t)) / a;
111 return Complex(f64).new(w, 0.25 * math.ln(a));
112}
113
114const epsilon = 0.0001;
115
116test "complex.catan32" {
117 const a = Complex(f32).new(5, 3);
118 const c = atan(a);
119
120 debug.assert(math.approxEq(f32, c.re, 1.423679, epsilon));
121 debug.assert(math.approxEq(f32, c.im, 0.086569, epsilon));
122}
123
124test "complex.catan64" {
125 const a = Complex(f64).new(5, 3);
126 const c = atan(a);
127
128 debug.assert(math.approxEq(f64, c.re, 1.423679, epsilon));
129 debug.assert(math.approxEq(f64, c.im, 0.086569, epsilon));
130}
std/math/complex/atanh.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn atanh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = Complex(T).new(-z.im, z.re);
10 const r = cmath.atan(q);
11 return Complex(T).new(r.im, -r.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.catanh" {
17 const a = Complex(f32).new(5, 3);
18 const c = atanh(a);
19
20 debug.assert(math.approxEq(f32, c.re, 0.146947, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 1.480870, epsilon));
22}
std/math/complex/conj.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn conj(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 return Complex(T).new(z.re, -z.im);
10}
11
12test "complex.conj" {
13 const a = Complex(f32).new(5, 3);
14 const c = a.conjugate();
15
16 debug.assert(c.re == 5 and c.im == -3);
17}
std/math/complex/cos.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn cos(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const p = Complex(T).new(-z.im, z.re);
10 return cmath.cosh(p);
11}
12
13const epsilon = 0.0001;
14
15test "complex.ccos" {
16 const a = Complex(f32).new(5, 3);
17 const c = cos(a);
18
19 debug.assert(math.approxEq(f32, c.re, 2.855815, epsilon));
20 debug.assert(math.approxEq(f32, c.im, 9.606383, epsilon));
21}
std/math/complex/cosh.zig created+165
......@@ -0,0 +1,165 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7const ldexp_cexp = @import("ldexp.zig").ldexp_cexp;
8
9pub fn cosh(z: var) Complex(@typeOf(z.re)) {
10 const T = @typeOf(z.re);
11 return switch (T) {
12 f32 => cosh32(z),
13 f64 => cosh64(z),
14 else => @compileError("cosh not implemented for " ++ @typeName(z)),
15 };
16}
17
18fn cosh32(z: *const Complex(f32)) Complex(f32) {
19 const x = z.re;
20 const y = z.im;
21
22 const hx = @bitCast(u32, x);
23 const ix = hx & 0x7fffffff;
24
25 const hy = @bitCast(u32, y);
26 const iy = hy & 0x7fffffff;
27
28 if (ix < 0x7f800000 and iy < 0x7f800000) {
29 if (iy == 0) {
30 return Complex(f32).new(math.cosh(x), y);
31 }
32 // small x: normal case
33 if (ix < 0x41100000) {
34 return Complex(f32).new(math.cosh(x) * math.cos(y), math.sinh(x) * math.sin(y));
35 }
36
37 // |x|>= 9, so cosh(x) ~= exp(|x|)
38 if (ix < 0x42b17218) {
39 // x < 88.7: exp(|x|) won't overflow
40 const h = math.exp(math.fabs(x)) * 0.5;
41 return Complex(f32).new(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y));
42 }
43 // x < 192.7: scale to avoid overflow
44 else if (ix < 0x4340b1e7) {
45 const v = Complex(f32).new(math.fabs(x), y);
46 const r = ldexp_cexp(v, -1);
47 return Complex(f32).new(x, y * math.copysign(f32, 1, x));
48 }
49 // x >= 192.7: result always overflows
50 else {
51 const h = 0x1p127 * x;
52 return Complex(f32).new(h * h * math.cos(y), h * math.sin(y));
53 }
54 }
55
56 if (ix == 0 and iy >= 0x7f800000) {
57 return Complex(f32).new(y - y, math.copysign(f32, 0, x * (y - y)));
58 }
59
60 if (iy == 0 and ix >= 0x7f800000) {
61 if (hx & 0x7fffff == 0) {
62 return Complex(f32).new(x * x, math.copysign(f32, 0, x) * y);
63 }
64 return Complex(f32).new(x, math.copysign(f32, 0, (x + x) * y));
65 }
66
67 if (ix < 0x7f800000 and iy >= 0x7f800000) {
68 return Complex(f32).new(y - y, x * (y - y));
69 }
70
71 if (ix >= 0x7f800000 and (hx & 0x7fffff) == 0) {
72 if (iy >= 0x7f800000) {
73 return Complex(f32).new(x * x, x * (y - y));
74 }
75 return Complex(f32).new((x * x) * math.cos(y), x * math.sin(y));
76 }
77
78 return Complex(f32).new((x * x) * (y - y), (x + x) * (y - y));
79}
80
81fn cosh64(z: *const Complex(f64)) Complex(f64) {
82 const x = z.re;
83 const y = z.im;
84
85 const fx = @bitCast(u64, x);
86 const hx = @intCast(u32, fx >> 32);
87 const lx = @truncate(u32, fx);
88 const ix = hx & 0x7fffffff;
89
90 const fy = @bitCast(u64, y);
91 const hy = @intCast(u32, fy >> 32);
92 const ly = @truncate(u32, fy);
93 const iy = hy & 0x7fffffff;
94
95 // nearly non-exceptional case where x, y are finite
96 if (ix < 0x7ff00000 and iy < 0x7ff00000) {
97 if (iy | ly == 0) {
98 return Complex(f64).new(math.cosh(x), x * y);
99 }
100 // small x: normal case
101 if (ix < 0x40360000) {
102 return Complex(f64).new(math.cosh(x) * math.cos(y), math.sinh(x) * math.sin(y));
103 }
104
105 // |x|>= 22, so cosh(x) ~= exp(|x|)
106 if (ix < 0x40862e42) {
107 // x < 710: exp(|x|) won't overflow
108 const h = math.exp(math.fabs(x)) * 0.5;
109 return Complex(f64).new(h * math.cos(y), math.copysign(f64, h, x) * math.sin(y));
110 }
111 // x < 1455: scale to avoid overflow
112 else if (ix < 0x4096bbaa) {
113 const v = Complex(f64).new(math.fabs(x), y);
114 const r = ldexp_cexp(v, -1);
115 return Complex(f64).new(x, y * math.copysign(f64, 1, x));
116 }
117 // x >= 1455: result always overflows
118 else {
119 const h = 0x1p1023;
120 return Complex(f64).new(h * h * math.cos(y), h * math.sin(y));
121 }
122 }
123
124 if (ix | lx == 0 and iy >= 0x7ff00000) {
125 return Complex(f64).new(y - y, math.copysign(f64, 0, x * (y - y)));
126 }
127
128 if (iy | ly == 0 and ix >= 0x7ff00000) {
129 if ((hx & 0xfffff) | lx == 0) {
130 return Complex(f64).new(x * x, math.copysign(f64, 0, x) * y);
131 }
132 return Complex(f64).new(x * x, math.copysign(f64, 0, (x + x) * y));
133 }
134
135 if (ix < 0x7ff00000 and iy >= 0x7ff00000) {
136 return Complex(f64).new(y - y, x * (y - y));
137 }
138
139 if (ix >= 0x7ff00000 and (hx & 0xfffff) | lx == 0) {
140 if (iy >= 0x7ff00000) {
141 return Complex(f64).new(x * x, x * (y - y));
142 }
143 return Complex(f64).new(x * x * math.cos(y), x * math.sin(y));
144 }
145
146 return Complex(f64).new((x * x) * (y - y), (x + x) * (y - y));
147}
148
149const epsilon = 0.0001;
150
151test "complex.ccosh32" {
152 const a = Complex(f32).new(5, 3);
153 const c = cosh(a);
154
155 debug.assert(math.approxEq(f32, c.re, -73.467300, epsilon));
156 debug.assert(math.approxEq(f32, c.im, 10.471557, epsilon));
157}
158
159test "complex.ccosh64" {
160 const a = Complex(f64).new(5, 3);
161 const c = cosh(a);
162
163 debug.assert(math.approxEq(f64, c.re, -73.467300, epsilon));
164 debug.assert(math.approxEq(f64, c.im, 10.471557, epsilon));
165}
std/math/complex/exp.zig created+134
......@@ -0,0 +1,134 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7const ldexp_cexp = @import("ldexp.zig").ldexp_cexp;
8
9pub fn exp(z: var) @typeOf(z) {
10 const T = @typeOf(z.re);
11
12 return switch (T) {
13 f32 => exp32(z),
14 f64 => exp64(z),
15 else => @compileError("exp not implemented for " ++ @typeName(z)),
16 };
17}
18
19fn exp32(z: Complex(f32)) Complex(f32) {
20 @setFloatMode(this, @import("builtin").FloatMode.Strict);
21
22 const exp_overflow = 0x42b17218; // max_exp * ln2 ~= 88.72283955
23 const cexp_overflow = 0x43400074; // (max_exp - min_denom_exp) * ln2
24
25 const x = z.re;
26 const y = z.im;
27
28 const hy = @bitCast(u32, y) & 0x7fffffff;
29 // cexp(x + i0) = exp(x) + i0
30 if (hy == 0) {
31 return Complex(f32).new(math.exp(x), y);
32 }
33
34 const hx = @bitCast(u32, x);
35 // cexp(0 + iy) = cos(y) + isin(y)
36 if ((hx & 0x7fffffff) == 0) {
37 return Complex(f32).new(math.cos(y), math.sin(y));
38 }
39
40 if (hy >= 0x7f800000) {
41 // cexp(finite|nan +- i inf|nan) = nan + i nan
42 if ((hx & 0x7fffffff) != 0x7f800000) {
43 return Complex(f32).new(y - y, y - y);
44 } // cexp(-inf +- i inf|nan) = 0 + i0
45 else if (hx & 0x80000000 != 0) {
46 return Complex(f32).new(0, 0);
47 } // cexp(+inf +- i inf|nan) = inf + i nan
48 else {
49 return Complex(f32).new(x, y - y);
50 }
51 }
52
53 // 88.7 <= x <= 192 so must scale
54 if (hx >= exp_overflow and hx <= cexp_overflow) {
55 return ldexp_cexp(z, 0);
56 } // - x < exp_overflow => exp(x) won't overflow (common)
57 // - x > cexp_overflow, so exp(x) * s overflows for s > 0
58 // - x = +-inf
59 // - x = nan
60 else {
61 const exp_x = math.exp(x);
62 return Complex(f32).new(exp_x * math.cos(y), exp_x * math.sin(y));
63 }
64}
65
66fn exp64(z: Complex(f64)) Complex(f64) {
67 const exp_overflow = 0x40862e42; // high bits of max_exp * ln2 ~= 710
68 const cexp_overflow = 0x4096b8e4; // (max_exp - min_denorm_exp) * ln2
69
70 const x = z.re;
71 const y = z.im;
72
73 const fy = @bitCast(u64, y);
74 const hy = u32(fy >> 32) & 0x7fffffff;
75 const ly = @truncate(u32, fy);
76
77 // cexp(x + i0) = exp(x) + i0
78 if (hy | ly == 0) {
79 return Complex(f64).new(math.exp(x), y);
80 }
81
82 const fx = @bitCast(u64, x);
83 const hx = u32(fx >> 32);
84 const lx = @truncate(u32, fx);
85
86 // cexp(0 + iy) = cos(y) + isin(y)
87 if ((hx & 0x7fffffff) | lx == 0) {
88 return Complex(f64).new(math.cos(y), math.sin(y));
89 }
90
91 if (hy >= 0x7ff00000) {
92 // cexp(finite|nan +- i inf|nan) = nan + i nan
93 if (lx != 0 or (hx & 0x7fffffff) != 0x7ff00000) {
94 return Complex(f64).new(y - y, y - y);
95 } // cexp(-inf +- i inf|nan) = 0 + i0
96 else if (hx & 0x80000000 != 0) {
97 return Complex(f64).new(0, 0);
98 } // cexp(+inf +- i inf|nan) = inf + i nan
99 else {
100 return Complex(f64).new(x, y - y);
101 }
102 }
103
104 // 709.7 <= x <= 1454.3 so must scale
105 if (hx >= exp_overflow and hx <= cexp_overflow) {
106 const r = ldexp_cexp(z, 0);
107 return r.*;
108 } // - x < exp_overflow => exp(x) won't overflow (common)
109 // - x > cexp_overflow, so exp(x) * s overflows for s > 0
110 // - x = +-inf
111 // - x = nan
112 else {
113 const exp_x = math.exp(x);
114 return Complex(f64).new(exp_x * math.cos(y), exp_x * math.sin(y));
115 }
116}
117
118const epsilon = 0.0001;
119
120test "complex.cexp32" {
121 const a = Complex(f32).new(5, 3);
122 const c = exp(a);
123
124 debug.assert(math.approxEq(f32, c.re, -146.927917, epsilon));
125 debug.assert(math.approxEq(f32, c.im, 20.944065, epsilon));
126}
127
128test "complex.cexp64" {
129 const a = Complex(f32).new(5, 3);
130 const c = exp(a);
131
132 debug.assert(math.approxEq(f64, c.re, -146.927917, epsilon));
133 debug.assert(math.approxEq(f64, c.im, 20.944065, epsilon));
134}
std/math/complex/index.zig created+171
......@@ -0,0 +1,171 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4
5pub const abs = @import("abs.zig").abs;
6pub const acosh = @import("acosh.zig").acosh;
7pub const acos = @import("acos.zig").acos;
8pub const arg = @import("arg.zig").arg;
9pub const asinh = @import("asinh.zig").asinh;
10pub const asin = @import("asin.zig").asin;
11pub const atanh = @import("atanh.zig").atanh;
12pub const atan = @import("atan.zig").atan;
13pub const conj = @import("conj.zig").conj;
14pub const cosh = @import("cosh.zig").cosh;
15pub const cos = @import("cos.zig").cos;
16pub const exp = @import("exp.zig").exp;
17pub const log = @import("log.zig").log;
18pub const pow = @import("pow.zig").pow;
19pub const proj = @import("proj.zig").proj;
20pub const sinh = @import("sinh.zig").sinh;
21pub const sin = @import("sin.zig").sin;
22pub const sqrt = @import("sqrt.zig").sqrt;
23pub const tanh = @import("tanh.zig").tanh;
24pub const tan = @import("tan.zig").tan;
25
26pub fn Complex(comptime T: type) type {
27 return struct {
28 const Self = this;
29
30 re: T,
31 im: T,
32
33 pub fn new(re: T, im: T) Self {
34 return Self{
35 .re = re,
36 .im = im,
37 };
38 }
39
40 pub fn add(self: Self, other: Self) Self {
41 return Self{
42 .re = self.re + other.re,
43 .im = self.im + other.im,
44 };
45 }
46
47 pub fn sub(self: Self, other: Self) Self {
48 return Self{
49 .re = self.re - other.re,
50 .im = self.im - other.im,
51 };
52 }
53
54 pub fn mul(self: Self, other: Self) Self {
55 return Self{
56 .re = self.re * other.re - self.im * other.im,
57 .im = self.im * other.re + self.re * other.im,
58 };
59 }
60
61 pub fn div(self: Self, other: Self) Self {
62 const re_num = self.re * other.re + self.im * other.im;
63 const im_num = self.im * other.re - self.re * other.im;
64 const den = other.re * other.re + other.im * other.im;
65
66 return Self{
67 .re = re_num / den,
68 .im = im_num / den,
69 };
70 }
71
72 pub fn conjugate(self: Self) Self {
73 return Self{
74 .re = self.re,
75 .im = -self.im,
76 };
77 }
78
79 pub fn reciprocal(self: Self) Self {
80 const m = self.re * self.re + self.im * self.im;
81 return Self{
82 .re = self.re / m,
83 .im = -self.im / m,
84 };
85 }
86
87 pub fn magnitude(self: Self) T {
88 return math.sqrt(self.re * self.re + self.im * self.im);
89 }
90 };
91}
92
93const epsilon = 0.0001;
94
95test "complex.add" {
96 const a = Complex(f32).new(5, 3);
97 const b = Complex(f32).new(2, 7);
98 const c = a.add(b);
99
100 debug.assert(c.re == 7 and c.im == 10);
101}
102
103test "complex.sub" {
104 const a = Complex(f32).new(5, 3);
105 const b = Complex(f32).new(2, 7);
106 const c = a.sub(b);
107
108 debug.assert(c.re == 3 and c.im == -4);
109}
110
111test "complex.mul" {
112 const a = Complex(f32).new(5, 3);
113 const b = Complex(f32).new(2, 7);
114 const c = a.mul(b);
115
116 debug.assert(c.re == -11 and c.im == 41);
117}
118
119test "complex.div" {
120 const a = Complex(f32).new(5, 3);
121 const b = Complex(f32).new(2, 7);
122 const c = a.div(b);
123
124 debug.assert(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and
125 math.approxEq(f32, c.im, f32(-29) / 53, epsilon));
126}
127
128test "complex.conjugate" {
129 const a = Complex(f32).new(5, 3);
130 const c = a.conjugate();
131
132 debug.assert(c.re == 5 and c.im == -3);
133}
134
135test "complex.reciprocal" {
136 const a = Complex(f32).new(5, 3);
137 const c = a.reciprocal();
138
139 debug.assert(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and
140 math.approxEq(f32, c.im, f32(-3) / 34, epsilon));
141}
142
143test "complex.magnitude" {
144 const a = Complex(f32).new(5, 3);
145 const c = a.magnitude();
146
147 debug.assert(math.approxEq(f32, c, 5.83095, epsilon));
148}
149
150test "complex.cmath" {
151 _ = @import("abs.zig");
152 _ = @import("acosh.zig");
153 _ = @import("acos.zig");
154 _ = @import("arg.zig");
155 _ = @import("asinh.zig");
156 _ = @import("asin.zig");
157 _ = @import("atanh.zig");
158 _ = @import("atan.zig");
159 _ = @import("conj.zig");
160 _ = @import("cosh.zig");
161 _ = @import("cos.zig");
162 _ = @import("exp.zig");
163 _ = @import("log.zig");
164 _ = @import("pow.zig");
165 _ = @import("proj.zig");
166 _ = @import("sinh.zig");
167 _ = @import("sin.zig");
168 _ = @import("sqrt.zig");
169 _ = @import("tanh.zig");
170 _ = @import("tan.zig");
171}
std/math/complex/ldexp.zig created+73
......@@ -0,0 +1,73 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn ldexp_cexp(z: var, expt: i32) @typeOf(z) {
8 const T = @typeOf(z.re);
9
10 return switch (T) {
11 f32 => ldexp_cexp32(z, expt),
12 f64 => ldexp_cexp64(z, expt),
13 else => unreachable,
14 };
15}
16
17fn frexp_exp32(x: f32, expt: *i32) f32 {
18 const k = 235; // reduction constant
19 const kln2 = 162.88958740; // k * ln2
20
21 const exp_x = math.exp(x - kln2);
22 const hx = @bitCast(u32, exp_x);
23 // TODO zig should allow this cast implicitly because it should know the value is in range
24 expt.* = @intCast(i32, hx >> 23) - (0x7f + 127) + k;
25 return @bitCast(f32, (hx & 0x7fffff) | ((0x7f + 127) << 23));
26}
27
28fn ldexp_cexp32(z: Complex(f32), expt: i32) Complex(f32) {
29 var ex_expt: i32 = undefined;
30 const exp_x = frexp_exp32(z.re, &ex_expt);
31 const exptf = expt + ex_expt;
32
33 const half_expt1 = @divTrunc(exptf, 2);
34 const scale1 = @bitCast(f32, (0x7f + half_expt1) << 23);
35
36 const half_expt2 = exptf - half_expt1;
37 const scale2 = @bitCast(f32, (0x7f + half_expt2) << 23);
38
39 return Complex(f32).new(math.cos(z.im) * exp_x * scale1 * scale2, math.sin(z.im) * exp_x * scale1 * scale2);
40}
41
42fn frexp_exp64(x: f64, expt: *i32) f64 {
43 const k = 1799; // reduction constant
44 const kln2 = 1246.97177782734161156; // k * ln2
45
46 const exp_x = math.exp(x - kln2);
47
48 const fx = @bitCast(u64, x);
49 const hx = @intCast(u32, fx >> 32);
50 const lx = @truncate(u32, fx);
51
52 expt.* = @intCast(i32, hx >> 20) - (0x3ff + 1023) + k;
53
54 const high_word = (hx & 0xfffff) | ((0x3ff + 1023) << 20);
55 return @bitCast(f64, (u64(high_word) << 32) | lx);
56}
57
58fn ldexp_cexp64(z: Complex(f64), expt: i32) Complex(f64) {
59 var ex_expt: i32 = undefined;
60 const exp_x = frexp_exp64(z.re, &ex_expt);
61 const exptf = i64(expt + ex_expt);
62
63 const half_expt1 = @divTrunc(exptf, 2);
64 const scale1 = @bitCast(f64, (0x3ff + half_expt1) << 20);
65
66 const half_expt2 = exptf - half_expt1;
67 const scale2 = @bitCast(f64, (0x3ff + half_expt2) << 20);
68
69 return Complex(f64).new(
70 math.cos(z.im) * exp_x * scale1 * scale2,
71 math.sin(z.im) * exp_x * scale1 * scale2,
72 );
73}
std/math/complex/log.zig created+23
......@@ -0,0 +1,23 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn log(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const r = cmath.abs(z);
10 const phi = cmath.arg(z);
11
12 return Complex(T).new(math.ln(r), phi);
13}
14
15const epsilon = 0.0001;
16
17test "complex.clog" {
18 const a = Complex(f32).new(5, 3);
19 const c = log(a);
20
21 debug.assert(math.approxEq(f32, c.re, 1.763180, epsilon));
22 debug.assert(math.approxEq(f32, c.im, 0.540419, epsilon));
23}
std/math/complex/pow.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn pow(comptime T: type, z: *const T, c: *const T) T {
8 const p = cmath.log(z);
9 const q = c.mul(p);
10 return cmath.exp(q);
11}
12
13const epsilon = 0.0001;
14
15test "complex.cpow" {
16 const a = Complex(f32).new(5, 3);
17 const b = Complex(f32).new(2.3, -1.3);
18 const c = pow(Complex(f32), a, b);
19
20 debug.assert(math.approxEq(f32, c.re, 58.049110, epsilon));
21 debug.assert(math.approxEq(f32, c.im, -101.003433, epsilon));
22}
std/math/complex/proj.zig created+24
......@@ -0,0 +1,24 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn proj(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9
10 if (math.isInf(z.re) or math.isInf(z.im)) {
11 return Complex(T).new(math.inf(T), math.copysign(T, 0, z.re));
12 }
13
14 return Complex(T).new(z.re, z.im);
15}
16
17const epsilon = 0.0001;
18
19test "complex.cproj" {
20 const a = Complex(f32).new(5, 3);
21 const c = proj(a);
22
23 debug.assert(c.re == 5 and c.im == 3);
24}
std/math/complex/sin.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn sin(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const p = Complex(T).new(-z.im, z.re);
10 const q = cmath.sinh(p);
11 return Complex(T).new(q.im, -q.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.csin" {
17 const a = Complex(f32).new(5, 3);
18 const c = sin(a);
19
20 debug.assert(math.approxEq(f32, c.re, -9.654126, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 2.841692, epsilon));
22}
std/math/complex/sinh.zig created+164
......@@ -0,0 +1,164 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7const ldexp_cexp = @import("ldexp.zig").ldexp_cexp;
8
9pub fn sinh(z: var) @typeOf(z) {
10 const T = @typeOf(z.re);
11 return switch (T) {
12 f32 => sinh32(z),
13 f64 => sinh64(z),
14 else => @compileError("tan not implemented for " ++ @typeName(z)),
15 };
16}
17
18fn sinh32(z: Complex(f32)) Complex(f32) {
19 const x = z.re;
20 const y = z.im;
21
22 const hx = @bitCast(u32, x);
23 const ix = hx & 0x7fffffff;
24
25 const hy = @bitCast(u32, y);
26 const iy = hy & 0x7fffffff;
27
28 if (ix < 0x7f800000 and iy < 0x7f800000) {
29 if (iy == 0) {
30 return Complex(f32).new(math.sinh(x), y);
31 }
32 // small x: normal case
33 if (ix < 0x41100000) {
34 return Complex(f32).new(math.sinh(x) * math.cos(y), math.cosh(x) * math.sin(y));
35 }
36
37 // |x|>= 9, so cosh(x) ~= exp(|x|)
38 if (ix < 0x42b17218) {
39 // x < 88.7: exp(|x|) won't overflow
40 const h = math.exp(math.fabs(x)) * 0.5;
41 return Complex(f32).new(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y));
42 }
43 // x < 192.7: scale to avoid overflow
44 else if (ix < 0x4340b1e7) {
45 const v = Complex(f32).new(math.fabs(x), y);
46 const r = ldexp_cexp(v, -1);
47 return Complex(f32).new(x * math.copysign(f32, 1, x), y);
48 }
49 // x >= 192.7: result always overflows
50 else {
51 const h = 0x1p127 * x;
52 return Complex(f32).new(h * math.cos(y), h * h * math.sin(y));
53 }
54 }
55
56 if (ix == 0 and iy >= 0x7f800000) {
57 return Complex(f32).new(math.copysign(f32, 0, x * (y - y)), y - y);
58 }
59
60 if (iy == 0 and ix >= 0x7f800000) {
61 if (hx & 0x7fffff == 0) {
62 return Complex(f32).new(x, y);
63 }
64 return Complex(f32).new(x, math.copysign(f32, 0, y));
65 }
66
67 if (ix < 0x7f800000 and iy >= 0x7f800000) {
68 return Complex(f32).new(y - y, x * (y - y));
69 }
70
71 if (ix >= 0x7f800000 and (hx & 0x7fffff) == 0) {
72 if (iy >= 0x7f800000) {
73 return Complex(f32).new(x * x, x * (y - y));
74 }
75 return Complex(f32).new(x * math.cos(y), math.inf_f32 * math.sin(y));
76 }
77
78 return Complex(f32).new((x * x) * (y - y), (x + x) * (y - y));
79}
80
81fn sinh64(z: Complex(f64)) Complex(f64) {
82 const x = z.re;
83 const y = z.im;
84
85 const fx = @bitCast(u64, x);
86 const hx = @intCast(u32, fx >> 32);
87 const lx = @truncate(u32, fx);
88 const ix = hx & 0x7fffffff;
89
90 const fy = @bitCast(u64, y);
91 const hy = @intCast(u32, fy >> 32);
92 const ly = @truncate(u32, fy);
93 const iy = hy & 0x7fffffff;
94
95 if (ix < 0x7ff00000 and iy < 0x7ff00000) {
96 if (iy | ly == 0) {
97 return Complex(f64).new(math.sinh(x), y);
98 }
99 // small x: normal case
100 if (ix < 0x40360000) {
101 return Complex(f64).new(math.sinh(x) * math.cos(y), math.cosh(x) * math.sin(y));
102 }
103
104 // |x|>= 22, so cosh(x) ~= exp(|x|)
105 if (ix < 0x40862e42) {
106 // x < 710: exp(|x|) won't overflow
107 const h = math.exp(math.fabs(x)) * 0.5;
108 return Complex(f64).new(math.copysign(f64, h, x) * math.cos(y), h * math.sin(y));
109 }
110 // x < 1455: scale to avoid overflow
111 else if (ix < 0x4096bbaa) {
112 const v = Complex(f64).new(math.fabs(x), y);
113 const r = ldexp_cexp(v, -1);
114 return Complex(f64).new(x * math.copysign(f64, 1, x), y);
115 }
116 // x >= 1455: result always overflows
117 else {
118 const h = 0x1p1023 * x;
119 return Complex(f64).new(h * math.cos(y), h * h * math.sin(y));
120 }
121 }
122
123 if (ix | lx == 0 and iy >= 0x7ff00000) {
124 return Complex(f64).new(math.copysign(f64, 0, x * (y - y)), y - y);
125 }
126
127 if (iy | ly == 0 and ix >= 0x7ff00000) {
128 if ((hx & 0xfffff) | lx == 0) {
129 return Complex(f64).new(x, y);
130 }
131 return Complex(f64).new(x, math.copysign(f64, 0, y));
132 }
133
134 if (ix < 0x7ff00000 and iy >= 0x7ff00000) {
135 return Complex(f64).new(y - y, x * (y - y));
136 }
137
138 if (ix >= 0x7ff00000 and (hx & 0xfffff) | lx == 0) {
139 if (iy >= 0x7ff00000) {
140 return Complex(f64).new(x * x, x * (y - y));
141 }
142 return Complex(f64).new(x * math.cos(y), math.inf_f64 * math.sin(y));
143 }
144
145 return Complex(f64).new((x * x) * (y - y), (x + x) * (y - y));
146}
147
148const epsilon = 0.0001;
149
150test "complex.csinh32" {
151 const a = Complex(f32).new(5, 3);
152 const c = sinh(a);
153
154 debug.assert(math.approxEq(f32, c.re, -73.460617, epsilon));
155 debug.assert(math.approxEq(f32, c.im, 10.472508, epsilon));
156}
157
158test "complex.csinh64" {
159 const a = Complex(f64).new(5, 3);
160 const c = sinh(a);
161
162 debug.assert(math.approxEq(f64, c.re, -73.460617, epsilon));
163 debug.assert(math.approxEq(f64, c.im, 10.472508, epsilon));
164}
std/math/complex/sqrt.zig created+138
......@@ -0,0 +1,138 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn sqrt(z: var) @typeOf(z) {
8 const T = @typeOf(z.re);
9
10 return switch (T) {
11 f32 => sqrt32(z),
12 f64 => sqrt64(z),
13 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
14 };
15}
16
17fn sqrt32(z: Complex(f32)) Complex(f32) {
18 const x = z.re;
19 const y = z.im;
20
21 if (x == 0 and y == 0) {
22 return Complex(f32).new(0, y);
23 }
24 if (math.isInf(y)) {
25 return Complex(f32).new(math.inf(f32), y);
26 }
27 if (math.isNan(x)) {
28 // raise invalid if y is not nan
29 const t = (y - y) / (y - y);
30 return Complex(f32).new(x, t);
31 }
32 if (math.isInf(x)) {
33 // sqrt(inf + i nan) = inf + nan i
34 // sqrt(inf + iy) = inf + i0
35 // sqrt(-inf + i nan) = nan +- inf i
36 // sqrt(-inf + iy) = 0 + inf i
37 if (math.signbit(x)) {
38 return Complex(f32).new(math.fabs(x - y), math.copysign(f32, x, y));
39 } else {
40 return Complex(f32).new(x, math.copysign(f32, y - y, y));
41 }
42 }
43
44 // y = nan special case is handled fine below
45
46 // double-precision avoids overflow with correct rounding.
47 const dx = f64(x);
48 const dy = f64(y);
49
50 if (dx >= 0) {
51 const t = math.sqrt((dx + math.hypot(f64, dx, dy)) * 0.5);
52 return Complex(f32).new(
53 @floatCast(f32, t),
54 @floatCast(f32, dy / (2.0 * t)),
55 );
56 } else {
57 const t = math.sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);
58 return Complex(f32).new(
59 @floatCast(f32, math.fabs(y) / (2.0 * t)),
60 @floatCast(f32, math.copysign(f64, t, y)),
61 );
62 }
63}
64
65fn sqrt64(z: Complex(f64)) Complex(f64) {
66 // may encounter overflow for im,re >= DBL_MAX / (1 + sqrt(2))
67 const threshold = 0x1.a827999fcef32p+1022;
68
69 var x = z.re;
70 var y = z.im;
71
72 if (x == 0 and y == 0) {
73 return Complex(f64).new(0, y);
74 }
75 if (math.isInf(y)) {
76 return Complex(f64).new(math.inf(f64), y);
77 }
78 if (math.isNan(x)) {
79 // raise invalid if y is not nan
80 const t = (y - y) / (y - y);
81 return Complex(f64).new(x, t);
82 }
83 if (math.isInf(x)) {
84 // sqrt(inf + i nan) = inf + nan i
85 // sqrt(inf + iy) = inf + i0
86 // sqrt(-inf + i nan) = nan +- inf i
87 // sqrt(-inf + iy) = 0 + inf i
88 if (math.signbit(x)) {
89 return Complex(f64).new(math.fabs(x - y), math.copysign(f64, x, y));
90 } else {
91 return Complex(f64).new(x, math.copysign(f64, y - y, y));
92 }
93 }
94
95 // y = nan special case is handled fine below
96
97 // scale to avoid overflow
98 var scale = false;
99 if (math.fabs(x) >= threshold or math.fabs(y) >= threshold) {
100 x *= 0.25;
101 y *= 0.25;
102 scale = true;
103 }
104
105 var result: Complex(f64) = undefined;
106 if (x >= 0) {
107 const t = math.sqrt((x + math.hypot(f64, x, y)) * 0.5);
108 result = Complex(f64).new(t, y / (2.0 * t));
109 } else {
110 const t = math.sqrt((-x + math.hypot(f64, x, y)) * 0.5);
111 result = Complex(f64).new(math.fabs(y) / (2.0 * t), math.copysign(f64, t, y));
112 }
113
114 if (scale) {
115 result.re *= 2;
116 result.im *= 2;
117 }
118
119 return result;
120}
121
122const epsilon = 0.0001;
123
124test "complex.csqrt32" {
125 const a = Complex(f32).new(5, 3);
126 const c = sqrt(a);
127
128 debug.assert(math.approxEq(f32, c.re, 2.327117, epsilon));
129 debug.assert(math.approxEq(f32, c.im, 0.644574, epsilon));
130}
131
132test "complex.csqrt64" {
133 const a = Complex(f64).new(5, 3);
134 const c = sqrt(a);
135
136 debug.assert(math.approxEq(f64, c.re, 2.3271175190399496, epsilon));
137 debug.assert(math.approxEq(f64, c.im, 0.6445742373246469, epsilon));
138}
std/math/complex/tan.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn tan(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = Complex(T).new(-z.im, z.re);
10 const r = cmath.tanh(q);
11 return Complex(T).new(r.im, -r.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.ctan" {
17 const a = Complex(f32).new(5, 3);
18 const c = tan(a);
19
20 debug.assert(math.approxEq(f32, c.re, -0.002708233, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 1.004165, epsilon));
22}
std/math/complex/tanh.zig created+113
......@@ -0,0 +1,113 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn tanh(z: var) @typeOf(z) {
8 const T = @typeOf(z.re);
9 return switch (T) {
10 f32 => tanh32(z),
11 f64 => tanh64(z),
12 else => @compileError("tan not implemented for " ++ @typeName(z)),
13 };
14}
15
16fn tanh32(z: Complex(f32)) Complex(f32) {
17 const x = z.re;
18 const y = z.im;
19
20 const hx = @bitCast(u32, x);
21 const ix = hx & 0x7fffffff;
22
23 if (ix >= 0x7f800000) {
24 if (ix & 0x7fffff != 0) {
25 const r = if (y == 0) y else x * y;
26 return Complex(f32).new(x, r);
27 }
28 const xx = @bitCast(f32, hx - 0x40000000);
29 const r = if (math.isInf(y)) y else math.sin(y) * math.cos(y);
30 return Complex(f32).new(xx, math.copysign(f32, 0, r));
31 }
32
33 if (!math.isFinite(y)) {
34 const r = if (ix != 0) y - y else x;
35 return Complex(f32).new(r, y - y);
36 }
37
38 // x >= 11
39 if (ix >= 0x41300000) {
40 const exp_mx = math.exp(-math.fabs(x));
41 return Complex(f32).new(math.copysign(f32, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx);
42 }
43
44 // Kahan's algorithm
45 const t = math.tan(y);
46 const beta = 1.0 + t * t;
47 const s = math.sinh(x);
48 const rho = math.sqrt(1 + s * s);
49 const den = 1 + beta * s * s;
50
51 return Complex(f32).new((beta * rho * s) / den, t / den);
52}
53
54fn tanh64(z: Complex(f64)) Complex(f64) {
55 const x = z.re;
56 const y = z.im;
57
58 const fx = @bitCast(u64, x);
59 // TODO: zig should allow this conversion implicitly because it can notice that the value necessarily
60 // fits in range.
61 const hx = @intCast(u32, fx >> 32);
62 const lx = @truncate(u32, fx);
63 const ix = hx & 0x7fffffff;
64
65 if (ix >= 0x7ff00000) {
66 if ((ix & 0x7fffff) | lx != 0) {
67 const r = if (y == 0) y else x * y;
68 return Complex(f64).new(x, r);
69 }
70
71 const xx = @bitCast(f64, (u64(hx - 0x40000000) << 32) | lx);
72 const r = if (math.isInf(y)) y else math.sin(y) * math.cos(y);
73 return Complex(f64).new(xx, math.copysign(f64, 0, r));
74 }
75
76 if (!math.isFinite(y)) {
77 const r = if (ix != 0) y - y else x;
78 return Complex(f64).new(r, y - y);
79 }
80
81 // x >= 22
82 if (ix >= 0x40360000) {
83 const exp_mx = math.exp(-math.fabs(x));
84 return Complex(f64).new(math.copysign(f64, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx);
85 }
86
87 // Kahan's algorithm
88 const t = math.tan(y);
89 const beta = 1.0 + t * t;
90 const s = math.sinh(x);
91 const rho = math.sqrt(1 + s * s);
92 const den = 1 + beta * s * s;
93
94 return Complex(f64).new((beta * rho * s) / den, t / den);
95}
96
97const epsilon = 0.0001;
98
99test "complex.ctanh32" {
100 const a = Complex(f32).new(5, 3);
101 const c = tanh(a);
102
103 debug.assert(math.approxEq(f32, c.re, 0.999913, epsilon));
104 debug.assert(math.approxEq(f32, c.im, -0.000025, epsilon));
105}
106
107test "complex.ctanh64" {
108 const a = Complex(f64).new(5, 3);
109 const c = tanh(a);
110
111 debug.assert(math.approxEq(f64, c.re, 0.999913, epsilon));
112 debug.assert(math.approxEq(f64, c.im, -0.000025, epsilon));
113}
std/math/copysign.zig+18
......@@ -4,12 +4,22 @@ const assert = std.debug.assert;
44
55pub fn copysign(comptime T: type, x: T, y: T) T {
66 return switch (T) {
7 f16 => copysign16(x, y),
78 f32 => copysign32(x, y),
89 f64 => copysign64(x, y),
910 else => @compileError("copysign not implemented for " ++ @typeName(T)),
1011 };
1112}
1213
14fn copysign16(x: f16, y: f16) f16 {
15 const ux = @bitCast(u16, x);
16 const uy = @bitCast(u16, y);
17
18 const h1 = ux & (@maxValue(u16) / 2);
19 const h2 = uy & (u16(1) << 15);
20 return @bitCast(f16, h1 | h2);
21}
22
1323fn copysign32(x: f32, y: f32) f32 {
1424 const ux = @bitCast(u32, x);
1525 const uy = @bitCast(u32, y);
......@@ -29,10 +39,18 @@ fn copysign64(x: f64, y: f64) f64 {
2939}
3040
3141test "math.copysign" {
42 assert(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0));
3243 assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
3344 assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
3445}
3546
47test "math.copysign16" {
48 assert(copysign16(5.0, 1.0) == 5.0);
49 assert(copysign16(5.0, -1.0) == -5.0);
50 assert(copysign16(-5.0, -1.0) == -5.0);
51 assert(copysign16(-5.0, 1.0) == 5.0);
52}
53
3654test "math.copysign32" {
3755 assert(copysign32(5.0, 1.0) == 5.0);
3856 assert(copysign32(5.0, -1.0) == -5.0);
std/math/cos.zig+8-8
......@@ -18,20 +18,20 @@ pub fn cos(x: var) @typeOf(x) {
1818}
1919
2020// sin polynomial coefficients
21const S0 = 1.58962301576546568060E-10;
21const S0 = 1.58962301576546568060E-10;
2222const S1 = -2.50507477628578072866E-8;
23const S2 = 2.75573136213857245213E-6;
23const S2 = 2.75573136213857245213E-6;
2424const S3 = -1.98412698295895385996E-4;
25const S4 = 8.33333333332211858878E-3;
25const S4 = 8.33333333332211858878E-3;
2626const S5 = -1.66666666666666307295E-1;
2727
2828// cos polynomial coeffiecients
2929const C0 = -1.13585365213876817300E-11;
30const C1 = 2.08757008419747316778E-9;
30const C1 = 2.08757008419747316778E-9;
3131const C2 = -2.75573141792967388112E-7;
32const C3 = 2.48015872888517045348E-5;
32const C3 = 2.48015872888517045348E-5;
3333const C4 = -1.38888888888730564116E-3;
34const C5 = 4.16666666666665929218E-2;
34const C5 = 4.16666666666665929218E-2;
3535
3636// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
3737//
......@@ -55,7 +55,7 @@ fn cos32(x_: f32) f32 {
5555 }
5656
5757 var y = math.floor(x * m4pi);
58 var j = i64(y);
58 var j = @floatToInt(i64, y);
5959
6060 if (j & 1 == 1) {
6161 j += 1;
......@@ -106,7 +106,7 @@ fn cos64(x_: f64) f64 {
106106 }
107107
108108 var y = math.floor(x * m4pi);
109 var j = i64(y);
109 var j = @floatToInt(i64, y);
110110
111111 if (j & 1 == 1) {
112112 j += 1;
std/math/cosh.zig+1-1
......@@ -49,7 +49,7 @@ fn cosh32(x: f32) f32 {
4949
5050fn cosh64(x: f64) f64 {
5151 const u = @bitCast(u64, x);
52 const w = u32(u >> 32);
52 const w = @intCast(u32, u >> 32);
5353 const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
5454
5555 // TODO: Shouldn't need this explicit check.
std/math/exp.zig+24-23
......@@ -6,6 +6,7 @@
66const std = @import("../index.zig");
77const math = std.math;
88const assert = std.debug.assert;
9const builtin = @import("builtin");
910
1011pub fn exp(x: var) @typeOf(x) {
1112 const T = @typeOf(x);
......@@ -17,16 +18,18 @@ pub fn exp(x: var) @typeOf(x) {
1718}
1819
1920fn exp32(x_: f32) f32 {
20 const half = []f32 { 0.5, -0.5 };
21 @setFloatMode(this, builtin.FloatMode.Strict);
22
23 const half = []f32{ 0.5, -0.5 };
2124 const ln2hi = 6.9314575195e-1;
2225 const ln2lo = 1.4286067653e-6;
23 const invln2 = 1.4426950216e+0;
26 const invln2 = 1.4426950216e+0;
2427 const P1 = 1.6666625440e-1;
2528 const P2 = -2.7667332906e-3;
2629
2730 var x = x_;
2831 var hx = @bitCast(u32, x);
29 const sign = i32(hx >> 31);
32 const sign = @intCast(i32, hx >> 31);
3033 hx &= 0x7FFFFFFF;
3134
3235 if (math.isNan(x)) {
......@@ -44,7 +47,7 @@ fn exp32(x_: f32) f32 {
4447 return x * 0x1.0p127;
4548 }
4649 if (sign != 0) {
47 math.forceEval(-0x1.0p-149 / x); // overflow
50 math.forceEval(-0x1.0p-149 / x); // overflow
4851 // x <= -103.972084
4952 if (hx >= 0x42CFF1B5) {
5053 return 0;
......@@ -60,13 +63,12 @@ fn exp32(x_: f32) f32 {
6063 if (hx > 0x3EB17218) {
6164 // |x| > 1.5 * ln2
6265 if (hx > 0x3F851592) {
63 k = i32(invln2 * x + half[usize(sign)]);
64 }
65 else {
66 k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]);
67 } else {
6668 k = 1 - sign - sign;
6769 }
6870
69 const fk = f32(k);
71 const fk = @intToFloat(f32, k);
7072 hi = x - fk * ln2hi;
7173 lo = fk * ln2lo;
7274 x = hi - lo;
......@@ -76,8 +78,7 @@ fn exp32(x_: f32) f32 {
7678 k = 0;
7779 hi = x;
7880 lo = 0;
79 }
80 else {
81 } else {
8182 math.forceEval(0x1.0p127 + x); // inexact
8283 return 1 + x;
8384 }
......@@ -94,20 +95,22 @@ fn exp32(x_: f32) f32 {
9495}
9596
9697fn exp64(x_: f64) f64 {
97 const half = []const f64 { 0.5, -0.5 };
98 @setFloatMode(this, builtin.FloatMode.Strict);
99
100 const half = []const f64{ 0.5, -0.5 };
98101 const ln2hi: f64 = 6.93147180369123816490e-01;
99102 const ln2lo: f64 = 1.90821492927058770002e-10;
100103 const invln2: f64 = 1.44269504088896338700e+00;
101 const P1: f64 = 1.66666666666666019037e-01;
102 const P2: f64 = -2.77777777770155933842e-03;
103 const P3: f64 = 6.61375632143793436117e-05;
104 const P4: f64 = -1.65339022054652515390e-06;
105 const P5: f64 = 4.13813679705723846039e-08;
104 const P1: f64 = 1.66666666666666019037e-01;
105 const P2: f64 = -2.77777777770155933842e-03;
106 const P3: f64 = 6.61375632143793436117e-05;
107 const P4: f64 = -1.65339022054652515390e-06;
108 const P5: f64 = 4.13813679705723846039e-08;
106109
107110 var x = x_;
108111 var ux = @bitCast(u64, x);
109112 var hx = ux >> 32;
110 const sign = i32(hx >> 31);
113 const sign = @intCast(i32, hx >> 31);
111114 hx &= 0x7FFFFFFF;
112115
113116 if (math.isNan(x)) {
......@@ -145,13 +148,12 @@ fn exp64(x_: f64) f64 {
145148 if (hx > 0x3EB17218) {
146149 // |x| >= 1.5 * ln2
147150 if (hx > 0x3FF0A2B2) {
148 k = i32(invln2 * x + half[usize(sign)]);
149 }
150 else {
151 k = @floatToInt(i32, invln2 * x + half[@intCast(usize, sign)]);
152 } else {
151153 k = 1 - sign - sign;
152154 }
153155
154 const dk = f64(k);
156 const dk = @intToFloat(f64, k);
155157 hi = x - dk * ln2hi;
156158 lo = dk * ln2lo;
157159 x = hi - lo;
......@@ -161,8 +163,7 @@ fn exp64(x_: f64) f64 {
161163 k = 0;
162164 hi = x;
163165 lo = 0;
164 }
165 else {
166 } else {
166167 // inexact if x != 0
167168 // math.forceEval(0x1.0p1023 + x);
168169 return 1 + x;
std/math/exp2.zig+158-158
......@@ -16,7 +16,7 @@ pub fn exp2(x: var) @typeOf(x) {
1616 };
1717}
1818
19const exp2ft = []const f64 {
19const exp2ft = []const f64{
2020 0x1.6a09e667f3bcdp-1,
2121 0x1.7a11473eb0187p-1,
2222 0x1.8ace5422aa0dbp-1,
......@@ -38,8 +38,8 @@ const exp2ft = []const f64 {
3838fn exp2_32(x: f32) f32 {
3939 @setFloatMode(this, @import("builtin").FloatMode.Strict);
4040
41 const tblsiz = u32(exp2ft.len);
42 const redux: f32 = 0x1.8p23 / f32(tblsiz);
41 const tblsiz = @intCast(u32, exp2ft.len);
42 const redux: f32 = 0x1.8p23 / @intToFloat(f32, tblsiz);
4343 const P1: f32 = 0x1.62e430p-1;
4444 const P2: f32 = 0x1.ebfbe0p-3;
4545 const P3: f32 = 0x1.c6b348p-5;
......@@ -75,212 +75,212 @@ fn exp2_32(x: f32) f32 {
7575 }
7676
7777 var uf = x + redux;
78 var i0 = @bitCast(u32, uf);
79 i0 += tblsiz / 2;
78 var i_0 = @bitCast(u32, uf);
79 i_0 += tblsiz / 2;
8080
81 const k = i0 / tblsiz;
81 const k = i_0 / tblsiz;
8282 // NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the
8383 // intended result but should confirm how GCC/Clang handle this to ensure.
8484 const uk = @bitCast(f64, u64(0x3FF + k) << 52);
85 i0 &= tblsiz - 1;
85 i_0 &= tblsiz - 1;
8686 uf -= redux;
8787
8888 const z: f64 = x - uf;
89 var r: f64 = exp2ft[i0];
89 var r: f64 = exp2ft[i_0];
9090 const t: f64 = r * z;
9191 r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
92 return f32(r * uk);
92 return @floatCast(f32, r * uk);
9393}
9494
95const exp2dt = []f64 {
95const exp2dt = []f64{
9696 // exp2(z + eps) eps
97 0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
98 0x1.6b052fa751744p-1, 0x1.8000p-50,
97 0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
98 0x1.6b052fa751744p-1, 0x1.8000p-50,
9999 0x1.6c012750bd9fep-1, -0x1.8780p-45,
100 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
100 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
101101 0x1.6dfb23c651a29p-1, -0x1.8000p-50,
102102 0x1.6ef9298593ae3p-1, -0x1.c000p-52,
103103 0x1.6ff7df9519386p-1, -0x1.fd80p-45,
104104 0x1.70f7466f42da3p-1, -0x1.c880p-45,
105 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
105 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
106106 0x1.72f8286eacf05p-1, -0x1.8300p-44,
107107 0x1.73f9a48a58152p-1, -0x1.0c00p-47,
108 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
109 0x1.75feb564267f1p-1, 0x1.3e00p-47,
108 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
109 0x1.75feb564267f1p-1, 0x1.3e00p-47,
110110 0x1.77024b1ab6d48p-1, -0x1.7d00p-45,
111111 0x1.780694fde5d38p-1, -0x1.d000p-50,
112 0x1.790b938ac1d00p-1, 0x1.3000p-49,
112 0x1.790b938ac1d00p-1, 0x1.3000p-49,
113113 0x1.7a11473eb0178p-1, -0x1.d000p-49,
114 0x1.7b17b0976d060p-1, 0x1.0400p-45,
115 0x1.7c1ed0130c133p-1, 0x1.0000p-53,
114 0x1.7b17b0976d060p-1, 0x1.0400p-45,
115 0x1.7c1ed0130c133p-1, 0x1.0000p-53,
116116 0x1.7d26a62ff8636p-1, -0x1.6900p-45,
117117 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47,
118118 0x1.7f3878491c3e8p-1, -0x1.4580p-45,
119 0x1.80427543e1b4ep-1, 0x1.3000p-44,
120 0x1.814d2add1071ap-1, 0x1.f000p-47,
119 0x1.80427543e1b4ep-1, 0x1.3000p-44,
120 0x1.814d2add1071ap-1, 0x1.f000p-47,
121121 0x1.82589994ccd7ep-1, -0x1.1c00p-45,
122 0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
123 0x1.8471a4623cab5p-1, 0x1.7100p-43,
124 0x1.857f4179f5bbcp-1, 0x1.2600p-45,
122 0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
123 0x1.8471a4623cab5p-1, 0x1.7100p-43,
124 0x1.857f4179f5bbcp-1, 0x1.2600p-45,
125125 0x1.868d99b4491afp-1, -0x1.2c40p-44,
126126 0x1.879cad931a395p-1, -0x1.3000p-45,
127127 0x1.88ac7d98a65b8p-1, -0x1.a800p-45,
128128 0x1.89bd0a4785800p-1, -0x1.d000p-49,
129 0x1.8ace5422aa223p-1, 0x1.3280p-44,
130 0x1.8be05bad619fap-1, 0x1.2b40p-43,
129 0x1.8ace5422aa223p-1, 0x1.3280p-44,
130 0x1.8be05bad619fap-1, 0x1.2b40p-43,
131131 0x1.8cf3216b54383p-1, -0x1.ed00p-45,
132132 0x1.8e06a5e08664cp-1, -0x1.0500p-45,
133 0x1.8f1ae99157807p-1, 0x1.8280p-45,
133 0x1.8f1ae99157807p-1, 0x1.8280p-45,
134134 0x1.902fed0282c0ep-1, -0x1.cb00p-46,
135135 0x1.9145b0b91ff96p-1, -0x1.5e00p-47,
136 0x1.925c353aa2ff9p-1, 0x1.5400p-48,
137 0x1.93737b0cdc64ap-1, 0x1.7200p-46,
136 0x1.925c353aa2ff9p-1, 0x1.5400p-48,
137 0x1.93737b0cdc64ap-1, 0x1.7200p-46,
138138 0x1.948b82b5f98aep-1, -0x1.9000p-47,
139 0x1.95a44cbc852cbp-1, 0x1.5680p-45,
139 0x1.95a44cbc852cbp-1, 0x1.5680p-45,
140140 0x1.96bdd9a766f21p-1, -0x1.6d00p-44,
141141 0x1.97d829fde4e2ap-1, -0x1.1000p-47,
142 0x1.98f33e47a23a3p-1, 0x1.d000p-45,
142 0x1.98f33e47a23a3p-1, 0x1.d000p-45,
143143 0x1.9a0f170ca0604p-1, -0x1.8a40p-44,
144 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
145 0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
144 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
145 0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
146146 0x1.9d674194bb8c5p-1, -0x1.c000p-49,
147 0x1.9e86319e3238ep-1, 0x1.7d00p-46,
148 0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
147 0x1.9e86319e3238ep-1, 0x1.7d00p-46,
148 0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
149149 0x1.a0c667b5de54dp-1, -0x1.5000p-48,
150 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
151 0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
150 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
151 0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
152152 0x1.a42c980460a5dp-1, -0x1.af00p-46,
153 0x1.a5503b23e259bp-1, 0x1.b600p-47,
154 0x1.a674a8af46213p-1, 0x1.8880p-44,
155 0x1.a799e1330b3a7p-1, 0x1.1200p-46,
156 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
153 0x1.a5503b23e259bp-1, 0x1.b600p-47,
154 0x1.a674a8af46213p-1, 0x1.8880p-44,
155 0x1.a799e1330b3a7p-1, 0x1.1200p-46,
156 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
157157 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45,
158 0x1.ab0e521356fb8p-1, 0x1.b700p-45,
159 0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
160 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
158 0x1.ab0e521356fb8p-1, 0x1.b700p-45,
159 0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
160 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
161161 0x1.ae89f995ad2a3p-1, -0x1.c900p-45,
162 0x1.afb4ce622f367p-1, 0x1.6500p-46,
163 0x1.b0e07298db790p-1, 0x1.fd40p-45,
164 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
165 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
162 0x1.afb4ce622f367p-1, 0x1.6500p-46,
163 0x1.b0e07298db790p-1, 0x1.fd40p-45,
164 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
165 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
166166 0x1.b468415b747e7p-1, -0x1.8380p-44,
167 0x1.b59728de5593ap-1, 0x1.8000p-54,
168 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
169 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
167 0x1.b59728de5593ap-1, 0x1.8000p-54,
168 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
169 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
170170 0x1.b928cf22749b2p-1, -0x1.4c00p-47,
171171 0x1.ba5b030a10603p-1, -0x1.d700p-47,
172 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
173 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
172 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
173 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
174174 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46,
175175 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46,
176176 0x1.c06286141b2e9p-1, -0x1.1400p-46,
177 0x1.c199bdd8552e0p-1, 0x1.be00p-47,
177 0x1.c199bdd8552e0p-1, 0x1.be00p-47,
178178 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47,
179179 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47,
180 0x1.c544778fafd15p-1, 0x1.9660p-44,
180 0x1.c544778fafd15p-1, 0x1.9660p-44,
181181 0x1.c67f12e57d0cbp-1, -0x1.a100p-46,
182182 0x1.c7ba88988c1b6p-1, -0x1.8458p-42,
183183 0x1.c8f6d9406e733p-1, -0x1.a480p-46,
184 0x1.ca3405751c4dfp-1, 0x1.b000p-51,
185 0x1.cb720dcef9094p-1, 0x1.1400p-47,
186 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
187 0x1.cdf0b555dc412p-1, 0x1.3600p-48,
184 0x1.ca3405751c4dfp-1, 0x1.b000p-51,
185 0x1.cb720dcef9094p-1, 0x1.1400p-47,
186 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
187 0x1.cdf0b555dc412p-1, 0x1.3600p-48,
188188 0x1.cf3155b5bab3bp-1, -0x1.6900p-47,
189 0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
189 0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
190190 0x1.d1b532b08c8fap-1, -0x1.5e00p-46,
191 0x1.d2f87080d8a85p-1, 0x1.d280p-46,
192 0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
193 0x1.d5818dcfba491p-1, 0x1.f000p-50,
191 0x1.d2f87080d8a85p-1, 0x1.d280p-46,
192 0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
193 0x1.d5818dcfba491p-1, 0x1.f000p-50,
194194 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47,
195195 0x1.d80e316c9834ep-1, -0x1.cd80p-47,
196 0x1.d955d71ff6090p-1, 0x1.4c00p-48,
197 0x1.da9e603db32aep-1, 0x1.f900p-48,
198 0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
196 0x1.d955d71ff6090p-1, 0x1.4c00p-48,
197 0x1.da9e603db32aep-1, 0x1.f900p-48,
198 0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
199199 0x1.dd321f301b445p-1, -0x1.5200p-48,
200200 0x1.de7d5641c05bfp-1, -0x1.d700p-46,
201201 0x1.dfc97337b9aecp-1, -0x1.6140p-46,
202 0x1.e11676b197d5ep-1, 0x1.b480p-47,
203 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
204 0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
202 0x1.e11676b197d5ep-1, 0x1.b480p-47,
203 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
204 0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
205205 0x1.e502ee78b3fb4p-1, -0x1.9300p-47,
206206 0x1.e653924676d68p-1, -0x1.5000p-49,
207207 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47,
208208 0x1.e8f7977cdb726p-1, -0x1.3700p-48,
209 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
210 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
211 0x1.ecf482d8e680dp-1, 0x1.5500p-48,
212 0x1.ee4aaa2188514p-1, 0x1.6400p-51,
209 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
210 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
211 0x1.ecf482d8e680dp-1, 0x1.5500p-48,
212 0x1.ee4aaa2188514p-1, 0x1.6400p-51,
213213 0x1.efa1bee615a13p-1, -0x1.e800p-49,
214214 0x1.f0f9c1cb64106p-1, -0x1.a880p-48,
215215 0x1.f252b376bb963p-1, -0x1.c900p-45,
216 0x1.f3ac948dd7275p-1, 0x1.a000p-53,
216 0x1.f3ac948dd7275p-1, 0x1.a000p-53,
217217 0x1.f50765b6e4524p-1, -0x1.4f00p-48,
218 0x1.f6632798844fdp-1, 0x1.a800p-51,
219 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
218 0x1.f6632798844fdp-1, 0x1.a800p-51,
219 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
220220 0x1.f91d802243c82p-1, -0x1.4600p-50,
221221 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47,
222222 0x1.fbdba3692d511p-1, -0x1.0e00p-51,
223223 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46,
224 0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
225 0x1.0000000000000p+0, 0x0.0000p+0,
224 0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
225 0x1.0000000000000p+0, 0x0.0000p+0,
226226 0x1.00b1afa5abcbep+0, -0x1.3400p-52,
227227 0x1.0163da9fb3303p+0, -0x1.2170p-46,
228 0x1.02168143b0282p+0, 0x1.a400p-52,
229 0x1.02c9a3e77806cp+0, 0x1.f980p-49,
228 0x1.02168143b0282p+0, 0x1.a400p-52,
229 0x1.02c9a3e77806cp+0, 0x1.f980p-49,
230230 0x1.037d42e11bbcap+0, -0x1.7400p-51,
231 0x1.04315e86e7f89p+0, 0x1.8300p-50,
231 0x1.04315e86e7f89p+0, 0x1.8300p-50,
232232 0x1.04e5f72f65467p+0, -0x1.a3f0p-46,
233233 0x1.059b0d315855ap+0, -0x1.2840p-47,
234 0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
235 0x1.0706b29ddf71ap+0, 0x1.5240p-46,
234 0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
235 0x1.0706b29ddf71ap+0, 0x1.5240p-46,
236236 0x1.07bd42b72a82dp+0, -0x1.9a00p-49,
237 0x1.0874518759bd0p+0, 0x1.6400p-49,
237 0x1.0874518759bd0p+0, 0x1.6400p-49,
238238 0x1.092bdf66607c8p+0, -0x1.0780p-47,
239239 0x1.09e3ecac6f383p+0, -0x1.8000p-54,
240 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
240 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
241241 0x1.0b5586cf988fcp+0, -0x1.ac80p-48,
242 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
243 0x1.0cc922b724816p+0, 0x1.5200p-47,
242 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
243 0x1.0cc922b724816p+0, 0x1.5200p-47,
244244 0x1.0d83b23395dd8p+0, -0x1.ad00p-48,
245 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
245 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
246246 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47,
247247 0x1.0fb66affed2f0p+0, -0x1.d300p-47,
248 0x1.1073028d7234bp+0, 0x1.1500p-48,
249 0x1.11301d0125b5bp+0, 0x1.c000p-49,
250 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
251 0x1.12abdc06c31d5p+0, 0x1.8400p-49,
248 0x1.1073028d7234bp+0, 0x1.1500p-48,
249 0x1.11301d0125b5bp+0, 0x1.c000p-49,
250 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
251 0x1.12abdc06c31d5p+0, 0x1.8400p-49,
252252 0x1.136a814f2047dp+0, -0x1.ed00p-47,
253 0x1.1429aaea92de9p+0, 0x1.8e00p-49,
254 0x1.14e95934f3138p+0, 0x1.b400p-49,
255 0x1.15a98c8a58e71p+0, 0x1.5300p-47,
256 0x1.166a45471c3dfp+0, 0x1.3380p-47,
257 0x1.172b83c7d5211p+0, 0x1.8d40p-45,
253 0x1.1429aaea92de9p+0, 0x1.8e00p-49,
254 0x1.14e95934f3138p+0, 0x1.b400p-49,
255 0x1.15a98c8a58e71p+0, 0x1.5300p-47,
256 0x1.166a45471c3dfp+0, 0x1.3380p-47,
257 0x1.172b83c7d5211p+0, 0x1.8d40p-45,
258258 0x1.17ed48695bb9fp+0, -0x1.5d00p-47,
259259 0x1.18af9388c8d93p+0, -0x1.c880p-46,
260 0x1.1972658375d66p+0, 0x1.1f00p-46,
261 0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
260 0x1.1972658375d66p+0, 0x1.1f00p-46,
261 0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
262262 0x1.1af99f81387e3p+0, -0x1.7390p-43,
263 0x1.1bbe084045d54p+0, 0x1.4e40p-45,
263 0x1.1bbe084045d54p+0, 0x1.4e40p-45,
264264 0x1.1c82f95281c43p+0, -0x1.a200p-47,
265 0x1.1d4873168b9b2p+0, 0x1.3800p-49,
266 0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
267 0x1.1ed5022fcd938p+0, 0x1.1900p-47,
265 0x1.1d4873168b9b2p+0, 0x1.3800p-49,
266 0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
267 0x1.1ed5022fcd938p+0, 0x1.1900p-47,
268268 0x1.1f9c18438cdf7p+0, -0x1.b780p-46,
269 0x1.2063b88628d8fp+0, 0x1.d940p-45,
270 0x1.212be3578a81ep+0, 0x1.8000p-50,
271 0x1.21f49917ddd41p+0, 0x1.b340p-45,
272 0x1.22bdda2791323p+0, 0x1.9f80p-46,
269 0x1.2063b88628d8fp+0, 0x1.d940p-45,
270 0x1.212be3578a81ep+0, 0x1.8000p-50,
271 0x1.21f49917ddd41p+0, 0x1.b340p-45,
272 0x1.22bdda2791323p+0, 0x1.9f80p-46,
273273 0x1.2387a6e7561e7p+0, -0x1.9c80p-46,
274 0x1.2451ffb821427p+0, 0x1.2300p-47,
274 0x1.2451ffb821427p+0, 0x1.2300p-47,
275275 0x1.251ce4fb2a602p+0, -0x1.3480p-46,
276 0x1.25e85711eceb0p+0, 0x1.2700p-46,
277 0x1.26b4565e27d16p+0, 0x1.1d00p-46,
278 0x1.2780e341de00fp+0, 0x1.1ee0p-44,
276 0x1.25e85711eceb0p+0, 0x1.2700p-46,
277 0x1.26b4565e27d16p+0, 0x1.1d00p-46,
278 0x1.2780e341de00fp+0, 0x1.1ee0p-44,
279279 0x1.284dfe1f5633ep+0, -0x1.4c00p-46,
280280 0x1.291ba7591bb30p+0, -0x1.3d80p-46,
281 0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
281 0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
282282 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45,
283 0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
283 0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
284284 0x1.2c57e39771af9p+0, -0x1.0800p-46,
285285 0x1.2d285a6e402d9p+0, -0x1.ed00p-47,
286286 0x1.2df961f641579p+0, -0x1.4200p-48,
......@@ -290,81 +290,81 @@ const exp2dt = []f64 {
290290 0x1.31432edeea50bp+0, -0x1.0df8p-40,
291291 0x1.32170fc4cd7b8p+0, -0x1.2480p-45,
292292 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45,
293 0x1.33c08b2641766p+0, 0x1.ed00p-46,
293 0x1.33c08b2641766p+0, 0x1.ed00p-46,
294294 0x1.3496266e3fa27p+0, -0x1.c000p-50,
295295 0x1.356c55f929f0fp+0, -0x1.0d80p-44,
296 0x1.36431a2de88b9p+0, 0x1.2c80p-45,
297 0x1.371a7373aaa39p+0, 0x1.0600p-45,
296 0x1.36431a2de88b9p+0, 0x1.2c80p-45,
297 0x1.371a7373aaa39p+0, 0x1.0600p-45,
298298 0x1.37f26231e74fep+0, -0x1.6600p-46,
299299 0x1.38cae6d05d838p+0, -0x1.ae00p-47,
300300 0x1.39a401b713ec3p+0, -0x1.4720p-43,
301 0x1.3a7db34e5a020p+0, 0x1.8200p-47,
302 0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
303 0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
301 0x1.3a7db34e5a020p+0, 0x1.8200p-47,
302 0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
303 0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
304304 0x1.3d0e544ede122p+0, -0x1.7a00p-46,
305 0x1.3dea64c1234bbp+0, 0x1.6300p-45,
305 0x1.3dea64c1234bbp+0, 0x1.6300p-45,
306306 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43,
307307 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44,
308 0x1.40822c367a0bbp+0, 0x1.5b80p-45,
309 0x1.4160a21f72e95p+0, 0x1.ec00p-46,
308 0x1.40822c367a0bbp+0, 0x1.5b80p-45,
309 0x1.4160a21f72e95p+0, 0x1.ec00p-46,
310310 0x1.423fb27094646p+0, -0x1.3600p-46,
311 0x1.431f5d950a920p+0, 0x1.3980p-45,
312 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
311 0x1.431f5d950a920p+0, 0x1.3980p-45,
312 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
313313 0x1.44e0860618919p+0, -0x1.6c00p-48,
314314 0x1.45c2042a7d201p+0, -0x1.bc00p-47,
315315 0x1.46a41ed1d0016p+0, -0x1.2800p-46,
316 0x1.4786d668b3326p+0, 0x1.0e00p-44,
316 0x1.4786d668b3326p+0, 0x1.0e00p-44,
317317 0x1.486a2b5c13c00p+0, -0x1.d400p-45,
318 0x1.494e1e192af04p+0, 0x1.c200p-47,
318 0x1.494e1e192af04p+0, 0x1.c200p-47,
319319 0x1.4a32af0d7d372p+0, -0x1.e500p-46,
320 0x1.4b17dea6db801p+0, 0x1.7800p-47,
320 0x1.4b17dea6db801p+0, 0x1.7800p-47,
321321 0x1.4bfdad53629e1p+0, -0x1.3800p-46,
322 0x1.4ce41b817c132p+0, 0x1.0800p-47,
323 0x1.4dcb299fddddbp+0, 0x1.c700p-45,
322 0x1.4ce41b817c132p+0, 0x1.0800p-47,
323 0x1.4dcb299fddddbp+0, 0x1.c700p-45,
324324 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46,
325 0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
325 0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
326326 0x1.508417f4531c1p+0, -0x1.8c00p-47,
327327 0x1.516daa2cf662ap+0, -0x1.a000p-48,
328 0x1.5257de83f51eap+0, 0x1.a080p-43,
328 0x1.5257de83f51eap+0, 0x1.a080p-43,
329329 0x1.5342b569d4edap+0, -0x1.6d80p-45,
330330 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44,
331 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
332 0x1.56070dde9116bp+0, 0x1.4b00p-45,
333 0x1.56f4736b529dep+0, 0x1.15a0p-43,
331 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
332 0x1.56070dde9116bp+0, 0x1.4b00p-45,
333 0x1.56f4736b529dep+0, 0x1.15a0p-43,
334334 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45,
335335 0x1.58d12d497c76fp+0, -0x1.3080p-45,
336 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
336 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
337337 0x1.5ab07dd485427p+0, -0x1.4000p-51,
338 0x1.5ba11fba87af4p+0, 0x1.0080p-44,
338 0x1.5ba11fba87af4p+0, 0x1.0080p-44,
339339 0x1.5c9268a59460bp+0, -0x1.6c80p-45,
340 0x1.5d84590998e3fp+0, 0x1.69a0p-43,
340 0x1.5d84590998e3fp+0, 0x1.69a0p-43,
341341 0x1.5e76f15ad20e1p+0, -0x1.b400p-46,
342 0x1.5f6a320dcebcap+0, 0x1.7700p-46,
343 0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
344 0x1.6152ae6cdf715p+0, 0x1.1000p-47,
342 0x1.5f6a320dcebcap+0, 0x1.7700p-46,
343 0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
344 0x1.6152ae6cdf715p+0, 0x1.1000p-47,
345345 0x1.6247eb03a5531p+0, -0x1.5d00p-46,
346346 0x1.633dd1d1929b5p+0, -0x1.2d00p-46,
347347 0x1.6434634ccc313p+0, -0x1.a800p-49,
348348 0x1.652b9febc8efap+0, -0x1.8600p-45,
349 0x1.6623882553397p+0, 0x1.1fe0p-40,
349 0x1.6623882553397p+0, 0x1.1fe0p-40,
350350 0x1.671c1c708328ep+0, -0x1.7200p-44,
351 0x1.68155d44ca97ep+0, 0x1.6800p-49,
351 0x1.68155d44ca97ep+0, 0x1.6800p-49,
352352 0x1.690f4b19e9471p+0, -0x1.9780p-45,
353353};
354354
355355fn exp2_64(x: f64) f64 {
356356 @setFloatMode(this, @import("builtin").FloatMode.Strict);
357357
358 const tblsiz = u32(exp2dt.len / 2);
359 const redux: f64 = 0x1.8p52 / f64(tblsiz);
360 const P1: f64 = 0x1.62e42fefa39efp-1;
361 const P2: f64 = 0x1.ebfbdff82c575p-3;
362 const P3: f64 = 0x1.c6b08d704a0a6p-5;
363 const P4: f64 = 0x1.3b2ab88f70400p-7;
364 const P5: f64 = 0x1.5d88003875c74p-10;
358 const tblsiz = @intCast(u32, exp2dt.len / 2);
359 const redux: f64 = 0x1.8p52 / @intToFloat(f64, tblsiz);
360 const P1: f64 = 0x1.62e42fefa39efp-1;
361 const P2: f64 = 0x1.ebfbdff82c575p-3;
362 const P3: f64 = 0x1.c6b08d704a0a6p-5;
363 const P4: f64 = 0x1.3b2ab88f70400p-7;
364 const P5: f64 = 0x1.5d88003875c74p-10;
365365
366366 const ux = @bitCast(u64, x);
367 const ix = u32(ux >> 32) & 0x7FFFFFFF;
367 const ix = @intCast(u32, ux >> 32) & 0x7FFFFFFF;
368368
369369 // TODO: This should be handled beneath.
370370 if (math.isNan(x)) {
......@@ -386,7 +386,7 @@ fn exp2_64(x: f64) f64 {
386386 if (ux >> 63 != 0) {
387387 // underflow
388388 if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) {
389 math.forceEval(f32(-0x1.0p-149 / x));
389 math.forceEval(@floatCast(f32, -0x1.0p-149 / x));
390390 }
391391 if (x <= -1075) {
392392 return 0;
......@@ -401,18 +401,18 @@ fn exp2_64(x: f64) f64 {
401401 // reduce x
402402 var uf = x + redux;
403403 // NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here
404 var i0 = @truncate(u32, @bitCast(u64, uf));
405 i0 += tblsiz / 2;
404 var i_0 = @truncate(u32, @bitCast(u64, uf));
405 i_0 += tblsiz / 2;
406406
407 const k: u32 = i0 / tblsiz * tblsiz;
407 const k: u32 = i_0 / tblsiz * tblsiz;
408408 const ik = @bitCast(i32, k / tblsiz);
409 i0 %= tblsiz;
409 i_0 %= tblsiz;
410410 uf -= redux;
411411
412 // r = exp2(y) = exp2t[i0] * p(z - eps[i])
412 // r = exp2(y) = exp2t[i_0] * p(z - eps[i])
413413 var z = x - uf;
414 const t = exp2dt[2 * i0];
415 z -= exp2dt[2 * i0 + 1];
414 const t = exp2dt[2 * i_0];
415 z -= exp2dt[2 * i_0 + 1];
416416 const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
417417
418418 return math.scalbn(r, ik);
std/math/expm1.zig+29-23
......@@ -20,12 +20,16 @@ pub fn expm1(x: var) @typeOf(x) {
2020
2121fn expm1_32(x_: f32) f32 {
2222 @setFloatMode(this, builtin.FloatMode.Strict);
23
24 if (math.isNan(x_))
25 return math.nan(f32);
26
2327 const o_threshold: f32 = 8.8721679688e+01;
24 const ln2_hi: f32 = 6.9313812256e-01;
25 const ln2_lo: f32 = 9.0580006145e-06;
26 const invln2: f32 = 1.4426950216e+00;
28 const ln2_hi: f32 = 6.9313812256e-01;
29 const ln2_lo: f32 = 9.0580006145e-06;
30 const invln2: f32 = 1.4426950216e+00;
2731 const Q1: f32 = -3.3333212137e-2;
28 const Q2: f32 = 1.5807170421e-3;
32 const Q2: f32 = 1.5807170421e-3;
2933
3034 var x = x_;
3135 const ux = @bitCast(u32, x);
......@@ -78,8 +82,8 @@ fn expm1_32(x_: f32) f32 {
7882 kf += 0.5;
7983 }
8084
81 k = i32(kf);
82 const t = f32(k);
85 k = @floatToInt(i32, kf);
86 const t = @intToFloat(f32, k);
8387 hi = x - t * ln2_hi;
8488 lo = t * ln2_lo;
8589 }
......@@ -93,8 +97,7 @@ fn expm1_32(x_: f32) f32 {
9397 math.forceEval(x * x);
9498 }
9599 return x;
96 }
97 else {
100 } else {
98101 k = 0;
99102 }
100103
......@@ -124,7 +127,7 @@ fn expm1_32(x_: f32) f32 {
124127 }
125128 }
126129
127 const twopk = @bitCast(f32, u32((0x7F +% k) << 23));
130 const twopk = @bitCast(f32, @intCast(u32, (0x7F +% k) << 23));
128131
129132 if (k < 0 or k > 56) {
130133 var y = x - e + 1.0;
......@@ -137,7 +140,7 @@ fn expm1_32(x_: f32) f32 {
137140 return y - 1.0;
138141 }
139142
140 const uf = @bitCast(f32, u32(0x7F -% k) << 23);
143 const uf = @bitCast(f32, @intCast(u32, 0x7F -% k) << 23);
141144 if (k < 23) {
142145 return (x - e + (1 - uf)) * twopk;
143146 } else {
......@@ -147,19 +150,23 @@ fn expm1_32(x_: f32) f32 {
147150
148151fn expm1_64(x_: f64) f64 {
149152 @setFloatMode(this, builtin.FloatMode.Strict);
153
154 if (math.isNan(x_))
155 return math.nan(f64);
156
150157 const o_threshold: f64 = 7.09782712893383973096e+02;
151 const ln2_hi: f64 = 6.93147180369123816490e-01;
152 const ln2_lo: f64 = 1.90821492927058770002e-10;
153 const invln2: f64 = 1.44269504088896338700e+00;
158 const ln2_hi: f64 = 6.93147180369123816490e-01;
159 const ln2_lo: f64 = 1.90821492927058770002e-10;
160 const invln2: f64 = 1.44269504088896338700e+00;
154161 const Q1: f64 = -3.33333333333331316428e-02;
155 const Q2: f64 = 1.58730158725481460165e-03;
162 const Q2: f64 = 1.58730158725481460165e-03;
156163 const Q3: f64 = -7.93650757867487942473e-05;
157 const Q4: f64 = 4.00821782732936239552e-06;
164 const Q4: f64 = 4.00821782732936239552e-06;
158165 const Q5: f64 = -2.01099218183624371326e-07;
159166
160167 var x = x_;
161168 const ux = @bitCast(u64, x);
162 const hx = u32(ux >> 32) & 0x7FFFFFFF;
169 const hx = @intCast(u32, ux >> 32) & 0x7FFFFFFF;
163170 const sign = ux >> 63;
164171
165172 if (math.isNegativeInf(x)) {
......@@ -208,8 +215,8 @@ fn expm1_64(x_: f64) f64 {
208215 kf += 0.5;
209216 }
210217
211 k = i32(kf);
212 const t = f64(k);
218 k = @floatToInt(i32, kf);
219 const t = @intToFloat(f64, k);
213220 hi = x - t * ln2_hi;
214221 lo = t * ln2_lo;
215222 }
......@@ -220,11 +227,10 @@ fn expm1_64(x_: f64) f64 {
220227 // |x| < 2^(-54)
221228 else if (hx < 0x3C900000) {
222229 if (hx < 0x00100000) {
223 math.forceEval(f32(x));
230 math.forceEval(@floatCast(f32, x));
224231 }
225232 return x;
226 }
227 else {
233 } else {
228234 k = 0;
229235 }
230236
......@@ -254,7 +260,7 @@ fn expm1_64(x_: f64) f64 {
254260 }
255261 }
256262
257 const twopk = @bitCast(f64, u64(0x3FF +% k) << 52);
263 const twopk = @bitCast(f64, @intCast(u64, 0x3FF +% k) << 52);
258264
259265 if (k < 0 or k > 56) {
260266 var y = x - e + 1.0;
......@@ -267,7 +273,7 @@ fn expm1_64(x_: f64) f64 {
267273 return y - 1.0;
268274 }
269275
270 const uf = @bitCast(f64, u64(0x3FF -% k) << 52);
276 const uf = @bitCast(f64, @intCast(u64, 0x3FF -% k) << 52);
271277 if (k < 20) {
272278 return (x - e + (1 - uf)) * twopk;
273279 } else {
std/math/fabs.zig+19
......@@ -10,12 +10,19 @@ const assert = std.debug.assert;
1010pub fn fabs(x: var) @typeOf(x) {
1111 const T = @typeOf(x);
1212 return switch (T) {
13 f16 => fabs16(x),
1314 f32 => fabs32(x),
1415 f64 => fabs64(x),
1516 else => @compileError("fabs not implemented for " ++ @typeName(T)),
1617 };
1718}
1819
20fn fabs16(x: f16) f16 {
21 var u = @bitCast(u16, x);
22 u &= 0x7FFF;
23 return @bitCast(f16, u);
24}
25
1926fn fabs32(x: f32) f32 {
2027 var u = @bitCast(u32, x);
2128 u &= 0x7FFFFFFF;
......@@ -29,10 +36,16 @@ fn fabs64(x: f64) f64 {
2936}
3037
3138test "math.fabs" {
39 assert(fabs(f16(1.0)) == fabs16(1.0));
3240 assert(fabs(f32(1.0)) == fabs32(1.0));
3341 assert(fabs(f64(1.0)) == fabs64(1.0));
3442}
3543
44test "math.fabs16" {
45 assert(fabs16(1.0) == 1.0);
46 assert(fabs16(-1.0) == 1.0);
47}
48
3649test "math.fabs32" {
3750 assert(fabs32(1.0) == 1.0);
3851 assert(fabs32(-1.0) == 1.0);
......@@ -43,6 +56,12 @@ test "math.fabs64" {
4356 assert(fabs64(-1.0) == 1.0);
4457}
4558
59test "math.fabs16.special" {
60 assert(math.isPositiveInf(fabs(math.inf(f16))));
61 assert(math.isPositiveInf(fabs(-math.inf(f16))));
62 assert(math.isNan(fabs(math.nan(f16))));
63}
64
4665test "math.fabs32.special" {
4766 assert(math.isPositiveInf(fabs(math.inf(f32))));
4867 assert(math.isPositiveInf(fabs(-math.inf(f32))));
std/math/floor.zig+54-4
......@@ -12,15 +12,50 @@ const math = std.math;
1212pub fn floor(x: var) @typeOf(x) {
1313 const T = @typeOf(x);
1414 return switch (T) {
15 f16 => floor16(x),
1516 f32 => floor32(x),
1617 f64 => floor64(x),
1718 else => @compileError("floor not implemented for " ++ @typeName(T)),
1819 };
1920}
2021
22fn floor16(x: f16) f16 {
23 var u = @bitCast(u16, x);
24 const e = @intCast(i16, (u >> 10) & 31) - 15;
25 var m: u16 = undefined;
26
27 // TODO: Shouldn't need this explicit check.
28 if (x == 0.0) {
29 return x;
30 }
31
32 if (e >= 10) {
33 return x;
34 }
35
36 if (e >= 0) {
37 m = u16(1023) >> @intCast(u4, e);
38 if (u & m == 0) {
39 return x;
40 }
41 math.forceEval(x + 0x1.0p120);
42 if (u >> 15 != 0) {
43 u += m;
44 }
45 return @bitCast(f16, u & ~m);
46 } else {
47 math.forceEval(x + 0x1.0p120);
48 if (u >> 15 == 0) {
49 return 0.0;
50 } else {
51 return -1.0;
52 }
53 }
54}
55
2156fn floor32(x: f32) f32 {
2257 var u = @bitCast(u32, x);
23 const e = i32((u >> 23) & 0xFF) - 0x7F;
58 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
2459 var m: u32 = undefined;
2560
2661 // TODO: Shouldn't need this explicit check.
......@@ -33,7 +68,7 @@ fn floor32(x: f32) f32 {
3368 }
3469
3570 if (e >= 0) {
36 m = u32(0x007FFFFF) >> u5(e);
71 m = u32(0x007FFFFF) >> @intCast(u5, e);
3772 if (u & m == 0) {
3873 return x;
3974 }
......@@ -57,7 +92,7 @@ fn floor64(x: f64) f64 {
5792 const e = (u >> 52) & 0x7FF;
5893 var y: f64 = undefined;
5994
60 if (e >= 0x3FF+52 or x == 0) {
95 if (e >= 0x3FF + 52 or x == 0) {
6196 return x;
6297 }
6398
......@@ -69,7 +104,7 @@ fn floor64(x: f64) f64 {
69104 y = x + math.f64_toint - math.f64_toint - x;
70105 }
71106
72 if (e <= 0x3FF-1) {
107 if (e <= 0x3FF - 1) {
73108 math.forceEval(y);
74109 if (u >> 63 != 0) {
75110 return -1.0;
......@@ -84,10 +119,17 @@ fn floor64(x: f64) f64 {
84119}
85120
86121test "math.floor" {
122 assert(floor(f16(1.3)) == floor16(1.3));
87123 assert(floor(f32(1.3)) == floor32(1.3));
88124 assert(floor(f64(1.3)) == floor64(1.3));
89125}
90126
127test "math.floor16" {
128 assert(floor16(1.3) == 1.0);
129 assert(floor16(-1.3) == -2.0);
130 assert(floor16(0.2) == 0.0);
131}
132
91133test "math.floor32" {
92134 assert(floor32(1.3) == 1.0);
93135 assert(floor32(-1.3) == -2.0);
......@@ -100,6 +142,14 @@ test "math.floor64" {
100142 assert(floor64(0.2) == 0.0);
101143}
102144
145test "math.floor16.special" {
146 assert(floor16(0.0) == 0.0);
147 assert(floor16(-0.0) == -0.0);
148 assert(math.isPositiveInf(floor16(math.inf(f16))));
149 assert(math.isNegativeInf(floor16(-math.inf(f16))));
150 assert(math.isNan(floor16(math.nan(f16))));
151}
152
103153test "math.floor32.special" {
104154 assert(floor32(0.0) == 0.0);
105155 assert(floor32(-0.0) == -0.0);
std/math/fma.zig+8-5
......@@ -5,7 +5,7 @@ const assert = std.debug.assert;
55pub fn fma(comptime T: type, x: T, y: T, z: T) T {
66 return switch (T) {
77 f32 => fma32(x, y, z),
8 f64 => fma64(x, y ,z),
8 f64 => fma64(x, y, z),
99 else => @compileError("fma not implemented for " ++ @typeName(T)),
1010 };
1111}
......@@ -17,10 +17,10 @@ fn fma32(x: f32, y: f32, z: f32) f32 {
1717 const e = (u >> 52) & 0x7FF;
1818
1919 if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) {
20 return f32(xy_z);
20 return @floatCast(f32, xy_z);
2121 } else {
2222 // TODO: Handle inexact case with double-rounding
23 return f32(xy_z);
23 return @floatCast(f32, xy_z);
2424 }
2525}
2626
......@@ -71,7 +71,10 @@ fn fma64(x: f64, y: f64, z: f64) f64 {
7171 }
7272}
7373
74const dd = struct { hi: f64, lo: f64, };
74const dd = struct {
75 hi: f64,
76 lo: f64,
77};
7578
7679fn dd_add(a: f64, b: f64) dd {
7780 var ret: dd = undefined;
......@@ -121,7 +124,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 {
121124 var sum = dd_add(a, b);
122125 if (sum.lo != 0) {
123126 var uhii = @bitCast(u64, sum.hi);
124 const bits_lost = -i32((uhii >> 52) & 0x7FF) - scale + 1;
127 const bits_lost = -@intCast(i32, (uhii >> 52) & 0x7FF) - scale + 1;
125128 if ((bits_lost != 1) == (uhii & 1 != 0)) {
126129 const uloi = @bitCast(u64, sum.lo);
127130 uhii += 1 - (((uhii ^ uloi) >> 62) & 2);
std/math/frexp.zig+2-2
......@@ -30,7 +30,7 @@ fn frexp32(x: f32) frexp32_result {
3030 var result: frexp32_result = undefined;
3131
3232 var y = @bitCast(u32, x);
33 const e = i32(y >> 23) & 0xFF;
33 const e = @intCast(i32, y >> 23) & 0xFF;
3434
3535 if (e == 0) {
3636 if (x != 0) {
......@@ -67,7 +67,7 @@ fn frexp64(x: f64) frexp64_result {
6767 var result: frexp64_result = undefined;
6868
6969 var y = @bitCast(u64, x);
70 const e = i32(y >> 52) & 0x7FF;
70 const e = @intCast(i32, y >> 52) & 0x7FF;
7171
7272 if (e == 0) {
7373 if (x != 0) {
std/math/hypot.zig+6-6
......@@ -39,26 +39,26 @@ fn hypot32(x: f32, y: f32) f32 {
3939 }
4040
4141 var z: f32 = 1.0;
42 if (ux >= (0x7F+60) << 23) {
42 if (ux >= (0x7F + 60) << 23) {
4343 z = 0x1.0p90;
4444 xx *= 0x1.0p-90;
4545 yy *= 0x1.0p-90;
46 } else if (uy < (0x7F-60) << 23) {
46 } else if (uy < (0x7F - 60) << 23) {
4747 z = 0x1.0p-90;
4848 xx *= 0x1.0p-90;
4949 yy *= 0x1.0p-90;
5050 }
5151
52 return z * math.sqrt(f32(f64(x) * x + f64(y) * y));
52 return z * math.sqrt(@floatCast(f32, f64(x) * x + f64(y) * y));
5353}
5454
55fn sq(hi: &f64, lo: &f64, x: f64) void {
55fn sq(hi: *f64, lo: *f64, x: f64) void {
5656 const split: f64 = 0x1.0p27 + 1.0;
5757 const xc = x * split;
5858 const xh = x - xc + xc;
5959 const xl = x - xh;
60 *hi = x * x;
61 *lo = xh * xh - *hi + 2 * xh * xl + xl * xl;
60 hi.* = x * x;
61 lo.* = xh * xh - hi.* + 2 * xh * xl + xl * xl;
6262}
6363
6464fn hypot64(x: f64, y: f64) f64 {
std/math/ilogb.zig+2-2
......@@ -23,7 +23,7 @@ const fp_ilogb0 = fp_ilogbnan;
2323
2424fn ilogb32(x: f32) i32 {
2525 var u = @bitCast(u32, x);
26 var e = i32((u >> 23) & 0xFF);
26 var e = @intCast(i32, (u >> 23) & 0xFF);
2727
2828 // TODO: We should be able to merge this with the lower check.
2929 if (math.isNan(x)) {
......@@ -59,7 +59,7 @@ fn ilogb32(x: f32) i32 {
5959
6060fn ilogb64(x: f64) i32 {
6161 var u = @bitCast(u64, x);
62 var e = i32((u >> 52) & 0x7FF);
62 var e = @intCast(i32, (u >> 52) & 0x7FF);
6363
6464 if (math.isNan(x)) {
6565 return @maxValue(i32);
std/math/index.zig+143-54
......@@ -19,6 +19,18 @@ pub const f32_max = 3.40282346638528859812e+38;
1919pub const f32_epsilon = 1.1920928955078125e-07;
2020pub const f32_toint = 1.0 / f32_epsilon;
2121
22pub const f16_true_min = 0.000000059604644775390625; // 2**-24
23pub const f16_min = 0.00006103515625; // 2**-14
24pub const f16_max = 65504;
25pub const f16_epsilon = 0.0009765625; // 2**-10
26pub const f16_toint = 1.0 / f16_epsilon;
27
28pub const nan_u16 = u16(0x7C01);
29pub const nan_f16 = @bitCast(f16, nan_u16);
30
31pub const inf_u16 = u16(0x7C00);
32pub const inf_f16 = @bitCast(f16, inf_u16);
33
2234pub const nan_u32 = u32(0x7F800001);
2335pub const nan_f32 = @bitCast(f32, nan_u32);
2436
......@@ -44,15 +56,20 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
4456pub fn forceEval(value: var) void {
4557 const T = @typeOf(value);
4658 switch (T) {
59 f16 => {
60 var x: f16 = undefined;
61 const p = @ptrCast(*volatile f16, &x);
62 p.* = x;
63 },
4764 f32 => {
4865 var x: f32 = undefined;
49 const p = @ptrCast(&volatile f32, &x);
50 *p = x;
66 const p = @ptrCast(*volatile f32, &x);
67 p.* = x;
5168 },
5269 f64 => {
5370 var x: f64 = undefined;
54 const p = @ptrCast(&volatile f64, &x);
55 *p = x;
71 const p = @ptrCast(*volatile f64, &x);
72 p.* = x;
5673 },
5774 else => {
5875 @compileError("forceEval not implemented for " ++ @typeName(T));
......@@ -129,6 +146,11 @@ pub const cos = @import("cos.zig").cos;
129146pub const sin = @import("sin.zig").sin;
130147pub const tan = @import("tan.zig").tan;
131148
149pub const complex = @import("complex/index.zig");
150pub const Complex = complex.Complex;
151
152pub const big = @import("big/index.zig");
153
132154test "math" {
133155 _ = @import("nan.zig");
134156 _ = @import("isnan.zig");
......@@ -172,8 +194,37 @@ test "math" {
172194 _ = @import("sin.zig");
173195 _ = @import("cos.zig");
174196 _ = @import("tan.zig");
197
198 _ = @import("complex/index.zig");
199
200 _ = @import("big/index.zig");
201}
202
203pub fn floatMantissaBits(comptime T: type) comptime_int {
204 assert(@typeId(T) == builtin.TypeId.Float);
205
206 return switch (T.bit_count) {
207 16 => 10,
208 32 => 23,
209 64 => 52,
210 80 => 64,
211 128 => 112,
212 else => @compileError("unknown floating point type " ++ @typeName(T)),
213 };
175214}
176215
216pub fn floatExponentBits(comptime T: type) comptime_int {
217 assert(@typeId(T) == builtin.TypeId.Float);
218
219 return switch (T.bit_count) {
220 16 => 5,
221 32 => 8,
222 64 => 11,
223 80 => 15,
224 128 => 15,
225 else => @compileError("unknown floating point type " ++ @typeName(T)),
226 };
227}
177228
178229pub fn min(x: var, y: var) @typeOf(x + y) {
179230 return if (x < y) x else y;
......@@ -219,7 +270,7 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
219270/// A negative shift amount results in a right shift.
220271pub fn shl(comptime T: type, a: T, shift_amt: var) T {
221272 const abs_shift_amt = absCast(shift_amt);
222 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else Log2Int(T)(abs_shift_amt);
273 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
223274
224275 if (@typeOf(shift_amt).is_signed) {
225276 if (shift_amt >= 0) {
......@@ -243,7 +294,7 @@ test "math.shl" {
243294/// A negative shift amount results in a lefft shift.
244295pub fn shr(comptime T: type, a: T, shift_amt: var) T {
245296 const abs_shift_amt = absCast(shift_amt);
246 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else Log2Int(T)(abs_shift_amt);
297 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
247298
248299 if (@typeOf(shift_amt).is_signed) {
249300 if (shift_amt >= 0) {
......@@ -275,10 +326,10 @@ pub fn rotr(comptime T: type, x: T, r: var) T {
275326}
276327
277328test "math.rotr" {
278 assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
279 assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
280 assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
281 assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
329 assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
330 assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
331 assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
332 assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
282333 assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
283334}
284335
......@@ -294,16 +345,22 @@ pub fn rotl(comptime T: type, x: T, r: var) T {
294345}
295346
296347test "math.rotl" {
297 assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
298 assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
299 assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
300 assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
348 assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
349 assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
350 assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
351 assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
301352 assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
302353}
303354
304
305355pub fn Log2Int(comptime T: type) type {
306 return @IntType(false, log2(T.bit_count));
356 // comptime ceil log2
357 comptime var count = 0;
358 comptime var s = T.bit_count - 1;
359 inline while (s != 0) : (s >>= 1) {
360 count += 1;
361 }
362
363 return @IntType(false, count);
307364}
308365
309366test "math overflow functions" {
......@@ -318,14 +375,14 @@ fn testOverflow() void {
318375 assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
319376}
320377
321
322378pub fn absInt(x: var) !@typeOf(x) {
323379 const T = @typeOf(x);
324380 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
325381 comptime assert(T.is_signed); // must pass a signed integer to absInt
326 if (x == @minValue(@typeOf(x)))
382
383 if (x == @minValue(@typeOf(x))) {
327384 return error.Overflow;
328 {
385 } else {
329386 @setRuntimeSafety(false);
330387 return if (x < 0) -x else x;
331388 }
......@@ -344,10 +401,8 @@ pub const absFloat = @import("fabs.zig").fabs;
344401
345402pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
346403 @setRuntimeSafety(false);
347 if (denominator == 0)
348 return error.DivisionByZero;
349 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
350 return error.Overflow;
404 if (denominator == 0) return error.DivisionByZero;
405 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
351406 return @divTrunc(numerator, denominator);
352407}
353408
......@@ -367,10 +422,8 @@ fn testDivTrunc() void {
367422
368423pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
369424 @setRuntimeSafety(false);
370 if (denominator == 0)
371 return error.DivisionByZero;
372 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
373 return error.Overflow;
425 if (denominator == 0) return error.DivisionByZero;
426 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
374427 return @divFloor(numerator, denominator);
375428}
376429
......@@ -390,13 +443,10 @@ fn testDivFloor() void {
390443
391444pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
392445 @setRuntimeSafety(false);
393 if (denominator == 0)
394 return error.DivisionByZero;
395 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
396 return error.Overflow;
446 if (denominator == 0) return error.DivisionByZero;
447 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
397448 const result = @divTrunc(numerator, denominator);
398 if (result * denominator != numerator)
399 return error.UnexpectedRemainder;
449 if (result * denominator != numerator) return error.UnexpectedRemainder;
400450 return result;
401451}
402452
......@@ -418,10 +468,8 @@ fn testDivExact() void {
418468
419469pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
420470 @setRuntimeSafety(false);
421 if (denominator == 0)
422 return error.DivisionByZero;
423 if (denominator < 0)
424 return error.NegativeDenominator;
471 if (denominator == 0) return error.DivisionByZero;
472 if (denominator < 0) return error.NegativeDenominator;
425473 return @mod(numerator, denominator);
426474}
427475
......@@ -443,10 +491,8 @@ fn testMod() void {
443491
444492pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
445493 @setRuntimeSafety(false);
446 if (denominator == 0)
447 return error.DivisionByZero;
448 if (denominator < 0)
449 return error.NegativeDenominator;
494 if (denominator == 0) return error.DivisionByZero;
495 if (denominator < 0) return error.NegativeDenominator;
450496 return @rem(numerator, denominator);
451497}
452498
......@@ -470,10 +516,9 @@ fn testRem() void {
470516/// Result is an unsigned integer.
471517pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
472518 const uint = @IntType(false, @typeOf(x).bit_count);
473 if (x >= 0)
474 return uint(x);
519 if (x >= 0) return @intCast(uint, x);
475520
476 return uint(-(x + 1)) + 1;
521 return @intCast(uint, -(x + 1)) + 1;
477522}
478523
479524test "math.absCast" {
......@@ -490,17 +535,14 @@ test "math.absCast" {
490535/// Returns the negation of the integer parameter.
491536/// Result is a signed integer.
492537pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
493 if (@typeOf(x).is_signed)
494 return negate(x);
538 if (@typeOf(x).is_signed) return negate(x);
495539
496540 const int = @IntType(true, @typeOf(x).bit_count);
497 if (x > -@minValue(int))
498 return error.Overflow;
541 if (x > -@minValue(int)) return error.Overflow;
499542
500 if (x == -@minValue(int))
501 return @minValue(int);
543 if (x == -@minValue(int)) return @minValue(int);
502544
503 return -int(x);
545 return -@intCast(int, x);
504546}
505547
506548test "math.negateCast" {
......@@ -513,7 +555,7 @@ test "math.negateCast" {
513555 if (negateCast(u32(@maxValue(i32) + 10))) |_| unreachable else |err| assert(err == error.Overflow);
514556}
515557
516/// Cast an integer to a different integer type. If the value doesn't fit,
558/// Cast an integer to a different integer type. If the value doesn't fit,
517559/// return an error.
518560pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
519561 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
......@@ -523,7 +565,7 @@ pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
523565 } else if (@minValue(@typeOf(x)) < @minValue(T) and x < @minValue(T)) {
524566 return error.Overflow;
525567 } else {
526 return T(x);
568 return @intCast(T, x);
527569 }
528570}
529571
......@@ -537,11 +579,22 @@ test "math.cast" {
537579 assert(@typeOf(try cast(u8, u32(255))) == u8);
538580}
539581
582pub const AlignCastError = error{UnalignedMemory};
583
584/// Align cast a pointer but return an error if it's the wrong alignment
585pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alignCast(alignment, ptr)) {
586 const addr = @ptrToInt(ptr);
587 if (addr % alignment != 0) {
588 return error.UnalignedMemory;
589 }
590 return @alignCast(alignment, ptr);
591}
592
540593pub fn floorPowerOfTwo(comptime T: type, value: T) T {
541594 var x = value;
542595
543596 comptime var i = 1;
544 inline while(T.bit_count > i) : (i *= 2) {
597 inline while (T.bit_count > i) : (i *= 2) {
545598 x |= (x >> i);
546599 }
547600
......@@ -553,6 +606,32 @@ test "math.floorPowerOfTwo" {
553606 comptime testFloorPowerOfTwo();
554607}
555608
609pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
610 assert(x != 0);
611 return @intCast(Log2Int(T), T.bit_count - 1 - @clz(x));
612}
613
614pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
615 assert(x != 0);
616 const log2_val = log2_int(T, x);
617 if (T(1) << log2_val == x)
618 return log2_val;
619 return log2_val + 1;
620}
621
622test "std.math.log2_int_ceil" {
623 assert(log2_int_ceil(u32, 1) == 0);
624 assert(log2_int_ceil(u32, 2) == 1);
625 assert(log2_int_ceil(u32, 3) == 2);
626 assert(log2_int_ceil(u32, 4) == 2);
627 assert(log2_int_ceil(u32, 5) == 3);
628 assert(log2_int_ceil(u32, 6) == 3);
629 assert(log2_int_ceil(u32, 7) == 3);
630 assert(log2_int_ceil(u32, 8) == 3);
631 assert(log2_int_ceil(u32, 9) == 4);
632 assert(log2_int_ceil(u32, 10) == 4);
633}
634
556635fn testFloorPowerOfTwo() void {
557636 assert(floorPowerOfTwo(u32, 63) == 32);
558637 assert(floorPowerOfTwo(u32, 64) == 64);
......@@ -561,3 +640,13 @@ fn testFloorPowerOfTwo() void {
561640 assert(floorPowerOfTwo(u4, 8) == 8);
562641 assert(floorPowerOfTwo(u4, 9) == 8);
563642}
643
644pub fn lossyCast(comptime T: type, value: var) T {
645 switch (@typeInfo(@typeOf(value))) {
646 builtin.TypeId.Int => return @intToFloat(T, value),
647 builtin.TypeId.Float => return @floatCast(T, value),
648 builtin.TypeId.ComptimeInt => return T(value),
649 builtin.TypeId.ComptimeFloat => return T(value),
650 else => @compileError("bad type"),
651 }
652}
std/math/inf.zig+1-1
......@@ -1,9 +1,9 @@
11const std = @import("../index.zig");
22const math = std.math;
3const assert = std.debug.assert;
43
54pub fn inf(comptime T: type) T {
65 return switch (T) {
6 f16 => @bitCast(f16, math.inf_u16),
77 f32 => @bitCast(f32, math.inf_u32),
88 f64 => @bitCast(f64, math.inf_u64),
99 else => @compileError("inf not implemented for " ++ @typeName(T)),
std/math/isfinite.zig+8
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isFinite(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return bits & 0x7FFF < 0x7C00;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return bits & 0x7FFFFFFF < 0x7F800000;
......@@ -20,10 +24,14 @@ pub fn isFinite(x: var) bool {
2024}
2125
2226test "math.isFinite" {
27 assert(isFinite(f16(0.0)));
28 assert(isFinite(f16(-0.0)));
2329 assert(isFinite(f32(0.0)));
2430 assert(isFinite(f32(-0.0)));
2531 assert(isFinite(f64(0.0)));
2632 assert(isFinite(f64(-0.0)));
33 assert(!isFinite(math.inf(f16)));
34 assert(!isFinite(-math.inf(f16)));
2735 assert(!isFinite(math.inf(f32)));
2836 assert(!isFinite(-math.inf(f32)));
2937 assert(!isFinite(math.inf(f64)));
std/math/isinf.zig+22
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isInf(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return bits & 0x7FFF == 0x7C00;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return bits & 0x7FFFFFFF == 0x7F800000;
......@@ -22,6 +26,9 @@ pub fn isInf(x: var) bool {
2226pub fn isPositiveInf(x: var) bool {
2327 const T = @typeOf(x);
2428 switch (T) {
29 f16 => {
30 return @bitCast(u16, x) == 0x7C00;
31 },
2532 f32 => {
2633 return @bitCast(u32, x) == 0x7F800000;
2734 },
......@@ -37,6 +44,9 @@ pub fn isPositiveInf(x: var) bool {
3744pub fn isNegativeInf(x: var) bool {
3845 const T = @typeOf(x);
3946 switch (T) {
47 f16 => {
48 return @bitCast(u16, x) == 0xFC00;
49 },
4050 f32 => {
4151 return @bitCast(u32, x) == 0xFF800000;
4252 },
......@@ -50,10 +60,14 @@ pub fn isNegativeInf(x: var) bool {
5060}
5161
5262test "math.isInf" {
63 assert(!isInf(f16(0.0)));
64 assert(!isInf(f16(-0.0)));
5365 assert(!isInf(f32(0.0)));
5466 assert(!isInf(f32(-0.0)));
5567 assert(!isInf(f64(0.0)));
5668 assert(!isInf(f64(-0.0)));
69 assert(isInf(math.inf(f16)));
70 assert(isInf(-math.inf(f16)));
5771 assert(isInf(math.inf(f32)));
5872 assert(isInf(-math.inf(f32)));
5973 assert(isInf(math.inf(f64)));
......@@ -61,10 +75,14 @@ test "math.isInf" {
6175}
6276
6377test "math.isPositiveInf" {
78 assert(!isPositiveInf(f16(0.0)));
79 assert(!isPositiveInf(f16(-0.0)));
6480 assert(!isPositiveInf(f32(0.0)));
6581 assert(!isPositiveInf(f32(-0.0)));
6682 assert(!isPositiveInf(f64(0.0)));
6783 assert(!isPositiveInf(f64(-0.0)));
84 assert(isPositiveInf(math.inf(f16)));
85 assert(!isPositiveInf(-math.inf(f16)));
6886 assert(isPositiveInf(math.inf(f32)));
6987 assert(!isPositiveInf(-math.inf(f32)));
7088 assert(isPositiveInf(math.inf(f64)));
......@@ -72,10 +90,14 @@ test "math.isPositiveInf" {
7290}
7391
7492test "math.isNegativeInf" {
93 assert(!isNegativeInf(f16(0.0)));
94 assert(!isNegativeInf(f16(-0.0)));
7595 assert(!isNegativeInf(f32(0.0)));
7696 assert(!isNegativeInf(f32(-0.0)));
7797 assert(!isNegativeInf(f64(0.0)));
7898 assert(!isNegativeInf(f64(-0.0)));
99 assert(!isNegativeInf(math.inf(f16)));
100 assert(isNegativeInf(-math.inf(f16)));
79101 assert(!isNegativeInf(math.inf(f32)));
80102 assert(isNegativeInf(-math.inf(f32)));
81103 assert(!isNegativeInf(math.inf(f64)));
std/math/isnan.zig+6
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isNan(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return (bits & 0x7fff) > 0x7c00;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return bits & 0x7FFFFFFF > 0x7F800000;
......@@ -26,8 +30,10 @@ pub fn isSignalNan(x: var) bool {
2630}
2731
2832test "math.isNan" {
33 assert(isNan(math.nan(f16)));
2934 assert(isNan(math.nan(f32)));
3035 assert(isNan(math.nan(f64)));
36 assert(!isNan(f16(1.0)));
3137 assert(!isNan(f32(1.0)));
3238 assert(!isNan(f64(1.0)));
3339}
std/math/isnormal.zig+9
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isNormal(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return (bits + 1024) & 0x7FFF >= 2048;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
......@@ -20,8 +24,13 @@ pub fn isNormal(x: var) bool {
2024}
2125
2226test "math.isNormal" {
27 assert(!isNormal(math.nan(f16)));
2328 assert(!isNormal(math.nan(f32)));
2429 assert(!isNormal(math.nan(f64)));
30 assert(!isNormal(f16(0)));
31 assert(!isNormal(f32(0)));
32 assert(!isNormal(f64(0)));
33 assert(isNormal(f16(1.0)));
2534 assert(isNormal(f32(1.0)));
2635 assert(isNormal(f64(1.0)));
2736}
std/math/ln.zig+12-12
......@@ -14,7 +14,7 @@ const TypeId = builtin.TypeId;
1414pub fn ln(x: var) @typeOf(x) {
1515 const T = @typeOf(x);
1616 switch (@typeId(T)) {
17 TypeId.FloatLiteral => {
17 TypeId.ComptimeFloat => {
1818 return @typeOf(1.0)(ln_64(x));
1919 },
2020 TypeId.Float => {
......@@ -24,7 +24,7 @@ pub fn ln(x: var) @typeOf(x) {
2424 else => @compileError("ln not implemented for " ++ @typeName(T)),
2525 };
2626 },
27 TypeId.IntLiteral => {
27 TypeId.ComptimeInt => {
2828 return @typeOf(1)(math.floor(ln_64(f64(x))));
2929 },
3030 TypeId.Int => {
......@@ -71,7 +71,7 @@ pub fn ln_32(x_: f32) f32 {
7171
7272 // x into [sqrt(2) / 2, sqrt(2)]
7373 ix += 0x3F800000 - 0x3F3504F3;
74 k += i32(ix >> 23) - 0x7F;
74 k += @intCast(i32, ix >> 23) - 0x7F;
7575 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
7676 x = @bitCast(f32, ix);
7777
......@@ -83,12 +83,14 @@ pub fn ln_32(x_: f32) f32 {
8383 const t2 = z * (Lg1 + w * Lg3);
8484 const R = t2 + t1;
8585 const hfsq = 0.5 * f * f;
86 const dk = f32(k);
86 const dk = @intToFloat(f32, k);
8787
8888 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
8989}
9090
9191pub fn ln_64(x_: f64) f64 {
92 @setFloatMode(this, @import("builtin").FloatMode.Strict);
93
9294 const ln2_hi: f64 = 6.93147180369123816490e-01;
9395 const ln2_lo: f64 = 1.90821492927058770002e-10;
9496 const Lg1: f64 = 6.666666666666735130e-01;
......@@ -101,7 +103,7 @@ pub fn ln_64(x_: f64) f64 {
101103
102104 var x = x_;
103105 var ix = @bitCast(u64, x);
104 var hx = u32(ix >> 32);
106 var hx = @intCast(u32, ix >> 32);
105107 var k: i32 = 0;
106108
107109 if (hx < 0x00100000 or hx >> 31 != 0) {
......@@ -117,18 +119,16 @@ pub fn ln_64(x_: f64) f64 {
117119 // subnormal, scale x
118120 k -= 54;
119121 x *= 0x1.0p54;
120 hx = u32(@bitCast(u64, ix) >> 32);
121 }
122 else if (hx >= 0x7FF00000) {
122 hx = @intCast(u32, @bitCast(u64, ix) >> 32);
123 } else if (hx >= 0x7FF00000) {
123124 return x;
124 }
125 else if (hx == 0x3FF00000 and ix << 32 == 0) {
125 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
126126 return 0;
127127 }
128128
129129 // x into [sqrt(2) / 2, sqrt(2)]
130130 hx += 0x3FF00000 - 0x3FE6A09E;
131 k += i32(hx >> 20) - 0x3FF;
131 k += @intCast(i32, hx >> 20) - 0x3FF;
132132 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
133133 ix = (u64(hx) << 32) | (ix & 0xFFFFFFFF);
134134 x = @bitCast(f64, ix);
......@@ -141,7 +141,7 @@ pub fn ln_64(x_: f64) f64 {
141141 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
142142 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
143143 const R = t2 + t1;
144 const dk = f64(k);
144 const dk = @intToFloat(f64, k);
145145
146146 return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
147147}
std/math/log.zig+9-8
......@@ -9,26 +9,27 @@ pub fn log(comptime T: type, base: T, x: T) T {
99 return math.log2(x);
1010 } else if (base == 10) {
1111 return math.log10(x);
12 } else if ((@typeId(T) == TypeId.Float or @typeId(T) == TypeId.FloatLiteral) and base == math.e) {
12 } else if ((@typeId(T) == TypeId.Float or @typeId(T) == TypeId.ComptimeFloat) and base == math.e) {
1313 return math.ln(x);
1414 }
1515
16 const float_base = math.lossyCast(f64, base);
1617 switch (@typeId(T)) {
17 TypeId.FloatLiteral => {
18 return @typeOf(1.0)(math.ln(f64(x)) / math.ln(f64(base)));
18 TypeId.ComptimeFloat => {
19 return @typeOf(1.0)(math.ln(f64(x)) / math.ln(float_base));
1920 },
20 TypeId.IntLiteral => {
21 return @typeOf(1)(math.floor(math.ln(f64(x)) / math.ln(f64(base))));
21 TypeId.ComptimeInt => {
22 return @typeOf(1)(math.floor(math.ln(f64(x)) / math.ln(float_base)));
2223 },
2324 builtin.TypeId.Int => {
2425 // TODO implement integer log without using float math
25 return T(math.floor(math.ln(f64(x)) / math.ln(f64(base))));
26 return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base)));
2627 },
2728
2829 builtin.TypeId.Float => {
2930 switch (T) {
30 f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))),
31 f64 => return math.ln(x) / math.ln(f64(base)),
31 f32 => return @floatCast(f32, math.ln(f64(x)) / math.ln(float_base)),
32 f64 => return math.ln(x) / math.ln(float_base),
3233 else => @compileError("log not implemented for " ++ @typeName(T)),
3334 }
3435 },
std/math/log10.zig+17-19
......@@ -14,7 +14,7 @@ const TypeId = builtin.TypeId;
1414pub fn log10(x: var) @typeOf(x) {
1515 const T = @typeOf(x);
1616 switch (@typeId(T)) {
17 TypeId.FloatLiteral => {
17 TypeId.ComptimeFloat => {
1818 return @typeOf(1.0)(log10_64(x));
1919 },
2020 TypeId.Float => {
......@@ -24,21 +24,21 @@ pub fn log10(x: var) @typeOf(x) {
2424 else => @compileError("log10 not implemented for " ++ @typeName(T)),
2525 };
2626 },
27 TypeId.IntLiteral => {
27 TypeId.ComptimeInt => {
2828 return @typeOf(1)(math.floor(log10_64(f64(x))));
2929 },
3030 TypeId.Int => {
31 return T(math.floor(log10_64(f64(x))));
31 return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x))));
3232 },
3333 else => @compileError("log10 not implemented for " ++ @typeName(T)),
3434 }
3535}
3636
3737pub fn log10_32(x_: f32) f32 {
38 const ivln10hi: f32 = 4.3432617188e-01;
39 const ivln10lo: f32 = -3.1689971365e-05;
40 const log10_2hi: f32 = 3.0102920532e-01;
41 const log10_2lo: f32 = 7.9034151668e-07;
38 const ivln10hi: f32 = 4.3432617188e-01;
39 const ivln10lo: f32 = -3.1689971365e-05;
40 const log10_2hi: f32 = 3.0102920532e-01;
41 const log10_2lo: f32 = 7.9034151668e-07;
4242 const Lg1: f32 = 0xaaaaaa.0p-24;
4343 const Lg2: f32 = 0xccce13.0p-25;
4444 const Lg3: f32 = 0x91e9ee.0p-25;
......@@ -71,7 +71,7 @@ pub fn log10_32(x_: f32) f32 {
7171
7272 // x into [sqrt(2) / 2, sqrt(2)]
7373 ix += 0x3F800000 - 0x3F3504F3;
74 k += i32(ix >> 23) - 0x7F;
74 k += @intCast(i32, ix >> 23) - 0x7F;
7575 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
7676 x = @bitCast(f32, ix);
7777
......@@ -89,14 +89,14 @@ pub fn log10_32(x_: f32) f32 {
8989 u &= 0xFFFFF000;
9090 hi = @bitCast(f32, u);
9191 const lo = f - hi - hfsq + s * (hfsq + R);
92 const dk = f32(k);
92 const dk = @intToFloat(f32, k);
9393
9494 return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
9595}
9696
9797pub fn log10_64(x_: f64) f64 {
98 const ivln10hi: f64 = 4.34294481878168880939e-01;
99 const ivln10lo: f64 = 2.50829467116452752298e-11;
98 const ivln10hi: f64 = 4.34294481878168880939e-01;
99 const ivln10lo: f64 = 2.50829467116452752298e-11;
100100 const log10_2hi: f64 = 3.01029995663611771306e-01;
101101 const log10_2lo: f64 = 3.69423907715893078616e-13;
102102 const Lg1: f64 = 6.666666666666735130e-01;
......@@ -109,7 +109,7 @@ pub fn log10_64(x_: f64) f64 {
109109
110110 var x = x_;
111111 var ix = @bitCast(u64, x);
112 var hx = u32(ix >> 32);
112 var hx = @intCast(u32, ix >> 32);
113113 var k: i32 = 0;
114114
115115 if (hx < 0x00100000 or hx >> 31 != 0) {
......@@ -125,18 +125,16 @@ pub fn log10_64(x_: f64) f64 {
125125 // subnormal, scale x
126126 k -= 54;
127127 x *= 0x1.0p54;
128 hx = u32(@bitCast(u64, x) >> 32);
129 }
130 else if (hx >= 0x7FF00000) {
128 hx = @intCast(u32, @bitCast(u64, x) >> 32);
129 } else if (hx >= 0x7FF00000) {
131130 return x;
132 }
133 else if (hx == 0x3FF00000 and ix << 32 == 0) {
131 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
134132 return 0;
135133 }
136134
137135 // x into [sqrt(2) / 2, sqrt(2)]
138136 hx += 0x3FF00000 - 0x3FE6A09E;
139 k += i32(hx >> 20) - 0x3FF;
137 k += @intCast(i32, hx >> 20) - 0x3FF;
140138 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
141139 ix = (u64(hx) << 32) | (ix & 0xFFFFFFFF);
142140 x = @bitCast(f64, ix);
......@@ -159,7 +157,7 @@ pub fn log10_64(x_: f64) f64 {
159157
160158 // val_hi + val_lo ~ log10(1 + f) + k * log10(2)
161159 var val_hi = hi * ivln10hi;
162 const dk = f64(k);
160 const dk = @intToFloat(f64, k);
163161 const y = dk * log10_2hi;
164162 var val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi;
165163
std/math/log1p.zig+7-8
......@@ -68,7 +68,7 @@ fn log1p_32(x: f32) f32 {
6868 const uf = 1 + x;
6969 var iu = @bitCast(u32, uf);
7070 iu += 0x3F800000 - 0x3F3504F3;
71 k = i32(iu >> 23) - 0x7F;
71 k = @intCast(i32, iu >> 23) - 0x7F;
7272
7373 // correction to avoid underflow in c / u
7474 if (k < 25) {
......@@ -90,7 +90,7 @@ fn log1p_32(x: f32) f32 {
9090 const t2 = z * (Lg1 + w * Lg3);
9191 const R = t2 + t1;
9292 const hfsq = 0.5 * f * f;
93 const dk = f32(k);
93 const dk = @intToFloat(f32, k);
9494
9595 return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
9696}
......@@ -107,7 +107,7 @@ fn log1p_64(x: f64) f64 {
107107 const Lg7: f64 = 1.479819860511658591e-01;
108108
109109 var ix = @bitCast(u64, x);
110 var hx = u32(ix >> 32);
110 var hx = @intCast(u32, ix >> 32);
111111 var k: i32 = 1;
112112 var c: f64 = undefined;
113113 var f: f64 = undefined;
......@@ -138,17 +138,16 @@ fn log1p_64(x: f64) f64 {
138138 c = 0;
139139 f = x;
140140 }
141 }
142 else if (hx >= 0x7FF00000) {
141 } else if (hx >= 0x7FF00000) {
143142 return x;
144143 }
145144
146145 if (k != 0) {
147146 const uf = 1 + x;
148147 const hu = @bitCast(u64, uf);
149 var iu = u32(hu >> 32);
148 var iu = @intCast(u32, hu >> 32);
150149 iu += 0x3FF00000 - 0x3FE6A09E;
151 k = i32(iu >> 20) - 0x3FF;
150 k = @intCast(i32, iu >> 20) - 0x3FF;
152151
153152 // correction to avoid underflow in c / u
154153 if (k < 54) {
......@@ -171,7 +170,7 @@ fn log1p_64(x: f64) f64 {
171170 const t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
172171 const t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
173172 const R = t2 + t1;
174 const dk = f64(k);
173 const dk = @intToFloat(f64, k);
175174
176175 return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
177176}
std/math/log2.zig+14-16
......@@ -14,7 +14,7 @@ const TypeId = builtin.TypeId;
1414pub fn log2(x: var) @typeOf(x) {
1515 const T = @typeOf(x);
1616 switch (@typeId(T)) {
17 TypeId.FloatLiteral => {
17 TypeId.ComptimeFloat => {
1818 return @typeOf(1.0)(log2_64(x));
1919 },
2020 TypeId.Float => {
......@@ -24,26 +24,24 @@ pub fn log2(x: var) @typeOf(x) {
2424 else => @compileError("log2 not implemented for " ++ @typeName(T)),
2525 };
2626 },
27 TypeId.IntLiteral => comptime {
27 TypeId.ComptimeInt => comptime {
2828 var result = 0;
2929 var x_shifted = x;
30 while (b: {x_shifted >>= 1; break :b x_shifted != 0;}) : (result += 1) {}
30 while (b: {
31 x_shifted >>= 1;
32 break :b x_shifted != 0;
33 }) : (result += 1) {}
3134 return result;
3235 },
3336 TypeId.Int => {
34 return log2_int(T, x);
37 return math.log2_int(T, x);
3538 },
3639 else => @compileError("log2 not implemented for " ++ @typeName(T)),
3740 }
3841}
3942
40pub fn log2_int(comptime T: type, x: T) T {
41 assert(x != 0);
42 return T.bit_count - 1 - T(@clz(x));
43}
44
4543pub fn log2_32(x_: f32) f32 {
46 const ivln2hi: f32 = 1.4428710938e+00;
44 const ivln2hi: f32 = 1.4428710938e+00;
4745 const ivln2lo: f32 = -1.7605285393e-04;
4846 const Lg1: f32 = 0xaaaaaa.0p-24;
4947 const Lg2: f32 = 0xccce13.0p-25;
......@@ -77,7 +75,7 @@ pub fn log2_32(x_: f32) f32 {
7775
7876 // x into [sqrt(2) / 2, sqrt(2)]
7977 ix += 0x3F800000 - 0x3F3504F3;
80 k += i32(ix >> 23) - 0x7F;
78 k += @intCast(i32, ix >> 23) - 0x7F;
8179 ix = (ix & 0x007FFFFF) + 0x3F3504F3;
8280 x = @bitCast(f32, ix);
8381
......@@ -95,7 +93,7 @@ pub fn log2_32(x_: f32) f32 {
9593 u &= 0xFFFFF000;
9694 hi = @bitCast(f32, u);
9795 const lo = f - hi - hfsq + s * (hfsq + R);
98 return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k);
96 return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @intToFloat(f32, k);
9997}
10098
10199pub fn log2_64(x_: f64) f64 {
......@@ -111,7 +109,7 @@ pub fn log2_64(x_: f64) f64 {
111109
112110 var x = x_;
113111 var ix = @bitCast(u64, x);
114 var hx = u32(ix >> 32);
112 var hx = @intCast(u32, ix >> 32);
115113 var k: i32 = 0;
116114
117115 if (hx < 0x00100000 or hx >> 31 != 0) {
......@@ -127,7 +125,7 @@ pub fn log2_64(x_: f64) f64 {
127125 // subnormal, scale x
128126 k -= 54;
129127 x *= 0x1.0p54;
130 hx = u32(@bitCast(u64, x) >> 32);
128 hx = @intCast(u32, @bitCast(u64, x) >> 32);
131129 } else if (hx >= 0x7FF00000) {
132130 return x;
133131 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
......@@ -136,7 +134,7 @@ pub fn log2_64(x_: f64) f64 {
136134
137135 // x into [sqrt(2) / 2, sqrt(2)]
138136 hx += 0x3FF00000 - 0x3FE6A09E;
139 k += i32(hx >> 20) - 0x3FF;
137 k += @intCast(i32, hx >> 20) - 0x3FF;
140138 hx = (hx & 0x000FFFFF) + 0x3FE6A09E;
141139 ix = (u64(hx) << 32) | (ix & 0xFFFFFFFF);
142140 x = @bitCast(f64, ix);
......@@ -161,7 +159,7 @@ pub fn log2_64(x_: f64) f64 {
161159 var val_lo = (lo + hi) * ivln2lo + lo * ivln2hi;
162160
163161 // spadd(val_hi, val_lo, y)
164 const y = f64(k);
162 const y = @intToFloat(f64, k);
165163 const ww = y + val_hi;
166164 val_lo += (y - ww) + val_hi;
167165 val_hi = ww;
std/math/modf.zig+4-4
......@@ -29,7 +29,7 @@ fn modf32(x: f32) modf32_result {
2929 var result: modf32_result = undefined;
3030
3131 const u = @bitCast(u32, x);
32 const e = i32((u >> 23) & 0xFF) - 0x7F;
32 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
3333 const us = u & 0x80000000;
3434
3535 // TODO: Shouldn't need this.
......@@ -57,7 +57,7 @@ fn modf32(x: f32) modf32_result {
5757 return result;
5858 }
5959
60 const mask = u32(0x007FFFFF) >> u5(e);
60 const mask = u32(0x007FFFFF) >> @intCast(u5, e);
6161 if (u & mask == 0) {
6262 result.ipart = x;
6363 result.fpart = @bitCast(f32, us);
......@@ -74,7 +74,7 @@ fn modf64(x: f64) modf64_result {
7474 var result: modf64_result = undefined;
7575
7676 const u = @bitCast(u64, x);
77 const e = i32((u >> 52) & 0x7FF) - 0x3FF;
77 const e = @intCast(i32, (u >> 52) & 0x7FF) - 0x3FF;
7878 const us = u & (1 << 63);
7979
8080 if (math.isInf(x)) {
......@@ -101,7 +101,7 @@ fn modf64(x: f64) modf64_result {
101101 return result;
102102 }
103103
104 const mask = u64(@maxValue(u64) >> 12) >> u6(e);
104 const mask = u64(@maxValue(u64) >> 12) >> @intCast(u6, e);
105105 if (u & mask == 0) {
106106 result.ipart = x;
107107 result.fpart = @bitCast(f64, us);
std/math/nan.zig+2
......@@ -2,6 +2,7 @@ const math = @import("index.zig");
22
33pub fn nan(comptime T: type) T {
44 return switch (T) {
5 f16 => @bitCast(f16, math.nan_u16),
56 f32 => @bitCast(f32, math.nan_u32),
67 f64 => @bitCast(f64, math.nan_u64),
78 else => @compileError("nan not implemented for " ++ @typeName(T)),
......@@ -12,6 +13,7 @@ pub fn nan(comptime T: type) T {
1213// representation in the future when required.
1314pub fn snan(comptime T: type) T {
1415 return switch (T) {
16 f16 => @bitCast(f16, math.nan_u16),
1517 f32 => @bitCast(f32, math.nan_u32),
1618 f64 => @bitCast(f64, math.nan_u64),
1719 else => @compileError("snan not implemented for " ++ @typeName(T)),
std/math/pow.zig+2-3
......@@ -28,7 +28,6 @@ const assert = std.debug.assert;
2828
2929// This implementation is taken from the go stlib, musl is a bit more complex.
3030pub fn pow(comptime T: type, x: T, y: T) T {
31
3231 @setFloatMode(this, @import("builtin").FloatMode.Strict);
3332
3433 if (T != f32 and T != f64) {
......@@ -147,7 +146,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
147146 var xe = r2.exponent;
148147 var x1 = r2.significand;
149148
150 var i = i32(yi);
149 var i = @floatToInt(i32, yi);
151150 while (i != 0) : (i >>= 1) {
152151 if (i & 1 == 1) {
153152 a1 *= x1;
......@@ -172,7 +171,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
172171
173172fn isOddInteger(x: f64) bool {
174173 const r = math.modf(x);
175 return r.fpart == 0.0 and i64(r.ipart) & 1 == 1;
174 return r.fpart == 0.0 and @floatToInt(i64, r.ipart) & 1 == 1;
176175}
177176
178177test "math.pow" {
std/math/round.zig+4-4
......@@ -24,13 +24,13 @@ fn round32(x_: f32) f32 {
2424 const e = (u >> 23) & 0xFF;
2525 var y: f32 = undefined;
2626
27 if (e >= 0x7F+23) {
27 if (e >= 0x7F + 23) {
2828 return x;
2929 }
3030 if (u >> 31 != 0) {
3131 x = -x;
3232 }
33 if (e < 0x7F-1) {
33 if (e < 0x7F - 1) {
3434 math.forceEval(x + math.f32_toint);
3535 return 0 * @bitCast(f32, u);
3636 }
......@@ -61,13 +61,13 @@ fn round64(x_: f64) f64 {
6161 const e = (u >> 52) & 0x7FF;
6262 var y: f64 = undefined;
6363
64 if (e >= 0x3FF+52) {
64 if (e >= 0x3FF + 52) {
6565 return x;
6666 }
6767 if (u >> 63 != 0) {
6868 x = -x;
6969 }
70 if (e < 0x3ff-1) {
70 if (e < 0x3ff - 1) {
7171 math.forceEval(x + math.f64_toint);
7272 return 0 * @bitCast(f64, u);
7373 }
std/math/scalbn.zig+2-2
......@@ -37,7 +37,7 @@ fn scalbn32(x: f32, n_: i32) f32 {
3737 }
3838 }
3939
40 const u = u32(n +% 0x7F) << 23;
40 const u = @intCast(u32, n +% 0x7F) << 23;
4141 return y * @bitCast(f32, u);
4242}
4343
......@@ -67,7 +67,7 @@ fn scalbn64(x: f64, n_: i32) f64 {
6767 }
6868 }
6969
70 const u = u64(n +% 0x3FF) << 52;
70 const u = @intCast(u64, n +% 0x3FF) << 52;
7171 return y * @bitCast(f64, u);
7272}
7373
std/math/signbit.zig+12
......@@ -5,12 +5,18 @@ const assert = std.debug.assert;
55pub fn signbit(x: var) bool {
66 const T = @typeOf(x);
77 return switch (T) {
8 f16 => signbit16(x),
89 f32 => signbit32(x),
910 f64 => signbit64(x),
1011 else => @compileError("signbit not implemented for " ++ @typeName(T)),
1112 };
1213}
1314
15fn signbit16(x: f16) bool {
16 const bits = @bitCast(u16, x);
17 return bits >> 15 != 0;
18}
19
1420fn signbit32(x: f32) bool {
1521 const bits = @bitCast(u32, x);
1622 return bits >> 31 != 0;
......@@ -22,10 +28,16 @@ fn signbit64(x: f64) bool {
2228}
2329
2430test "math.signbit" {
31 assert(signbit(f16(4.0)) == signbit16(4.0));
2532 assert(signbit(f32(4.0)) == signbit32(4.0));
2633 assert(signbit(f64(4.0)) == signbit64(4.0));
2734}
2835
36test "math.signbit16" {
37 assert(!signbit16(4.0));
38 assert(signbit16(-3.0));
39}
40
2941test "math.signbit32" {
3042 assert(!signbit32(4.0));
3143 assert(signbit32(-3.0));
std/math/sin.zig+8-8
......@@ -19,20 +19,20 @@ pub fn sin(x: var) @typeOf(x) {
1919}
2020
2121// sin polynomial coefficients
22const S0 = 1.58962301576546568060E-10;
22const S0 = 1.58962301576546568060E-10;
2323const S1 = -2.50507477628578072866E-8;
24const S2 = 2.75573136213857245213E-6;
24const S2 = 2.75573136213857245213E-6;
2525const S3 = -1.98412698295895385996E-4;
26const S4 = 8.33333333332211858878E-3;
26const S4 = 8.33333333332211858878E-3;
2727const S5 = -1.66666666666666307295E-1;
2828
2929// cos polynomial coeffiecients
3030const C0 = -1.13585365213876817300E-11;
31const C1 = 2.08757008419747316778E-9;
31const C1 = 2.08757008419747316778E-9;
3232const C2 = -2.75573141792967388112E-7;
33const C3 = 2.48015872888517045348E-5;
33const C3 = 2.48015872888517045348E-5;
3434const C4 = -1.38888888888730564116E-3;
35const C5 = 4.16666666666665929218E-2;
35const C5 = 4.16666666666665929218E-2;
3636
3737// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
3838//
......@@ -60,7 +60,7 @@ fn sin32(x_: f32) f32 {
6060 }
6161
6262 var y = math.floor(x * m4pi);
63 var j = i64(y);
63 var j = @floatToInt(i64, y);
6464
6565 if (j & 1 == 1) {
6666 j += 1;
......@@ -112,7 +112,7 @@ fn sin64(x_: f64) f64 {
112112 }
113113
114114 var y = math.floor(x * m4pi);
115 var j = i64(y);
115 var j = @floatToInt(i64, y);
116116
117117 if (j & 1 == 1) {
118118 j += 1;
std/math/sinh.zig+1-1
......@@ -57,7 +57,7 @@ fn sinh64(x: f64) f64 {
5757 @setFloatMode(this, @import("builtin").FloatMode.Strict);
5858
5959 const u = @bitCast(u64, x);
60 const w = u32(u >> 32);
60 const w = @intCast(u32, u >> 32);
6161 const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
6262
6363 if (x == 0.0 or math.isNan(x)) {
std/math/sqrt.zig+56-262
......@@ -14,27 +14,9 @@ const TypeId = builtin.TypeId;
1414pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typeOf(x).bit_count / 2) else @typeOf(x)) {
1515 const T = @typeOf(x);
1616 switch (@typeId(T)) {
17 TypeId.FloatLiteral => {
18 return T(sqrt64(x));
19 },
20 TypeId.Float => {
21 switch (T) {
22 f32 => {
23 switch (builtin.arch) {
24 builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt32(x),
25 else => return sqrt32(x),
26 }
27 },
28 f64 => {
29 switch (builtin.arch) {
30 builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt64(x),
31 else => return sqrt64(x),
32 }
33 },
34 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
35 }
36 },
37 TypeId.IntLiteral => comptime {
17 TypeId.ComptimeFloat => return T(@sqrt(f64, x)), // TODO upgrade to f128
18 TypeId.Float => return @sqrt(T, x),
19 TypeId.ComptimeInt => comptime {
3820 if (x > @maxValue(u128)) {
3921 @compileError("sqrt not implemented for comptime_int greater than 128 bits");
4022 }
......@@ -43,269 +25,81 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ
4325 }
4426 return T(sqrt_int(u128, x));
4527 },
46 TypeId.Int => {
47 return sqrt_int(T, x);
48 },
28 TypeId.Int => return sqrt_int(T, x),
4929 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
5030 }
5131}
5232
53fn sqrt32(x: f32) f32 {
54 const tiny: f32 = 1.0e-30;
55 const sign: i32 = @bitCast(i32, u32(0x80000000));
56 var ix: i32 = @bitCast(i32, x);
57
58 if ((ix & 0x7F800000) == 0x7F800000) {
59 return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
60 }
61
62 // zero
63 if (ix <= 0) {
64 if (ix & ~sign == 0) {
65 return x; // sqrt (+-0) = +-0
66 }
67 if (ix < 0) {
68 return math.snan(f32);
69 }
70 }
71
72 // normalize
73 var m = ix >> 23;
74 if (m == 0) {
75 // subnormal
76 var i: i32 = 0;
77 while (ix & 0x00800000 == 0) : (i += 1) {
78 ix <<= 1;
79 }
80 m -= i - 1;
81 }
82
83 m -= 127; // unbias exponent
84 ix = (ix & 0x007FFFFF) | 0x00800000;
85
86 if (m & 1 != 0) { // odd m, double x to even
87 ix += ix;
88 }
89
90 m >>= 1; // m = [m / 2]
91
92 // sqrt(x) bit by bit
93 ix += ix;
94 var q: i32 = 0; // q = sqrt(x)
95 var s: i32 = 0;
96 var r: i32 = 0x01000000; // r = moving bit right -> left
97
98 while (r != 0) {
99 const t = s + r;
100 if (t <= ix) {
101 s = t + r;
102 ix -= t;
103 q += r;
104 }
105 ix += ix;
106 r >>= 1;
107 }
108
109 // floating add to find rounding direction
110 if (ix != 0) {
111 var z = 1.0 - tiny; // inexact
112 if (z >= 1.0) {
113 z = 1.0 + tiny;
114 if (z > 1.0) {
115 q += 2;
116 } else {
117 if (q & 1 != 0) {
118 q += 1;
119 }
120 }
121 }
122 }
123
124 ix = (q >> 1) + 0x3f000000;
125 ix += m << 23;
126 return @bitCast(f32, ix);
33test "math.sqrt" {
34 assert(sqrt(f16(0.0)) == @sqrt(f16, 0.0));
35 assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0));
36 assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0));
12737}
12838
129// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
130// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
131// potentially some edge cases remaining that are not handled in the same way.
132fn sqrt64(x: f64) f64 {
133 const tiny: f64 = 1.0e-300;
134 const sign: u32 = 0x80000000;
135 const u = @bitCast(u64, x);
136
137 var ix0 = u32(u >> 32);
138 var ix1 = u32(u & 0xFFFFFFFF);
139
140 // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
141 if (ix0 & 0x7FF00000 == 0x7FF00000) {
142 return x * x + x;
143 }
144
145 // sqrt(+-0) = +-0
146 if (x == 0.0) {
147 return x;
148 }
149 // sqrt(-ve) = snan
150 if (ix0 & sign != 0) {
151 return math.snan(f64);
152 }
153
154 // normalize x
155 var m = i32(ix0 >> 20);
156 if (m == 0) {
157 // subnormal
158 while (ix0 == 0) {
159 m -= 21;
160 ix0 |= ix1 >> 11;
161 ix1 <<= 21;
162 }
163
164 // subnormal
165 var i: u32 = 0;
166 while (ix0 & 0x00100000 == 0) : (i += 1) {
167 ix0 <<= 1;
168 }
169 m -= i32(i) - 1;
170 ix0 |= ix1 >> u5(32 - i);
171 ix1 <<= u5(i);
172 }
173
174 // unbias exponent
175 m -= 1023;
176 ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
177 if (m & 1 != 0) {
178 ix0 += ix0 + (ix1 >> 31);
179 ix1 = ix1 +% ix1;
180 }
181 m >>= 1;
182
183 // sqrt(x) bit by bit
184 ix0 += ix0 + (ix1 >> 31);
185 ix1 = ix1 +% ix1;
186
187 var q: u32 = 0;
188 var q1: u32 = 0;
189 var s0: u32 = 0;
190 var s1: u32 = 0;
191 var r: u32 = 0x00200000;
192 var t: u32 = undefined;
193 var t1: u32 = undefined;
194
195 while (r != 0) {
196 t = s0 +% r;
197 if (t <= ix0) {
198 s0 = t + r;
199 ix0 -= t;
200 q += r;
201 }
202 ix0 = ix0 +% ix0 +% (ix1 >> 31);
203 ix1 = ix1 +% ix1;
204 r >>= 1;
205 }
206
207 r = sign;
208 while (r != 0) {
209 t = s1 +% r;
210 t = s0;
211 if (t < ix0 or (t == ix0 and t1 <= ix1)) {
212 s1 = t1 +% r;
213 if (t1 & sign == sign and s1 & sign == 0) {
214 s0 += 1;
215 }
216 ix0 -= t;
217 if (ix1 < t1) {
218 ix0 -= 1;
219 }
220 ix1 = ix1 -% t1;
221 q1 += r;
222 }
223 ix0 = ix0 +% ix0 +% (ix1 >> 31);
224 ix1 = ix1 +% ix1;
225 r >>= 1;
226 }
227
228 // rounding direction
229 if (ix0 | ix1 != 0) {
230 var z = 1.0 - tiny; // raise inexact
231 if (z >= 1.0) {
232 z = 1.0 + tiny;
233 if (q1 == 0xFFFFFFFF) {
234 q1 = 0;
235 q += 1;
236 } else if (z > 1.0) {
237 if (q1 == 0xFFFFFFFE) {
238 q += 1;
239 }
240 q1 += 2;
241 } else {
242 q1 += q1 & 1;
243 }
244 }
245 }
246
247 ix0 = (q >> 1) + 0x3FE00000;
248 ix1 = q1 >> 1;
249 if (q & 1 != 0) {
250 ix1 |= 0x80000000;
251 }
252
253 // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
254 // behaviour at least.
255 var iix0 = i32(ix0);
256 iix0 = iix0 +% (m << 20);
39test "math.sqrt16" {
40 const epsilon = 0.000001;
25741
258 const uz = (u64(iix0) << 32) | ix1;
259 return @bitCast(f64, uz);
260}
261
262test "math.sqrt" {
263 assert(sqrt(f32(0.0)) == sqrt32(0.0));
264 assert(sqrt(f64(0.0)) == sqrt64(0.0));
42 assert(@sqrt(f16, 0.0) == 0.0);
43 assert(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon));
44 assert(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon));
45 assert(@sqrt(f16, 4.0) == 2.0);
46 assert(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon));
47 assert(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon));
48 assert(@sqrt(f16, 64.0) == 8.0);
49 assert(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon));
50 assert(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon));
26551}
26652
26753test "math.sqrt32" {
26854 const epsilon = 0.000001;
26955
270 assert(sqrt32(0.0) == 0.0);
271 assert(math.approxEq(f32, sqrt32(2.0), 1.414214, epsilon));
272 assert(math.approxEq(f32, sqrt32(3.6), 1.897367, epsilon));
273 assert(sqrt32(4.0) == 2.0);
274 assert(math.approxEq(f32, sqrt32(7.539840), 2.745877, epsilon));
275 assert(math.approxEq(f32, sqrt32(19.230934), 4.385309, epsilon));
276 assert(sqrt32(64.0) == 8.0);
277 assert(math.approxEq(f32, sqrt32(64.1), 8.006248, epsilon));
278 assert(math.approxEq(f32, sqrt32(8942.230469), 94.563370, epsilon));
56 assert(@sqrt(f32, 0.0) == 0.0);
57 assert(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon));
58 assert(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon));
59 assert(@sqrt(f32, 4.0) == 2.0);
60 assert(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon));
61 assert(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon));
62 assert(@sqrt(f32, 64.0) == 8.0);
63 assert(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon));
64 assert(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon));
27965}
28066
28167test "math.sqrt64" {
28268 const epsilon = 0.000001;
28369
284 assert(sqrt64(0.0) == 0.0);
285 assert(math.approxEq(f64, sqrt64(2.0), 1.414214, epsilon));
286 assert(math.approxEq(f64, sqrt64(3.6), 1.897367, epsilon));
287 assert(sqrt64(4.0) == 2.0);
288 assert(math.approxEq(f64, sqrt64(7.539840), 2.745877, epsilon));
289 assert(math.approxEq(f64, sqrt64(19.230934), 4.385309, epsilon));
290 assert(sqrt64(64.0) == 8.0);
291 assert(math.approxEq(f64, sqrt64(64.1), 8.006248, epsilon));
292 assert(math.approxEq(f64, sqrt64(8942.230469), 94.563367, epsilon));
70 assert(@sqrt(f64, 0.0) == 0.0);
71 assert(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon));
72 assert(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon));
73 assert(@sqrt(f64, 4.0) == 2.0);
74 assert(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon));
75 assert(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon));
76 assert(@sqrt(f64, 64.0) == 8.0);
77 assert(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon));
78 assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon));
79}
80
81test "math.sqrt16.special" {
82 assert(math.isPositiveInf(@sqrt(f16, math.inf(f16))));
83 assert(@sqrt(f16, 0.0) == 0.0);
84 assert(@sqrt(f16, -0.0) == -0.0);
85 assert(math.isNan(@sqrt(f16, -1.0)));
86 assert(math.isNan(@sqrt(f16, math.nan(f16))));
29387}
29488
29589test "math.sqrt32.special" {
296 assert(math.isPositiveInf(sqrt32(math.inf(f32))));
297 assert(sqrt32(0.0) == 0.0);
298 assert(sqrt32(-0.0) == -0.0);
299 assert(math.isNan(sqrt32(-1.0)));
300 assert(math.isNan(sqrt32(math.nan(f32))));
90 assert(math.isPositiveInf(@sqrt(f32, math.inf(f32))));
91 assert(@sqrt(f32, 0.0) == 0.0);
92 assert(@sqrt(f32, -0.0) == -0.0);
93 assert(math.isNan(@sqrt(f32, -1.0)));
94 assert(math.isNan(@sqrt(f32, math.nan(f32))));
30195}
30296
30397test "math.sqrt64.special" {
304 assert(math.isPositiveInf(sqrt64(math.inf(f64))));
305 assert(sqrt64(0.0) == 0.0);
306 assert(sqrt64(-0.0) == -0.0);
307 assert(math.isNan(sqrt64(-1.0)));
308 assert(math.isNan(sqrt64(math.nan(f64))));
98 assert(math.isPositiveInf(@sqrt(f64, math.inf(f64))));
99 assert(@sqrt(f64, 0.0) == 0.0);
100 assert(@sqrt(f64, -0.0) == -0.0);
101 assert(math.isNan(@sqrt(f64, -1.0)));
102 assert(math.isNan(@sqrt(f64, math.nan(f64))));
309103}
310104
311105fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) {
......@@ -328,7 +122,7 @@ fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) {
328122 }
329123
330124 const ResultType = @IntType(false, T.bit_count / 2);
331 return ResultType(res);
125 return @intCast(ResultType, res);
332126}
333127
334128test "math.sqrt_int" {
std/math/tan.zig+5-5
......@@ -19,12 +19,12 @@ pub fn tan(x: var) @typeOf(x) {
1919}
2020
2121const Tp0 = -1.30936939181383777646E4;
22const Tp1 = 1.15351664838587416140E6;
22const Tp1 = 1.15351664838587416140E6;
2323const Tp2 = -1.79565251976484877988E7;
2424
25const Tq1 = 1.36812963470692954678E4;
25const Tq1 = 1.36812963470692954678E4;
2626const Tq2 = -1.32089234440210967447E6;
27const Tq3 = 2.50083801823357915839E7;
27const Tq3 = 2.50083801823357915839E7;
2828const Tq4 = -5.38695755929454629881E7;
2929
3030// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
......@@ -53,7 +53,7 @@ fn tan32(x_: f32) f32 {
5353 }
5454
5555 var y = math.floor(x * m4pi);
56 var j = i64(y);
56 var j = @floatToInt(i64, y);
5757
5858 if (j & 1 == 1) {
5959 j += 1;
......@@ -102,7 +102,7 @@ fn tan64(x_: f64) f64 {
102102 }
103103
104104 var y = math.floor(x * m4pi);
105 var j = i64(y);
105 var j = @floatToInt(i64, y);
106106
107107 if (j & 1 == 1) {
108108 j += 1;
std/math/tanh.zig+2-2
......@@ -68,7 +68,7 @@ fn tanh32(x: f32) f32 {
6868
6969fn tanh64(x: f64) f64 {
7070 const u = @bitCast(u64, x);
71 const w = u32(u >> 32);
71 const w = @intCast(u32, u >> 32);
7272 const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
7373
7474 var t: f64 = undefined;
......@@ -100,7 +100,7 @@ fn tanh64(x: f64) f64 {
100100 }
101101 // |x| is subnormal
102102 else {
103 math.forceEval(f32(x));
103 math.forceEval(@floatCast(f32, x));
104104 t = x;
105105 }
106106
std/math/trunc.zig+4-4
......@@ -19,7 +19,7 @@ pub fn trunc(x: var) @typeOf(x) {
1919
2020fn trunc32(x: f32) f32 {
2121 const u = @bitCast(u32, x);
22 var e = i32(((u >> 23) & 0xFF)) - 0x7F + 9;
22 var e = @intCast(i32, ((u >> 23) & 0xFF)) - 0x7F + 9;
2323 var m: u32 = undefined;
2424
2525 if (e >= 23 + 9) {
......@@ -29,7 +29,7 @@ fn trunc32(x: f32) f32 {
2929 e = 1;
3030 }
3131
32 m = u32(@maxValue(u32)) >> u5(e);
32 m = u32(@maxValue(u32)) >> @intCast(u5, e);
3333 if (u & m == 0) {
3434 return x;
3535 } else {
......@@ -40,7 +40,7 @@ fn trunc32(x: f32) f32 {
4040
4141fn trunc64(x: f64) f64 {
4242 const u = @bitCast(u64, x);
43 var e = i32(((u >> 52) & 0x7FF)) - 0x3FF + 12;
43 var e = @intCast(i32, ((u >> 52) & 0x7FF)) - 0x3FF + 12;
4444 var m: u64 = undefined;
4545
4646 if (e >= 52 + 12) {
......@@ -50,7 +50,7 @@ fn trunc64(x: f64) f64 {
5050 e = 1;
5151 }
5252
53 m = u64(@maxValue(u64)) >> u6(e);
53 m = u64(@maxValue(u64)) >> @intCast(u6, e);
5454 if (u & m == 0) {
5555 return x;
5656 } else {
std/math/x86_64/sqrt.zig deleted-15
......@@ -1,15 +0,0 @@
1pub fn sqrt32(x: f32) f32 {
2 return asm (
3 \\sqrtss %%xmm0, %%xmm0
4 : [ret] "={xmm0}" (-> f32)
5 : [x] "{xmm0}" (x)
6 );
7}
8
9pub fn sqrt64(x: f64) f64 {
10 return asm (
11 \\sqrtsd %%xmm0, %%xmm0
12 : [ret] "={xmm0}" (-> f64)
13 : [x] "{xmm0}" (x)
14 );
15}
std/mem.zig+274-95
......@@ -6,94 +6,111 @@ const builtin = @import("builtin");
66const mem = this;
77
88pub const Allocator = struct {
9 const Error = error {OutOfMemory};
9 pub const Error = error{OutOfMemory};
1010
1111 /// Allocate byte_count bytes and return them in a slice, with the
1212 /// slice's pointer aligned at least to alignment bytes.
1313 /// The returned newly allocated memory is undefined.
14 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
14 /// `alignment` is guaranteed to be >= 1
15 /// `alignment` is guaranteed to be a power of 2
16 allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8,
1517
1618 /// If `new_byte_count > old_mem.len`:
1719 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
1820 /// * alignment >= alignment of old_mem.ptr
1921 ///
2022 /// If `new_byte_count <= old_mem.len`:
21 /// * this function must return successfully.
23 /// * this function must return successfully.
2224 /// * alignment <= alignment of old_mem.ptr
2325 ///
24 /// The returned newly allocated memory is undefined.
25 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
26 /// When `reallocFn` returns,
27 /// `return_value[0..min(old_mem.len, new_byte_count)]` must be the same
28 /// as `old_mem` was when `reallocFn` is called. The bytes of
29 /// `return_value[old_mem.len..]` have undefined values.
30 /// `alignment` is guaranteed to be >= 1
31 /// `alignment` is guaranteed to be a power of 2
32 reallocFn: fn (self: *Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
2633
2734 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
28 freeFn: fn (self: &Allocator, old_mem: []u8) void,
35 freeFn: fn (self: *Allocator, old_mem: []u8) void,
36
37 /// Call `destroy` with the result
38 /// TODO this is deprecated. use createOne instead
39 pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) {
40 const T = @typeOf(init);
41 if (@sizeOf(T) == 0) return &(T{});
42 const slice = try self.alloc(T, 1);
43 const ptr = &slice[0];
44 ptr.* = init;
45 return ptr;
46 }
2947
30 fn create(self: &Allocator, comptime T: type) !&T {
48 /// Call `destroy` with the result.
49 /// Returns undefined memory.
50 pub fn createOne(self: *Allocator, comptime T: type) Error!*T {
51 if (@sizeOf(T) == 0) return &(T{});
3152 const slice = try self.alloc(T, 1);
3253 return &slice[0];
3354 }
3455
35 fn destroy(self: &Allocator, ptr: var) void {
36 self.free(ptr[0..1]);
56 /// `ptr` should be the return value of `create`
57 pub fn destroy(self: *Allocator, ptr: var) void {
58 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
59 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);
3760 }
3861
39 fn alloc(self: &Allocator, comptime T: type, n: usize) ![]T {
62 pub fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {
4063 return self.alignedAlloc(T, @alignOf(T), n);
4164 }
4265
43 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
44 n: usize) ![]align(alignment) T
45 {
66 pub fn alignedAlloc(self: *Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {
4667 if (n == 0) {
47 return (&align(alignment) T)(undefined)[0..0];
68 return ([*]align(alignment) T)(undefined)[0..0];
4869 }
4970 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
5071 const byte_slice = try self.allocFn(self, byte_count, alignment);
5172 assert(byte_slice.len == byte_count);
52 // This loop should get optimized out in ReleaseFast mode
73 // This loop gets optimized out in ReleaseFast mode
5374 for (byte_slice) |*byte| {
54 *byte = undefined;
75 byte.* = undefined;
5576 }
56 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
77 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
5778 }
5879
59 fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
80 pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
6081 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
6182 }
6283
63 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
64 old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
65 {
84 pub fn alignedRealloc(self: *Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {
6685 if (old_mem.len == 0) {
67 return self.alloc(T, n);
86 return self.alignedAlloc(T, alignment, n);
6887 }
6988 if (n == 0) {
7089 self.free(old_mem);
71 return (&align(alignment) T)(undefined)[0..0];
90 return ([*]align(alignment) T)(undefined)[0..0];
7291 }
7392
74 const old_byte_slice = ([]u8)(old_mem);
93 const old_byte_slice = @sliceToBytes(old_mem);
7594 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
7695 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
7796 assert(byte_slice.len == byte_count);
7897 if (n > old_mem.len) {
79 // This loop should get optimized out in ReleaseFast mode
98 // This loop gets optimized out in ReleaseFast mode
8099 for (byte_slice[old_byte_slice.len..]) |*byte| {
81 *byte = undefined;
100 byte.* = undefined;
82101 }
83102 }
84 return ([]T)(@alignCast(alignment, byte_slice));
103 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
85104 }
86105
87106 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
88107 /// Unlike `realloc`, this function cannot fail.
89108 /// Shrinking to 0 is the same as calling `free`.
90 fn shrink(self: &Allocator, comptime T: type, old_mem: []T, n: usize) []T {
109 pub fn shrink(self: *Allocator, comptime T: type, old_mem: []T, n: usize) []T {
91110 return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
92111 }
93112
94 fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29,
95 old_mem: []align(alignment) T, n: usize) []align(alignment) T
96 {
113 pub fn alignedShrink(self: *Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {
97114 if (n == 0) {
98115 self.free(old_mem);
99116 return old_mem[0..0];
......@@ -105,33 +122,51 @@ pub const Allocator = struct {
105122 // n <= old_mem.len and the multiplication didn't overflow for that operation.
106123 const byte_count = @sizeOf(T) * n;
107124
108 const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable;
125 const byte_slice = self.reallocFn(self, @sliceToBytes(old_mem), byte_count, alignment) catch unreachable;
109126 assert(byte_slice.len == byte_count);
110 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
127 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
111128 }
112129
113 fn free(self: &Allocator, memory: var) void {
114 const bytes = ([]const u8)(memory);
115 if (bytes.len == 0)
116 return;
117 const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
130 pub fn free(self: *Allocator, memory: var) void {
131 const bytes = @sliceToBytes(memory);
132 if (bytes.len == 0) return;
133 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
118134 self.freeFn(self, non_const_ptr[0..bytes.len]);
119135 }
120136};
121137
122138/// Copy all of source into dest at position 0.
123139/// dest.len must be >= source.len.
140/// dest.ptr must be <= src.ptr.
124141pub fn copy(comptime T: type, dest: []T, source: []const T) void {
125142 // TODO instead of manually doing this check for the whole array
126143 // and turning off runtime safety, the compiler should detect loops like
127144 // this and automatically omit safety checks for loops
128145 @setRuntimeSafety(false);
129146 assert(dest.len >= source.len);
130 for (source) |s, i| dest[i] = s;
147 for (source) |s, i|
148 dest[i] = s;
149}
150
151/// Copy all of source into dest at position 0.
152/// dest.len must be >= source.len.
153/// dest.ptr must be >= src.ptr.
154pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void {
155 // TODO instead of manually doing this check for the whole array
156 // and turning off runtime safety, the compiler should detect loops like
157 // this and automatically omit safety checks for loops
158 @setRuntimeSafety(false);
159 assert(dest.len >= source.len);
160 var i = source.len;
161 while (i > 0) {
162 i -= 1;
163 dest[i] = source[i];
164 }
131165}
132166
133167pub fn set(comptime T: type, dest: []T, value: T) void {
134 for (dest) |*d| *d = value;
168 for (dest) |*d|
169 d.* = value;
135170}
136171
137172/// Returns true if lhs < rhs, false otherwise
......@@ -163,13 +198,35 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
163198 return true;
164199}
165200
201/// Returns true if all elements in a slice are equal to the scalar value provided
202pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
203 for (slice) |item| {
204 if (item != scalar) return false;
205 }
206 return true;
207}
208
166209/// Copies ::m to newly allocated memory. Caller is responsible to free it.
167pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
210pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T {
168211 const new_buf = try allocator.alloc(T, m.len);
169212 copy(T, new_buf, m);
170213 return new_buf;
171214}
172215
216/// Remove values from the beginning of a slice.
217pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
218 var begin: usize = 0;
219 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
220 return slice[begin..];
221}
222
223/// Remove values from the end of a slice.
224pub fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
225 var end: usize = slice.len;
226 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
227 return slice[0..end];
228}
229
173230/// Remove values from the beginning and end of a slice.
174231pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
175232 var begin: usize = 0;
......@@ -180,6 +237,8 @@ pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []co
180237}
181238
182239test "mem.trim" {
240 assert(eql(u8, trimLeft(u8, " foo\n ", " \n"), "foo\n "));
241 assert(eql(u8, trimRight(u8, " foo\n ", " \n"), " foo"));
183242 assert(eql(u8, trim(u8, " foo\n ", " \n"), "foo"));
184243 assert(eql(u8, trim(u8, "foo", " \n"), "foo"));
185244}
......@@ -189,11 +248,20 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
189248 return indexOfScalarPos(T, slice, 0, value);
190249}
191250
251/// Linear search for the last index of a scalar value inside a slice.
252pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
253 var i: usize = slice.len;
254 while (i != 0) {
255 i -= 1;
256 if (slice[i] == value) return i;
257 }
258 return null;
259}
260
192261pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
193262 var i: usize = start_index;
194263 while (i < slice.len) : (i += 1) {
195 if (slice[i] == value)
196 return i;
264 if (slice[i] == value) return i;
197265 }
198266 return null;
199267}
......@@ -202,12 +270,22 @@ pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize
202270 return indexOfAnyPos(T, slice, 0, values);
203271}
204272
273pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
274 var i: usize = slice.len;
275 while (i != 0) {
276 i -= 1;
277 for (values) |value| {
278 if (slice[i] == value) return i;
279 }
280 }
281 return null;
282}
283
205284pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
206285 var i: usize = start_index;
207286 while (i < slice.len) : (i += 1) {
208287 for (values) |value| {
209 if (slice[i] == value)
210 return i;
288 if (slice[i] == value) return i;
211289 }
212290 }
213291 return null;
......@@ -217,25 +295,46 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
217295 return indexOfPos(T, haystack, 0, needle);
218296}
219297
298/// Find the index in a slice of a sub-slice, searching from the end backwards.
299/// To start looking at a different index, slice the haystack first.
300/// TODO is there even a better algorithm for this?
301pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
302 if (needle.len > haystack.len) return null;
303
304 var i: usize = haystack.len - needle.len;
305 while (true) : (i -= 1) {
306 if (mem.eql(T, haystack[i .. i + needle.len], needle)) return i;
307 if (i == 0) return null;
308 }
309}
310
220311// TODO boyer-moore algorithm
221312pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
222 if (needle.len > haystack.len)
223 return null;
313 if (needle.len > haystack.len) return null;
224314
225315 var i: usize = start_index;
226316 const end = haystack.len - needle.len;
227317 while (i <= end) : (i += 1) {
228 if (eql(T, haystack[i .. i + needle.len], needle))
229 return i;
318 if (eql(T, haystack[i .. i + needle.len], needle)) return i;
230319 }
231320 return null;
232321}
233322
234323test "mem.indexOf" {
235 assert(??indexOf(u8, "one two three four", "four") == 14);
324 assert(indexOf(u8, "one two three four", "four").? == 14);
325 assert(lastIndexOf(u8, "one two three two four", "two").? == 14);
236326 assert(indexOf(u8, "one two three four", "gour") == null);
237 assert(??indexOf(u8, "foo", "foo") == 0);
327 assert(lastIndexOf(u8, "one two three four", "gour") == null);
328 assert(indexOf(u8, "foo", "foo").? == 0);
329 assert(lastIndexOf(u8, "foo", "foo").? == 0);
238330 assert(indexOf(u8, "foo", "fool") == null);
331 assert(lastIndexOf(u8, "foo", "lfoo") == null);
332 assert(lastIndexOf(u8, "foo", "fool") == null);
333
334 assert(indexOf(u8, "foo foo", "foo").? == 0);
335 assert(lastIndexOf(u8, "foo foo", "foo").? == 4);
336 assert(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
337 assert(lastIndexOfScalar(u8, "boo", 'o').? == 2);
239338}
240339
241340/// Reads an integer from memory with size equal to bytes.len.
......@@ -256,7 +355,7 @@ pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T {
256355 builtin.Endian.Little => {
257356 const ShiftType = math.Log2Int(T);
258357 for (bytes) |b, index| {
259 result = result | (T(b) << ShiftType(index * 8));
358 result = result | (T(b) << @intCast(ShiftType, index * 8));
260359 }
261360 },
262361 }
......@@ -271,9 +370,12 @@ pub fn readIntBE(comptime T: type, bytes: []const u8) T {
271370 }
272371 assert(bytes.len == @sizeOf(T));
273372 var result: T = 0;
274 {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
275 result = (result << 8) | T(bytes[i]);
276 }}
373 {
374 comptime var i = 0;
375 inline while (i < @sizeOf(T)) : (i += 1) {
376 result = (result << 8) | T(bytes[i]);
377 }
378 }
277379 return result;
278380}
279381
......@@ -285,9 +387,12 @@ pub fn readIntLE(comptime T: type, bytes: []const u8) T {
285387 }
286388 assert(bytes.len == @sizeOf(T));
287389 var result: T = 0;
288 {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
289 result |= T(bytes[i]) << i * 8;
290 }}
390 {
391 comptime var i = 0;
392 inline while (i < @sizeOf(T)) : (i += 1) {
393 result |= T(bytes[i]) << i * 8;
394 }
395 }
291396 return result;
292397}
293398
......@@ -309,7 +414,7 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
309414 },
310415 builtin.Endian.Little => {
311416 for (buf) |*b| {
312 *b = @truncate(u8, bits);
417 b.* = @truncate(u8, bits);
313418 bits >>= 8;
314419 }
315420 },
......@@ -317,7 +422,6 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
317422 assert(bits == 0);
318423}
319424
320
321425pub fn hash_slice_u8(k: []const u8) u32 {
322426 // FNV 32-bit hash
323427 var h: u32 = 2166136261;
......@@ -336,7 +440,7 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
336440/// split(" abc def ghi ", " ")
337441/// Will return slices for "abc", "def", "ghi", null, in that order.
338442pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
339 return SplitIterator {
443 return SplitIterator{
340444 .index = 0,
341445 .buffer = buffer,
342446 .split_bytes = split_bytes,
......@@ -345,22 +449,36 @@ pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
345449
346450test "mem.split" {
347451 var it = split(" abc def ghi ", " ");
348 assert(eql(u8, ??it.next(), "abc"));
349 assert(eql(u8, ??it.next(), "def"));
350 assert(eql(u8, ??it.next(), "ghi"));
452 assert(eql(u8, it.next().?, "abc"));
453 assert(eql(u8, it.next().?, "def"));
454 assert(eql(u8, it.next().?, "ghi"));
351455 assert(it.next() == null);
352456}
353457
354458pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
355 return if (needle.len > haystack.len) false else eql(T, haystack[0 .. needle.len], needle);
459 return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
460}
461
462test "mem.startsWith" {
463 assert(startsWith(u8, "Bob", "Bo"));
464 assert(!startsWith(u8, "Needle in haystack", "haystack"));
465}
466
467pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
468 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
469}
470
471test "mem.endsWith" {
472 assert(endsWith(u8, "Needle in haystack", "haystack"));
473 assert(!endsWith(u8, "Bob", "Bo"));
356474}
357475
358476pub const SplitIterator = struct {
359477 buffer: []const u8,
360 split_bytes: []const u8,
478 split_bytes: []const u8,
361479 index: usize,
362480
363 pub fn next(self: &SplitIterator) ?[]const u8 {
481 pub fn next(self: *SplitIterator) ?[]const u8 {
364482 // move to beginning of token
365483 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
366484 const start = self.index;
......@@ -376,14 +494,14 @@ pub const SplitIterator = struct {
376494 }
377495
378496 /// Returns a slice of the remaining bytes. Does not affect iterator state.
379 pub fn rest(self: &const SplitIterator) []const u8 {
497 pub fn rest(self: *const SplitIterator) []const u8 {
380498 // move to beginning of token
381499 var index: usize = self.index;
382500 while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {}
383501 return self.buffer[index..];
384502 }
385503
386 fn isSplitByte(self: &const SplitIterator, byte: u8) bool {
504 fn isSplitByte(self: *const SplitIterator, byte: u8) bool {
387505 for (self.split_bytes) |split_byte| {
388506 if (byte == split_byte) {
389507 return true;
......@@ -395,7 +513,7 @@ pub const SplitIterator = struct {
395513
396514/// Naively combines a series of strings with a separator.
397515/// Allocates memory for the result, which must be freed by the caller.
398pub fn join(allocator: &Allocator, sep: u8, strings: ...) ![]u8 {
516pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {
399517 comptime assert(strings.len >= 1);
400518 var total_strings_len: usize = strings.len; // 1 sep per string
401519 {
......@@ -443,29 +561,47 @@ test "testReadInt" {
443561}
444562fn testReadIntImpl() void {
445563 {
446 const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
447 assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
448 assert(readIntBE(u32, bytes) == 0x12345678);
449 assert(readIntBE(i32, bytes) == 0x12345678);
564 const bytes = []u8{
565 0x12,
566 0x34,
567 0x56,
568 0x78,
569 };
570 assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
571 assert(readIntBE(u32, bytes) == 0x12345678);
572 assert(readIntBE(i32, bytes) == 0x12345678);
450573 assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
451 assert(readIntLE(u32, bytes) == 0x78563412);
452 assert(readIntLE(i32, bytes) == 0x78563412);
574 assert(readIntLE(u32, bytes) == 0x78563412);
575 assert(readIntLE(i32, bytes) == 0x78563412);
453576 }
454577 {
455 const buf = []u8{0x00, 0x00, 0x12, 0x34};
578 const buf = []u8{
579 0x00,
580 0x00,
581 0x12,
582 0x34,
583 };
456584 const answer = readInt(buf, u64, builtin.Endian.Big);
457585 assert(answer == 0x00001234);
458586 }
459587 {
460 const buf = []u8{0x12, 0x34, 0x00, 0x00};
588 const buf = []u8{
589 0x12,
590 0x34,
591 0x00,
592 0x00,
593 };
461594 const answer = readInt(buf, u64, builtin.Endian.Little);
462595 assert(answer == 0x00003412);
463596 }
464597 {
465 const bytes = []u8{0xff, 0xfe};
466 assert(readIntBE(u16, bytes) == 0xfffe);
598 const bytes = []u8{
599 0xff,
600 0xfe,
601 };
602 assert(readIntBE(u16, bytes) == 0xfffe);
467603 assert(readIntBE(i16, bytes) == -0x0002);
468 assert(readIntLE(u16, bytes) == 0xfeff);
604 assert(readIntLE(u16, bytes) == 0xfeff);
469605 assert(readIntLE(i16, bytes) == -0x0101);
470606 }
471607}
......@@ -478,19 +614,38 @@ fn testWriteIntImpl() void {
478614 var bytes: [4]u8 = undefined;
479615
480616 writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
481 assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
617 assert(eql(u8, bytes, []u8{
618 0x12,
619 0x34,
620 0x56,
621 0x78,
622 }));
482623
483624 writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
484 assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
625 assert(eql(u8, bytes, []u8{
626 0x12,
627 0x34,
628 0x56,
629 0x78,
630 }));
485631
486632 writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
487 assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));
633 assert(eql(u8, bytes, []u8{
634 0x00,
635 0x00,
636 0x12,
637 0x34,
638 }));
488639
489640 writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
490 assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
641 assert(eql(u8, bytes, []u8{
642 0x34,
643 0x12,
644 0x00,
645 0x00,
646 }));
491647}
492648
493
494649pub fn min(comptime T: type, slice: []const T) T {
495650 var best = slice[0];
496651 for (slice[1..]) |item| {
......@@ -515,10 +670,10 @@ test "mem.max" {
515670 assert(max(u8, "abcdefg") == 'g');
516671}
517672
518pub fn swap(comptime T: type, a: &T, b: &T) void {
519 const tmp = *a;
520 *a = *b;
521 *b = tmp;
673pub fn swap(comptime T: type, a: *T, b: *T) void {
674 const tmp = a.*;
675 a.* = b.*;
676 b.* = tmp;
522677}
523678
524679/// In-place order reversal of a slice
......@@ -531,10 +686,22 @@ pub fn reverse(comptime T: type, items: []T) void {
531686}
532687
533688test "std.mem.reverse" {
534 var arr = []i32{ 5, 3, 1, 2, 4 };
689 var arr = []i32{
690 5,
691 3,
692 1,
693 2,
694 4,
695 };
535696 reverse(i32, arr[0..]);
536697
537 assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }));
698 assert(eql(i32, arr, []i32{
699 4,
700 2,
701 1,
702 3,
703 5,
704 }));
538705}
539706
540707/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
......@@ -546,13 +713,25 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
546713}
547714
548715test "std.mem.rotate" {
549 var arr = []i32{ 5, 3, 1, 2, 4 };
716 var arr = []i32{
717 5,
718 3,
719 1,
720 2,
721 4,
722 };
550723 rotate(i32, arr[0..], 2);
551724
552 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
725 assert(eql(i32, arr, []i32{
726 1,
727 2,
728 4,
729 5,
730 3,
731 }));
553732}
554733
555// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
734// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by
556735// endian-casting the pointer and then dereferencing
557736
558737pub fn endianSwapIfLe(comptime T: type, x: T) T {
std/net.zig+13-15
......@@ -19,9 +19,9 @@ pub const Address = struct {
1919 os_addr: OsAddress,
2020
2121 pub fn initIp4(ip4: u32, port: u16) Address {
22 return Address {
23 .os_addr = posix.sockaddr {
24 .in = posix.sockaddr_in {
22 return Address{
23 .os_addr = posix.sockaddr{
24 .in = posix.sockaddr_in{
2525 .family = posix.AF_INET,
2626 .port = std.mem.endianSwapIfLe(u16, port),
2727 .addr = ip4,
......@@ -31,11 +31,11 @@ pub const Address = struct {
3131 };
3232 }
3333
34 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
35 return Address {
34 pub fn initIp6(ip6: *const Ip6Addr, port: u16) Address {
35 return Address{
3636 .family = posix.AF_INET6,
37 .os_addr = posix.sockaddr {
38 .in6 = posix.sockaddr_in6 {
37 .os_addr = posix.sockaddr{
38 .in6 = posix.sockaddr_in6{
3939 .family = posix.AF_INET6,
4040 .port = std.mem.endianSwapIfLe(u16, port),
4141 .flowinfo = 0,
......@@ -46,17 +46,15 @@ pub const Address = struct {
4646 };
4747 }
4848
49 pub fn initPosix(addr: &const posix.sockaddr) Address {
50 return Address {
51 .os_addr = *addr,
52 };
49 pub fn initPosix(addr: *const posix.sockaddr) Address {
50 return Address{ .os_addr = addr.* };
5351 }
5452
55 pub fn format(self: &const Address, out_stream: var) !void {
53 pub fn format(self: *const Address, out_stream: var) !void {
5654 switch (self.os_addr.in.family) {
5755 posix.AF_INET => {
5856 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
59 const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
57 const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]);
6058 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
6159 },
6260 posix.AF_INET6 => {
......@@ -70,7 +68,7 @@ pub const Address = struct {
7068
7169pub fn parseIp4(buf: []const u8) !u32 {
7270 var result: u32 = undefined;
73 const out_ptr = ([]u8)((&result)[0..1]);
71 const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
7472
7573 var x: u8 = 0;
7674 var index: u8 = 0;
......@@ -98,7 +96,7 @@ pub fn parseIp4(buf: []const u8) !u32 {
9896 }
9997 } else {
10098 return error.InvalidCharacter;
101 }
99 }
102100 }
103101 if (index == 3 and saw_any_digits) {
104102 out_ptr[index] = x;
std/os/child_process.zig+137-133
......@@ -20,7 +20,7 @@ pub const ChildProcess = struct {
2020 pub handle: if (is_windows) windows.HANDLE else void,
2121 pub thread_handle: if (is_windows) windows.HANDLE else void,
2222
23 pub allocator: &mem.Allocator,
23 pub allocator: *mem.Allocator,
2424
2525 pub stdin: ?os.File,
2626 pub stdout: ?os.File,
......@@ -31,7 +31,7 @@ pub const ChildProcess = struct {
3131 pub argv: []const []const u8,
3232
3333 /// Leave as null to use the current env map using the supplied allocator.
34 pub env_map: ?&const BufMap,
34 pub env_map: ?*const BufMap,
3535
3636 pub stdin_behavior: StdIo,
3737 pub stdout_behavior: StdIo,
......@@ -47,9 +47,9 @@ pub const ChildProcess = struct {
4747 pub cwd: ?[]const u8,
4848
4949 err_pipe: if (is_windows) void else [2]i32,
50 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
50 llnode: if (is_windows) void else LinkedList(*ChildProcess).Node,
5151
52 pub const SpawnError = error {
52 pub const SpawnError = error{
5353 ProcessFdQuotaExceeded,
5454 Unexpected,
5555 NotDir,
......@@ -84,11 +84,8 @@ pub const ChildProcess = struct {
8484
8585 /// First argument in argv is the executable.
8686 /// On success must call deinit.
87 pub fn init(argv: []const []const u8, allocator: &mem.Allocator) !&ChildProcess {
88 const child = try allocator.create(ChildProcess);
89 errdefer allocator.destroy(child);
90
91 *child = ChildProcess {
87 pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {
88 const child = try allocator.create(ChildProcess{
9289 .allocator = allocator,
9390 .argv = argv,
9491 .pid = undefined,
......@@ -99,27 +96,29 @@ pub const ChildProcess = struct {
9996 .term = null,
10097 .env_map = null,
10198 .cwd = null,
102 .uid = if (is_windows) {} else null,
103 .gid = if (is_windows) {} else null,
99 .uid = if (is_windows) {} else
100 null,
101 .gid = if (is_windows) {} else
102 null,
104103 .stdin = null,
105104 .stdout = null,
106105 .stderr = null,
107106 .stdin_behavior = StdIo.Inherit,
108107 .stdout_behavior = StdIo.Inherit,
109108 .stderr_behavior = StdIo.Inherit,
110 };
111
109 });
110 errdefer allocator.destroy(child);
112111 return child;
113112 }
114113
115 pub fn setUserName(self: &ChildProcess, name: []const u8) !void {
114 pub fn setUserName(self: *ChildProcess, name: []const u8) !void {
116115 const user_info = try os.getUserInfo(name);
117116 self.uid = user_info.uid;
118117 self.gid = user_info.gid;
119118 }
120119
121120 /// On success must call `kill` or `wait`.
122 pub fn spawn(self: &ChildProcess) !void {
121 pub fn spawn(self: *ChildProcess) !void {
123122 if (is_windows) {
124123 return self.spawnWindows();
125124 } else {
......@@ -127,13 +126,13 @@ pub const ChildProcess = struct {
127126 }
128127 }
129128
130 pub fn spawnAndWait(self: &ChildProcess) !Term {
129 pub fn spawnAndWait(self: *ChildProcess) !Term {
131130 try self.spawn();
132131 return self.wait();
133132 }
134133
135134 /// Forcibly terminates child process and then cleans up all resources.
136 pub fn kill(self: &ChildProcess) !Term {
135 pub fn kill(self: *ChildProcess) !Term {
137136 if (is_windows) {
138137 return self.killWindows(1);
139138 } else {
......@@ -141,7 +140,7 @@ pub const ChildProcess = struct {
141140 }
142141 }
143142
144 pub fn killWindows(self: &ChildProcess, exit_code: windows.UINT) !Term {
143 pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {
145144 if (self.term) |term| {
146145 self.cleanupStreams();
147146 return term;
......@@ -154,10 +153,10 @@ pub const ChildProcess = struct {
154153 };
155154 }
156155 try self.waitUnwrappedWindows();
157 return ??self.term;
156 return self.term.?;
158157 }
159158
160 pub fn killPosix(self: &ChildProcess) !Term {
159 pub fn killPosix(self: *ChildProcess) !Term {
161160 if (self.term) |term| {
162161 self.cleanupStreams();
163162 return term;
......@@ -173,11 +172,11 @@ pub const ChildProcess = struct {
173172 };
174173 }
175174 self.waitUnwrapped();
176 return ??self.term;
175 return self.term.?;
177176 }
178177
179178 /// Blocks until child process terminates and then cleans up all resources.
180 pub fn wait(self: &ChildProcess) !Term {
179 pub fn wait(self: *ChildProcess) !Term {
181180 if (is_windows) {
182181 return self.waitWindows();
183182 } else {
......@@ -193,9 +192,7 @@ pub const ChildProcess = struct {
193192
194193 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
195194 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
196 pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,
197 env_map: ?&const BufMap, max_output_size: usize) !ExecResult
198 {
195 pub fn exec(allocator: *mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?*const BufMap, max_output_size: usize) !ExecResult {
199196 const child = try ChildProcess.init(argv, allocator);
200197 defer child.deinit();
201198
......@@ -212,52 +209,52 @@ pub const ChildProcess = struct {
212209 defer Buffer.deinit(&stdout);
213210 defer Buffer.deinit(&stderr);
214211
215 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
216 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
212 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
213 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
217214
218215 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
219216 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
220217
221 return ExecResult {
218 return ExecResult{
222219 .term = try child.wait(),
223220 .stdout = stdout.toOwnedSlice(),
224221 .stderr = stderr.toOwnedSlice(),
225222 };
226223 }
227224
228 fn waitWindows(self: &ChildProcess) !Term {
225 fn waitWindows(self: *ChildProcess) !Term {
229226 if (self.term) |term| {
230227 self.cleanupStreams();
231228 return term;
232229 }
233230
234231 try self.waitUnwrappedWindows();
235 return ??self.term;
232 return self.term.?;
236233 }
237234
238 fn waitPosix(self: &ChildProcess) !Term {
235 fn waitPosix(self: *ChildProcess) !Term {
239236 if (self.term) |term| {
240237 self.cleanupStreams();
241238 return term;
242239 }
243240
244241 self.waitUnwrapped();
245 return ??self.term;
242 return self.term.?;
246243 }
247244
248 pub fn deinit(self: &ChildProcess) void {
245 pub fn deinit(self: *ChildProcess) void {
249246 self.allocator.destroy(self);
250247 }
251248
252 fn waitUnwrappedWindows(self: &ChildProcess) !void {
249 fn waitUnwrappedWindows(self: *ChildProcess) !void {
253250 const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
254251
255252 self.term = (SpawnError!Term)(x: {
256253 var exit_code: windows.DWORD = undefined;
257254 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
258 break :x Term { .Unknown = 0 };
255 break :x Term{ .Unknown = 0 };
259256 } else {
260 break :x Term { .Exited = @bitCast(i32, exit_code)};
257 break :x Term{ .Exited = @bitCast(i32, exit_code) };
261258 }
262259 });
263260
......@@ -267,7 +264,7 @@ pub const ChildProcess = struct {
267264 return result;
268265 }
269266
270 fn waitUnwrapped(self: &ChildProcess) void {
267 fn waitUnwrapped(self: *ChildProcess) void {
271268 var status: i32 = undefined;
272269 while (true) {
273270 const err = posix.getErrno(posix.waitpid(self.pid, &status, 0));
......@@ -283,17 +280,26 @@ pub const ChildProcess = struct {
283280 }
284281 }
285282
286 fn handleWaitResult(self: &ChildProcess, status: i32) void {
283 fn handleWaitResult(self: *ChildProcess, status: i32) void {
287284 self.term = self.cleanupAfterWait(status);
288285 }
289286
290 fn cleanupStreams(self: &ChildProcess) void {
291 if (self.stdin) |*stdin| { stdin.close(); self.stdin = null; }
292 if (self.stdout) |*stdout| { stdout.close(); self.stdout = null; }
293 if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }
287 fn cleanupStreams(self: *ChildProcess) void {
288 if (self.stdin) |*stdin| {
289 stdin.close();
290 self.stdin = null;
291 }
292 if (self.stdout) |*stdout| {
293 stdout.close();
294 self.stdout = null;
295 }
296 if (self.stderr) |*stderr| {
297 stderr.close();
298 self.stderr = null;
299 }
294300 }
295301
296 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
302 fn cleanupAfterWait(self: *ChildProcess, status: i32) !Term {
297303 defer {
298304 os.close(self.err_pipe[0]);
299305 os.close(self.err_pipe[1]);
......@@ -309,7 +315,7 @@ pub const ChildProcess = struct {
309315 // Here we potentially return the fork child's error
310316 // from the parent pid.
311317 if (err_int != @maxValue(ErrInt)) {
312 return SpawnError(err_int);
318 return @errSetCast(SpawnError, @intToError(err_int));
313319 }
314320
315321 return statusToTerm(status);
......@@ -317,25 +323,30 @@ pub const ChildProcess = struct {
317323
318324 fn statusToTerm(status: i32) Term {
319325 return if (posix.WIFEXITED(status))
320 Term { .Exited = posix.WEXITSTATUS(status) }
326 Term{ .Exited = posix.WEXITSTATUS(status) }
321327 else if (posix.WIFSIGNALED(status))
322 Term { .Signal = posix.WTERMSIG(status) }
328 Term{ .Signal = posix.WTERMSIG(status) }
323329 else if (posix.WIFSTOPPED(status))
324 Term { .Stopped = posix.WSTOPSIG(status) }
330 Term{ .Stopped = posix.WSTOPSIG(status) }
325331 else
326 Term { .Unknown = status }
327 ;
332 Term{ .Unknown = status };
328333 }
329334
330 fn spawnPosix(self: &ChildProcess) !void {
335 fn spawnPosix(self: *ChildProcess) !void {
331336 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
332 errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
337 errdefer if (self.stdin_behavior == StdIo.Pipe) {
338 destroyPipe(stdin_pipe);
339 };
333340
334341 const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
335 errdefer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };
342 errdefer if (self.stdout_behavior == StdIo.Pipe) {
343 destroyPipe(stdout_pipe);
344 };
336345
337346 const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
338 errdefer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
347 errdefer if (self.stderr_behavior == StdIo.Pipe) {
348 destroyPipe(stderr_pipe);
349 };
339350
340351 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
341352 const dev_null_fd = if (any_ignore) blk: {
......@@ -346,7 +357,9 @@ pub const ChildProcess = struct {
346357 } else blk: {
347358 break :blk undefined;
348359 };
349 defer { if (any_ignore) os.close(dev_null_fd); }
360 defer {
361 if (any_ignore) os.close(dev_null_fd);
362 }
350363
351364 var env_map_owned: BufMap = undefined;
352365 var we_own_env_map: bool = undefined;
......@@ -358,7 +371,9 @@ pub const ChildProcess = struct {
358371 env_map_owned = try os.getEnvMap(self.allocator);
359372 break :x &env_map_owned;
360373 };
361 defer { if (we_own_env_map) env_map_owned.deinit(); }
374 defer {
375 if (we_own_env_map) env_map_owned.deinit();
376 }
362377
363378 // This pipe is used to communicate errors between the time of fork
364379 // and execve from the child process to the parent process.
......@@ -375,17 +390,12 @@ pub const ChildProcess = struct {
375390 }
376391 if (pid_result == 0) {
377392 // we are the child
378
379 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch
380 |err| forkChildErrReport(err_pipe[1], err);
381 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch
382 |err| forkChildErrReport(err_pipe[1], err);
383 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch
384 |err| forkChildErrReport(err_pipe[1], err);
393 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
394 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
395 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
385396
386397 if (self.cwd) |cwd| {
387 os.changeCurDir(self.allocator, cwd) catch
388 |err| forkChildErrReport(err_pipe[1], err);
398 os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err);
389399 }
390400
391401 if (self.gid) |gid| {
......@@ -396,12 +406,11 @@ pub const ChildProcess = struct {
396406 os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
397407 }
398408
399 os.posixExecve(self.argv, env_map, self.allocator) catch
400 |err| forkChildErrReport(err_pipe[1], err);
409 os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
401410 }
402411
403412 // we are the parent
404 const pid = i32(pid_result);
413 const pid = @intCast(i32, pid_result);
405414 if (self.stdin_behavior == StdIo.Pipe) {
406415 self.stdin = os.File.openHandle(stdin_pipe[1]);
407416 } else {
......@@ -420,40 +429,44 @@ pub const ChildProcess = struct {
420429
421430 self.pid = pid;
422431 self.err_pipe = err_pipe;
423 self.llnode = LinkedList(&ChildProcess).Node.init(self);
432 self.llnode = LinkedList(*ChildProcess).Node.init(self);
424433 self.term = null;
425434
426 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
427 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
428 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
435 if (self.stdin_behavior == StdIo.Pipe) {
436 os.close(stdin_pipe[0]);
437 }
438 if (self.stdout_behavior == StdIo.Pipe) {
439 os.close(stdout_pipe[1]);
440 }
441 if (self.stderr_behavior == StdIo.Pipe) {
442 os.close(stderr_pipe[1]);
443 }
429444 }
430445
431 fn spawnWindows(self: &ChildProcess) !void {
432 const saAttr = windows.SECURITY_ATTRIBUTES {
446 fn spawnWindows(self: *ChildProcess) !void {
447 const saAttr = windows.SECURITY_ATTRIBUTES{
433448 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
434449 .bInheritHandle = windows.TRUE,
435450 .lpSecurityDescriptor = null,
436451 };
437452
438 const any_ignore = (self.stdin_behavior == StdIo.Ignore or
439 self.stdout_behavior == StdIo.Ignore or
440 self.stderr_behavior == StdIo.Ignore);
453 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
441454
442455 const nul_handle = if (any_ignore) blk: {
443456 const nul_file_path = "NUL";
444457 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;
445458 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
446 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
447 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
459 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
448460 } else blk: {
449461 break :blk undefined;
450462 };
451 defer { if (any_ignore) os.close(nul_handle); }
463 defer {
464 if (any_ignore) os.close(nul_handle);
465 }
452466 if (any_ignore) {
453467 try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
454468 }
455469
456
457470 var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
458471 var g_hChildStd_IN_Wr: ?windows.HANDLE = null;
459472 switch (self.stdin_behavior) {
......@@ -470,7 +483,9 @@ pub const ChildProcess = struct {
470483 g_hChildStd_IN_Rd = null;
471484 },
472485 }
473 errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr); };
486 errdefer if (self.stdin_behavior == StdIo.Pipe) {
487 windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr);
488 };
474489
475490 var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;
476491 var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;
......@@ -488,7 +503,9 @@ pub const ChildProcess = struct {
488503 g_hChildStd_OUT_Wr = null;
489504 },
490505 }
491 errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr); };
506 errdefer if (self.stdin_behavior == StdIo.Pipe) {
507 windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr);
508 };
492509
493510 var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;
494511 var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;
......@@ -506,12 +523,14 @@ pub const ChildProcess = struct {
506523 g_hChildStd_ERR_Wr = null;
507524 },
508525 }
509 errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };
526 errdefer if (self.stdin_behavior == StdIo.Pipe) {
527 windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr);
528 };
510529
511530 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
512531 defer self.allocator.free(cmd_line);
513532
514 var siStartInfo = windows.STARTUPINFOA {
533 var siStartInfo = windows.STARTUPINFOA{
515534 .cb = @sizeOf(windows.STARTUPINFOA),
516535 .hStdError = g_hChildStd_ERR_Wr,
517536 .hStdOutput = g_hChildStd_OUT_Wr,
......@@ -534,19 +553,11 @@ pub const ChildProcess = struct {
534553 };
535554 var piProcInfo: windows.PROCESS_INFORMATION = undefined;
536555
537 const cwd_slice = if (self.cwd) |cwd|
538 try cstr.addNullByte(self.allocator, cwd)
539 else
540 null
541 ;
556 const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;
542557 defer if (cwd_slice) |cwd| self.allocator.free(cwd);
543558 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
544559
545 const maybe_envp_buf = if (self.env_map) |env_map|
546 try os.createWindowsEnvBlock(self.allocator, env_map)
547 else
548 null
549 ;
560 const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;
550561 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
551562 const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
552563
......@@ -563,11 +574,8 @@ pub const ChildProcess = struct {
563574 };
564575 defer self.allocator.free(app_name);
565576
566 windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr,
567 &siStartInfo, &piProcInfo) catch |no_path_err|
568 {
569 if (no_path_err != error.FileNotFound)
570 return no_path_err;
577 windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
578 if (no_path_err != error.FileNotFound) return no_path_err;
571579
572580 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
573581 defer self.allocator.free(PATH);
......@@ -577,9 +585,7 @@ pub const ChildProcess = struct {
577585 const joined_path = try os.path.join(self.allocator, search_path, app_name);
578586 defer self.allocator.free(joined_path);
579587
580 if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr,
581 &siStartInfo, &piProcInfo)) |_|
582 {
588 if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo)) |_| {
583589 break;
584590 } else |err| if (err == error.FileNotFound) {
585591 continue;
......@@ -609,9 +615,15 @@ pub const ChildProcess = struct {
609615 self.thread_handle = piProcInfo.hThread;
610616 self.term = null;
611617
612 if (self.stdin_behavior == StdIo.Pipe) { os.close(??g_hChildStd_IN_Rd); }
613 if (self.stderr_behavior == StdIo.Pipe) { os.close(??g_hChildStd_ERR_Wr); }
614 if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); }
618 if (self.stdin_behavior == StdIo.Pipe) {
619 os.close(g_hChildStd_IN_Rd.?);
620 }
621 if (self.stderr_behavior == StdIo.Pipe) {
622 os.close(g_hChildStd_ERR_Wr.?);
623 }
624 if (self.stdout_behavior == StdIo.Pipe) {
625 os.close(g_hChildStd_OUT_Wr.?);
626 }
615627 }
616628
617629 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
......@@ -622,15 +634,10 @@ pub const ChildProcess = struct {
622634 StdIo.Ignore => try os.posixDup2(dev_null_fd, std_fileno),
623635 }
624636 }
625
626637};
627638
628fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,
629 lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void
630{
631 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,
632 @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0)
633 {
639fn windowsCreateProcess(app_name: [*]u8, cmd_line: [*]u8, envp_ptr: ?[*]u8, cwd_ptr: ?[*]u8, lpStartupInfo: *windows.STARTUPINFOA, lpProcessInformation: *windows.PROCESS_INFORMATION) !void {
640 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0, @ptrCast(?*c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0) {
634641 const err = windows.GetLastError();
635642 return switch (err) {
636643 windows.ERROR.FILE_NOT_FOUND, windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
......@@ -641,18 +648,16 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?
641648 }
642649}
643650
644
645
646
647651/// Caller must dealloc.
648652/// Guarantees a null byte at result[result.len].
649fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) ![]u8 {
653fn windowsCreateCommandLine(allocator: *mem.Allocator, argv: []const []const u8) ![]u8 {
650654 var buf = try Buffer.initSize(allocator, 0);
651655 defer buf.deinit();
652656
657 var buf_stream = &io.BufferOutStream.init(&buf).stream;
658
653659 for (argv) |arg, arg_i| {
654 if (arg_i != 0)
655 try buf.appendByte(' ');
660 if (arg_i != 0) try buf.appendByte(' ');
656661 if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
657662 try buf.append(arg);
658663 continue;
......@@ -663,18 +668,18 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)
663668 switch (byte) {
664669 '\\' => backslash_count += 1,
665670 '"' => {
666 try buf.appendByteNTimes('\\', backslash_count * 2 + 1);
671 try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
667672 try buf.appendByte('"');
668673 backslash_count = 0;
669674 },
670675 else => {
671 try buf.appendByteNTimes('\\', backslash_count);
676 try buf_stream.writeByteNTimes('\\', backslash_count);
672677 try buf.appendByte(byte);
673678 backslash_count = 0;
674679 },
675680 }
676681 }
677 try buf.appendByteNTimes('\\', backslash_count * 2);
682 try buf_stream.writeByteNTimes('\\', backslash_count * 2);
678683 try buf.appendByte('"');
679684 }
680685
......@@ -686,12 +691,11 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
686691 if (wr) |h| os.close(h);
687692}
688693
689
690694// TODO: workaround for bug where the `const` from `&const` is dropped when the type is
691695// a namespace field lookup
692696const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
693697
694fn windowsMakePipe(rd: &windows.HANDLE, wr: &windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
698fn windowsMakePipe(rd: *windows.HANDLE, wr: *windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
695699 if (windows.CreatePipe(rd, wr, sattr, 0) == 0) {
696700 const err = windows.GetLastError();
697701 return switch (err) {
......@@ -709,24 +713,24 @@ fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.D
709713 }
710714}
711715
712fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
716fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
713717 var rd_h: windows.HANDLE = undefined;
714718 var wr_h: windows.HANDLE = undefined;
715719 try windowsMakePipe(&rd_h, &wr_h, sattr);
716720 errdefer windowsDestroyPipe(rd_h, wr_h);
717721 try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
718 *rd = rd_h;
719 *wr = wr_h;
722 rd.* = rd_h;
723 wr.* = wr_h;
720724}
721725
722fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
726fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
723727 var rd_h: windows.HANDLE = undefined;
724728 var wr_h: windows.HANDLE = undefined;
725729 try windowsMakePipe(&rd_h, &wr_h, sattr);
726730 errdefer windowsDestroyPipe(rd_h, wr_h);
727731 try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
728 *rd = rd_h;
729 *wr = wr_h;
732 rd.* = rd_h;
733 wr.* = wr_h;
730734}
731735
732736fn makePipe() ![2]i32 {
......@@ -741,15 +745,15 @@ fn makePipe() ![2]i32 {
741745 return fds;
742746}
743747
744fn destroyPipe(pipe: &const [2]i32) void {
745 os.close((*pipe)[0]);
746 os.close((*pipe)[1]);
748fn destroyPipe(pipe: *const [2]i32) void {
749 os.close((pipe.*)[0]);
750 os.close((pipe.*)[1]);
747751}
748752
749753// Child of fork calls this to report an error to the fork parent.
750754// Then the child exits.
751755fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
752 _ = writeIntFd(fd, ErrInt(err));
756 _ = writeIntFd(fd, ErrInt(@errorToInt(err)));
753757 posix.exit(1);
754758}
755759
std/os/darwin.zig+643-130
......@@ -2,7 +2,7 @@ const std = @import("../index.zig");
22const c = std.c;
33const assert = std.debug.assert;
44
5pub use @import("darwin_errno.zig");
5pub use @import("darwin/errno.zig");
66
77pub const PATH_MAX = 1024;
88
......@@ -10,33 +10,75 @@ pub const STDIN_FILENO = 0;
1010pub const STDOUT_FILENO = 1;
1111pub const STDERR_FILENO = 2;
1212
13pub const PROT_NONE = 0x00; /// [MC2] no permissions
14pub const PROT_READ = 0x01; /// [MC2] pages can be read
15pub const PROT_WRITE = 0x02; /// [MC2] pages can be written
16pub const PROT_EXEC = 0x04; /// [MC2] pages can be executed
17
18pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
19pub const MAP_FILE = 0x0000; /// map from file (default)
20pub const MAP_FIXED = 0x0010; /// interpret addr exactly
21pub const MAP_HASSEMAPHORE = 0x0200; /// region may contain semaphores
22pub const MAP_PRIVATE = 0x0002; /// changes are private
23pub const MAP_SHARED = 0x0001; /// share changes
24pub const MAP_NOCACHE = 0x0400; /// don't cache pages for this mapping
25pub const MAP_NORESERVE = 0x0040; /// don't reserve needed swap area
13/// [MC2] no permissions
14pub const PROT_NONE = 0x00;
15
16/// [MC2] pages can be read
17pub const PROT_READ = 0x01;
18
19/// [MC2] pages can be written
20pub const PROT_WRITE = 0x02;
21
22/// [MC2] pages can be executed
23pub const PROT_EXEC = 0x04;
24
25/// allocated from memory, swap space
26pub const MAP_ANONYMOUS = 0x1000;
27
28/// map from file (default)
29pub const MAP_FILE = 0x0000;
30
31/// interpret addr exactly
32pub const MAP_FIXED = 0x0010;
33
34/// region may contain semaphores
35pub const MAP_HASSEMAPHORE = 0x0200;
36
37/// changes are private
38pub const MAP_PRIVATE = 0x0002;
39
40/// share changes
41pub const MAP_SHARED = 0x0001;
42
43/// don't cache pages for this mapping
44pub const MAP_NOCACHE = 0x0400;
45
46/// don't reserve needed swap area
47pub const MAP_NORESERVE = 0x0040;
2648pub const MAP_FAILED = @maxValue(usize);
2749
28pub const WNOHANG = 0x00000001; /// [XSI] no hang in wait/no child to reap
29pub const WUNTRACED = 0x00000002; /// [XSI] notify on stop, untraced child
50/// [XSI] no hang in wait/no child to reap
51pub const WNOHANG = 0x00000001;
52
53/// [XSI] notify on stop, untraced child
54pub const WUNTRACED = 0x00000002;
55
56/// take signal on signal stack
57pub const SA_ONSTACK = 0x0001;
58
59/// restart system on signal return
60pub const SA_RESTART = 0x0002;
61
62/// reset to SIG_DFL when taking signal
63pub const SA_RESETHAND = 0x0004;
64
65/// do not generate SIGCHLD on child stop
66pub const SA_NOCLDSTOP = 0x0008;
67
68/// don't mask the signal we're delivering
69pub const SA_NODEFER = 0x0010;
70
71/// don't keep zombies around
72pub const SA_NOCLDWAIT = 0x0020;
73
74/// signal handler with SA_SIGINFO args
75pub const SA_SIGINFO = 0x0040;
3076
31pub const SA_ONSTACK = 0x0001; /// take signal on signal stack
32pub const SA_RESTART = 0x0002; /// restart system on signal return
33pub const SA_RESETHAND = 0x0004; /// reset to SIG_DFL when taking signal
34pub const SA_NOCLDSTOP = 0x0008; /// do not generate SIGCHLD on child stop
35pub const SA_NODEFER = 0x0010; /// don't mask the signal we're delivering
36pub const SA_NOCLDWAIT = 0x0020; /// don't keep zombies around
37pub const SA_SIGINFO = 0x0040; /// signal handler with SA_SIGINFO args
38pub const SA_USERTRAMP = 0x0100; /// do not bounce off kernel's sigtramp
39pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64bit regs information
77/// do not bounce off kernel's sigtramp
78pub const SA_USERTRAMP = 0x0100;
79
80/// signal handler with SA_SIGINFO args with 64bit regs information
81pub const SA_64REGSET = 0x0200;
4082
4183pub const O_LARGEFILE = 0x0000;
4284pub const O_PATH = 0x0000;
......@@ -46,20 +88,47 @@ pub const X_OK = 1;
4688pub const W_OK = 2;
4789pub const R_OK = 4;
4890
49pub const O_RDONLY = 0x0000; /// open for reading only
50pub const O_WRONLY = 0x0001; /// open for writing only
51pub const O_RDWR = 0x0002; /// open for reading and writing
52pub const O_NONBLOCK = 0x0004; /// do not block on open or for data to become available
53pub const O_APPEND = 0x0008; /// append on each write
54pub const O_CREAT = 0x0200; /// create file if it does not exist
55pub const O_TRUNC = 0x0400; /// truncate size to 0
56pub const O_EXCL = 0x0800; /// error if O_CREAT and the file exists
57pub const O_SHLOCK = 0x0010; /// atomically obtain a shared lock
58pub const O_EXLOCK = 0x0020; /// atomically obtain an exclusive lock
59pub const O_NOFOLLOW = 0x0100; /// do not follow symlinks
60pub const O_SYMLINK = 0x200000; /// allow open of symlinks
61pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
62pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
91/// open for reading only
92pub const O_RDONLY = 0x0000;
93
94/// open for writing only
95pub const O_WRONLY = 0x0001;
96
97/// open for reading and writing
98pub const O_RDWR = 0x0002;
99
100/// do not block on open or for data to become available
101pub const O_NONBLOCK = 0x0004;
102
103/// append on each write
104pub const O_APPEND = 0x0008;
105
106/// create file if it does not exist
107pub const O_CREAT = 0x0200;
108
109/// truncate size to 0
110pub const O_TRUNC = 0x0400;
111
112/// error if O_CREAT and the file exists
113pub const O_EXCL = 0x0800;
114
115/// atomically obtain a shared lock
116pub const O_SHLOCK = 0x0010;
117
118/// atomically obtain an exclusive lock
119pub const O_EXLOCK = 0x0020;
120
121/// do not follow symlinks
122pub const O_NOFOLLOW = 0x0100;
123
124/// allow open of symlinks
125pub const O_SYMLINK = 0x200000;
126
127/// descriptor requested for event notifications only
128pub const O_EVTONLY = 0x8000;
129
130/// mark as close-on-exec
131pub const O_CLOEXEC = 0x1000000;
63132
64133pub const O_ACCMODE = 3;
65134pub const O_ALERT = 536870912;
......@@ -87,57 +156,445 @@ pub const DT_LNK = 10;
87156pub const DT_SOCK = 12;
88157pub const DT_WHT = 14;
89158
90pub const SIG_BLOCK = 1; /// block specified signal set
91pub const SIG_UNBLOCK = 2; /// unblock specified signal set
92pub const SIG_SETMASK = 3; /// set specified signal set
93
94pub const SIGHUP = 1; /// hangup
95pub const SIGINT = 2; /// interrupt
96pub const SIGQUIT = 3; /// quit
97pub const SIGILL = 4; /// illegal instruction (not reset when caught)
98pub const SIGTRAP = 5; /// trace trap (not reset when caught)
99pub const SIGABRT = 6; /// abort()
100pub const SIGPOLL = 7; /// pollable event ([XSR] generated, not supported)
101pub const SIGIOT = SIGABRT; /// compatibility
102pub const SIGEMT = 7; /// EMT instruction
103pub const SIGFPE = 8; /// floating point exception
104pub const SIGKILL = 9; /// kill (cannot be caught or ignored)
105pub const SIGBUS = 10; /// bus error
106pub const SIGSEGV = 11; /// segmentation violation
107pub const SIGSYS = 12; /// bad argument to system call
108pub const SIGPIPE = 13; /// write on a pipe with no one to read it
109pub const SIGALRM = 14; /// alarm clock
110pub const SIGTERM = 15; /// software termination signal from kill
111pub const SIGURG = 16; /// urgent condition on IO channel
112pub const SIGSTOP = 17; /// sendable stop signal not from tty
113pub const SIGTSTP = 18; /// stop signal from tty
114pub const SIGCONT = 19; /// continue a stopped process
115pub const SIGCHLD = 20; /// to parent on child stop or exit
116pub const SIGTTIN = 21; /// to readers pgrp upon background tty read
117pub const SIGTTOU = 22; /// like TTIN for output if (tp->t_local&LTOSTOP)
118pub const SIGIO = 23; /// input/output possible signal
119pub const SIGXCPU = 24; /// exceeded CPU time limit
120pub const SIGXFSZ = 25; /// exceeded file size limit
121pub const SIGVTALRM = 26; /// virtual time alarm
122pub const SIGPROF = 27; /// profiling time alarm
123pub const SIGWINCH = 28; /// window size changes
124pub const SIGINFO = 29; /// information request
125pub const SIGUSR1 = 30; /// user defined signal 1
126pub const SIGUSR2 = 31; /// user defined signal 2
127
128fn wstatus(x: i32) i32 { return x & 0o177; }
159/// block specified signal set
160pub const SIG_BLOCK = 1;
161
162/// unblock specified signal set
163pub const SIG_UNBLOCK = 2;
164
165/// set specified signal set
166pub const SIG_SETMASK = 3;
167
168/// hangup
169pub const SIGHUP = 1;
170
171/// interrupt
172pub const SIGINT = 2;
173
174/// quit
175pub const SIGQUIT = 3;
176
177/// illegal instruction (not reset when caught)
178pub const SIGILL = 4;
179
180/// trace trap (not reset when caught)
181pub const SIGTRAP = 5;
182
183/// abort()
184pub const SIGABRT = 6;
185
186/// pollable event ([XSR] generated, not supported)
187pub const SIGPOLL = 7;
188
189/// compatibility
190pub const SIGIOT = SIGABRT;
191
192/// EMT instruction
193pub const SIGEMT = 7;
194
195/// floating point exception
196pub const SIGFPE = 8;
197
198/// kill (cannot be caught or ignored)
199pub const SIGKILL = 9;
200
201/// bus error
202pub const SIGBUS = 10;
203
204/// segmentation violation
205pub const SIGSEGV = 11;
206
207/// bad argument to system call
208pub const SIGSYS = 12;
209
210/// write on a pipe with no one to read it
211pub const SIGPIPE = 13;
212
213/// alarm clock
214pub const SIGALRM = 14;
215
216/// software termination signal from kill
217pub const SIGTERM = 15;
218
219/// urgent condition on IO channel
220pub const SIGURG = 16;
221
222/// sendable stop signal not from tty
223pub const SIGSTOP = 17;
224
225/// stop signal from tty
226pub const SIGTSTP = 18;
227
228/// continue a stopped process
229pub const SIGCONT = 19;
230
231/// to parent on child stop or exit
232pub const SIGCHLD = 20;
233
234/// to readers pgrp upon background tty read
235pub const SIGTTIN = 21;
236
237/// like TTIN for output if (tp->t_local&LTOSTOP)
238pub const SIGTTOU = 22;
239
240/// input/output possible signal
241pub const SIGIO = 23;
242
243/// exceeded CPU time limit
244pub const SIGXCPU = 24;
245
246/// exceeded file size limit
247pub const SIGXFSZ = 25;
248
249/// virtual time alarm
250pub const SIGVTALRM = 26;
251
252/// profiling time alarm
253pub const SIGPROF = 27;
254
255/// window size changes
256pub const SIGWINCH = 28;
257
258/// information request
259pub const SIGINFO = 29;
260
261/// user defined signal 1
262pub const SIGUSR1 = 30;
263
264/// user defined signal 2
265pub const SIGUSR2 = 31;
266
267/// no flag value
268pub const KEVENT_FLAG_NONE = 0x000;
269
270/// immediate timeout
271pub const KEVENT_FLAG_IMMEDIATE = 0x001;
272
273/// output events only include change
274pub const KEVENT_FLAG_ERROR_EVENTS = 0x002;
275
276/// add event to kq (implies enable)
277pub const EV_ADD = 0x0001;
278
279/// delete event from kq
280pub const EV_DELETE = 0x0002;
281
282/// enable event
283pub const EV_ENABLE = 0x0004;
284
285/// disable event (not reported)
286pub const EV_DISABLE = 0x0008;
287
288/// only report one occurrence
289pub const EV_ONESHOT = 0x0010;
290
291/// clear event state after reporting
292pub const EV_CLEAR = 0x0020;
293
294/// force immediate event output
295/// ... with or without EV_ERROR
296/// ... use KEVENT_FLAG_ERROR_EVENTS
297/// on syscalls supporting flags
298pub const EV_RECEIPT = 0x0040;
299
300/// disable event after reporting
301pub const EV_DISPATCH = 0x0080;
302
303/// unique kevent per udata value
304pub const EV_UDATA_SPECIFIC = 0x0100;
305
306/// ... in combination with EV_DELETE
307/// will defer delete until udata-specific
308/// event enabled. EINPROGRESS will be
309/// returned to indicate the deferral
310pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC;
311
312/// report that source has vanished
313/// ... only valid with EV_DISPATCH2
314pub const EV_VANISHED = 0x0200;
315
316/// reserved by system
317pub const EV_SYSFLAGS = 0xF000;
318
319/// filter-specific flag
320pub const EV_FLAG0 = 0x1000;
321
322/// filter-specific flag
323pub const EV_FLAG1 = 0x2000;
324
325/// EOF detected
326pub const EV_EOF = 0x8000;
327
328/// error, data contains errno
329pub const EV_ERROR = 0x4000;
330
331pub const EV_POLL = EV_FLAG0;
332pub const EV_OOBAND = EV_FLAG1;
333
334pub const EVFILT_READ = -1;
335pub const EVFILT_WRITE = -2;
336
337/// attached to aio requests
338pub const EVFILT_AIO = -3;
339
340/// attached to vnodes
341pub const EVFILT_VNODE = -4;
342
343/// attached to struct proc
344pub const EVFILT_PROC = -5;
345
346/// attached to struct proc
347pub const EVFILT_SIGNAL = -6;
348
349/// timers
350pub const EVFILT_TIMER = -7;
351
352/// Mach portsets
353pub const EVFILT_MACHPORT = -8;
354
355/// Filesystem events
356pub const EVFILT_FS = -9;
357
358/// User events
359pub const EVFILT_USER = -10;
360
361/// Virtual memory events
362pub const EVFILT_VM = -12;
363
364/// Exception events
365pub const EVFILT_EXCEPT = -15;
366
367pub const EVFILT_SYSCOUNT = 17;
368
369/// On input, NOTE_TRIGGER causes the event to be triggered for output.
370pub const NOTE_TRIGGER = 0x01000000;
371
372/// ignore input fflags
373pub const NOTE_FFNOP = 0x00000000;
374
375/// and fflags
376pub const NOTE_FFAND = 0x40000000;
377
378/// or fflags
379pub const NOTE_FFOR = 0x80000000;
380
381/// copy fflags
382pub const NOTE_FFCOPY = 0xc0000000;
383
384/// mask for operations
385pub const NOTE_FFCTRLMASK = 0xc0000000;
386pub const NOTE_FFLAGSMASK = 0x00ffffff;
387
388/// low water mark
389pub const NOTE_LOWAT = 0x00000001;
390
391/// OOB data
392pub const NOTE_OOB = 0x00000002;
393
394/// vnode was removed
395pub const NOTE_DELETE = 0x00000001;
396
397/// data contents changed
398pub const NOTE_WRITE = 0x00000002;
399
400/// size increased
401pub const NOTE_EXTEND = 0x00000004;
402
403/// attributes changed
404pub const NOTE_ATTRIB = 0x00000008;
405
406/// link count changed
407pub const NOTE_LINK = 0x00000010;
408
409/// vnode was renamed
410pub const NOTE_RENAME = 0x00000020;
411
412/// vnode access was revoked
413pub const NOTE_REVOKE = 0x00000040;
414
415/// No specific vnode event: to test for EVFILT_READ activation
416pub const NOTE_NONE = 0x00000080;
417
418/// vnode was unlocked by flock(2)
419pub const NOTE_FUNLOCK = 0x00000100;
420
421/// process exited
422pub const NOTE_EXIT = 0x80000000;
423
424/// process forked
425pub const NOTE_FORK = 0x40000000;
426
427/// process exec'd
428pub const NOTE_EXEC = 0x20000000;
429
430/// shared with EVFILT_SIGNAL
431pub const NOTE_SIGNAL = 0x08000000;
432
433/// exit status to be returned, valid for child process only
434pub const NOTE_EXITSTATUS = 0x04000000;
435
436/// provide details on reasons for exit
437pub const NOTE_EXIT_DETAIL = 0x02000000;
438
439/// mask for signal & exit status
440pub const NOTE_PDATAMASK = 0x000fffff;
441pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
442
443pub const NOTE_EXIT_DETAIL_MASK = 0x00070000;
444pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000;
445pub const NOTE_EXIT_MEMORY = 0x00020000;
446pub const NOTE_EXIT_CSERROR = 0x00040000;
447
448/// will react on memory pressure
449pub const NOTE_VM_PRESSURE = 0x80000000;
450
451/// will quit on memory pressure, possibly after cleaning up dirty state
452pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000;
453
454/// will quit immediately on memory pressure
455pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000;
456
457/// there was an error
458pub const NOTE_VM_ERROR = 0x10000000;
459
460/// data is seconds
461pub const NOTE_SECONDS = 0x00000001;
462
463/// data is microseconds
464pub const NOTE_USECONDS = 0x00000002;
465
466/// data is nanoseconds
467pub const NOTE_NSECONDS = 0x00000004;
468
469/// absolute timeout
470pub const NOTE_ABSOLUTE = 0x00000008;
471
472/// ext[1] holds leeway for power aware timers
473pub const NOTE_LEEWAY = 0x00000010;
474
475/// system does minimal timer coalescing
476pub const NOTE_CRITICAL = 0x00000020;
477
478/// system does maximum timer coalescing
479pub const NOTE_BACKGROUND = 0x00000040;
480pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080;
481
482/// data is mach absolute time units
483pub const NOTE_MACHTIME = 0x00000100;
484
485pub const AF_UNSPEC: c_int = 0;
486pub const AF_LOCAL: c_int = 1;
487pub const AF_UNIX: c_int = AF_LOCAL;
488pub const AF_INET: c_int = 2;
489pub const AF_SYS_CONTROL: c_int = 2;
490pub const AF_IMPLINK: c_int = 3;
491pub const AF_PUP: c_int = 4;
492pub const AF_CHAOS: c_int = 5;
493pub const AF_NS: c_int = 6;
494pub const AF_ISO: c_int = 7;
495pub const AF_OSI: c_int = AF_ISO;
496pub const AF_ECMA: c_int = 8;
497pub const AF_DATAKIT: c_int = 9;
498pub const AF_CCITT: c_int = 10;
499pub const AF_SNA: c_int = 11;
500pub const AF_DECnet: c_int = 12;
501pub const AF_DLI: c_int = 13;
502pub const AF_LAT: c_int = 14;
503pub const AF_HYLINK: c_int = 15;
504pub const AF_APPLETALK: c_int = 16;
505pub const AF_ROUTE: c_int = 17;
506pub const AF_LINK: c_int = 18;
507pub const AF_XTP: c_int = 19;
508pub const AF_COIP: c_int = 20;
509pub const AF_CNT: c_int = 21;
510pub const AF_RTIP: c_int = 22;
511pub const AF_IPX: c_int = 23;
512pub const AF_SIP: c_int = 24;
513pub const AF_PIP: c_int = 25;
514pub const AF_ISDN: c_int = 28;
515pub const AF_E164: c_int = AF_ISDN;
516pub const AF_KEY: c_int = 29;
517pub const AF_INET6: c_int = 30;
518pub const AF_NATM: c_int = 31;
519pub const AF_SYSTEM: c_int = 32;
520pub const AF_NETBIOS: c_int = 33;
521pub const AF_PPP: c_int = 34;
522pub const AF_MAX: c_int = 40;
523
524pub const PF_UNSPEC: c_int = AF_UNSPEC;
525pub const PF_LOCAL: c_int = AF_LOCAL;
526pub const PF_UNIX: c_int = PF_LOCAL;
527pub const PF_INET: c_int = AF_INET;
528pub const PF_IMPLINK: c_int = AF_IMPLINK;
529pub const PF_PUP: c_int = AF_PUP;
530pub const PF_CHAOS: c_int = AF_CHAOS;
531pub const PF_NS: c_int = AF_NS;
532pub const PF_ISO: c_int = AF_ISO;
533pub const PF_OSI: c_int = AF_ISO;
534pub const PF_ECMA: c_int = AF_ECMA;
535pub const PF_DATAKIT: c_int = AF_DATAKIT;
536pub const PF_CCITT: c_int = AF_CCITT;
537pub const PF_SNA: c_int = AF_SNA;
538pub const PF_DECnet: c_int = AF_DECnet;
539pub const PF_DLI: c_int = AF_DLI;
540pub const PF_LAT: c_int = AF_LAT;
541pub const PF_HYLINK: c_int = AF_HYLINK;
542pub const PF_APPLETALK: c_int = AF_APPLETALK;
543pub const PF_ROUTE: c_int = AF_ROUTE;
544pub const PF_LINK: c_int = AF_LINK;
545pub const PF_XTP: c_int = AF_XTP;
546pub const PF_COIP: c_int = AF_COIP;
547pub const PF_CNT: c_int = AF_CNT;
548pub const PF_SIP: c_int = AF_SIP;
549pub const PF_IPX: c_int = AF_IPX;
550pub const PF_RTIP: c_int = AF_RTIP;
551pub const PF_PIP: c_int = AF_PIP;
552pub const PF_ISDN: c_int = AF_ISDN;
553pub const PF_KEY: c_int = AF_KEY;
554pub const PF_INET6: c_int = AF_INET6;
555pub const PF_NATM: c_int = AF_NATM;
556pub const PF_SYSTEM: c_int = AF_SYSTEM;
557pub const PF_NETBIOS: c_int = AF_NETBIOS;
558pub const PF_PPP: c_int = AF_PPP;
559pub const PF_MAX: c_int = AF_MAX;
560
561pub const SYSPROTO_EVENT: c_int = 1;
562pub const SYSPROTO_CONTROL: c_int = 2;
563
564pub const SOCK_STREAM: c_int = 1;
565pub const SOCK_DGRAM: c_int = 2;
566pub const SOCK_RAW: c_int = 3;
567pub const SOCK_RDM: c_int = 4;
568pub const SOCK_SEQPACKET: c_int = 5;
569pub const SOCK_MAXADDRLEN: c_int = 255;
570
571fn wstatus(x: i32) i32 {
572 return x & 0o177;
573}
129574const wstopped = 0o177;
130pub fn WEXITSTATUS(x: i32) i32 { return x >> 8; }
131pub fn WTERMSIG(x: i32) i32 { return wstatus(x); }
132pub fn WSTOPSIG(x: i32) i32 { return x >> 8; }
133pub fn WIFEXITED(x: i32) bool { return wstatus(x) == 0; }
134pub fn WIFSTOPPED(x: i32) bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }
135pub fn WIFSIGNALED(x: i32) bool { return wstatus(x) != wstopped and wstatus(x) != 0; }
575pub fn WEXITSTATUS(x: i32) i32 {
576 return x >> 8;
577}
578pub fn WTERMSIG(x: i32) i32 {
579 return wstatus(x);
580}
581pub fn WSTOPSIG(x: i32) i32 {
582 return x >> 8;
583}
584pub fn WIFEXITED(x: i32) bool {
585 return wstatus(x) == 0;
586}
587pub fn WIFSTOPPED(x: i32) bool {
588 return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
589}
590pub fn WIFSIGNALED(x: i32) bool {
591 return wstatus(x) != wstopped and wstatus(x) != 0;
592}
136593
137594/// Get the errno from a syscall return value, or 0 for no error.
138595pub fn getErrno(r: usize) usize {
139596 const signed_r = @bitCast(isize, r);
140 return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
597 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
141598}
142599
143600pub fn close(fd: i32) usize {
......@@ -156,7 +613,7 @@ pub fn isatty(fd: i32) bool {
156613 return c.isatty(fd) != 0;
157614}
158615
159pub fn fstat(fd: i32, buf: &c.Stat) usize {
616pub fn fstat(fd: i32, buf: *c.Stat) usize {
160617 return errnoWrap(c.@"fstat$INODE64"(fd, buf));
161618}
162619
......@@ -164,7 +621,8 @@ pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
164621 return errnoWrap(c.lseek(fd, offset, whence));
165622}
166623
167pub fn open(path: &const u8, flags: u32, mode: usize) usize {
624// TODO https://github.com/ziglang/zig/issues/265 on the whole file
625pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
168626 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
169627}
170628
......@@ -172,83 +630,123 @@ pub fn raise(sig: i32) usize {
172630 return errnoWrap(c.raise(sig));
173631}
174632
175pub fn read(fd: i32, buf: &u8, nbyte: usize) usize {
176 return errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte));
633pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
634 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
177635}
178636
179pub fn stat(noalias path: &const u8, noalias buf: &stat) usize {
637pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
180638 return errnoWrap(c.stat(path, buf));
181639}
182640
183pub fn write(fd: i32, buf: &const u8, nbyte: usize) usize {
184 return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte));
641pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
642 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
185643}
186644
187pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,
188 offset: isize) usize
189{
190 const ptr_result = c.mmap(@ptrCast(&c_void, address), length,
191 @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
645pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
646 const ptr_result = c.mmap(
647 @ptrCast(*c_void, address),
648 length,
649 @bitCast(c_int, @intCast(c_uint, prot)),
650 @bitCast(c_int, c_uint(flags)),
651 fd,
652 offset,
653 );
192654 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
193655 return errnoWrap(isize_result);
194656}
195657
196pub fn munmap(address: &u8, length: usize) usize {
197 return errnoWrap(c.munmap(@ptrCast(&c_void, address), length));
658pub fn munmap(address: usize, length: usize) usize {
659 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
198660}
199661
200pub fn unlink(path: &const u8) usize {
662pub fn unlink(path: [*]const u8) usize {
201663 return errnoWrap(c.unlink(path));
202664}
203665
204pub fn getcwd(buf: &u8, size: usize) usize {
205 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;
666pub fn getcwd(buf: [*]u8, size: usize) usize {
667 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
206668}
207669
208pub fn waitpid(pid: i32, status: &i32, options: u32) usize {
670pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
209671 comptime assert(i32.bit_count == c_int.bit_count);
210 return errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options)));
672 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
211673}
212674
213675pub fn fork() usize {
214676 return errnoWrap(c.fork());
215677}
216678
217pub fn access(path: &const u8, mode: u32) usize {
679pub fn access(path: [*]const u8, mode: u32) usize {
218680 return errnoWrap(c.access(path, mode));
219681}
220682
221pub fn pipe(fds: &[2]i32) usize {
683pub fn pipe(fds: *[2]i32) usize {
222684 comptime assert(i32.bit_count == c_int.bit_count);
223 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
685 return errnoWrap(c.pipe(@ptrCast(*[2]c_int, fds)));
224686}
225687
226
227pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
688pub fn getdirentries64(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
228689 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
229690}
230691
231pub fn mkdir(path: &const u8, mode: u32) usize {
692pub fn kqueue() usize {
693 return errnoWrap(c.kqueue());
694}
695
696pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
697 return errnoWrap(c.kevent(
698 kq,
699 changelist.ptr,
700 @intCast(c_int, changelist.len),
701 eventlist.ptr,
702 @intCast(c_int, eventlist.len),
703 timeout,
704 ));
705}
706
707pub fn kevent64(
708 kq: i32,
709 changelist: []const kevent64_s,
710 eventlist: []kevent64_s,
711 flags: u32,
712 timeout: ?*const timespec,
713) usize {
714 return errnoWrap(c.kevent64(kq, changelist.ptr, changelist.len, eventlist.ptr, eventlist.len, flags, timeout));
715}
716
717pub fn mkdir(path: [*]const u8, mode: u32) usize {
232718 return errnoWrap(c.mkdir(path, mode));
233719}
234720
235pub fn symlink(existing: &const u8, new: &const u8) usize {
721pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
236722 return errnoWrap(c.symlink(existing, new));
237723}
238724
239pub fn rename(old: &const u8, new: &const u8) usize {
725pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
726 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
727}
728
729pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
730 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
731}
732
733pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
734 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
735}
736
737pub fn rename(old: [*]const u8, new: [*]const u8) usize {
240738 return errnoWrap(c.rename(old, new));
241739}
242740
243pub fn rmdir(path: &const u8) usize {
741pub fn rmdir(path: [*]const u8) usize {
244742 return errnoWrap(c.rmdir(path));
245743}
246744
247pub fn chdir(path: &const u8) usize {
745pub fn chdir(path: [*]const u8) usize {
248746 return errnoWrap(c.chdir(path));
249747}
250748
251pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {
749pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
252750 return errnoWrap(c.execve(path, argv, envp));
253751}
254752
......@@ -256,16 +754,20 @@ pub fn dup2(old: i32, new: i32) usize {
256754 return errnoWrap(c.dup2(old, new));
257755}
258756
259pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) usize {
757pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
260758 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
261759}
262760
263pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
761pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize {
762 return errnoWrap(c.gettimeofday(tv, tz));
763}
764
765pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
264766 return errnoWrap(c.nanosleep(req, rem));
265767}
266768
267pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) usize {
268 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
769pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
770 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
269771}
270772
271773pub fn setreuid(ruid: u32, euid: u32) usize {
......@@ -276,26 +778,26 @@ pub fn setregid(rgid: u32, egid: u32) usize {
276778 return errnoWrap(c.setregid(rgid, egid));
277779}
278780
279pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {
781pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
280782 return errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset));
281783}
282784
283pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
785pub fn sigaction(sig: u5, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
284786 assert(sig != SIGKILL);
285787 assert(sig != SIGSTOP);
286 var cact = c.Sigaction {
287 .handler = @ptrCast(extern fn(c_int)void, act.handler),
788 var cact = c.Sigaction{
789 .handler = @ptrCast(extern fn (c_int) void, act.handler),
288790 .sa_flags = @bitCast(c_int, act.flags),
289791 .sa_mask = act.mask,
290792 };
291793 var coact: c.Sigaction = undefined;
292 const result = errnoWrap(c.sigaction(sig, &cact, &coact));
794 const result = errnoWrap(c.sigaction(sig, *cact, *coact));
293795 if (result != 0) {
294796 return result;
295797 }
296798 if (oact) |old| {
297 *old = Sigaction {
298 .handler = @ptrCast(extern fn(i32)void, coact.handler),
799 old.* = Sigaction{
800 .handler = @ptrCast(extern fn (i32) void, coact.handler),
299801 .flags = @bitCast(u32, coact.sa_flags),
300802 .mask = coact.sa_mask,
301803 };
......@@ -313,20 +815,31 @@ pub const dirent = c.dirent;
313815pub const sa_family_t = c.sa_family_t;
314816pub const sockaddr = c.sockaddr;
315817
818/// Renamed from `kevent` to `Kevent` to avoid conflict with the syscall.
819pub const Kevent = c.Kevent;
820pub const kevent64_s = c.kevent64_s;
821
316822/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
317823pub const Sigaction = struct {
318 handler: extern fn(i32)void,
824 handler: extern fn (i32) void,
319825 mask: sigset_t,
320826 flags: u32,
321827};
322828
323pub fn sigaddset(set: &sigset_t, signo: u5) void {
324 *set |= u32(1) << (signo - 1);
829pub fn sigaddset(set: *sigset_t, signo: u5) void {
830 set.* |= u32(1) << (signo - 1);
325831}
326832
327833/// Takes the return value from a syscall and formats it back in the way
328834/// that the kernel represents it to libc. Errno was a mistake, let's make
329835/// it go away forever.
330836fn errnoWrap(value: isize) usize {
331 return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
837 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
332838}
839
840pub const timezone = c.timezone;
841pub const timeval = c.timeval;
842pub const mach_timebase_info_data = c.mach_timebase_info_data;
843
844pub const mach_absolute_time = c.mach_absolute_time;
845pub const mach_timebase_info = c.mach_timebase_info;
std/os/darwin/errno.zig created+328
......@@ -0,0 +1,328 @@
1/// Operation not permitted
2pub const EPERM = 1;
3
4/// No such file or directory
5pub const ENOENT = 2;
6
7/// No such process
8pub const ESRCH = 3;
9
10/// Interrupted system call
11pub const EINTR = 4;
12
13/// Input/output error
14pub const EIO = 5;
15
16/// Device not configured
17pub const ENXIO = 6;
18
19/// Argument list too long
20pub const E2BIG = 7;
21
22/// Exec format error
23pub const ENOEXEC = 8;
24
25/// Bad file descriptor
26pub const EBADF = 9;
27
28/// No child processes
29pub const ECHILD = 10;
30
31/// Resource deadlock avoided
32pub const EDEADLK = 11;
33
34/// Cannot allocate memory
35pub const ENOMEM = 12;
36
37/// Permission denied
38pub const EACCES = 13;
39
40/// Bad address
41pub const EFAULT = 14;
42
43/// Block device required
44pub const ENOTBLK = 15;
45
46/// Device / Resource busy
47pub const EBUSY = 16;
48
49/// File exists
50pub const EEXIST = 17;
51
52/// Cross-device link
53pub const EXDEV = 18;
54
55/// Operation not supported by device
56pub const ENODEV = 19;
57
58/// Not a directory
59pub const ENOTDIR = 20;
60
61/// Is a directory
62pub const EISDIR = 21;
63
64/// Invalid argument
65pub const EINVAL = 22;
66
67/// Too many open files in system
68pub const ENFILE = 23;
69
70/// Too many open files
71pub const EMFILE = 24;
72
73/// Inappropriate ioctl for device
74pub const ENOTTY = 25;
75
76/// Text file busy
77pub const ETXTBSY = 26;
78
79/// File too large
80pub const EFBIG = 27;
81
82/// No space left on device
83pub const ENOSPC = 28;
84
85/// Illegal seek
86pub const ESPIPE = 29;
87
88/// Read-only file system
89pub const EROFS = 30;
90
91/// Too many links
92pub const EMLINK = 31;
93/// Broken pipe
94
95// math software
96pub const EPIPE = 32;
97
98/// Numerical argument out of domain
99pub const EDOM = 33;
100/// Result too large
101
102// non-blocking and interrupt i/o
103pub const ERANGE = 34;
104
105/// Resource temporarily unavailable
106pub const EAGAIN = 35;
107
108/// Operation would block
109pub const EWOULDBLOCK = EAGAIN;
110
111/// Operation now in progress
112pub const EINPROGRESS = 36;
113/// Operation already in progress
114
115// ipc/network software -- argument errors
116pub const EALREADY = 37;
117
118/// Socket operation on non-socket
119pub const ENOTSOCK = 38;
120
121/// Destination address required
122pub const EDESTADDRREQ = 39;
123
124/// Message too long
125pub const EMSGSIZE = 40;
126
127/// Protocol wrong type for socket
128pub const EPROTOTYPE = 41;
129
130/// Protocol not available
131pub const ENOPROTOOPT = 42;
132
133/// Protocol not supported
134pub const EPROTONOSUPPORT = 43;
135
136/// Socket type not supported
137pub const ESOCKTNOSUPPORT = 44;
138
139/// Operation not supported
140pub const ENOTSUP = 45;
141
142/// Protocol family not supported
143pub const EPFNOSUPPORT = 46;
144
145/// Address family not supported by protocol family
146pub const EAFNOSUPPORT = 47;
147
148/// Address already in use
149pub const EADDRINUSE = 48;
150/// Can't assign requested address
151
152// ipc/network software -- operational errors
153pub const EADDRNOTAVAIL = 49;
154
155/// Network is down
156pub const ENETDOWN = 50;
157
158/// Network is unreachable
159pub const ENETUNREACH = 51;
160
161/// Network dropped connection on reset
162pub const ENETRESET = 52;
163
164/// Software caused connection abort
165pub const ECONNABORTED = 53;
166
167/// Connection reset by peer
168pub const ECONNRESET = 54;
169
170/// No buffer space available
171pub const ENOBUFS = 55;
172
173/// Socket is already connected
174pub const EISCONN = 56;
175
176/// Socket is not connected
177pub const ENOTCONN = 57;
178
179/// Can't send after socket shutdown
180pub const ESHUTDOWN = 58;
181
182/// Too many references: can't splice
183pub const ETOOMANYREFS = 59;
184
185/// Operation timed out
186pub const ETIMEDOUT = 60;
187
188/// Connection refused
189pub const ECONNREFUSED = 61;
190
191/// Too many levels of symbolic links
192pub const ELOOP = 62;
193
194/// File name too long
195pub const ENAMETOOLONG = 63;
196
197/// Host is down
198pub const EHOSTDOWN = 64;
199
200/// No route to host
201pub const EHOSTUNREACH = 65;
202/// Directory not empty
203
204// quotas & mush
205pub const ENOTEMPTY = 66;
206
207/// Too many processes
208pub const EPROCLIM = 67;
209
210/// Too many users
211pub const EUSERS = 68;
212/// Disc quota exceeded
213
214// Network File System
215pub const EDQUOT = 69;
216
217/// Stale NFS file handle
218pub const ESTALE = 70;
219
220/// Too many levels of remote in path
221pub const EREMOTE = 71;
222
223/// RPC struct is bad
224pub const EBADRPC = 72;
225
226/// RPC version wrong
227pub const ERPCMISMATCH = 73;
228
229/// RPC prog. not avail
230pub const EPROGUNAVAIL = 74;
231
232/// Program version wrong
233pub const EPROGMISMATCH = 75;
234
235/// Bad procedure for program
236pub const EPROCUNAVAIL = 76;
237
238/// No locks available
239pub const ENOLCK = 77;
240
241/// Function not implemented
242pub const ENOSYS = 78;
243
244/// Inappropriate file type or format
245pub const EFTYPE = 79;
246
247/// Authentication error
248pub const EAUTH = 80;
249/// Need authenticator
250
251// Intelligent device errors
252pub const ENEEDAUTH = 81;
253
254/// Device power is off
255pub const EPWROFF = 82;
256
257/// Device error, e.g. paper out
258pub const EDEVERR = 83;
259/// Value too large to be stored in data type
260
261// Program loading errors
262pub const EOVERFLOW = 84;
263
264/// Bad executable
265pub const EBADEXEC = 85;
266
267/// Bad CPU type in executable
268pub const EBADARCH = 86;
269
270/// Shared library version mismatch
271pub const ESHLIBVERS = 87;
272
273/// Malformed Macho file
274pub const EBADMACHO = 88;
275
276/// Operation canceled
277pub const ECANCELED = 89;
278
279/// Identifier removed
280pub const EIDRM = 90;
281
282/// No message of desired type
283pub const ENOMSG = 91;
284
285/// Illegal byte sequence
286pub const EILSEQ = 92;
287
288/// Attribute not found
289pub const ENOATTR = 93;
290
291/// Bad message
292pub const EBADMSG = 94;
293
294/// Reserved
295pub const EMULTIHOP = 95;
296
297/// No message available on STREAM
298pub const ENODATA = 96;
299
300/// Reserved
301pub const ENOLINK = 97;
302
303/// No STREAM resources
304pub const ENOSR = 98;
305
306/// Not a STREAM
307pub const ENOSTR = 99;
308
309/// Protocol error
310pub const EPROTO = 100;
311
312/// STREAM ioctl timeout
313pub const ETIME = 101;
314
315/// No such policy registered
316pub const ENOPOLICY = 103;
317
318/// State not recoverable
319pub const ENOTRECOVERABLE = 104;
320
321/// Previous owner died
322pub const EOWNERDEAD = 105;
323
324/// Interface output queue is full
325pub const EQFULL = 106;
326
327/// Must be equal largest errno
328pub const ELAST = 106;
std/os/darwin_errno.zig deleted-142
......@@ -1,142 +0,0 @@
1
2pub const EPERM = 1; /// Operation not permitted
3pub const ENOENT = 2; /// No such file or directory
4pub const ESRCH = 3; /// No such process
5pub const EINTR = 4; /// Interrupted system call
6pub const EIO = 5; /// Input/output error
7pub const ENXIO = 6; /// Device not configured
8pub const E2BIG = 7; /// Argument list too long
9pub const ENOEXEC = 8; /// Exec format error
10pub const EBADF = 9; /// Bad file descriptor
11pub const ECHILD = 10; /// No child processes
12pub const EDEADLK = 11; /// Resource deadlock avoided
13
14pub const ENOMEM = 12; /// Cannot allocate memory
15pub const EACCES = 13; /// Permission denied
16pub const EFAULT = 14; /// Bad address
17pub const ENOTBLK = 15; /// Block device required
18pub const EBUSY = 16; /// Device / Resource busy
19pub const EEXIST = 17; /// File exists
20pub const EXDEV = 18; /// Cross-device link
21pub const ENODEV = 19; /// Operation not supported by device
22pub const ENOTDIR = 20; /// Not a directory
23pub const EISDIR = 21; /// Is a directory
24pub const EINVAL = 22; /// Invalid argument
25pub const ENFILE = 23; /// Too many open files in system
26pub const EMFILE = 24; /// Too many open files
27pub const ENOTTY = 25; /// Inappropriate ioctl for device
28pub const ETXTBSY = 26; /// Text file busy
29pub const EFBIG = 27; /// File too large
30pub const ENOSPC = 28; /// No space left on device
31pub const ESPIPE = 29; /// Illegal seek
32pub const EROFS = 30; /// Read-only file system
33pub const EMLINK = 31; /// Too many links
34pub const EPIPE = 32; /// Broken pipe
35
36// math software
37pub const EDOM = 33; /// Numerical argument out of domain
38pub const ERANGE = 34; /// Result too large
39
40// non-blocking and interrupt i/o
41pub const EAGAIN = 35; /// Resource temporarily unavailable
42pub const EWOULDBLOCK = EAGAIN; /// Operation would block
43pub const EINPROGRESS = 36; /// Operation now in progress
44pub const EALREADY = 37; /// Operation already in progress
45
46// ipc/network software -- argument errors
47pub const ENOTSOCK = 38; /// Socket operation on non-socket
48pub const EDESTADDRREQ = 39; /// Destination address required
49pub const EMSGSIZE = 40; /// Message too long
50pub const EPROTOTYPE = 41; /// Protocol wrong type for socket
51pub const ENOPROTOOPT = 42; /// Protocol not available
52pub const EPROTONOSUPPORT = 43; /// Protocol not supported
53
54pub const ESOCKTNOSUPPORT = 44; /// Socket type not supported
55
56pub const ENOTSUP = 45; /// Operation not supported
57
58pub const EPFNOSUPPORT = 46; /// Protocol family not supported
59pub const EAFNOSUPPORT = 47; /// Address family not supported by protocol family
60pub const EADDRINUSE = 48; /// Address already in use
61pub const EADDRNOTAVAIL = 49; /// Can't assign requested address
62
63// ipc/network software -- operational errors
64pub const ENETDOWN = 50; /// Network is down
65pub const ENETUNREACH = 51; /// Network is unreachable
66pub const ENETRESET = 52; /// Network dropped connection on reset
67pub const ECONNABORTED = 53; /// Software caused connection abort
68pub const ECONNRESET = 54; /// Connection reset by peer
69pub const ENOBUFS = 55; /// No buffer space available
70pub const EISCONN = 56; /// Socket is already connected
71pub const ENOTCONN = 57; /// Socket is not connected
72
73pub const ESHUTDOWN = 58; /// Can't send after socket shutdown
74pub const ETOOMANYREFS = 59; /// Too many references: can't splice
75
76pub const ETIMEDOUT = 60; /// Operation timed out
77pub const ECONNREFUSED = 61; /// Connection refused
78
79pub const ELOOP = 62; /// Too many levels of symbolic links
80pub const ENAMETOOLONG = 63; /// File name too long
81
82pub const EHOSTDOWN = 64; /// Host is down
83pub const EHOSTUNREACH = 65; /// No route to host
84pub const ENOTEMPTY = 66; /// Directory not empty
85
86// quotas & mush
87pub const EPROCLIM = 67; /// Too many processes
88pub const EUSERS = 68; /// Too many users
89pub const EDQUOT = 69; /// Disc quota exceeded
90
91// Network File System
92pub const ESTALE = 70; /// Stale NFS file handle
93pub const EREMOTE = 71; /// Too many levels of remote in path
94pub const EBADRPC = 72; /// RPC struct is bad
95pub const ERPCMISMATCH = 73; /// RPC version wrong
96pub const EPROGUNAVAIL = 74; /// RPC prog. not avail
97pub const EPROGMISMATCH = 75; /// Program version wrong
98pub const EPROCUNAVAIL = 76; /// Bad procedure for program
99
100pub const ENOLCK = 77; /// No locks available
101pub const ENOSYS = 78; /// Function not implemented
102
103pub const EFTYPE = 79; /// Inappropriate file type or format
104pub const EAUTH = 80; /// Authentication error
105pub const ENEEDAUTH = 81; /// Need authenticator
106
107// Intelligent device errors
108pub const EPWROFF = 82; /// Device power is off
109pub const EDEVERR = 83; /// Device error, e.g. paper out
110
111pub const EOVERFLOW = 84; /// Value too large to be stored in data type
112
113// Program loading errors
114pub const EBADEXEC = 85; /// Bad executable
115pub const EBADARCH = 86; /// Bad CPU type in executable
116pub const ESHLIBVERS = 87; /// Shared library version mismatch
117pub const EBADMACHO = 88; /// Malformed Macho file
118
119pub const ECANCELED = 89; /// Operation canceled
120
121pub const EIDRM = 90; /// Identifier removed
122pub const ENOMSG = 91; /// No message of desired type
123pub const EILSEQ = 92; /// Illegal byte sequence
124pub const ENOATTR = 93; /// Attribute not found
125
126pub const EBADMSG = 94; /// Bad message
127pub const EMULTIHOP = 95; /// Reserved
128pub const ENODATA = 96; /// No message available on STREAM
129pub const ENOLINK = 97; /// Reserved
130pub const ENOSR = 98; /// No STREAM resources
131pub const ENOSTR = 99; /// Not a STREAM
132pub const EPROTO = 100; /// Protocol error
133pub const ETIME = 101; /// STREAM ioctl timeout
134
135pub const ENOPOLICY = 103; /// No such policy registered
136
137pub const ENOTRECOVERABLE = 104; /// State not recoverable
138pub const EOWNERDEAD = 105; /// Previous owner died
139
140pub const EQFULL = 106; /// Interface output queue is full
141pub const ELAST = 106; /// Must be equal largest errno
142
std/os/epoch.zig created+26
......@@ -0,0 +1,26 @@
1/// Epoch reference times in terms of their difference from
2/// posix epoch in seconds.
3pub const posix = 0; //Jan 01, 1970 AD
4pub const dos = 315532800; //Jan 01, 1980 AD
5pub const ios = 978307200; //Jan 01, 2001 AD
6pub const openvms = -3506716800; //Nov 17, 1858 AD
7pub const zos = -2208988800; //Jan 01, 1900 AD
8pub const windows = -11644473600; //Jan 01, 1601 AD
9pub const amiga = 252460800; //Jan 01, 1978 AD
10pub const pickos = -63244800; //Dec 31, 1967 AD
11pub const gps = 315964800; //Jan 06, 1980 AD
12pub const clr = -62135769600; //Jan 01, 0001 AD
13
14pub const unix = posix;
15pub const android = posix;
16pub const os2 = dos;
17pub const bios = dos;
18pub const vfat = dos;
19pub const ntfs = windows;
20pub const ntp = zos;
21pub const jbase = pickos;
22pub const aros = amiga;
23pub const morphos = amiga;
24pub const brew = gps;
25pub const atsc = gps;
26pub const go = clr;
std/os/file.zig+100-85
......@@ -15,18 +15,24 @@ pub const File = struct {
1515 /// The OS-specific file descriptor or file handle.
1616 handle: os.FileHandle,
1717
18 const OpenError = os.WindowsOpenError || os.PosixOpenError;
18 pub const OpenError = os.WindowsOpenError || os.PosixOpenError;
1919
2020 /// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
2121 /// Call close to clean up.
22 pub fn openRead(allocator: &mem.Allocator, path: []const u8) OpenError!File {
22 pub fn openRead(allocator: *mem.Allocator, path: []const u8) OpenError!File {
2323 if (is_posix) {
24 const flags = posix.O_LARGEFILE|posix.O_RDONLY;
24 const flags = posix.O_LARGEFILE | posix.O_RDONLY;
2525 const fd = try os.posixOpen(allocator, path, flags, 0);
2626 return openHandle(fd);
2727 } else if (is_windows) {
28 const handle = try os.windowsOpen(allocator, path, windows.GENERIC_READ, windows.FILE_SHARE_READ,
29 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
28 const handle = try os.windowsOpen(
29 allocator,
30 path,
31 windows.GENERIC_READ,
32 windows.FILE_SHARE_READ,
33 windows.OPEN_EXISTING,
34 windows.FILE_ATTRIBUTE_NORMAL,
35 );
3036 return openHandle(handle);
3137 } else {
3238 @compileError("TODO implement openRead for this OS");
......@@ -34,94 +40,111 @@ pub const File = struct {
3440 }
3541
3642 /// Calls `openWriteMode` with os.default_file_mode for the mode.
37 pub fn openWrite(allocator: &mem.Allocator, path: []const u8) OpenError!File {
43 pub fn openWrite(allocator: *mem.Allocator, path: []const u8) OpenError!File {
3844 return openWriteMode(allocator, path, os.default_file_mode);
39
4045 }
4146
4247 /// If the path does not exist it will be created.
4348 /// If a file already exists in the destination it will be truncated.
4449 /// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
4550 /// Call close to clean up.
46 pub fn openWriteMode(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) OpenError!File {
51 pub fn openWriteMode(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) OpenError!File {
4752 if (is_posix) {
48 const flags = posix.O_LARGEFILE|posix.O_WRONLY|posix.O_CREAT|posix.O_CLOEXEC|posix.O_TRUNC;
53 const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
4954 const fd = try os.posixOpen(allocator, path, flags, file_mode);
5055 return openHandle(fd);
5156 } else if (is_windows) {
52 const handle = try os.windowsOpen(allocator, path, windows.GENERIC_WRITE,
53 windows.FILE_SHARE_WRITE|windows.FILE_SHARE_READ|windows.FILE_SHARE_DELETE,
54 windows.CREATE_ALWAYS, windows.FILE_ATTRIBUTE_NORMAL);
57 const handle = try os.windowsOpen(
58 allocator,
59 path,
60 windows.GENERIC_WRITE,
61 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
62 windows.CREATE_ALWAYS,
63 windows.FILE_ATTRIBUTE_NORMAL,
64 );
5565 return openHandle(handle);
5666 } else {
5767 @compileError("TODO implement openWriteMode for this OS");
5868 }
59
6069 }
6170
6271 /// If the path does not exist it will be created.
6372 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
6473 /// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
6574 /// Call close to clean up.
66 pub fn openWriteNoClobber(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) OpenError!File {
75 pub fn openWriteNoClobber(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) OpenError!File {
6776 if (is_posix) {
68 const flags = posix.O_LARGEFILE|posix.O_WRONLY|posix.O_CREAT|posix.O_CLOEXEC|posix.O_EXCL;
77 const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_EXCL;
6978 const fd = try os.posixOpen(allocator, path, flags, file_mode);
7079 return openHandle(fd);
7180 } else if (is_windows) {
72 const handle = try os.windowsOpen(allocator, path, windows.GENERIC_WRITE,
73 windows.FILE_SHARE_WRITE|windows.FILE_SHARE_READ|windows.FILE_SHARE_DELETE,
74 windows.CREATE_NEW, windows.FILE_ATTRIBUTE_NORMAL);
81 const handle = try os.windowsOpen(
82 allocator,
83 path,
84 windows.GENERIC_WRITE,
85 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
86 windows.CREATE_NEW,
87 windows.FILE_ATTRIBUTE_NORMAL,
88 );
7589 return openHandle(handle);
7690 } else {
7791 @compileError("TODO implement openWriteMode for this OS");
7892 }
79
8093 }
8194
8295 pub fn openHandle(handle: os.FileHandle) File {
83 return File {
84 .handle = handle,
85 };
96 return File{ .handle = handle };
8697 }
8798
88 pub fn access(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool {
99 pub const AccessError = error{
100 PermissionDenied,
101 NotFound,
102 NameTooLong,
103 BadMode,
104 BadPathName,
105 Io,
106 SystemResources,
107 OutOfMemory,
108
109 Unexpected,
110 };
111
112 pub fn access(allocator: *mem.Allocator, path: []const u8) AccessError!void {
89113 const path_with_null = try std.cstr.addNullByte(allocator, path);
90114 defer allocator.free(path_with_null);
91115
92116 if (is_posix) {
93 // mode is ignored and is always F_OK for now
94117 const result = posix.access(path_with_null.ptr, posix.F_OK);
95118 const err = posix.getErrno(result);
96 if (err > 0) {
97 return switch (err) {
98 posix.EACCES => error.PermissionDenied,
99 posix.EROFS => error.PermissionDenied,
100 posix.ELOOP => error.PermissionDenied,
101 posix.ETXTBSY => error.PermissionDenied,
102 posix.ENOTDIR => error.NotFound,
103 posix.ENOENT => error.NotFound,
119 switch (err) {
120 0 => return,
121 posix.EACCES => return error.PermissionDenied,
122 posix.EROFS => return error.PermissionDenied,
123 posix.ELOOP => return error.PermissionDenied,
124 posix.ETXTBSY => return error.PermissionDenied,
125 posix.ENOTDIR => return error.NotFound,
126 posix.ENOENT => return error.NotFound,
104127
105 posix.ENAMETOOLONG => error.NameTooLong,
106 posix.EINVAL => error.BadMode,
107 posix.EFAULT => error.BadPathName,
108 posix.EIO => error.Io,
109 posix.ENOMEM => error.SystemResources,
110 else => os.unexpectedErrorPosix(err),
111 };
128 posix.ENAMETOOLONG => return error.NameTooLong,
129 posix.EINVAL => unreachable,
130 posix.EFAULT => return error.BadPathName,
131 posix.EIO => return error.Io,
132 posix.ENOMEM => return error.SystemResources,
133 else => return os.unexpectedErrorPosix(err),
112134 }
113 return true;
114135 } else if (is_windows) {
115 if (os.windows.PathFileExists(path_with_null.ptr) == os.windows.TRUE) {
116 return true;
136 if (os.windows.GetFileAttributesA(path_with_null.ptr) != os.windows.INVALID_FILE_ATTRIBUTES) {
137 return;
117138 }
118139
119140 const err = windows.GetLastError();
120 return switch (err) {
121 windows.ERROR.FILE_NOT_FOUND => error.NotFound,
122 windows.ERROR.ACCESS_DENIED => error.PermissionDenied,
123 else => os.unexpectedErrorWindows(err),
124 };
141 switch (err) {
142 windows.ERROR.FILE_NOT_FOUND,
143 windows.ERROR.PATH_NOT_FOUND,
144 => return error.NotFound,
145 windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
146 else => return os.unexpectedErrorWindows(err),
147 }
125148 } else {
126149 @compileError("TODO implement access for this OS");
127150 }
......@@ -129,17 +152,17 @@ pub const File = struct {
129152
130153 /// Upon success, the stream is in an uninitialized state. To continue using it,
131154 /// you must use the open() function.
132 pub fn close(self: &File) void {
155 pub fn close(self: *File) void {
133156 os.close(self.handle);
134157 self.handle = undefined;
135158 }
136159
137160 /// Calls `os.isTty` on `self.handle`.
138 pub fn isTty(self: &File) bool {
161 pub fn isTty(self: *File) bool {
139162 return os.isTty(self.handle);
140163 }
141164
142 pub fn seekForward(self: &File, amount: isize) !void {
165 pub fn seekForward(self: *File, amount: isize) !void {
143166 switch (builtin.os) {
144167 Os.linux, Os.macosx, Os.ios => {
145168 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
......@@ -168,7 +191,7 @@ pub const File = struct {
168191 }
169192 }
170193
171 pub fn seekTo(self: &File, pos: usize) !void {
194 pub fn seekTo(self: *File, pos: usize) !void {
172195 switch (builtin.os) {
173196 Os.linux, Os.macosx, Os.ios => {
174197 const ipos = try math.cast(isize, pos);
......@@ -199,7 +222,7 @@ pub const File = struct {
199222 }
200223 }
201224
202 pub fn getPos(self: &File) !usize {
225 pub fn getPos(self: *File) !usize {
203226 switch (builtin.os) {
204227 Os.linux, Os.macosx, Os.ios => {
205228 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
......@@ -217,7 +240,7 @@ pub const File = struct {
217240 return result;
218241 },
219242 Os.windows => {
220 var pos : windows.LARGE_INTEGER = undefined;
243 var pos: windows.LARGE_INTEGER = undefined;
221244 if (windows.SetFilePointerEx(self.handle, 0, &pos, windows.FILE_CURRENT) == 0) {
222245 const err = windows.GetLastError();
223246 return switch (err) {
......@@ -227,31 +250,16 @@ pub const File = struct {
227250 }
228251
229252 assert(pos >= 0);
230 if (@sizeOf(@typeOf(pos)) > @sizeOf(usize)) {
231 if (pos > @maxValue(usize)) {
232 return error.FilePosLargerThanPointerRange;
233 }
234 }
235
236 return usize(pos);
253 return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange;
237254 },
238255 else => @compileError("unsupported OS"),
239256 }
240257 }
241258
242 pub fn getEndPos(self: &File) !usize {
259 pub fn getEndPos(self: *File) !usize {
243260 if (is_posix) {
244 var stat: posix.Stat = undefined;
245 const err = posix.getErrno(posix.fstat(self.handle, &stat));
246 if (err > 0) {
247 return switch (err) {
248 posix.EBADF => error.BadFd,
249 posix.ENOMEM => error.SystemResources,
250 else => os.unexpectedErrorPosix(err),
251 };
252 }
253
254 return usize(stat.size);
261 const stat = try os.posixFStat(self.handle);
262 return @intCast(usize, stat.size);
255263 } else if (is_windows) {
256264 var file_size: windows.LARGE_INTEGER = undefined;
257265 if (windows.GetFileSizeEx(self.handle, &file_size) == 0) {
......@@ -262,19 +270,19 @@ pub const File = struct {
262270 }
263271 if (file_size < 0)
264272 return error.Overflow;
265 return math.cast(usize, u64(file_size));
273 return math.cast(usize, @intCast(u64, file_size));
266274 } else {
267275 @compileError("TODO support getEndPos on this OS");
268276 }
269277 }
270278
271 pub const ModeError = error {
279 pub const ModeError = error{
272280 BadFd,
273281 SystemResources,
274282 Unexpected,
275283 };
276284
277 fn mode(self: &File) ModeError!os.FileMode {
285 pub fn mode(self: *File) ModeError!os.FileMode {
278286 if (is_posix) {
279287 var stat: posix.Stat = undefined;
280288 const err = posix.getErrno(posix.fstat(self.handle, &stat));
......@@ -296,22 +304,29 @@ pub const File = struct {
296304 }
297305 }
298306
299 pub const ReadError = error {};
307 pub const ReadError = error{
308 BadFd,
309 Io,
310 IsDir,
311
312 Unexpected,
313 };
300314
301 pub fn read(self: &File, buffer: []u8) !usize {
315 pub fn read(self: *File, buffer: []u8) ReadError!usize {
302316 if (is_posix) {
303317 var index: usize = 0;
304318 while (index < buffer.len) {
305 const amt_read = posix.read(self.handle, &buffer[index], buffer.len - index);
319 const amt_read = posix.read(self.handle, buffer.ptr + index, buffer.len - index);
306320 const read_err = posix.getErrno(amt_read);
307321 if (read_err > 0) {
308322 switch (read_err) {
309 posix.EINTR => continue,
323 posix.EINTR => continue,
310324 posix.EINVAL => unreachable,
311325 posix.EFAULT => unreachable,
312 posix.EBADF => return error.BadFd,
313 posix.EIO => return error.Io,
314 else => return os.unexpectedErrorPosix(read_err),
326 posix.EBADF => return error.BadFd,
327 posix.EIO => return error.Io,
328 posix.EISDIR => return error.IsDir,
329 else => return os.unexpectedErrorPosix(read_err),
315330 }
316331 }
317332 if (amt_read == 0) return index;
......@@ -321,9 +336,9 @@ pub const File = struct {
321336 } else if (is_windows) {
322337 var index: usize = 0;
323338 while (index < buffer.len) {
324 const want_read_count = windows.DWORD(math.min(windows.DWORD(@maxValue(windows.DWORD)), buffer.len - index));
339 const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(@maxValue(windows.DWORD)), buffer.len - index));
325340 var amt_read: windows.DWORD = undefined;
326 if (windows.ReadFile(self.handle, @ptrCast(&c_void, &buffer[index]), want_read_count, &amt_read, null) == 0) {
341 if (windows.ReadFile(self.handle, @ptrCast(*c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) {
327342 const err = windows.GetLastError();
328343 return switch (err) {
329344 windows.ERROR.OPERATION_ABORTED => continue,
......@@ -342,7 +357,7 @@ pub const File = struct {
342357
343358 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
344359
345 fn write(self: &File, bytes: []const u8) WriteError!void {
360 pub fn write(self: *File, bytes: []const u8) WriteError!void {
346361 if (is_posix) {
347362 try os.posixWrite(self.handle, bytes);
348363 } else if (is_windows) {
std/os/get_app_data_dir.zig created+69
......@@ -0,0 +1,69 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const unicode = std.unicode;
4const mem = std.mem;
5const os = std.os;
6
7pub const GetAppDataDirError = error{
8 OutOfMemory,
9 AppDataDirUnavailable,
10};
11
12/// Caller owns returned memory.
13pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
14 switch (builtin.os) {
15 builtin.Os.windows => {
16 var dir_path_ptr: [*]u16 = undefined;
17 switch (os.windows.SHGetKnownFolderPath(
18 &os.windows.FOLDERID_LocalAppData,
19 os.windows.KF_FLAG_CREATE,
20 null,
21 &dir_path_ptr,
22 )) {
23 os.windows.S_OK => {
24 defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
25 const global_dir = unicode.utf16leToUtf8(allocator, utf16lePtrSlice(dir_path_ptr)) catch |err| switch (err) {
26 error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
27 error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
28 error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
29 error.OutOfMemory => return error.OutOfMemory,
30 };
31 defer allocator.free(global_dir);
32 return os.path.join(allocator, global_dir, appname);
33 },
34 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
35 else => return error.AppDataDirUnavailable,
36 }
37 },
38 builtin.Os.macosx => {
39 const home_dir = os.getEnvPosix("HOME") orelse {
40 // TODO look in /etc/passwd
41 return error.AppDataDirUnavailable;
42 };
43 return os.path.join(allocator, home_dir, "Library", "Application Support", appname);
44 },
45 builtin.Os.linux => {
46 const home_dir = os.getEnvPosix("HOME") orelse {
47 // TODO look in /etc/passwd
48 return error.AppDataDirUnavailable;
49 };
50 return os.path.join(allocator, home_dir, ".local", "share", appname);
51 },
52 else => @compileError("Unsupported OS"),
53 }
54}
55
56fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
57 var index: usize = 0;
58 while (ptr[index] != 0) : (index += 1) {}
59 return ptr[0..index];
60}
61
62test "std.os.getAppDataDir" {
63 var buf: [512]u8 = undefined;
64 const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
65
66 // We can't actually validate the result
67 _ = getAppDataDir(allocator, "zig") catch return;
68}
69
std/os/get_user_id.zig+7-7
......@@ -74,27 +74,27 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
7474 '\n' => return error.CorruptPasswordFile,
7575 else => {
7676 const digit = switch (byte) {
77 '0' ... '9' => byte - '0',
77 '0'...'9' => byte - '0',
7878 else => return error.CorruptPasswordFile,
7979 };
80 if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;
81 if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;
80 if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile;
81 if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile;
8282 },
8383 },
8484 State.ReadGroupId => switch (byte) {
8585 '\n', ':' => {
86 return UserInfo {
86 return UserInfo{
8787 .uid = uid,
8888 .gid = gid,
8989 };
9090 },
9191 else => {
9292 const digit = switch (byte) {
93 '0' ... '9' => byte - '0',
93 '0'...'9' => byte - '0',
9494 else => return error.CorruptPasswordFile,
9595 };
96 if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile;
97 if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile;
96 if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile;
97 if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile;
9898 },
9999 },
100100 }
std/os/index.zig+837-318
......@@ -2,26 +2,30 @@ const std = @import("../index.zig");
22const builtin = @import("builtin");
33const Os = builtin.Os;
44const is_windows = builtin.os == Os.windows;
5const is_posix = switch (builtin.os) {
6 builtin.Os.linux, builtin.Os.macosx => true,
7 else => false,
8};
59const os = this;
610
711test "std.os" {
812 _ = @import("child_process.zig");
913 _ = @import("darwin.zig");
10 _ = @import("darwin_errno.zig");
14 _ = @import("darwin/errno.zig");
1115 _ = @import("get_user_id.zig");
12 _ = @import("linux/errno.zig");
1316 _ = @import("linux/index.zig");
14 _ = @import("linux/x86_64.zig");
1517 _ = @import("path.zig");
1618 _ = @import("test.zig");
19 _ = @import("time.zig");
1720 _ = @import("windows/index.zig");
21 _ = @import("get_app_data_dir.zig");
1822}
1923
2024pub const windows = @import("windows/index.zig");
2125pub const darwin = @import("darwin.zig");
2226pub const linux = @import("linux/index.zig");
2327pub const zen = @import("zen.zig");
24pub const posix = switch(builtin.os) {
28pub const posix = switch (builtin.os) {
2529 Os.linux => linux,
2630 Os.macosx, Os.ios => darwin,
2731 Os.zen => zen,
......@@ -32,6 +36,7 @@ pub const net = @import("net.zig");
3236pub const ChildProcess = @import("child_process.zig").ChildProcess;
3337pub const path = @import("path.zig");
3438pub const File = @import("file.zig").File;
39pub const time = @import("time.zig");
3540
3641pub const FileMode = switch (builtin.os) {
3742 Os.windows => void,
......@@ -54,15 +59,27 @@ pub const windowsWrite = windows_util.windowsWrite;
5459pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
5560pub const windowsOpen = windows_util.windowsOpen;
5661pub const windowsLoadDll = windows_util.windowsLoadDll;
57pub const windowsUnloadDll = windows_util.windowsUnloadDll;
62pub const windowsUnloadDll = windows_util.windowsUnloadDll;
5863pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
5964
65pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;
66pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;
67
68pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;
69pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;
70
71pub const WindowsWaitResult = windows_util.WindowsWaitResult;
72pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;
73
6074pub const WindowsWaitError = windows_util.WaitError;
6175pub const WindowsOpenError = windows_util.OpenError;
6276pub const WindowsWriteError = windows_util.WriteError;
6377
6478pub const FileHandle = if (is_windows) windows.HANDLE else i32;
6579
80pub const getAppDataDir = @import("get_app_data_dir.zig").getAppDataDir;
81pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirError;
82
6683const debug = std.debug;
6784const assert = debug.assert;
6885
......@@ -93,9 +110,9 @@ pub fn getRandomBytes(buf: []u8) !void {
93110 switch (err) {
94111 posix.EINVAL => unreachable,
95112 posix.EFAULT => unreachable,
96 posix.EINTR => continue,
113 posix.EINTR => continue,
97114 posix.ENOSYS => {
98 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC, 0);
115 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
99116 defer close(fd);
100117
101118 try posixRead(fd, buf);
......@@ -107,22 +124,16 @@ pub fn getRandomBytes(buf: []u8) !void {
107124 return;
108125 },
109126 Os.macosx, Os.ios => {
110 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC, 0);
127 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
111128 defer close(fd);
112129
113130 try posixRead(fd, buf);
114131 },
115132 Os.windows => {
116 var hCryptProv: windows.HCRYPTPROV = undefined;
117 if (windows.CryptAcquireContextA(&hCryptProv, null, null, windows.PROV_RSA_FULL, 0) == 0) {
118 const err = windows.GetLastError();
119 return switch (err) {
120 else => unexpectedErrorWindows(err),
121 };
122 }
123 defer _ = windows.CryptReleaseContext(hCryptProv, 0);
124
125 if (windows.CryptGenRandom(hCryptProv, windows.DWORD(buf.len), buf.ptr) == 0) {
133 // Call RtlGenRandom() instead of CryptGetRandom() on Windows
134 // https://github.com/rust-lang-nursery/rand/issues/111
135 // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
136 if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
126137 const err = windows.GetLastError();
127138 return switch (err) {
128139 else => unexpectedErrorWindows(err),
......@@ -130,7 +141,7 @@ pub fn getRandomBytes(buf: []u8) !void {
130141 }
131142 },
132143 Os.zen => {
133 const randomness = []u8 {42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45};
144 const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
134145 var i: usize = 0;
135146 while (i < buf.len) : (i += 1) {
136147 if (i > randomness.len) return error.Unknown;
......@@ -142,8 +153,14 @@ pub fn getRandomBytes(buf: []u8) !void {
142153}
143154
144155test "os.getRandomBytes" {
145 var buf: [50]u8 = undefined;
146 try getRandomBytes(buf[0..]);
156 var buf_a: [50]u8 = undefined;
157 var buf_b: [50]u8 = undefined;
158 // Call Twice
159 try getRandomBytes(buf_a[0..]);
160 try getRandomBytes(buf_b[0..]);
161
162 // Check if random (not 100% conclusive)
163 assert( !mem.eql(u8, buf_a, buf_b) );
147164}
148165
149166/// Raises a signal in the current kernel thread, ending its execution.
......@@ -215,13 +232,13 @@ pub fn close(handle: FileHandle) void {
215232/// Calls POSIX read, and keeps trying if it gets interrupted.
216233pub fn posixRead(fd: i32, buf: []u8) !void {
217234 // Linux can return EINVAL when read amount is > 0x7ffff000
218 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274
235 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
219236 const max_buf_len = 0x7ffff000;
220237
221238 var index: usize = 0;
222239 while (index < buf.len) {
223240 const want_to_read = math.min(buf.len - index, usize(max_buf_len));
224 const rc = posix.read(fd, &buf[index], want_to_read);
241 const rc = posix.read(fd, buf.ptr + index, want_to_read);
225242 const err = posix.getErrno(rc);
226243 if (err > 0) {
227244 return switch (err) {
......@@ -239,7 +256,7 @@ pub fn posixRead(fd: i32, buf: []u8) !void {
239256 }
240257}
241258
242pub const PosixWriteError = error {
259pub const PosixWriteError = error{
243260 WouldBlock,
244261 FileClosed,
245262 DestinationAddressRequired,
......@@ -255,35 +272,35 @@ pub const PosixWriteError = error {
255272/// Calls POSIX write, and keeps trying if it gets interrupted.
256273pub fn posixWrite(fd: i32, bytes: []const u8) !void {
257274 // Linux can return EINVAL when write amount is > 0x7ffff000
258 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856
275 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
259276 const max_bytes_len = 0x7ffff000;
260277
261278 var index: usize = 0;
262279 while (index < bytes.len) {
263280 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
264 const rc = posix.write(fd, &bytes[index], amt_to_write);
281 const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
265282 const write_err = posix.getErrno(rc);
266283 if (write_err > 0) {
267284 return switch (write_err) {
268 posix.EINTR => continue,
285 posix.EINTR => continue,
269286 posix.EINVAL, posix.EFAULT => unreachable,
270287 posix.EAGAIN => PosixWriteError.WouldBlock,
271288 posix.EBADF => PosixWriteError.FileClosed,
272289 posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
273290 posix.EDQUOT => PosixWriteError.DiskQuota,
274 posix.EFBIG => PosixWriteError.FileTooBig,
275 posix.EIO => PosixWriteError.InputOutput,
291 posix.EFBIG => PosixWriteError.FileTooBig,
292 posix.EIO => PosixWriteError.InputOutput,
276293 posix.ENOSPC => PosixWriteError.NoSpaceLeft,
277 posix.EPERM => PosixWriteError.AccessDenied,
278 posix.EPIPE => PosixWriteError.BrokenPipe,
279 else => unexpectedErrorPosix(write_err),
294 posix.EPERM => PosixWriteError.AccessDenied,
295 posix.EPIPE => PosixWriteError.BrokenPipe,
296 else => unexpectedErrorPosix(write_err),
280297 };
281298 }
282299 index += rc;
283300 }
284301}
285302
286pub const PosixOpenError = error {
303pub const PosixOpenError = error{
287304 OutOfMemory,
288305 AccessDenied,
289306 FileTooBig,
......@@ -304,14 +321,15 @@ pub const PosixOpenError = error {
304321/// ::file_path needs to be copied in memory to add a null terminating byte.
305322/// Calls POSIX open, keeps trying if it gets interrupted, and translates
306323/// the return value into zig errors.
307pub fn posixOpen(allocator: &Allocator, file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
324pub fn posixOpen(allocator: *Allocator, file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
308325 const path_with_null = try cstr.addNullByte(allocator, file_path);
309326 defer allocator.free(path_with_null);
310327
311328 return posixOpenC(path_with_null.ptr, flags, perm);
312329}
313330
314pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 {
331// TODO https://github.com/ziglang/zig/issues/265
332pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
315333 while (true) {
316334 const result = posix.open(file_path, flags, perm);
317335 const err = posix.getErrno(result);
......@@ -338,7 +356,7 @@ pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 {
338356 else => return unexpectedErrorPosix(err),
339357 }
340358 }
341 return i32(result);
359 return @intCast(i32, result);
342360 }
343361}
344362
......@@ -357,19 +375,19 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
357375 }
358376}
359377
360pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) ![]?&u8 {
378pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
361379 const envp_count = env_map.count();
362 const envp_buf = try allocator.alloc(?&u8, envp_count + 1);
363 mem.set(?&u8, envp_buf, null);
380 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
381 mem.set(?[*]u8, envp_buf, null);
364382 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
365383 {
366384 var it = env_map.iterator();
367385 var i: usize = 0;
368386 while (it.next()) |pair| : (i += 1) {
369387 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
370 @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);
388 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
371389 env_buf[pair.key.len] = '=';
372 @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);
390 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
373391 env_buf[env_buf.len - 1] = 0;
374392
375393 envp_buf[i] = env_buf.ptr;
......@@ -380,7 +398,7 @@ pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap)
380398 return envp_buf;
381399}
382400
383pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void {
401pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
384402 for (envp_buf) |env| {
385403 const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
386404 allocator.free(env_buf);
......@@ -393,11 +411,9 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void {
393411/// pointers after the args and after the environment variables.
394412/// `argv[0]` is the executable path.
395413/// This function also uses the PATH environment variable to get the full path to the executable.
396pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
397 allocator: &Allocator) !void
398{
399 const argv_buf = try allocator.alloc(?&u8, argv.len + 1);
400 mem.set(?&u8, argv_buf, null);
414pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
415 const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
416 mem.set(?[*]u8, argv_buf, null);
401417 defer {
402418 for (argv_buf) |arg| {
403419 const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
......@@ -407,7 +423,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
407423 }
408424 for (argv) |arg, i| {
409425 const arg_buf = try allocator.alloc(u8, arg.len + 1);
410 @memcpy(&arg_buf[0], arg.ptr, arg.len);
426 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
411427 arg_buf[arg.len] = 0;
412428
413429 argv_buf[i] = arg_buf.ptr;
......@@ -419,10 +435,10 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
419435
420436 const exe_path = argv[0];
421437 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
422 return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
438 return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
423439 }
424440
425 const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
441 const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
426442 // PATH.len because it is >= the largest search_path
427443 // +1 for the / to join the search path and exe_path
428444 // +1 for the null terminating byte
......@@ -450,7 +466,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
450466 return posixExecveErrnoToErr(err);
451467}
452468
453pub const PosixExecveError = error {
469pub const PosixExecveError = error{
454470 SystemResources,
455471 AccessDenied,
456472 InvalidExe,
......@@ -478,21 +494,22 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError {
478494 };
479495}
480496
481pub var posix_environ_raw: []&u8 = undefined;
497pub var linux_aux_raw = []usize{0} ** 38;
498pub var posix_environ_raw: [][*]u8 = undefined;
482499
483500/// Caller must free result when done.
484pub fn getEnvMap(allocator: &Allocator) !BufMap {
501/// TODO make this go through libc when we have it
502pub fn getEnvMap(allocator: *Allocator) !BufMap {
485503 var result = BufMap.init(allocator);
486504 errdefer result.deinit();
487505
488506 if (is_windows) {
489 const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
507 const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory;
490508 defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
491509
492510 var i: usize = 0;
493511 while (true) {
494 if (ptr[i] == 0)
495 return result;
512 if (ptr[i] == 0) return result;
496513
497514 const key_start = i;
498515
......@@ -517,7 +534,7 @@ pub fn getEnvMap(allocator: &Allocator) !BufMap {
517534
518535 var end_i: usize = line_i;
519536 while (ptr[end_i] != 0) : (end_i += 1) {}
520 const value = ptr[line_i + 1..end_i];
537 const value = ptr[line_i + 1 .. end_i];
521538
522539 try result.set(key, value);
523540 }
......@@ -525,25 +542,31 @@ pub fn getEnvMap(allocator: &Allocator) !BufMap {
525542 }
526543}
527544
545/// TODO make this go through libc when we have it
528546pub fn getEnvPosix(key: []const u8) ?[]const u8 {
529547 for (posix_environ_raw) |ptr| {
530548 var line_i: usize = 0;
531549 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
532550 const this_key = ptr[0..line_i];
533 if (!mem.eql(u8, key, this_key))
534 continue;
551 if (!mem.eql(u8, key, this_key)) continue;
535552
536553 var end_i: usize = line_i;
537554 while (ptr[end_i] != 0) : (end_i += 1) {}
538 const this_value = ptr[line_i + 1..end_i];
555 const this_value = ptr[line_i + 1 .. end_i];
539556
540557 return this_value;
541558 }
542559 return null;
543560}
544561
562pub const GetEnvVarOwnedError = error{
563 OutOfMemory,
564 EnvironmentVariableNotFound,
565};
566
545567/// Caller must free returned memory.
546pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) ![]u8 {
568/// TODO make this go through libc when we have it
569pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
547570 if (is_windows) {
548571 const key_with_null = try cstr.addNullByte(allocator, key);
549572 defer allocator.free(key_with_null);
......@@ -552,14 +575,17 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) ![]u8 {
552575 errdefer allocator.free(buf);
553576
554577 while (true) {
555 const windows_buf_len = try math.cast(windows.DWORD, buf.len);
578 const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
556579 const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
557580
558581 if (result == 0) {
559582 const err = windows.GetLastError();
560583 return switch (err) {
561584 windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
562 else => unexpectedErrorWindows(err),
585 else => {
586 _ = unexpectedErrorWindows(err);
587 return error.EnvironmentVariableNotFound;
588 },
563589 };
564590 }
565591
......@@ -571,20 +597,20 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) ![]u8 {
571597 return allocator.shrink(u8, buf, result);
572598 }
573599 } else {
574 const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound;
600 const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
575601 return mem.dupe(allocator, u8, result);
576602 }
577603}
578604
579605/// Caller must free the returned memory.
580pub fn getCwd(allocator: &Allocator) ![]u8 {
606pub fn getCwd(allocator: *Allocator) ![]u8 {
581607 switch (builtin.os) {
582608 Os.windows => {
583609 var buf = try allocator.alloc(u8, 256);
584610 errdefer allocator.free(buf);
585611
586612 while (true) {
587 const result = windows.GetCurrentDirectoryA(windows.WORD(buf.len), buf.ptr);
613 const result = windows.GetCurrentDirectoryA(@intCast(windows.WORD, buf.len), buf.ptr);
588614
589615 if (result == 0) {
590616 const err = windows.GetLastError();
......@@ -626,7 +652,7 @@ test "os.getCwd" {
626652
627653pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
628654
629pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) SymLinkError!void {
655pub fn symLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) SymLinkError!void {
630656 if (is_windows) {
631657 return symLinkWindows(allocator, existing_path, new_path);
632658 } else {
......@@ -634,12 +660,12 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
634660 }
635661}
636662
637pub const WindowsSymLinkError = error {
663pub const WindowsSymLinkError = error{
638664 OutOfMemory,
639665 Unexpected,
640666};
641667
642pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
668pub fn symLinkWindows(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
643669 const existing_with_null = try cstr.addNullByte(allocator, existing_path);
644670 defer allocator.free(existing_with_null);
645671 const new_with_null = try cstr.addNullByte(allocator, new_path);
......@@ -653,7 +679,7 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path
653679 }
654680}
655681
656pub const PosixSymLinkError = error {
682pub const PosixSymLinkError = error{
657683 OutOfMemory,
658684 AccessDenied,
659685 DiskQuota,
......@@ -669,7 +695,7 @@ pub const PosixSymLinkError = error {
669695 Unexpected,
670696};
671697
672pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
698pub fn symLinkPosix(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
673699 const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2);
674700 defer allocator.free(full_buf);
675701
......@@ -677,7 +703,7 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path:
677703 mem.copy(u8, existing_buf, existing_path);
678704 existing_buf[existing_path.len] = 0;
679705
680 const new_buf = full_buf[existing_path.len + 1..];
706 const new_buf = full_buf[existing_path.len + 1 ..];
681707 mem.copy(u8, new_buf, new_path);
682708 new_buf[new_path.len] = 0;
683709
......@@ -702,11 +728,9 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path:
702728}
703729
704730// here we replace the standard +/ with -_ so that it can be used in a file name
705const b64_fs_encoder = base64.Base64Encoder.init(
706 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
707 base64.standard_pad_char);
731const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
708732
709pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void {
733pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
710734 if (symLink(allocator, existing_path, new_path)) {
711735 return;
712736 } else |err| switch (err) {
......@@ -714,7 +738,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:
714738 else => return err, // TODO zig should know this set does not include PathAlreadyExists
715739 }
716740
717 const dirname = os.path.dirname(new_path);
741 const dirname = os.path.dirname(new_path) orelse ".";
718742
719743 var rand_buf: [12]u8 = undefined;
720744 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
......@@ -732,10 +756,25 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:
732756 else => return err, // TODO zig should know this set does not include PathAlreadyExists
733757 }
734758 }
735
736759}
737760
738pub fn deleteFile(allocator: &Allocator, file_path: []const u8) !void {
761pub const DeleteFileError = error{
762 FileNotFound,
763 AccessDenied,
764 FileBusy,
765 FileSystem,
766 IsDir,
767 SymLinkLoop,
768 NameTooLong,
769 NotDir,
770 SystemResources,
771 ReadOnlyFileSystem,
772 OutOfMemory,
773
774 Unexpected,
775};
776
777pub fn deleteFile(allocator: *Allocator, file_path: []const u8) DeleteFileError!void {
739778 if (builtin.os == Os.windows) {
740779 return deleteFileWindows(allocator, file_path);
741780 } else {
......@@ -743,7 +782,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) !void {
743782 }
744783}
745784
746pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void {
785pub fn deleteFileWindows(allocator: *Allocator, file_path: []const u8) !void {
747786 const buf = try allocator.alloc(u8, file_path.len + 1);
748787 defer allocator.free(buf);
749788
......@@ -761,7 +800,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void {
761800 }
762801}
763802
764pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void {
803pub fn deleteFilePosix(allocator: *Allocator, file_path: []const u8) !void {
765804 const buf = try allocator.alloc(u8, file_path.len + 1);
766805 defer allocator.free(buf);
767806
......@@ -792,7 +831,7 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void {
792831/// there is a possibility of power loss or application termination leaving temporary files present
793832/// in the same directory as dest_path.
794833/// Destination file will have the same mode as the source file.
795pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) !void {
834pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []const u8) !void {
796835 var in_file = try os.File.openRead(allocator, source_path);
797836 defer in_file.close();
798837
......@@ -814,7 +853,7 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con
814853/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
815854/// merged and readily available,
816855/// there is a possibility of power loss or application termination leaving temporary files present
817pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: FileMode) !void {
856pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: []const u8, mode: FileMode) !void {
818857 var in_file = try os.File.openRead(allocator, source_path);
819858 defer in_file.close();
820859
......@@ -832,7 +871,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
832871}
833872
834873pub const AtomicFile = struct {
835 allocator: &Allocator,
874 allocator: *Allocator,
836875 file: os.File,
837876 tmp_path: []u8,
838877 dest_path: []const u8,
......@@ -840,18 +879,24 @@ pub const AtomicFile = struct {
840879
841880 /// dest_path must remain valid for the lifetime of AtomicFile
842881 /// call finish to atomically replace dest_path with contents
843 pub fn init(allocator: &Allocator, dest_path: []const u8, mode: FileMode) !AtomicFile {
882 pub fn init(allocator: *Allocator, dest_path: []const u8, mode: FileMode) !AtomicFile {
844883 const dirname = os.path.dirname(dest_path);
845884
846885 var rand_buf: [12]u8 = undefined;
847 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
886
887 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
888 const tmp_path = try allocator.alloc(u8, dirname_component_len +
889 base64.Base64Encoder.calcSize(rand_buf.len));
848890 errdefer allocator.free(tmp_path);
849 mem.copy(u8, tmp_path[0..], dirname);
850 tmp_path[dirname.len] = os.path.sep;
891
892 if (dirname) |dir| {
893 mem.copy(u8, tmp_path[0..], dir);
894 tmp_path[dir.len] = os.path.sep;
895 }
851896
852897 while (true) {
853898 try getRandomBytes(rand_buf[0..]);
854 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
899 b64_fs_encoder.encode(tmp_path[dirname_component_len..], rand_buf);
855900
856901 const file = os.File.openWriteNoClobber(allocator, tmp_path, mode) catch |err| switch (err) {
857902 error.PathAlreadyExists => continue,
......@@ -860,7 +905,7 @@ pub const AtomicFile = struct {
860905 else => return err,
861906 };
862907
863 return AtomicFile {
908 return AtomicFile{
864909 .allocator = allocator,
865910 .file = file,
866911 .tmp_path = tmp_path,
......@@ -871,7 +916,7 @@ pub const AtomicFile = struct {
871916 }
872917
873918 /// always call deinit, even after successful finish()
874 pub fn deinit(self: &AtomicFile) void {
919 pub fn deinit(self: *AtomicFile) void {
875920 if (!self.finished) {
876921 self.file.close();
877922 deleteFile(self.allocator, self.tmp_path) catch {};
......@@ -880,7 +925,7 @@ pub const AtomicFile = struct {
880925 }
881926 }
882927
883 pub fn finish(self: &AtomicFile) !void {
928 pub fn finish(self: *AtomicFile) !void {
884929 assert(!self.finished);
885930 self.file.close();
886931 try rename(self.allocator, self.tmp_path, self.dest_path);
......@@ -889,7 +934,7 @@ pub const AtomicFile = struct {
889934 }
890935};
891936
892pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) !void {
937pub fn rename(allocator: *Allocator, old_path: []const u8, new_path: []const u8) !void {
893938 const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2);
894939 defer allocator.free(full_buf);
895940
......@@ -897,12 +942,12 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
897942 mem.copy(u8, old_buf, old_path);
898943 old_buf[old_path.len] = 0;
899944
900 const new_buf = full_buf[old_path.len + 1..];
945 const new_buf = full_buf[old_path.len + 1 ..];
901946 mem.copy(u8, new_buf, new_path);
902947 new_buf[new_path.len] = 0;
903948
904949 if (is_windows) {
905 const flags = windows.MOVEFILE_REPLACE_EXISTING|windows.MOVEFILE_WRITE_THROUGH;
950 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
906951 if (windows.MoveFileExA(old_buf.ptr, new_buf.ptr, flags) == 0) {
907952 const err = windows.GetLastError();
908953 return switch (err) {
......@@ -934,7 +979,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
934979 }
935980}
936981
937pub fn makeDir(allocator: &Allocator, dir_path: []const u8) !void {
982pub fn makeDir(allocator: *Allocator, dir_path: []const u8) !void {
938983 if (is_windows) {
939984 return makeDirWindows(allocator, dir_path);
940985 } else {
......@@ -942,7 +987,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) !void {
942987 }
943988}
944989
945pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) !void {
990pub fn makeDirWindows(allocator: *Allocator, dir_path: []const u8) !void {
946991 const path_buf = try cstr.addNullByte(allocator, dir_path);
947992 defer allocator.free(path_buf);
948993
......@@ -956,7 +1001,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) !void {
9561001 }
9571002}
9581003
959pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void {
1004pub fn makeDirPosix(allocator: *Allocator, dir_path: []const u8) !void {
9601005 const path_buf = try cstr.addNullByte(allocator, dir_path);
9611006 defer allocator.free(path_buf);
9621007
......@@ -982,7 +1027,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void {
9821027
9831028/// Calls makeDir recursively to make an entire path. Returns success if the path
9841029/// already exists and is a directory.
985pub fn makePath(allocator: &Allocator, full_path: []const u8) !void {
1030pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
9861031 const resolved_path = try path.resolve(allocator, full_path);
9871032 defer allocator.free(resolved_path);
9881033
......@@ -993,63 +1038,88 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) !void {
9931038 // TODO stat the file and return an error if it's not a directory
9941039 // this is important because otherwise a dangling symlink
9951040 // could cause an infinite loop
996 if (end_index == resolved_path.len)
997 return;
1041 if (end_index == resolved_path.len) return;
9981042 } else if (err == error.FileNotFound) {
9991043 // march end_index backward until next path component
10001044 while (true) {
10011045 end_index -= 1;
1002 if (os.path.isSep(resolved_path[end_index]))
1003 break;
1046 if (os.path.isSep(resolved_path[end_index])) break;
10041047 }
10051048 continue;
10061049 } else {
10071050 return err;
10081051 }
10091052 };
1010 if (end_index == resolved_path.len)
1011 return;
1053 if (end_index == resolved_path.len) return;
10121054 // march end_index forward until next path component
10131055 while (true) {
10141056 end_index += 1;
1015 if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index]))
1016 break;
1057 if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
10171058 }
10181059 }
10191060}
10201061
1062pub const DeleteDirError = error{
1063 AccessDenied,
1064 FileBusy,
1065 SymLinkLoop,
1066 NameTooLong,
1067 FileNotFound,
1068 SystemResources,
1069 NotDir,
1070 DirNotEmpty,
1071 ReadOnlyFileSystem,
1072 OutOfMemory,
1073
1074 Unexpected,
1075};
1076
10211077/// Returns ::error.DirNotEmpty if the directory is not empty.
10221078/// To delete a directory recursively, see ::deleteTree
1023pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
1079pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) DeleteDirError!void {
10241080 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
10251081 defer allocator.free(path_buf);
10261082
10271083 mem.copy(u8, path_buf, dir_path);
10281084 path_buf[dir_path.len] = 0;
10291085
1030 const err = posix.getErrno(posix.rmdir(path_buf.ptr));
1031 if (err > 0) {
1032 return switch (err) {
1033 posix.EACCES, posix.EPERM => error.AccessDenied,
1034 posix.EBUSY => error.FileBusy,
1035 posix.EFAULT, posix.EINVAL => unreachable,
1036 posix.ELOOP => error.SymLinkLoop,
1037 posix.ENAMETOOLONG => error.NameTooLong,
1038 posix.ENOENT => error.FileNotFound,
1039 posix.ENOMEM => error.SystemResources,
1040 posix.ENOTDIR => error.NotDir,
1041 posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
1042 posix.EROFS => error.ReadOnlyFileSystem,
1043 else => unexpectedErrorPosix(err),
1044 };
1086 switch (builtin.os) {
1087 Os.windows => {
1088 if (windows.RemoveDirectoryA(path_buf.ptr) == 0) {
1089 const err = windows.GetLastError();
1090 return switch (err) {
1091 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1092 windows.ERROR.DIR_NOT_EMPTY => error.DirNotEmpty,
1093 else => unexpectedErrorWindows(err),
1094 };
1095 }
1096 },
1097 Os.linux, Os.macosx, Os.ios => {
1098 const err = posix.getErrno(posix.rmdir(path_buf.ptr));
1099 if (err > 0) {
1100 return switch (err) {
1101 posix.EACCES, posix.EPERM => error.AccessDenied,
1102 posix.EBUSY => error.FileBusy,
1103 posix.EFAULT, posix.EINVAL => unreachable,
1104 posix.ELOOP => error.SymLinkLoop,
1105 posix.ENAMETOOLONG => error.NameTooLong,
1106 posix.ENOENT => error.FileNotFound,
1107 posix.ENOMEM => error.SystemResources,
1108 posix.ENOTDIR => error.NotDir,
1109 posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
1110 posix.EROFS => error.ReadOnlyFileSystem,
1111 else => unexpectedErrorPosix(err),
1112 };
1113 }
1114 },
1115 else => @compileError("unimplemented"),
10451116 }
10461117}
10471118
10481119/// Whether ::full_path describes a symlink, file, or directory, this function
10491120/// removes it. If it cannot be removed because it is a non-empty directory,
10501121/// this function recursively removes its entries and then tries again.
1051// TODO non-recursive implementation
1052const DeleteTreeError = error {
1122const DeleteTreeError = error{
10531123 OutOfMemory,
10541124 AccessDenied,
10551125 FileTooBig,
......@@ -1071,7 +1141,7 @@ const DeleteTreeError = error {
10711141 DirNotEmpty,
10721142 Unexpected,
10731143};
1074pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
1144pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
10751145 start_over: while (true) {
10761146 var got_access_denied = false;
10771147 // First, try deleting the item as a file. This way we don't follow sym links.
......@@ -1090,8 +1160,8 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
10901160 error.NotDir,
10911161 error.FileSystem,
10921162 error.FileBusy,
1093 error.Unexpected
1094 => return err,
1163 error.Unexpected,
1164 => return err,
10951165 }
10961166 {
10971167 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
......@@ -1115,8 +1185,8 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
11151185 error.SystemResources,
11161186 error.NoSpaceLeft,
11171187 error.PathAlreadyExists,
1118 error.Unexpected
1119 => return err,
1188 error.Unexpected,
1189 => return err,
11201190 };
11211191 defer dir.close();
11221192
......@@ -1127,8 +1197,8 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
11271197 try full_entry_buf.resize(full_path.len + entry.name.len + 1);
11281198 const full_entry_path = full_entry_buf.toSlice();
11291199 mem.copy(u8, full_entry_path, full_path);
1130 full_entry_path[full_path.len] = '/';
1131 mem.copy(u8, full_entry_path[full_path.len + 1..], entry.name);
1200 full_entry_path[full_path.len] = path.sep;
1201 mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
11321202
11331203 try deleteTree(allocator, full_entry_path);
11341204 }
......@@ -1138,16 +1208,29 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
11381208}
11391209
11401210pub const Dir = struct {
1141 fd: i32,
1142 darwin_seek: darwin_seek_t,
1143 allocator: &Allocator,
1144 buf: []u8,
1145 index: usize,
1146 end_index: usize,
1147
1148 const darwin_seek_t = switch (builtin.os) {
1149 Os.macosx, Os.ios => i64,
1150 else => void,
1211 handle: Handle,
1212 allocator: *Allocator,
1213
1214 pub const Handle = switch (builtin.os) {
1215 Os.macosx, Os.ios => struct {
1216 fd: i32,
1217 seek: i64,
1218 buf: []u8,
1219 index: usize,
1220 end_index: usize,
1221 },
1222 Os.linux => struct {
1223 fd: i32,
1224 buf: []u8,
1225 index: usize,
1226 end_index: usize,
1227 },
1228 Os.windows => struct {
1229 handle: windows.HANDLE,
1230 find_file_data: windows.WIN32_FIND_DATAA,
1231 first: bool,
1232 },
1233 else => @compileError("unimplemented"),
11511234 };
11521235
11531236 pub const Entry = struct {
......@@ -1167,78 +1250,122 @@ pub const Dir = struct {
11671250 };
11681251 };
11691252
1170 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
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 };
1181 return Dir {
1253 pub const OpenError = error{
1254 PathNotFound,
1255 NotDir,
1256 AccessDenied,
1257 FileTooBig,
1258 IsDir,
1259 SymLinkLoop,
1260 ProcessFdQuotaExceeded,
1261 NameTooLong,
1262 SystemFdQuotaExceeded,
1263 NoDevice,
1264 SystemResources,
1265 NoSpaceLeft,
1266 PathAlreadyExists,
1267 OutOfMemory,
1268
1269 Unexpected,
1270 };
1271
1272 pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
1273 return Dir{
11821274 .allocator = allocator,
1183 .fd = fd,
1184 .darwin_seek = darwin_seek_init,
1185 .index = 0,
1186 .end_index = 0,
1187 .buf = []u8{},
1275 .handle = switch (builtin.os) {
1276 Os.windows => blk: {
1277 var find_file_data: windows.WIN32_FIND_DATAA = undefined;
1278 const handle = try windows_util.windowsFindFirstFile(allocator, dir_path, &find_file_data);
1279 break :blk Handle{
1280 .handle = handle,
1281 .find_file_data = find_file_data, // TODO guaranteed copy elision
1282 .first = true,
1283 };
1284 },
1285 Os.macosx, Os.ios => Handle{
1286 .fd = try posixOpen(
1287 allocator,
1288 dir_path,
1289 posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
1290 0,
1291 ),
1292 .seek = 0,
1293 .index = 0,
1294 .end_index = 0,
1295 .buf = []u8{},
1296 },
1297 Os.linux => Handle{
1298 .fd = try posixOpen(
1299 allocator,
1300 dir_path,
1301 posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
1302 0,
1303 ),
1304 .index = 0,
1305 .end_index = 0,
1306 .buf = []u8{},
1307 },
1308 else => @compileError("unimplemented"),
1309 },
11881310 };
11891311 }
11901312
1191 pub fn close(self: &Dir) void {
1192 self.allocator.free(self.buf);
1193 os.close(self.fd);
1313 pub fn close(self: *Dir) void {
1314 switch (builtin.os) {
1315 Os.windows => {
1316 _ = windows.FindClose(self.handle.handle);
1317 },
1318 Os.macosx, Os.ios, Os.linux => {
1319 self.allocator.free(self.handle.buf);
1320 os.close(self.handle.fd);
1321 },
1322 else => @compileError("unimplemented"),
1323 }
11941324 }
11951325
11961326 /// Memory such as file names referenced in this returned entry becomes invalid
1197 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1198 pub fn next(self: &Dir) !?Entry {
1327 /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
1328 pub fn next(self: *Dir) !?Entry {
11991329 switch (builtin.os) {
12001330 Os.linux => return self.nextLinux(),
12011331 Os.macosx, Os.ios => return self.nextDarwin(),
12021332 Os.windows => return self.nextWindows(),
1203 else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
1333 else => @compileError("unimplemented"),
12041334 }
12051335 }
12061336
1207 fn nextDarwin(self: &Dir) !?Entry {
1337 fn nextDarwin(self: *Dir) !?Entry {
12081338 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);
1339 if (self.handle.index >= self.handle.end_index) {
1340 if (self.handle.buf.len == 0) {
1341 self.handle.buf = try self.allocator.alloc(u8, page_size);
12121342 }
12131343
12141344 while (true) {
1215 const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len,
1216 &self.darwin_seek);
1345 const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
12171346 const err = posix.getErrno(result);
12181347 if (err > 0) {
12191348 switch (err) {
12201349 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
12211350 posix.EINVAL => {
1222 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1351 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
12231352 continue;
12241353 },
12251354 else => return unexpectedErrorPosix(err),
12261355 }
12271356 }
1228 if (result == 0)
1229 return null;
1230 self.index = 0;
1231 self.end_index = result;
1357 if (result == 0) return null;
1358 self.handle.index = 0;
1359 self.handle.end_index = result;
12321360 break;
12331361 }
12341362 }
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;
1363 const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1364 const next_index = self.handle.index + darwin_entry.d_reclen;
1365 self.handle.index = next_index;
12381366
1239 const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen];
1367 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
12401368
1241 // skip . and .. entries
12421369 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
12431370 continue :start_over;
12441371 }
......@@ -1254,56 +1381,76 @@ pub const Dir = struct {
12541381 posix.DT_WHT => Entry.Kind.Whiteout,
12551382 else => Entry.Kind.Unknown,
12561383 };
1257 return Entry {
1384 return Entry{
12581385 .name = name,
12591386 .kind = entry_kind,
12601387 };
12611388 }
12621389 }
12631390
1264 fn nextWindows(self: &Dir) !?Entry {
1265 @compileError("TODO support Dir.next for windows");
1391 fn nextWindows(self: *Dir) !?Entry {
1392 while (true) {
1393 if (self.handle.first) {
1394 self.handle.first = false;
1395 } else {
1396 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
1397 return null;
1398 }
1399 const name = std.cstr.toSlice(self.handle.find_file_data.cFileName[0..].ptr);
1400 if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
1401 continue;
1402 const kind = blk: {
1403 const attrs = self.handle.find_file_data.dwFileAttributes;
1404 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
1405 if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
1406 if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
1407 break :blk Entry.Kind.Unknown;
1408 };
1409 return Entry{
1410 .name = name,
1411 .kind = kind,
1412 };
1413 }
12661414 }
12671415
1268 fn nextLinux(self: &Dir) !?Entry {
1416 fn nextLinux(self: *Dir) !?Entry {
12691417 start_over: while (true) {
1270 if (self.index >= self.end_index) {
1271 if (self.buf.len == 0) {
1272 self.buf = try self.allocator.alloc(u8, page_size);
1418 if (self.handle.index >= self.handle.end_index) {
1419 if (self.handle.buf.len == 0) {
1420 self.handle.buf = try self.allocator.alloc(u8, page_size);
12731421 }
12741422
12751423 while (true) {
1276 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
1424 const result = posix.getdents(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
12771425 const err = posix.getErrno(result);
12781426 if (err > 0) {
12791427 switch (err) {
12801428 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
12811429 posix.EINVAL => {
1282 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1430 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
12831431 continue;
12841432 },
12851433 else => return unexpectedErrorPosix(err),
12861434 }
12871435 }
1288 if (result == 0)
1289 return null;
1290 self.index = 0;
1291 self.end_index = result;
1436 if (result == 0) return null;
1437 self.handle.index = 0;
1438 self.handle.end_index = result;
12921439 break;
12931440 }
12941441 }
1295 const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1296 const next_index = self.index + linux_entry.d_reclen;
1297 self.index = next_index;
1442 const linux_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1443 const next_index = self.handle.index + linux_entry.d_reclen;
1444 self.handle.index = next_index;
12981445
1299 const name = cstr.toSlice(&linux_entry.d_name);
1446 const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
13001447
13011448 // skip . and .. entries
13021449 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
13031450 continue :start_over;
13041451 }
13051452
1306 const type_char = self.buf[next_index - 1];
1453 const type_char = self.handle.buf[next_index - 1];
13071454 const entry_kind = switch (type_char) {
13081455 posix.DT_BLK => Entry.Kind.BlockDevice,
13091456 posix.DT_CHR => Entry.Kind.CharacterDevice,
......@@ -1314,7 +1461,7 @@ pub const Dir = struct {
13141461 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
13151462 else => Entry.Kind.Unknown,
13161463 };
1317 return Entry {
1464 return Entry{
13181465 .name = name,
13191466 .kind = entry_kind,
13201467 };
......@@ -1322,7 +1469,7 @@ pub const Dir = struct {
13221469 }
13231470};
13241471
1325pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void {
1472pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
13261473 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
13271474 defer allocator.free(path_buf);
13281475
......@@ -1346,7 +1493,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void {
13461493}
13471494
13481495/// Read value of a symbolic link.
1349pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
1496pub fn readLink(allocator: *Allocator, pathname: []const u8) ![]u8 {
13501497 const path_buf = try allocator.alloc(u8, pathname.len + 1);
13511498 defer allocator.free(path_buf);
13521499
......@@ -1379,50 +1526,6 @@ pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
13791526 }
13801527}
13811528
1382pub fn sleep(seconds: usize, nanoseconds: usize) void {
1383 switch(builtin.os) {
1384 Os.linux, Os.macosx, Os.ios => {
1385 posixSleep(u63(seconds), u63(nanoseconds));
1386 },
1387 Os.windows => {
1388 const milliseconds = seconds * 1000 + nanoseconds / 1000000;
1389 windows.Sleep(windows.DWORD(milliseconds));
1390 },
1391 else => @compileError("Unsupported OS"),
1392 }
1393}
1394
1395const u63 = @IntType(false, 63);
1396pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
1397 var req = posix.timespec {
1398 .tv_sec = seconds,
1399 .tv_nsec = nanoseconds,
1400 };
1401 var rem: posix.timespec = undefined;
1402 while (true) {
1403 const ret_val = posix.nanosleep(&req, &rem);
1404 const err = posix.getErrno(ret_val);
1405 if (err == 0) return;
1406 switch (err) {
1407 posix.EFAULT => unreachable,
1408 posix.EINVAL => {
1409 // Sometimes Darwin returns EINVAL for no reason.
1410 // We treat it as a spurious wakeup.
1411 return;
1412 },
1413 posix.EINTR => {
1414 req = rem;
1415 continue;
1416 },
1417 else => return,
1418 }
1419 }
1420}
1421
1422test "os.sleep" {
1423 sleep(0, 1);
1424}
1425
14261529pub fn posix_setuid(uid: u32) !void {
14271530 const err = posix.getErrno(posix.setuid(uid));
14281531 if (err == 0) return;
......@@ -1467,7 +1570,7 @@ pub fn posix_setregid(rgid: u32, egid: u32) !void {
14671570 };
14681571}
14691572
1470pub const WindowsGetStdHandleErrs = error {
1573pub const WindowsGetStdHandleErrs = error{
14711574 NoStdHandles,
14721575 Unexpected,
14731576};
......@@ -1491,24 +1594,22 @@ pub const ArgIteratorPosix = struct {
14911594 count: usize,
14921595
14931596 pub fn init() ArgIteratorPosix {
1494 return ArgIteratorPosix {
1597 return ArgIteratorPosix{
14951598 .index = 0,
14961599 .count = raw.len,
14971600 };
14981601 }
14991602
1500 pub fn next(self: &ArgIteratorPosix) ?[]const u8 {
1501 if (self.index == self.count)
1502 return null;
1603 pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
1604 if (self.index == self.count) return null;
15031605
15041606 const s = raw[self.index];
15051607 self.index += 1;
15061608 return cstr.toSlice(s);
15071609 }
15081610
1509 pub fn skip(self: &ArgIteratorPosix) bool {
1510 if (self.index == self.count)
1511 return false;
1611 pub fn skip(self: *ArgIteratorPosix) bool {
1612 if (self.index == self.count) return false;
15121613
15131614 self.index += 1;
15141615 return true;
......@@ -1516,12 +1617,12 @@ pub const ArgIteratorPosix = struct {
15161617
15171618 /// This is marked as public but actually it's only meant to be used
15181619 /// internally by zig's startup code.
1519 pub var raw: []&u8 = undefined;
1620 pub var raw: [][*]u8 = undefined;
15201621};
15211622
15221623pub const ArgIteratorWindows = struct {
15231624 index: usize,
1524 cmd_line: &const u8,
1625 cmd_line: [*]const u8,
15251626 in_quote: bool,
15261627 quote_count: usize,
15271628 seen_quote_count: usize,
......@@ -1532,8 +1633,8 @@ pub const ArgIteratorWindows = struct {
15321633 return initWithCmdLine(windows.GetCommandLineA());
15331634 }
15341635
1535 pub fn initWithCmdLine(cmd_line: &const u8) ArgIteratorWindows {
1536 return ArgIteratorWindows {
1636 pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
1637 return ArgIteratorWindows{
15371638 .index = 0,
15381639 .cmd_line = cmd_line,
15391640 .in_quote = false,
......@@ -1543,7 +1644,7 @@ pub const ArgIteratorWindows = struct {
15431644 }
15441645
15451646 /// You must free the returned memory when done.
1546 pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?(NextError![]u8) {
1647 pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
15471648 // march forward over whitespace
15481649 while (true) : (self.index += 1) {
15491650 const byte = self.cmd_line[self.index];
......@@ -1557,7 +1658,7 @@ pub const ArgIteratorWindows = struct {
15571658 return self.internalNext(allocator);
15581659 }
15591660
1560 pub fn skip(self: &ArgIteratorWindows) bool {
1661 pub fn skip(self: *ArgIteratorWindows) bool {
15611662 // march forward over whitespace
15621663 while (true) : (self.index += 1) {
15631664 const byte = self.cmd_line[self.index];
......@@ -1596,7 +1697,7 @@ pub const ArgIteratorWindows = struct {
15961697 }
15971698 }
15981699
1599 fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) NextError![]u8 {
1700 fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
16001701 var buf = try Buffer.initSize(allocator, 0);
16011702 defer buf.deinit();
16021703
......@@ -1640,14 +1741,14 @@ pub const ArgIteratorWindows = struct {
16401741 }
16411742 }
16421743
1643 fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) !void {
1744 fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
16441745 var i: usize = 0;
16451746 while (i < emit_count) : (i += 1) {
16461747 try buf.appendByte('\\');
16471748 }
16481749 }
16491750
1650 fn countQuotes(cmd_line: &const u8) usize {
1751 fn countQuotes(cmd_line: [*]const u8) usize {
16511752 var result: usize = 0;
16521753 var backslash_count: usize = 0;
16531754 var index: usize = 0;
......@@ -1666,7 +1767,6 @@ pub const ArgIteratorWindows = struct {
16661767 }
16671768 }
16681769 }
1669
16701770};
16711771
16721772pub const ArgIterator = struct {
......@@ -1675,30 +1775,28 @@ pub const ArgIterator = struct {
16751775 inner: InnerType,
16761776
16771777 pub fn init() ArgIterator {
1678 return ArgIterator {
1679 .inner = InnerType.init(),
1680 };
1778 return ArgIterator{ .inner = InnerType.init() };
16811779 }
16821780
16831781 pub const NextError = ArgIteratorWindows.NextError;
1684
1782
16851783 /// You must free the returned memory when done.
1686 pub fn next(self: &ArgIterator, allocator: &Allocator) ?(NextError![]u8) {
1784 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
16871785 if (builtin.os == Os.windows) {
16881786 return self.inner.next(allocator);
16891787 } else {
1690 return mem.dupe(allocator, u8, self.inner.next() ?? return null);
1788 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
16911789 }
16921790 }
16931791
16941792 /// If you only are targeting posix you can call this and not need an allocator.
1695 pub fn nextPosix(self: &ArgIterator) ?[]const u8 {
1793 pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
16961794 return self.inner.next();
16971795 }
16981796
16991797 /// Parse past 1 argument without capturing it.
17001798 /// Returns `true` if skipped an arg, `false` if we are at the end.
1701 pub fn skip(self: &ArgIterator) bool {
1799 pub fn skip(self: *ArgIterator) bool {
17021800 return self.inner.skip();
17031801 }
17041802};
......@@ -1708,7 +1806,7 @@ pub fn args() ArgIterator {
17081806}
17091807
17101808/// Caller must call freeArgs on result.
1711pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 {
1809pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
17121810 // TODO refactor to only make 1 allocation.
17131811 var it = args();
17141812 var contents = try Buffer.initSize(allocator, 0);
......@@ -1731,7 +1829,7 @@ pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 {
17311829 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
17321830 errdefer allocator.free(buf);
17331831
1734 const result_slice_list = ([][]u8)(buf[0..slice_list_bytes]);
1832 const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
17351833 const result_contents = buf[slice_list_bytes..];
17361834 mem.copy(u8, result_contents, contents_slice);
17371835
......@@ -1745,32 +1843,37 @@ pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 {
17451843 return result_slice_list;
17461844}
17471845
1748pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) void {
1846pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
17491847 var total_bytes: usize = 0;
17501848 for (args_alloc) |arg| {
17511849 total_bytes += @sizeOf([]u8) + arg.len;
17521850 }
1753 const unaligned_allocated_buf = @ptrCast(&const u8, args_alloc.ptr)[0..total_bytes];
1851 const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
17541852 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
17551853 return allocator.free(aligned_allocated_buf);
17561854}
17571855
17581856test "windows arg parsing" {
1759 testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"});
1760 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"});
1761 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{"a\\\\\\b", "de fg", "h"});
1762 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{"a\\\"b", "c", "d"});
1763 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{"a\\\\b c", "d", "e"});
1764 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{"a", "b", "c", "\"d", "f"});
1765
1766 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"",
1767 [][]const u8{".\\..\\zig-cache\\build", "bin\\zig.exe", ".\\..", ".\\..\\zig-cache", "--help"});
1768}
1769
1770fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const u8) void {
1857 testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
1858 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
1859 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
1860 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
1861 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
1862 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
1863
1864 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
1865 ".\\..\\zig-cache\\build",
1866 "bin\\zig.exe",
1867 ".\\..",
1868 ".\\..\\zig-cache",
1869 "--help",
1870 });
1871}
1872
1873fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
17711874 var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
17721875 for (expected_args) |expected_arg| {
1773 const arg = ??it.next(debug.global_allocator) catch unreachable;
1876 const arg = it.next(debug.global_allocator).? catch unreachable;
17741877 assert(mem.eql(u8, arg, expected_arg));
17751878 }
17761879 assert(it.next(debug.global_allocator) == null);
......@@ -1778,7 +1881,7 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
17781881
17791882// TODO make this a build variable that you can set
17801883const unexpected_error_tracing = false;
1781const UnexpectedError = error {
1884const UnexpectedError = error{
17821885 /// The Operating System returned an undocumented error code.
17831886 Unexpected,
17841887};
......@@ -1824,7 +1927,7 @@ pub fn openSelfExe() !os.File {
18241927test "openSelfExe" {
18251928 switch (builtin.os) {
18261929 Os.linux, Os.macosx, Os.ios => (try openSelfExe()).close(),
1827 else => return, // Unsupported OS.
1930 else => return, // Unsupported OS.
18281931 }
18291932}
18301933
......@@ -1834,7 +1937,7 @@ test "openSelfExe" {
18341937/// This function may return an error if the current executable
18351938/// was deleted after spawning.
18361939/// Caller owns returned memory.
1837pub fn selfExePath(allocator: &mem.Allocator) ![]u8 {
1940pub fn selfExePath(allocator: *mem.Allocator) ![]u8 {
18381941 switch (builtin.os) {
18391942 Os.linux => {
18401943 // If the currently executing binary has been deleted,
......@@ -1877,7 +1980,7 @@ pub fn selfExePath(allocator: &mem.Allocator) ![]u8 {
18771980
18781981/// Get the directory path that contains the current executable.
18791982/// Caller owns returned memory.
1880pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 {
1983pub fn selfExeDirPath(allocator: *mem.Allocator) ![]u8 {
18811984 switch (builtin.os) {
18821985 Os.linux => {
18831986 // If the currently executing binary has been deleted,
......@@ -1886,13 +1989,13 @@ pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 {
18861989 // the executable was in when it was run.
18871990 const full_exe_path = try readLink(allocator, "/proc/self/exe");
18881991 errdefer allocator.free(full_exe_path);
1889 const dir = path.dirname(full_exe_path);
1992 const dir = path.dirname(full_exe_path) orelse ".";
18901993 return allocator.shrink(u8, full_exe_path, dir.len);
18911994 },
18921995 Os.windows, Os.macosx, Os.ios => {
18931996 const self_exe_path = try selfExePath(allocator);
18941997 errdefer allocator.free(self_exe_path);
1895 const dirname = os.path.dirname(self_exe_path);
1998 const dirname = os.path.dirname(self_exe_path) orelse ".";
18961999 return allocator.shrink(u8, self_exe_path, dirname.len);
18972000 },
18982001 else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)),
......@@ -1911,7 +2014,7 @@ pub fn isTty(handle: FileHandle) bool {
19112014 }
19122015}
19132016
1914pub const PosixSocketError = error {
2017pub const PosixSocketError = error{
19152018 /// Permission to create a socket of the specified type and/or
19162019 /// pro‐tocol is denied.
19172020 PermissionDenied,
......@@ -1940,7 +2043,7 @@ pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
19402043 const rc = posix.socket(domain, socket_type, protocol);
19412044 const err = posix.getErrno(rc);
19422045 switch (err) {
1943 0 => return i32(rc),
2046 0 => return @intCast(i32, rc),
19442047 posix.EACCES => return PosixSocketError.PermissionDenied,
19452048 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
19462049 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
......@@ -1952,9 +2055,9 @@ pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
19522055 }
19532056}
19542057
1955pub const PosixBindError = error {
2058pub const PosixBindError = error{
19562059 /// The address is protected, and the user is not the superuser.
1957 /// For UNIX domain sockets: Search permission is denied on a component
2060 /// For UNIX domain sockets: Search permission is denied on a component
19582061 /// of the path prefix.
19592062 AccessDenied,
19602063
......@@ -1977,7 +2080,7 @@ pub const PosixBindError = error {
19772080
19782081 /// A nonexistent interface was requested or the requested address was not local.
19792082 AddressNotAvailable,
1980
2083
19812084 /// addr points outside the user's accessible address space.
19822085 PageFault,
19832086
......@@ -2003,7 +2106,7 @@ pub const PosixBindError = error {
20032106};
20042107
20052108/// addr is `&const T` where T is one of the sockaddr
2006pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
2109pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
20072110 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
20082111 const err = posix.getErrno(rc);
20092112 switch (err) {
......@@ -2025,7 +2128,7 @@ pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
20252128 }
20262129}
20272130
2028const PosixListenError = error {
2131const PosixListenError = error{
20292132 /// Another socket is already listening on the same port.
20302133 /// For Internet domain sockets, the socket referred to by sockfd had not previously
20312134 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
......@@ -2058,7 +2161,7 @@ pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
20582161 }
20592162}
20602163
2061pub const PosixAcceptError = error {
2164pub const PosixAcceptError = error{
20622165 /// The socket is marked nonblocking and no connections are present to be accepted.
20632166 WouldBlock,
20642167
......@@ -2066,7 +2169,7 @@ pub const PosixAcceptError = error {
20662169 FileDescriptorClosed,
20672170
20682171 ConnectionAborted,
2069
2172
20702173 /// The addr argument is not in a writable part of the user address space.
20712174 PageFault,
20722175
......@@ -2079,7 +2182,7 @@ pub const PosixAcceptError = error {
20792182
20802183 /// The system-wide limit on the total number of open files has been reached.
20812184 SystemFdQuotaExceeded,
2082
2185
20832186 /// Not enough free memory. This often means that the memory allocation is limited
20842187 /// by the socket buffer limits, not by the system memory.
20852188 SystemResources,
......@@ -2098,13 +2201,13 @@ pub const PosixAcceptError = error {
20982201 Unexpected,
20992202};
21002203
2101pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2204pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
21022205 while (true) {
21032206 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
21042207 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
21052208 const err = posix.getErrno(rc);
21062209 switch (err) {
2107 0 => return i32(rc),
2210 0 => return @intCast(i32, rc),
21082211 posix.EINTR => continue,
21092212 else => return unexpectedErrorPosix(err),
21102213
......@@ -2124,7 +2227,7 @@ pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!
21242227 }
21252228}
21262229
2127pub const LinuxEpollCreateError = error {
2230pub const LinuxEpollCreateError = error{
21282231 /// Invalid value specified in flags.
21292232 InvalidSyscall,
21302233
......@@ -2147,7 +2250,7 @@ pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
21472250 const rc = posix.epoll_create1(flags);
21482251 const err = posix.getErrno(rc);
21492252 switch (err) {
2150 0 => return i32(rc),
2253 0 => return @intCast(i32, rc),
21512254 else => return unexpectedErrorPosix(err),
21522255
21532256 posix.EINVAL => return LinuxEpollCreateError.InvalidSyscall,
......@@ -2157,7 +2260,7 @@ pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
21572260 }
21582261}
21592262
2160pub const LinuxEpollCtlError = error {
2263pub const LinuxEpollCtlError = error{
21612264 /// epfd or fd is not a valid file descriptor.
21622265 InvalidFileDescriptor,
21632266
......@@ -2197,7 +2300,7 @@ pub const LinuxEpollCtlError = error {
21972300 Unexpected,
21982301};
21992302
2200pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) LinuxEpollCtlError!void {
2303pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
22012304 const rc = posix.epoll_ctl(epfd, op, fd, event);
22022305 const err = posix.getErrno(rc);
22032306 switch (err) {
......@@ -2217,7 +2320,7 @@ pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) Lin
22172320
22182321pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
22192322 while (true) {
2220 const rc = posix.epoll_wait(epfd, events.ptr, u32(events.len), timeout);
2323 const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
22212324 const err = posix.getErrno(rc);
22222325 switch (err) {
22232326 0 => return rc,
......@@ -2230,7 +2333,31 @@ pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usiz
22302333 }
22312334}
22322335
2233pub const PosixGetSockNameError = error {
2336pub const LinuxEventFdError = error{
2337 InvalidFlagValue,
2338 SystemResources,
2339 ProcessFdQuotaExceeded,
2340 SystemFdQuotaExceeded,
2341
2342 Unexpected,
2343};
2344
2345pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
2346 const rc = posix.eventfd(initval, flags);
2347 const err = posix.getErrno(rc);
2348 switch (err) {
2349 0 => return @intCast(i32, rc),
2350 else => return unexpectedErrorPosix(err),
2351
2352 posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
2353 posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
2354 posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
2355 posix.ENODEV => return LinuxEventFdError.SystemResources,
2356 posix.ENOMEM => return LinuxEventFdError.SystemResources,
2357 }
2358}
2359
2360pub const PosixGetSockNameError = error{
22342361 /// Insufficient resources were available in the system to perform the operation.
22352362 SystemResources,
22362363
......@@ -2254,7 +2381,7 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
22542381 }
22552382}
22562383
2257pub const PosixConnectError = error {
2384pub const PosixConnectError = error{
22582385 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
22592386 /// file, or search permission is denied for one of the directories in the path prefix.
22602387 /// or
......@@ -2290,7 +2417,7 @@ pub const PosixConnectError = error {
22902417 Unexpected,
22912418};
22922419
2293pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2420pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
22942421 while (true) {
22952422 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
22962423 const err = posix.getErrno(rc);
......@@ -2321,7 +2448,7 @@ pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectEr
23212448
23222449/// Same as posixConnect except it is for blocking socket file descriptors.
23232450/// It expects to receive EINPROGRESS.
2324pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2451pub fn posixConnectAsync(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
23252452 while (true) {
23262453 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
23272454 const err = posix.getErrno(rc);
......@@ -2352,7 +2479,7 @@ pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConn
23522479pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
23532480 var err_code: i32 = undefined;
23542481 var size: u32 = @sizeOf(i32);
2355 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast(&u8, &err_code), &size);
2482 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
23562483 assert(size == 4);
23572484 const err = posix.getErrno(rc);
23582485 switch (err) {
......@@ -2378,9 +2505,401 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
23782505 },
23792506 else => return unexpectedErrorPosix(err),
23802507 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.
2508 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
23822509 posix.EINVAL => unreachable,
23832510 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
23842511 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
23852512 }
23862513}
2514
2515pub const Thread = struct {
2516 data: Data,
2517
2518 pub const use_pthreads = is_posix and builtin.link_libc;
2519 pub const Data = if (use_pthreads)
2520 struct {
2521 handle: c.pthread_t,
2522 stack_addr: usize,
2523 stack_len: usize,
2524 }
2525 else switch (builtin.os) {
2526 builtin.Os.linux => struct {
2527 pid: i32,
2528 stack_addr: usize,
2529 stack_len: usize,
2530 },
2531 builtin.Os.windows => struct {
2532 handle: windows.HANDLE,
2533 alloc_start: *c_void,
2534 heap_handle: windows.HANDLE,
2535 },
2536 else => @compileError("Unsupported OS"),
2537 };
2538
2539 pub fn wait(self: *const Thread) void {
2540 if (use_pthreads) {
2541 const err = c.pthread_join(self.data.handle, null);
2542 switch (err) {
2543 0 => {},
2544 posix.EINVAL => unreachable,
2545 posix.ESRCH => unreachable,
2546 posix.EDEADLK => unreachable,
2547 else => unreachable,
2548 }
2549 assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0);
2550 } else switch (builtin.os) {
2551 builtin.Os.linux => {
2552 while (true) {
2553 const pid_value = @atomicLoad(i32, &self.data.pid, builtin.AtomicOrder.SeqCst);
2554 if (pid_value == 0) break;
2555 const rc = linux.futex_wait(@ptrToInt(&self.data.pid), linux.FUTEX_WAIT, pid_value, null);
2556 switch (linux.getErrno(rc)) {
2557 0 => continue,
2558 posix.EINTR => continue,
2559 posix.EAGAIN => continue,
2560 else => unreachable,
2561 }
2562 }
2563 assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0);
2564 },
2565 builtin.Os.windows => {
2566 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
2567 assert(windows.CloseHandle(self.data.handle) != 0);
2568 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
2569 },
2570 else => @compileError("Unsupported OS"),
2571 }
2572 }
2573};
2574
2575pub const SpawnThreadError = error{
2576 /// A system-imposed limit on the number of threads was encountered.
2577 /// There are a number of limits that may trigger this error:
2578 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
2579 /// which limits the number of processes and threads for a real
2580 /// user ID, was reached;
2581 /// * the kernel's system-wide limit on the number of processes and
2582 /// threads, /proc/sys/kernel/threads-max, was reached (see
2583 /// proc(5));
2584 /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
2585 /// reached (see proc(5)); or
2586 /// * the PID limit (pids.max) imposed by the cgroup "process num‐
2587 /// ber" (PIDs) controller was reached.
2588 ThreadQuotaExceeded,
2589
2590 /// The kernel cannot allocate sufficient memory to allocate a task structure
2591 /// for the child, or to copy those parts of the caller's context that need to
2592 /// be copied.
2593 SystemResources,
2594
2595 /// Not enough userland memory to spawn the thread.
2596 OutOfMemory,
2597
2598 Unexpected,
2599};
2600
2601/// caller must call wait on the returned thread
2602/// fn startFn(@typeOf(context)) T
2603/// where T is u8, noreturn, void, or !void
2604/// caller must call wait on the returned thread
2605pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
2606 // TODO compile-time call graph analysis to determine stack upper bound
2607 // https://github.com/ziglang/zig/issues/157
2608 const default_stack_size = 8 * 1024 * 1024;
2609
2610 const Context = @typeOf(context);
2611 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
2612
2613 if (builtin.os == builtin.Os.windows) {
2614 const WinThread = struct {
2615 const OuterContext = struct {
2616 thread: Thread,
2617 inner: Context,
2618 };
2619 extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
2620 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
2621 switch (@typeId(@typeOf(startFn).ReturnType)) {
2622 builtin.TypeId.Int => {
2623 return startFn(arg);
2624 },
2625 builtin.TypeId.Void => {
2626 startFn(arg);
2627 return 0;
2628 },
2629 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
2630 }
2631 }
2632 };
2633
2634 const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
2635 const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
2636 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
2637 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
2638 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
2639 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext{
2640 .thread = Thread{
2641 .data = Thread.Data{
2642 .heap_handle = heap_handle,
2643 .alloc_start = bytes_ptr,
2644 .handle = undefined,
2645 },
2646 },
2647 .inner = context,
2648 }) catch unreachable;
2649
2650 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
2651 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
2652 const err = windows.GetLastError();
2653 return switch (err) {
2654 else => os.unexpectedErrorWindows(err),
2655 };
2656 };
2657 return &outer_context.thread;
2658 }
2659
2660 const MainFuncs = struct {
2661 extern fn linuxThreadMain(ctx_addr: usize) u8 {
2662 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
2663
2664 switch (@typeId(@typeOf(startFn).ReturnType)) {
2665 builtin.TypeId.Int => {
2666 return startFn(arg);
2667 },
2668 builtin.TypeId.Void => {
2669 startFn(arg);
2670 return 0;
2671 },
2672 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
2673 }
2674 }
2675 extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
2676 if (@sizeOf(Context) == 0) {
2677 _ = startFn({});
2678 return null;
2679 } else {
2680 _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
2681 return null;
2682 }
2683 }
2684 };
2685
2686 const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
2687
2688 const mmap_len = default_stack_size;
2689 const stack_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
2690 if (stack_addr == posix.MAP_FAILED) return error.OutOfMemory;
2691 errdefer assert(posix.munmap(stack_addr, mmap_len) == 0);
2692
2693 var stack_end: usize = stack_addr + mmap_len;
2694 var arg: usize = undefined;
2695 if (@sizeOf(Context) != 0) {
2696 stack_end -= @sizeOf(Context);
2697 stack_end -= stack_end % @alignOf(Context);
2698 assert(stack_end >= stack_addr);
2699 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, stack_end));
2700 context_ptr.* = context;
2701 arg = stack_end;
2702 }
2703
2704 stack_end -= @sizeOf(Thread);
2705 stack_end -= stack_end % @alignOf(Thread);
2706 assert(stack_end >= stack_addr);
2707 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, stack_end));
2708
2709 thread_ptr.data.stack_addr = stack_addr;
2710 thread_ptr.data.stack_len = mmap_len;
2711
2712 if (builtin.os == builtin.Os.windows) {
2713 // use windows API directly
2714 @compileError("TODO support spawnThread for Windows");
2715 } else if (Thread.use_pthreads) {
2716 // use pthreads
2717 var attr: c.pthread_attr_t = undefined;
2718 if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
2719 defer assert(c.pthread_attr_destroy(&attr) == 0);
2720
2721 // align to page
2722 stack_end -= stack_end % os.page_size;
2723 assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 0);
2724
2725 const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
2726 switch (err) {
2727 0 => return thread_ptr,
2728 posix.EAGAIN => return SpawnThreadError.SystemResources,
2729 posix.EPERM => unreachable,
2730 posix.EINVAL => unreachable,
2731 else => return unexpectedErrorPosix(@intCast(usize, err)),
2732 }
2733 } else if (builtin.os == builtin.Os.linux) {
2734 // use linux API directly. TODO use posix.CLONE_SETTLS and initialize thread local storage correctly
2735 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND | posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
2736 const newtls: usize = 0;
2737 const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.pid, newtls, &thread_ptr.data.pid);
2738 const err = posix.getErrno(rc);
2739 switch (err) {
2740 0 => return thread_ptr,
2741 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
2742 posix.EINVAL => unreachable,
2743 posix.ENOMEM => return SpawnThreadError.SystemResources,
2744 posix.ENOSPC => unreachable,
2745 posix.EPERM => unreachable,
2746 posix.EUSERS => unreachable,
2747 else => return unexpectedErrorPosix(err),
2748 }
2749 } else {
2750 @compileError("Unsupported OS");
2751 }
2752}
2753
2754pub fn posixWait(pid: i32) i32 {
2755 var status: i32 = undefined;
2756 while (true) {
2757 const err = posix.getErrno(posix.waitpid(pid, &status, 0));
2758 switch (err) {
2759 0 => return status,
2760 posix.EINTR => continue,
2761 posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
2762 posix.EINVAL => unreachable, // The options argument was invalid
2763 else => unreachable,
2764 }
2765 }
2766}
2767
2768pub fn posixFStat(fd: i32) !posix.Stat {
2769 var stat: posix.Stat = undefined;
2770 const err = posix.getErrno(posix.fstat(fd, &stat));
2771 if (err > 0) {
2772 return switch (err) {
2773 posix.EBADF => error.BadFd,
2774 posix.ENOMEM => error.SystemResources,
2775 else => os.unexpectedErrorPosix(err),
2776 };
2777 }
2778
2779 return stat;
2780}
2781
2782pub const CpuCountError = error{
2783 OutOfMemory,
2784 PermissionDenied,
2785 Unexpected,
2786};
2787
2788pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
2789 switch (builtin.os) {
2790 builtin.Os.macosx => {
2791 var count: c_int = undefined;
2792 var count_len: usize = @sizeOf(c_int);
2793 const rc = posix.sysctlbyname(c"hw.logicalcpu", @ptrCast(*c_void, &count), &count_len, null, 0);
2794 const err = posix.getErrno(rc);
2795 switch (err) {
2796 0 => return @intCast(usize, count),
2797 posix.EFAULT => unreachable,
2798 posix.EINVAL => unreachable,
2799 posix.ENOMEM => return CpuCountError.OutOfMemory,
2800 posix.ENOTDIR => unreachable,
2801 posix.EISDIR => unreachable,
2802 posix.ENOENT => unreachable,
2803 posix.EPERM => unreachable,
2804 else => return os.unexpectedErrorPosix(err),
2805 }
2806 },
2807 builtin.Os.linux => {
2808 const usize_count = 16;
2809 const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
2810
2811 var set = try allocator.alloc(usize, usize_count);
2812 defer allocator.free(set);
2813
2814 while (true) {
2815 const rc = posix.sched_getaffinity(0, set);
2816 const err = posix.getErrno(rc);
2817 switch (err) {
2818 0 => {
2819 if (rc < set.len * @sizeOf(usize)) {
2820 const result = set[0 .. rc / @sizeOf(usize)];
2821 var sum: usize = 0;
2822 for (result) |x| {
2823 sum += @popCount(x);
2824 }
2825 return sum;
2826 } else {
2827 set = try allocator.realloc(usize, set, set.len * 2);
2828 continue;
2829 }
2830 },
2831 posix.EFAULT => unreachable,
2832 posix.EINVAL => unreachable,
2833 posix.EPERM => return CpuCountError.PermissionDenied,
2834 posix.ESRCH => unreachable,
2835 else => return os.unexpectedErrorPosix(err),
2836 }
2837 }
2838 },
2839 builtin.Os.windows => {
2840 var system_info: windows.SYSTEM_INFO = undefined;
2841 windows.GetSystemInfo(&system_info);
2842 return @intCast(usize, system_info.dwNumberOfProcessors);
2843 },
2844 else => @compileError("unsupported OS"),
2845 }
2846}
2847
2848pub const BsdKQueueError = error{
2849 /// The per-process limit on the number of open file descriptors has been reached.
2850 ProcessFdQuotaExceeded,
2851
2852 /// The system-wide limit on the total number of open files has been reached.
2853 SystemFdQuotaExceeded,
2854
2855 Unexpected,
2856};
2857
2858pub fn bsdKQueue() BsdKQueueError!i32 {
2859 const rc = posix.kqueue();
2860 const err = posix.getErrno(rc);
2861 switch (err) {
2862 0 => return @intCast(i32, rc),
2863 posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
2864 posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
2865 else => return unexpectedErrorPosix(err),
2866 }
2867}
2868
2869pub const BsdKEventError = error{
2870 /// The process does not have permission to register a filter.
2871 AccessDenied,
2872
2873 /// The event could not be found to be modified or deleted.
2874 EventNotFound,
2875
2876 /// No memory was available to register the event.
2877 SystemResources,
2878
2879 /// The specified process to attach to does not exist.
2880 ProcessNotFound,
2881};
2882
2883pub fn bsdKEvent(
2884 kq: i32,
2885 changelist: []const posix.Kevent,
2886 eventlist: []posix.Kevent,
2887 timeout: ?*const posix.timespec,
2888) BsdKEventError!usize {
2889 while (true) {
2890 const rc = posix.kevent(kq, changelist, eventlist, timeout);
2891 const err = posix.getErrno(rc);
2892 switch (err) {
2893 0 => return rc,
2894 posix.EACCES => return BsdKEventError.AccessDenied,
2895 posix.EFAULT => unreachable,
2896 posix.EBADF => unreachable,
2897 posix.EINTR => continue,
2898 posix.EINVAL => unreachable,
2899 posix.ENOENT => return BsdKEventError.EventNotFound,
2900 posix.ENOMEM => return BsdKEventError.SystemResources,
2901 posix.ESRCH => return BsdKEventError.ProcessNotFound,
2902 else => unreachable,
2903 }
2904 }
2905}
std/os/linux/errno.zig+425-144
......@@ -1,146 +1,427 @@
1pub const EPERM = 1; /// Operation not permitted
2pub const ENOENT = 2; /// No such file or directory
3pub const ESRCH = 3; /// No such process
4pub const EINTR = 4; /// Interrupted system call
5pub const EIO = 5; /// I/O error
6pub const ENXIO = 6; /// No such device or address
7pub const E2BIG = 7; /// Arg list too long
8pub const ENOEXEC = 8; /// Exec format error
9pub const EBADF = 9; /// Bad file number
10pub const ECHILD = 10; /// No child processes
11pub const EAGAIN = 11; /// Try again
12pub const ENOMEM = 12; /// Out of memory
13pub const EACCES = 13; /// Permission denied
14pub const EFAULT = 14; /// Bad address
15pub const ENOTBLK = 15; /// Block device required
16pub const EBUSY = 16; /// Device or resource busy
17pub const EEXIST = 17; /// File exists
18pub const EXDEV = 18; /// Cross-device link
19pub const ENODEV = 19; /// No such device
20pub const ENOTDIR = 20; /// Not a directory
21pub const EISDIR = 21; /// Is a directory
22pub const EINVAL = 22; /// Invalid argument
23pub const ENFILE = 23; /// File table overflow
24pub const EMFILE = 24; /// Too many open files
25pub const ENOTTY = 25; /// Not a typewriter
26pub const ETXTBSY = 26; /// Text file busy
27pub const EFBIG = 27; /// File too large
28pub const ENOSPC = 28; /// No space left on device
29pub const ESPIPE = 29; /// Illegal seek
30pub const EROFS = 30; /// Read-only file system
31pub const EMLINK = 31; /// Too many links
32pub const EPIPE = 32; /// Broken pipe
33pub const EDOM = 33; /// Math argument out of domain of func
34pub const ERANGE = 34; /// Math result not representable
35pub const EDEADLK = 35; /// Resource deadlock would occur
36pub const ENAMETOOLONG = 36; /// File name too long
37pub const ENOLCK = 37; /// No record locks available
38pub const ENOSYS = 38; /// Function not implemented
39pub const ENOTEMPTY = 39; /// Directory not empty
40pub const ELOOP = 40; /// Too many symbolic links encountered
41pub const EWOULDBLOCK = EAGAIN; /// Operation would block
42pub const ENOMSG = 42; /// No message of desired type
43pub const EIDRM = 43; /// Identifier removed
44pub const ECHRNG = 44; /// Channel number out of range
45pub const EL2NSYNC = 45; /// Level 2 not synchronized
46pub const EL3HLT = 46; /// Level 3 halted
47pub const EL3RST = 47; /// Level 3 reset
48pub const ELNRNG = 48; /// Link number out of range
49pub const EUNATCH = 49; /// Protocol driver not attached
50pub const ENOCSI = 50; /// No CSI structure available
51pub const EL2HLT = 51; /// Level 2 halted
52pub const EBADE = 52; /// Invalid exchange
53pub const EBADR = 53; /// Invalid request descriptor
54pub const EXFULL = 54; /// Exchange full
55pub const ENOANO = 55; /// No anode
56pub const EBADRQC = 56; /// Invalid request code
57pub const EBADSLT = 57; /// Invalid slot
58
59pub const EBFONT = 59; /// Bad font file format
60pub const ENOSTR = 60; /// Device not a stream
61pub const ENODATA = 61; /// No data available
62pub const ETIME = 62; /// Timer expired
63pub const ENOSR = 63; /// Out of streams resources
64pub const ENONET = 64; /// Machine is not on the network
65pub const ENOPKG = 65; /// Package not installed
66pub const EREMOTE = 66; /// Object is remote
67pub const ENOLINK = 67; /// Link has been severed
68pub const EADV = 68; /// Advertise error
69pub const ESRMNT = 69; /// Srmount error
70pub const ECOMM = 70; /// Communication error on send
71pub const EPROTO = 71; /// Protocol error
72pub const EMULTIHOP = 72; /// Multihop attempted
73pub const EDOTDOT = 73; /// RFS specific error
74pub const EBADMSG = 74; /// Not a data message
75pub const EOVERFLOW = 75; /// Value too large for defined data type
76pub const ENOTUNIQ = 76; /// Name not unique on network
77pub const EBADFD = 77; /// File descriptor in bad state
78pub const EREMCHG = 78; /// Remote address changed
79pub const ELIBACC = 79; /// Can not access a needed shared library
80pub const ELIBBAD = 80; /// Accessing a corrupted shared library
81pub const ELIBSCN = 81; /// .lib section in a.out corrupted
82pub const ELIBMAX = 82; /// Attempting to link in too many shared libraries
83pub const ELIBEXEC = 83; /// Cannot exec a shared library directly
84pub const EILSEQ = 84; /// Illegal byte sequence
85pub const ERESTART = 85; /// Interrupted system call should be restarted
86pub const ESTRPIPE = 86; /// Streams pipe error
87pub const EUSERS = 87; /// Too many users
88pub const ENOTSOCK = 88; /// Socket operation on non-socket
89pub const EDESTADDRREQ = 89; /// Destination address required
90pub const EMSGSIZE = 90; /// Message too long
91pub const EPROTOTYPE = 91; /// Protocol wrong type for socket
92pub const ENOPROTOOPT = 92; /// Protocol not available
93pub const EPROTONOSUPPORT = 93; /// Protocol not supported
94pub const ESOCKTNOSUPPORT = 94; /// Socket type not supported
95pub const EOPNOTSUPP = 95; /// Operation not supported on transport endpoint
96pub const EPFNOSUPPORT = 96; /// Protocol family not supported
97pub const EAFNOSUPPORT = 97; /// Address family not supported by protocol
98pub const EADDRINUSE = 98; /// Address already in use
99pub const EADDRNOTAVAIL = 99; /// Cannot assign requested address
100pub const ENETDOWN = 100; /// Network is down
101pub const ENETUNREACH = 101; /// Network is unreachable
102pub const ENETRESET = 102; /// Network dropped connection because of reset
103pub const ECONNABORTED = 103; /// Software caused connection abort
104pub const ECONNRESET = 104; /// Connection reset by peer
105pub const ENOBUFS = 105; /// No buffer space available
106pub const EISCONN = 106; /// Transport endpoint is already connected
107pub const ENOTCONN = 107; /// Transport endpoint is not connected
108pub const ESHUTDOWN = 108; /// Cannot send after transport endpoint shutdown
109pub const ETOOMANYREFS = 109; /// Too many references: cannot splice
110pub const ETIMEDOUT = 110; /// Connection timed out
111pub const ECONNREFUSED = 111; /// Connection refused
112pub const EHOSTDOWN = 112; /// Host is down
113pub const EHOSTUNREACH = 113; /// No route to host
114pub const EALREADY = 114; /// Operation already in progress
115pub const EINPROGRESS = 115; /// Operation now in progress
116pub const ESTALE = 116; /// Stale NFS file handle
117pub const EUCLEAN = 117; /// Structure needs cleaning
118pub const ENOTNAM = 118; /// Not a XENIX named type file
119pub const ENAVAIL = 119; /// No XENIX semaphores available
120pub const EISNAM = 120; /// Is a named type file
121pub const EREMOTEIO = 121; /// Remote I/O error
122pub const EDQUOT = 122; /// Quota exceeded
123
124pub const ENOMEDIUM = 123; /// No medium found
125pub const EMEDIUMTYPE = 124; /// Wrong medium type
1/// Operation not permitted
2pub const EPERM = 1;
3
4/// No such file or directory
5pub const ENOENT = 2;
6
7/// No such process
8pub const ESRCH = 3;
9
10/// Interrupted system call
11pub const EINTR = 4;
12
13/// I/O error
14pub const EIO = 5;
15
16/// No such device or address
17pub const ENXIO = 6;
18
19/// Arg list too long
20pub const E2BIG = 7;
21
22/// Exec format error
23pub const ENOEXEC = 8;
24
25/// Bad file number
26pub const EBADF = 9;
27
28/// No child processes
29pub const ECHILD = 10;
30
31/// Try again
32pub const EAGAIN = 11;
33
34/// Out of memory
35pub const ENOMEM = 12;
36
37/// Permission denied
38pub const EACCES = 13;
39
40/// Bad address
41pub const EFAULT = 14;
42
43/// Block device required
44pub const ENOTBLK = 15;
45
46/// Device or resource busy
47pub const EBUSY = 16;
48
49/// File exists
50pub const EEXIST = 17;
51
52/// Cross-device link
53pub const EXDEV = 18;
54
55/// No such device
56pub const ENODEV = 19;
57
58/// Not a directory
59pub const ENOTDIR = 20;
60
61/// Is a directory
62pub const EISDIR = 21;
63
64/// Invalid argument
65pub const EINVAL = 22;
66
67/// File table overflow
68pub const ENFILE = 23;
69
70/// Too many open files
71pub const EMFILE = 24;
72
73/// Not a typewriter
74pub const ENOTTY = 25;
75
76/// Text file busy
77pub const ETXTBSY = 26;
78
79/// File too large
80pub const EFBIG = 27;
81
82/// No space left on device
83pub const ENOSPC = 28;
84
85/// Illegal seek
86pub const ESPIPE = 29;
87
88/// Read-only file system
89pub const EROFS = 30;
90
91/// Too many links
92pub const EMLINK = 31;
93
94/// Broken pipe
95pub const EPIPE = 32;
96
97/// Math argument out of domain of func
98pub const EDOM = 33;
99
100/// Math result not representable
101pub const ERANGE = 34;
102
103/// Resource deadlock would occur
104pub const EDEADLK = 35;
105
106/// File name too long
107pub const ENAMETOOLONG = 36;
108
109/// No record locks available
110pub const ENOLCK = 37;
111
112/// Function not implemented
113pub const ENOSYS = 38;
114
115/// Directory not empty
116pub const ENOTEMPTY = 39;
117
118/// Too many symbolic links encountered
119pub const ELOOP = 40;
120
121/// Operation would block
122pub const EWOULDBLOCK = EAGAIN;
123
124/// No message of desired type
125pub const ENOMSG = 42;
126
127/// Identifier removed
128pub const EIDRM = 43;
129
130/// Channel number out of range
131pub const ECHRNG = 44;
132
133/// Level 2 not synchronized
134pub const EL2NSYNC = 45;
135
136/// Level 3 halted
137pub const EL3HLT = 46;
138
139/// Level 3 reset
140pub const EL3RST = 47;
141
142/// Link number out of range
143pub const ELNRNG = 48;
144
145/// Protocol driver not attached
146pub const EUNATCH = 49;
147
148/// No CSI structure available
149pub const ENOCSI = 50;
150
151/// Level 2 halted
152pub const EL2HLT = 51;
153
154/// Invalid exchange
155pub const EBADE = 52;
156
157/// Invalid request descriptor
158pub const EBADR = 53;
159
160/// Exchange full
161pub const EXFULL = 54;
162
163/// No anode
164pub const ENOANO = 55;
165
166/// Invalid request code
167pub const EBADRQC = 56;
168
169/// Invalid slot
170pub const EBADSLT = 57;
171
172/// Bad font file format
173pub const EBFONT = 59;
174
175/// Device not a stream
176pub const ENOSTR = 60;
177
178/// No data available
179pub const ENODATA = 61;
180
181/// Timer expired
182pub const ETIME = 62;
183
184/// Out of streams resources
185pub const ENOSR = 63;
186
187/// Machine is not on the network
188pub const ENONET = 64;
189
190/// Package not installed
191pub const ENOPKG = 65;
192
193/// Object is remote
194pub const EREMOTE = 66;
195
196/// Link has been severed
197pub const ENOLINK = 67;
198
199/// Advertise error
200pub const EADV = 68;
201
202/// Srmount error
203pub const ESRMNT = 69;
204
205/// Communication error on send
206pub const ECOMM = 70;
207
208/// Protocol error
209pub const EPROTO = 71;
210
211/// Multihop attempted
212pub const EMULTIHOP = 72;
213
214/// RFS specific error
215pub const EDOTDOT = 73;
216
217/// Not a data message
218pub const EBADMSG = 74;
219
220/// Value too large for defined data type
221pub const EOVERFLOW = 75;
222
223/// Name not unique on network
224pub const ENOTUNIQ = 76;
225
226/// File descriptor in bad state
227pub const EBADFD = 77;
228
229/// Remote address changed
230pub const EREMCHG = 78;
231
232/// Can not access a needed shared library
233pub const ELIBACC = 79;
234
235/// Accessing a corrupted shared library
236pub const ELIBBAD = 80;
237
238/// .lib section in a.out corrupted
239pub const ELIBSCN = 81;
240
241/// Attempting to link in too many shared libraries
242pub const ELIBMAX = 82;
243
244/// Cannot exec a shared library directly
245pub const ELIBEXEC = 83;
246
247/// Illegal byte sequence
248pub const EILSEQ = 84;
249
250/// Interrupted system call should be restarted
251pub const ERESTART = 85;
252
253/// Streams pipe error
254pub const ESTRPIPE = 86;
255
256/// Too many users
257pub const EUSERS = 87;
258
259/// Socket operation on non-socket
260pub const ENOTSOCK = 88;
261
262/// Destination address required
263pub const EDESTADDRREQ = 89;
264
265/// Message too long
266pub const EMSGSIZE = 90;
267
268/// Protocol wrong type for socket
269pub const EPROTOTYPE = 91;
270
271/// Protocol not available
272pub const ENOPROTOOPT = 92;
273
274/// Protocol not supported
275pub const EPROTONOSUPPORT = 93;
276
277/// Socket type not supported
278pub const ESOCKTNOSUPPORT = 94;
279
280/// Operation not supported on transport endpoint
281pub const EOPNOTSUPP = 95;
282
283/// Protocol family not supported
284pub const EPFNOSUPPORT = 96;
285
286/// Address family not supported by protocol
287pub const EAFNOSUPPORT = 97;
288
289/// Address already in use
290pub const EADDRINUSE = 98;
291
292/// Cannot assign requested address
293pub const EADDRNOTAVAIL = 99;
294
295/// Network is down
296pub const ENETDOWN = 100;
297
298/// Network is unreachable
299pub const ENETUNREACH = 101;
300
301/// Network dropped connection because of reset
302pub const ENETRESET = 102;
303
304/// Software caused connection abort
305pub const ECONNABORTED = 103;
306
307/// Connection reset by peer
308pub const ECONNRESET = 104;
309
310/// No buffer space available
311pub const ENOBUFS = 105;
312
313/// Transport endpoint is already connected
314pub const EISCONN = 106;
315
316/// Transport endpoint is not connected
317pub const ENOTCONN = 107;
318
319/// Cannot send after transport endpoint shutdown
320pub const ESHUTDOWN = 108;
321
322/// Too many references: cannot splice
323pub const ETOOMANYREFS = 109;
324
325/// Connection timed out
326pub const ETIMEDOUT = 110;
327
328/// Connection refused
329pub const ECONNREFUSED = 111;
330
331/// Host is down
332pub const EHOSTDOWN = 112;
333
334/// No route to host
335pub const EHOSTUNREACH = 113;
336
337/// Operation already in progress
338pub const EALREADY = 114;
339
340/// Operation now in progress
341pub const EINPROGRESS = 115;
342
343/// Stale NFS file handle
344pub const ESTALE = 116;
345
346/// Structure needs cleaning
347pub const EUCLEAN = 117;
348
349/// Not a XENIX named type file
350pub const ENOTNAM = 118;
351
352/// No XENIX semaphores available
353pub const ENAVAIL = 119;
354
355/// Is a named type file
356pub const EISNAM = 120;
357
358/// Remote I/O error
359pub const EREMOTEIO = 121;
360
361/// Quota exceeded
362pub const EDQUOT = 122;
363
364/// No medium found
365pub const ENOMEDIUM = 123;
366
367/// Wrong medium type
368pub const EMEDIUMTYPE = 124;
126369
127370// nameserver query return codes
128pub const ENSROK = 0; /// DNS server returned answer with no data
129pub const ENSRNODATA = 160; /// DNS server returned answer with no data
130pub const ENSRFORMERR = 161; /// DNS server claims query was misformatted
131pub const ENSRSERVFAIL = 162; /// DNS server returned general failure
132pub const ENSRNOTFOUND = 163; /// Domain name not found
133pub const ENSRNOTIMP = 164; /// DNS server does not implement requested operation
134pub const ENSRREFUSED = 165; /// DNS server refused query
135pub const ENSRBADQUERY = 166; /// Misformatted DNS query
136pub const ENSRBADNAME = 167; /// Misformatted domain name
137pub const ENSRBADFAMILY = 168; /// Unsupported address family
138pub const ENSRBADRESP = 169; /// Misformatted DNS reply
139pub const ENSRCONNREFUSED = 170; /// Could not contact DNS servers
140pub const ENSRTIMEOUT = 171; /// Timeout while contacting DNS servers
141pub const ENSROF = 172; /// End of file
142pub const ENSRFILE = 173; /// Error reading file
143pub const ENSRNOMEM = 174; /// Out of memory
144pub const ENSRDESTRUCTION = 175; /// Application terminated lookup
145pub const ENSRQUERYDOMAINTOOLONG = 176; /// Domain name is too long
146pub const ENSRCNAMELOOP = 177; /// Domain name is too long
371
372/// DNS server returned answer with no data
373pub const ENSROK = 0;
374
375/// DNS server returned answer with no data
376pub const ENSRNODATA = 160;
377
378/// DNS server claims query was misformatted
379pub const ENSRFORMERR = 161;
380
381/// DNS server returned general failure
382pub const ENSRSERVFAIL = 162;
383
384/// Domain name not found
385pub const ENSRNOTFOUND = 163;
386
387/// DNS server does not implement requested operation
388pub const ENSRNOTIMP = 164;
389
390/// DNS server refused query
391pub const ENSRREFUSED = 165;
392
393/// Misformatted DNS query
394pub const ENSRBADQUERY = 166;
395
396/// Misformatted domain name
397pub const ENSRBADNAME = 167;
398
399/// Unsupported address family
400pub const ENSRBADFAMILY = 168;
401
402/// Misformatted DNS reply
403pub const ENSRBADRESP = 169;
404
405/// Could not contact DNS servers
406pub const ENSRCONNREFUSED = 170;
407
408/// Timeout while contacting DNS servers
409pub const ENSRTIMEOUT = 171;
410
411/// End of file
412pub const ENSROF = 172;
413
414/// Error reading file
415pub const ENSRFILE = 173;
416
417/// Out of memory
418pub const ENSRNOMEM = 174;
419
420/// Application terminated lookup
421pub const ENSRDESTRUCTION = 175;
422
423/// Domain name is too long
424pub const ENSRQUERYDOMAINTOOLONG = 176;
425
426/// Domain name is too long
427pub const ENSRCNAMELOOP = 177;
std/os/linux/index.zig+408-301
......@@ -1,6 +1,7 @@
11const std = @import("../../index.zig");
22const assert = std.debug.assert;
33const builtin = @import("builtin");
4const vdso = @import("vdso.zig");
45pub use switch (builtin.arch) {
56 builtin.Arch.x86_64 => @import("x86_64.zig"),
67 builtin.Arch.i386 => @import("i386.zig"),
......@@ -14,95 +15,110 @@ pub const STDIN_FILENO = 0;
1415pub const STDOUT_FILENO = 1;
1516pub const STDERR_FILENO = 2;
1617
17pub const PROT_NONE = 0;
18pub const PROT_READ = 1;
19pub const PROT_WRITE = 2;
20pub const PROT_EXEC = 4;
18pub const FUTEX_WAIT = 0;
19pub const FUTEX_WAKE = 1;
20pub const FUTEX_FD = 2;
21pub const FUTEX_REQUEUE = 3;
22pub const FUTEX_CMP_REQUEUE = 4;
23pub const FUTEX_WAKE_OP = 5;
24pub const FUTEX_LOCK_PI = 6;
25pub const FUTEX_UNLOCK_PI = 7;
26pub const FUTEX_TRYLOCK_PI = 8;
27pub const FUTEX_WAIT_BITSET = 9;
28
29pub const FUTEX_PRIVATE_FLAG = 128;
30
31pub const FUTEX_CLOCK_REALTIME = 256;
32
33pub const PROT_NONE = 0;
34pub const PROT_READ = 1;
35pub const PROT_WRITE = 2;
36pub const PROT_EXEC = 4;
2137pub const PROT_GROWSDOWN = 0x01000000;
22pub const PROT_GROWSUP = 0x02000000;
23
24pub const MAP_FAILED = @maxValue(usize);
25pub const MAP_SHARED = 0x01;
26pub const MAP_PRIVATE = 0x02;
27pub const MAP_TYPE = 0x0f;
28pub const MAP_FIXED = 0x10;
29pub const MAP_ANONYMOUS = 0x20;
30pub const MAP_NORESERVE = 0x4000;
31pub const MAP_GROWSDOWN = 0x0100;
32pub const MAP_DENYWRITE = 0x0800;
38pub const PROT_GROWSUP = 0x02000000;
39
40pub const MAP_FAILED = @maxValue(usize);
41pub const MAP_SHARED = 0x01;
42pub const MAP_PRIVATE = 0x02;
43pub const MAP_TYPE = 0x0f;
44pub const MAP_FIXED = 0x10;
45pub const MAP_ANONYMOUS = 0x20;
46pub const MAP_NORESERVE = 0x4000;
47pub const MAP_GROWSDOWN = 0x0100;
48pub const MAP_DENYWRITE = 0x0800;
3349pub const MAP_EXECUTABLE = 0x1000;
34pub const MAP_LOCKED = 0x2000;
35pub const MAP_POPULATE = 0x8000;
36pub const MAP_NONBLOCK = 0x10000;
37pub const MAP_STACK = 0x20000;
38pub const MAP_HUGETLB = 0x40000;
39pub const MAP_FILE = 0;
50pub const MAP_LOCKED = 0x2000;
51pub const MAP_POPULATE = 0x8000;
52pub const MAP_NONBLOCK = 0x10000;
53pub const MAP_STACK = 0x20000;
54pub const MAP_HUGETLB = 0x40000;
55pub const MAP_FILE = 0;
4056
4157pub const F_OK = 0;
4258pub const X_OK = 1;
4359pub const W_OK = 2;
4460pub const R_OK = 4;
4561
46pub const WNOHANG = 1;
47pub const WUNTRACED = 2;
48pub const WSTOPPED = 2;
49pub const WEXITED = 4;
62pub const WNOHANG = 1;
63pub const WUNTRACED = 2;
64pub const WSTOPPED = 2;
65pub const WEXITED = 4;
5066pub const WCONTINUED = 8;
51pub const WNOWAIT = 0x1000000;
52
53pub const SA_NOCLDSTOP = 1;
54pub const SA_NOCLDWAIT = 2;
55pub const SA_SIGINFO = 4;
56pub const SA_ONSTACK = 0x08000000;
57pub const SA_RESTART = 0x10000000;
58pub const SA_NODEFER = 0x40000000;
59pub const SA_RESETHAND = 0x80000000;
60pub const SA_RESTORER = 0x04000000;
61
62pub const SIGHUP = 1;
63pub const SIGINT = 2;
64pub const SIGQUIT = 3;
65pub const SIGILL = 4;
66pub const SIGTRAP = 5;
67pub const SIGABRT = 6;
68pub const SIGIOT = SIGABRT;
69pub const SIGBUS = 7;
70pub const SIGFPE = 8;
71pub const SIGKILL = 9;
72pub const SIGUSR1 = 10;
73pub const SIGSEGV = 11;
74pub const SIGUSR2 = 12;
75pub const SIGPIPE = 13;
76pub const SIGALRM = 14;
77pub const SIGTERM = 15;
67pub const WNOWAIT = 0x1000000;
68
69pub const SA_NOCLDSTOP = 1;
70pub const SA_NOCLDWAIT = 2;
71pub const SA_SIGINFO = 4;
72pub const SA_ONSTACK = 0x08000000;
73pub const SA_RESTART = 0x10000000;
74pub const SA_NODEFER = 0x40000000;
75pub const SA_RESETHAND = 0x80000000;
76pub const SA_RESTORER = 0x04000000;
77
78pub const SIGHUP = 1;
79pub const SIGINT = 2;
80pub const SIGQUIT = 3;
81pub const SIGILL = 4;
82pub const SIGTRAP = 5;
83pub const SIGABRT = 6;
84pub const SIGIOT = SIGABRT;
85pub const SIGBUS = 7;
86pub const SIGFPE = 8;
87pub const SIGKILL = 9;
88pub const SIGUSR1 = 10;
89pub const SIGSEGV = 11;
90pub const SIGUSR2 = 12;
91pub const SIGPIPE = 13;
92pub const SIGALRM = 14;
93pub const SIGTERM = 15;
7894pub const SIGSTKFLT = 16;
79pub const SIGCHLD = 17;
80pub const SIGCONT = 18;
81pub const SIGSTOP = 19;
82pub const SIGTSTP = 20;
83pub const SIGTTIN = 21;
84pub const SIGTTOU = 22;
85pub const SIGURG = 23;
86pub const SIGXCPU = 24;
87pub const SIGXFSZ = 25;
95pub const SIGCHLD = 17;
96pub const SIGCONT = 18;
97pub const SIGSTOP = 19;
98pub const SIGTSTP = 20;
99pub const SIGTTIN = 21;
100pub const SIGTTOU = 22;
101pub const SIGURG = 23;
102pub const SIGXCPU = 24;
103pub const SIGXFSZ = 25;
88104pub const SIGVTALRM = 26;
89pub const SIGPROF = 27;
90pub const SIGWINCH = 28;
91pub const SIGIO = 29;
92pub const SIGPOLL = 29;
93pub const SIGPWR = 30;
94pub const SIGSYS = 31;
105pub const SIGPROF = 27;
106pub const SIGWINCH = 28;
107pub const SIGIO = 29;
108pub const SIGPOLL = 29;
109pub const SIGPWR = 30;
110pub const SIGSYS = 31;
95111pub const SIGUNUSED = SIGSYS;
96112
97113pub const O_RDONLY = 0o0;
98114pub const O_WRONLY = 0o1;
99pub const O_RDWR = 0o2;
115pub const O_RDWR = 0o2;
100116
101117pub const SEEK_SET = 0;
102118pub const SEEK_CUR = 1;
103119pub const SEEK_END = 2;
104120
105pub const SIG_BLOCK = 0;
121pub const SIG_BLOCK = 0;
106122pub const SIG_UNBLOCK = 1;
107123pub const SIG_SETMASK = 2;
108124
......@@ -391,7 +407,6 @@ pub const DT_LNK = 10;
391407pub const DT_SOCK = 12;
392408pub const DT_WHT = 14;
393409
394
395410pub const TCGETS = 0x5401;
396411pub const TCSETS = 0x5402;
397412pub const TCSETSW = 0x5403;
......@@ -508,6 +523,10 @@ pub const CLONE_NEWPID = 0x20000000;
508523pub const CLONE_NEWNET = 0x40000000;
509524pub const CLONE_IO = 0x80000000;
510525
526pub const EFD_SEMAPHORE = 1;
527pub const EFD_CLOEXEC = O_CLOEXEC;
528pub const EFD_NONBLOCK = O_NONBLOCK;
529
511530pub const MS_RDONLY = 1;
512531pub const MS_NOSUID = 2;
513532pub const MS_NODEV = 4;
......@@ -522,23 +541,23 @@ pub const MS_BIND = 4096;
522541pub const MS_MOVE = 8192;
523542pub const MS_REC = 16384;
524543pub const MS_SILENT = 32768;
525pub const MS_POSIXACL = (1<<16);
526pub const MS_UNBINDABLE = (1<<17);
527pub const MS_PRIVATE = (1<<18);
528pub const MS_SLAVE = (1<<19);
529pub const MS_SHARED = (1<<20);
530pub const MS_RELATIME = (1<<21);
531pub const MS_KERNMOUNT = (1<<22);
532pub const MS_I_VERSION = (1<<23);
533pub const MS_STRICTATIME = (1<<24);
534pub const MS_LAZYTIME = (1<<25);
535pub const MS_NOREMOTELOCK = (1<<27);
536pub const MS_NOSEC = (1<<28);
537pub const MS_BORN = (1<<29);
538pub const MS_ACTIVE = (1<<30);
539pub const MS_NOUSER = (1<<31);
540
541pub const MS_RMT_MASK = (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME);
544pub const MS_POSIXACL = (1 << 16);
545pub const MS_UNBINDABLE = (1 << 17);
546pub const MS_PRIVATE = (1 << 18);
547pub const MS_SLAVE = (1 << 19);
548pub const MS_SHARED = (1 << 20);
549pub const MS_RELATIME = (1 << 21);
550pub const MS_KERNMOUNT = (1 << 22);
551pub const MS_I_VERSION = (1 << 23);
552pub const MS_STRICTATIME = (1 << 24);
553pub const MS_LAZYTIME = (1 << 25);
554pub const MS_NOREMOTELOCK = (1 << 27);
555pub const MS_NOSEC = (1 << 28);
556pub const MS_BORN = (1 << 29);
557pub const MS_ACTIVE = (1 << 30);
558pub const MS_NOUSER = (1 << 31);
559
560pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
542561
543562pub const MS_MGC_VAL = 0xc0ed0000;
544563pub const MS_MGC_MSK = 0xffff0000;
......@@ -548,7 +567,6 @@ pub const MNT_DETACH = 2;
548567pub const MNT_EXPIRE = 4;
549568pub const UMOUNT_NOFOLLOW = 8;
550569
551
552570pub const S_IFMT = 0o170000;
553571
554572pub const S_IFDIR = 0o040000;
......@@ -609,15 +627,30 @@ pub const TFD_CLOEXEC = O_CLOEXEC;
609627pub const TFD_TIMER_ABSTIME = 1;
610628pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
611629
612fn unsigned(s: i32) u32 { return @bitCast(u32, s); }
613fn signed(s: u32) i32 { return @bitCast(i32, s); }
614pub fn WEXITSTATUS(s: i32) i32 { return signed((unsigned(s) & 0xff00) >> 8); }
615pub fn WTERMSIG(s: i32) i32 { return signed(unsigned(s) & 0x7f); }
616pub fn WSTOPSIG(s: i32) i32 { return WEXITSTATUS(s); }
617pub fn WIFEXITED(s: i32) bool { return WTERMSIG(s) == 0; }
618pub fn WIFSTOPPED(s: i32) bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }
619pub fn WIFSIGNALED(s: i32) bool { return (unsigned(s)&0xffff)-%1 < 0xff; }
620
630fn unsigned(s: i32) u32 {
631 return @bitCast(u32, s);
632}
633fn signed(s: u32) i32 {
634 return @bitCast(i32, s);
635}
636pub fn WEXITSTATUS(s: i32) i32 {
637 return signed((unsigned(s) & 0xff00) >> 8);
638}
639pub fn WTERMSIG(s: i32) i32 {
640 return signed(unsigned(s) & 0x7f);
641}
642pub fn WSTOPSIG(s: i32) i32 {
643 return WEXITSTATUS(s);
644}
645pub fn WIFEXITED(s: i32) bool {
646 return WTERMSIG(s) == 0;
647}
648pub fn WIFSTOPPED(s: i32) bool {
649 return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
650}
651pub fn WIFSIGNALED(s: i32) bool {
652 return (unsigned(s) & 0xffff) -% 1 < 0xff;
653}
621654
622655pub const winsize = extern struct {
623656 ws_row: u16,
......@@ -629,22 +662,25 @@ pub const winsize = extern struct {
629662/// Get the errno from a syscall return value, or 0 for no error.
630663pub fn getErrno(r: usize) usize {
631664 const signed_r = @bitCast(isize, r);
632 return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
665 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
633666}
634667
635668pub fn dup2(old: i32, new: i32) usize {
636 return syscall2(SYS_dup2, usize(old), usize(new));
669 return syscall2(SYS_dup2, @intCast(usize, old), @intCast(usize, new));
637670}
638671
639pub fn chdir(path: &const u8) usize {
672// TODO https://github.com/ziglang/zig/issues/265
673pub fn chdir(path: [*]const u8) usize {
640674 return syscall1(SYS_chdir, @ptrToInt(path));
641675}
642676
643pub fn chroot(path: &const u8) usize {
677// TODO https://github.com/ziglang/zig/issues/265
678pub fn chroot(path: [*]const u8) usize {
644679 return syscall1(SYS_chroot, @ptrToInt(path));
645680}
646681
647pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {
682// TODO https://github.com/ziglang/zig/issues/265
683pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
648684 return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
649685}
650686
......@@ -652,106 +688,131 @@ pub fn fork() usize {
652688 return syscall0(SYS_fork);
653689}
654690
655pub fn getcwd(buf: &u8, size: usize) usize {
691pub fn futex_wait(uaddr: usize, futex_op: u32, val: i32, timeout: ?*timespec) usize {
692 return syscall4(SYS_futex, uaddr, futex_op, @bitCast(u32, val), @ptrToInt(timeout));
693}
694
695pub fn getcwd(buf: [*]u8, size: usize) usize {
656696 return syscall2(SYS_getcwd, @ptrToInt(buf), size);
657697}
658698
659pub fn getdents(fd: i32, dirp: &u8, count: usize) usize {
660 return syscall3(SYS_getdents, usize(fd), @ptrToInt(dirp), count);
699pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
700 return syscall3(SYS_getdents, @intCast(usize, fd), @ptrToInt(dirp), count);
661701}
662702
663703pub fn isatty(fd: i32) bool {
664704 var wsz: winsize = undefined;
665 return syscall3(SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
705 return syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
666706}
667707
668pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) usize {
708// TODO https://github.com/ziglang/zig/issues/265
709pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
669710 return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
670711}
671712
672pub fn mkdir(path: &const u8, mode: u32) usize {
713// TODO https://github.com/ziglang/zig/issues/265
714pub fn mkdir(path: [*]const u8, mode: u32) usize {
673715 return syscall2(SYS_mkdir, @ptrToInt(path), mode);
674716}
675717
676pub fn mount(special: &const u8, dir: &const u8, fstype: &const u8, flags: usize, data: usize) usize {
718// TODO https://github.com/ziglang/zig/issues/265
719pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: usize, data: usize) usize {
677720 return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
678721}
679722
680pub fn umount(special: &const u8) usize {
723// TODO https://github.com/ziglang/zig/issues/265
724pub fn umount(special: [*]const u8) usize {
681725 return syscall2(SYS_umount2, @ptrToInt(special), 0);
682726}
683727
684pub fn umount2(special: &const u8, flags: u32) usize {
728// TODO https://github.com/ziglang/zig/issues/265
729pub fn umount2(special: [*]const u8, flags: u32) usize {
685730 return syscall2(SYS_umount2, @ptrToInt(special), flags);
686731}
687732
688pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {
689 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
690 @bitCast(usize, offset));
733pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
734 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset));
691735}
692736
693pub fn munmap(address: &u8, length: usize) usize {
694 return syscall2(SYS_munmap, @ptrToInt(address), length);
737pub fn munmap(address: usize, length: usize) usize {
738 return syscall2(SYS_munmap, address, length);
695739}
696740
697pub fn read(fd: i32, buf: &u8, count: usize) usize {
698 return syscall3(SYS_read, usize(fd), @ptrToInt(buf), count);
741pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
742 return syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count);
699743}
700744
701pub fn rmdir(path: &const u8) usize {
745// TODO https://github.com/ziglang/zig/issues/265
746pub fn rmdir(path: [*]const u8) usize {
702747 return syscall1(SYS_rmdir, @ptrToInt(path));
703748}
704749
705pub fn symlink(existing: &const u8, new: &const u8) usize {
750// TODO https://github.com/ziglang/zig/issues/265
751pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
706752 return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
707753}
708754
709pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {
710 return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
755pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
756 return syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset);
711757}
712758
713pub fn access(path: &const u8, mode: u32) usize {
759// TODO https://github.com/ziglang/zig/issues/265
760pub fn access(path: [*]const u8, mode: u32) usize {
714761 return syscall2(SYS_access, @ptrToInt(path), mode);
715762}
716763
717pub fn pipe(fd: &[2]i32) usize {
764pub fn pipe(fd: *[2]i32) usize {
718765 return pipe2(fd, 0);
719766}
720767
721pub fn pipe2(fd: &[2]i32, flags: usize) usize {
768pub fn pipe2(fd: *[2]i32, flags: usize) usize {
722769 return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
723770}
724771
725pub fn write(fd: i32, buf: &const u8, count: usize) usize {
726 return syscall3(SYS_write, usize(fd), @ptrToInt(buf), count);
772pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
773 return syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count);
727774}
728775
729pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) usize {
730 return syscall4(SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset);
776pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
777 return syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset);
731778}
732779
733pub fn rename(old: &const u8, new: &const u8) usize {
780// TODO https://github.com/ziglang/zig/issues/265
781pub fn rename(old: [*]const u8, new: [*]const u8) usize {
734782 return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new));
735783}
736784
737pub fn open(path: &const u8, flags: u32, perm: usize) usize {
785// TODO https://github.com/ziglang/zig/issues/265
786pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
738787 return syscall3(SYS_open, @ptrToInt(path), flags, perm);
739788}
740789
741pub fn create(path: &const u8, perm: usize) usize {
790// TODO https://github.com/ziglang/zig/issues/265
791pub fn create(path: [*]const u8, perm: usize) usize {
742792 return syscall2(SYS_creat, @ptrToInt(path), perm);
743793}
744794
745pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) usize {
746 return syscall4(SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode);
795// TODO https://github.com/ziglang/zig/issues/265
796pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
797 return syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode);
798}
799
800/// See also `clone` (from the arch-specific include)
801pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize {
802 return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
803}
804
805/// See also `clone` (from the arch-specific include)
806pub fn clone2(flags: usize, child_stack_ptr: usize) usize {
807 return syscall2(SYS_clone, flags, child_stack_ptr);
747808}
748809
749810pub fn close(fd: i32) usize {
750 return syscall1(SYS_close, usize(fd));
811 return syscall1(SYS_close, @intCast(usize, fd));
751812}
752813
753814pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
754 return syscall3(SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos);
815 return syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos);
755816}
756817
757818pub fn exit(status: i32) noreturn {
......@@ -759,23 +820,62 @@ pub fn exit(status: i32) noreturn {
759820 unreachable;
760821}
761822
762pub fn getrandom(buf: &u8, count: usize, flags: u32) usize {
763 return syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags));
823pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
824 return syscall3(SYS_getrandom, @ptrToInt(buf), count, @intCast(usize, flags));
764825}
765826
766827pub fn kill(pid: i32, sig: i32) usize {
767 return syscall2(SYS_kill, @bitCast(usize, isize(pid)), usize(sig));
828 return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @intCast(usize, sig));
768829}
769830
770pub fn unlink(path: &const u8) usize {
831// TODO https://github.com/ziglang/zig/issues/265
832pub fn unlink(path: [*]const u8) usize {
771833 return syscall1(SYS_unlink, @ptrToInt(path));
772834}
773835
774pub fn waitpid(pid: i32, status: &i32, options: i32) usize {
836pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
775837 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
776838}
777839
778pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
840pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
841 if (VDSO_CGT_SYM.len != 0) {
842 const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);
843 if (@ptrToInt(f) != 0) {
844 const rc = f(clk_id, tp);
845 switch (rc) {
846 0, @bitCast(usize, isize(-EINVAL)) => return rc,
847 else => {},
848 }
849 }
850 }
851 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
852}
853var vdso_clock_gettime = init_vdso_clock_gettime;
854extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
855 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
856 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
857 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
858 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
859 return f(clk, ts);
860}
861
862pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
863 return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
864}
865
866pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
867 return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
868}
869
870pub fn gettimeofday(tv: *timeval, tz: *timezone) usize {
871 return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
872}
873
874pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
875 return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
876}
877
878pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
779879 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
780880}
781881
......@@ -819,11 +919,11 @@ pub fn setegid(egid: u32) usize {
819919 return syscall1(SYS_setegid, egid);
820920}
821921
822pub fn getresuid(ruid: &u32, euid: &u32, suid: &u32) usize {
922pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize {
823923 return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
824924}
825925
826pub fn getresgid(rgid: &u32, egid: &u32, sgid: &u32) usize {
926pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize {
827927 return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
828928}
829929
......@@ -835,34 +935,34 @@ pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
835935 return syscall3(SYS_setresgid, rgid, egid, sgid);
836936}
837937
838pub fn getgroups(size: usize, list: &u32) usize {
938pub fn getgroups(size: usize, list: *u32) usize {
839939 return syscall2(SYS_getgroups, size, @ptrToInt(list));
840940}
841941
842pub fn setgroups(size: usize, list: &const u32) usize {
942pub fn setgroups(size: usize, list: *const u32) usize {
843943 return syscall2(SYS_setgroups, size, @ptrToInt(list));
844944}
845945
846946pub fn getpid() i32 {
847 return @bitCast(i32, u32(syscall0(SYS_getpid)));
947 return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
848948}
849949
850pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {
851 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);
950pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
951 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
852952}
853953
854pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
954pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
855955 assert(sig >= 1);
856956 assert(sig != SIGKILL);
857957 assert(sig != SIGSTOP);
858 var ksa = k_sigaction {
958 var ksa = k_sigaction{
859959 .handler = act.handler,
860960 .flags = act.flags | SA_RESTORER,
861961 .mask = undefined,
862 .restorer = @ptrCast(extern fn()void, restore_rt),
962 .restorer = @ptrCast(extern fn () void, restore_rt),
863963 };
864964 var ksa_old: k_sigaction = undefined;
865 @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);
965 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8);
866966 const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
867967 const err = getErrno(result);
868968 if (err != 0) {
......@@ -871,7 +971,7 @@ pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigacti
871971 if (oact) |old| {
872972 old.handler = ksa_old.handler;
873973 old.flags = @truncate(u32, ksa_old.flags);
874 @memcpy(@ptrCast(&u8, &old.mask), @ptrCast(&const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
974 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
875975 }
876976 return 0;
877977}
......@@ -882,53 +982,53 @@ const all_mask = []usize{@maxValue(usize)};
882982const app_mask = []usize{0xfffffffc7fffffff};
883983
884984const k_sigaction = extern struct {
885 handler: extern fn(i32)void,
985 handler: extern fn (i32) void,
886986 flags: usize,
887 restorer: extern fn()void,
987 restorer: extern fn () void,
888988 mask: [2]u32,
889989};
890990
891991/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
892992pub const Sigaction = struct {
893 handler: extern fn(i32)void,
993 handler: extern fn (i32) void,
894994 mask: sigset_t,
895995 flags: u32,
896996};
897997
898pub const SIG_ERR = @intToPtr(extern fn(i32)void, @maxValue(usize));
899pub const SIG_DFL = @intToPtr(extern fn(i32)void, 0);
900pub const SIG_IGN = @intToPtr(extern fn(i32)void, 1);
998pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize));
999pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
1000pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
9011001pub const empty_sigset = []usize{0} ** sigset_t.len;
9021002
9031003pub fn raise(sig: i32) usize {
9041004 var set: sigset_t = undefined;
9051005 blockAppSignals(&set);
906 const tid = i32(syscall0(SYS_gettid));
907 const ret = syscall2(SYS_tkill, usize(tid), usize(sig));
1006 const tid = @intCast(i32, syscall0(SYS_gettid));
1007 const ret = syscall2(SYS_tkill, @intCast(usize, tid), @intCast(usize, sig));
9081008 restoreSignals(&set);
9091009 return ret;
9101010}
9111011
912fn blockAllSignals(set: &sigset_t) void {
913 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8);
1012fn blockAllSignals(set: *sigset_t) void {
1013 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
9141014}
9151015
916fn blockAppSignals(set: &sigset_t) void {
917 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8);
1016fn blockAppSignals(set: *sigset_t) void {
1017 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
9181018}
9191019
920fn restoreSignals(set: &sigset_t) void {
921 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8);
1020fn restoreSignals(set: *sigset_t) void {
1021 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
9221022}
9231023
924pub fn sigaddset(set: &sigset_t, sig: u6) void {
1024pub fn sigaddset(set: *sigset_t, sig: u6) void {
9251025 const s = sig - 1;
926 (*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1));
1026 (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1));
9271027}
9281028
929pub fn sigismember(set: &const sigset_t, sig: u6) bool {
1029pub fn sigismember(set: *const sigset_t, sig: u6) bool {
9301030 const s = sig - 1;
931 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
1031 return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
9321032}
9331033
9341034pub const in_port_t = u16;
......@@ -956,145 +1056,151 @@ pub const sockaddr_in6 = extern struct {
9561056};
9571057
9581058pub const iovec = extern struct {
959 iov_base: &u8,
1059 iov_base: [*]u8,
9601060 iov_len: usize,
9611061};
9621062
963pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
964 return syscall3(SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len));
1063pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1064 return syscall3(SYS_getsockname, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len));
9651065}
9661066
967pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
968 return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
1067pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1068 return syscall3(SYS_getpeername, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len));
9691069}
9701070
9711071pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
9721072 return syscall3(SYS_socket, domain, socket_type, protocol);
9731073}
9741074
975pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize {
976 return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen));
1075pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
1076 return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @intCast(usize, optval), @ptrToInt(optlen));
9771077}
9781078
979pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: &u8, noalias optlen: &socklen_t) usize {
980 return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
1079pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
1080 return syscall5(SYS_getsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
9811081}
9821082
983pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
984 return syscall3(SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
1083pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
1084 return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
9851085}
9861086
987pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
988 return syscall3(SYS_connect, usize(fd), @ptrToInt(addr), usize(len));
1087pub fn connect(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
1088 return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));
9891089}
9901090
991pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {
992 return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
1091pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
1092 return syscall3(SYS_recvmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
9931093}
9941094
995pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
996 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize
997{
998 return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
1095pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
1096 return syscall6(SYS_recvfrom, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
9991097}
10001098
10011099pub fn shutdown(fd: i32, how: i32) usize {
1002 return syscall2(SYS_shutdown, usize(fd), usize(how));
1100 return syscall2(SYS_shutdown, @intCast(usize, fd), @intCast(usize, how));
10031101}
10041102
1005pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
1006 return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
1103pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
1104 return syscall3(SYS_bind, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));
10071105}
10081106
10091107pub fn listen(fd: i32, backlog: u32) usize {
1010 return syscall2(SYS_listen, usize(fd), backlog);
1108 return syscall2(SYS_listen, @intCast(usize, fd), backlog);
10111109}
10121110
1013pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {
1014 return syscall6(SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen));
1111pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
1112 return syscall6(SYS_sendto, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
10151113}
10161114
10171115pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
1018 return syscall4(SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]));
1116 return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(*fd[0]));
10191117}
10201118
1021pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) usize {
1119pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
10221120 return accept4(fd, addr, len, 0);
10231121}
10241122
1025pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) usize {
1026 return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
1123pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
1124 return syscall4(SYS_accept4, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len), flags);
10271125}
10281126
1029pub fn fstat(fd: i32, stat_buf: &Stat) usize {
1030 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
1127pub fn fstat(fd: i32, stat_buf: *Stat) usize {
1128 return syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf));
10311129}
10321130
1033pub fn stat(pathname: &const u8, statbuf: &Stat) usize {
1131// TODO https://github.com/ziglang/zig/issues/265
1132pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
10341133 return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf));
10351134}
10361135
1037pub fn lstat(pathname: &const u8, statbuf: &Stat) usize {
1136// TODO https://github.com/ziglang/zig/issues/265
1137pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
10381138 return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf));
10391139}
10401140
1041pub fn listxattr(path: &const u8, list: &u8, size: usize) usize {
1141// TODO https://github.com/ziglang/zig/issues/265
1142pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
10421143 return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
10431144}
10441145
1045pub fn llistxattr(path: &const u8, list: &u8, size: usize) usize {
1146// TODO https://github.com/ziglang/zig/issues/265
1147pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
10461148 return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
10471149}
10481150
1049pub fn flistxattr(fd: usize, list: &u8, size: usize) usize {
1151pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize {
10501152 return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
10511153}
10521154
1053pub fn getxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize {
1155// TODO https://github.com/ziglang/zig/issues/265
1156pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
10541157 return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
10551158}
10561159
1057pub fn lgetxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize {
1160// TODO https://github.com/ziglang/zig/issues/265
1161pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
10581162 return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
10591163}
10601164
1061pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize {
1165// TODO https://github.com/ziglang/zig/issues/265
1166pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize {
10621167 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
10631168}
10641169
1065pub fn setxattr(path: &const u8, name: &const u8, value: &const void,
1066 size: usize, flags: usize) usize {
1067
1068 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1069 size, flags);
1170// TODO https://github.com/ziglang/zig/issues/265
1171pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1172 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
10701173}
10711174
1072pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void,
1073 size: usize, flags: usize) usize {
1074
1075 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1076 size, flags);
1175// TODO https://github.com/ziglang/zig/issues/265
1176pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1177 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
10771178}
10781179
1079pub fn fsetxattr(fd: usize, name: &const u8, value: &const void,
1080 size: usize, flags: usize) usize {
1081
1082 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value),
1083 size, flags);
1180// TODO https://github.com/ziglang/zig/issues/265
1181pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1182 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
10841183}
10851184
1086pub fn removexattr(path: &const u8, name: &const u8) usize {
1185// TODO https://github.com/ziglang/zig/issues/265
1186pub fn removexattr(path: [*]const u8, name: [*]const u8) usize {
10871187 return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
10881188}
10891189
1090pub fn lremovexattr(path: &const u8, name: &const u8) usize {
1190// TODO https://github.com/ziglang/zig/issues/265
1191pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize {
10911192 return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
10921193}
10931194
1094pub fn fremovexattr(fd: usize, name: &const u8) usize {
1195// TODO https://github.com/ziglang/zig/issues/265
1196pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
10951197 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
10961198}
10971199
1200pub fn sched_getaffinity(pid: i32, set: []usize) usize {
1201 return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
1202}
1203
10981204pub const epoll_data = packed union {
10991205 ptr: usize,
11001206 fd: i32,
......@@ -1115,56 +1221,60 @@ pub fn epoll_create1(flags: usize) usize {
11151221 return syscall1(SYS_epoll_create1, flags);
11161222}
11171223
1118pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: &epoll_event) usize {
1119 return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
1224pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
1225 return syscall4(SYS_epoll_ctl, @intCast(usize, epoll_fd), @intCast(usize, op), @intCast(usize, fd), @ptrToInt(ev));
1226}
1227
1228pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
1229 return syscall4(SYS_epoll_wait, @intCast(usize, epoll_fd), @ptrToInt(events), @intCast(usize, maxevents), @intCast(usize, timeout));
11201230}
11211231
1122pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: u32, timeout: i32) usize {
1123 return syscall4(SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout));
1232pub fn eventfd(count: u32, flags: u32) usize {
1233 return syscall2(SYS_eventfd2, count, flags);
11241234}
11251235
11261236pub fn timerfd_create(clockid: i32, flags: u32) usize {
1127 return syscall2(SYS_timerfd_create, usize(clockid), usize(flags));
1237 return syscall2(SYS_timerfd_create, @intCast(usize, clockid), @intCast(usize, flags));
11281238}
11291239
11301240pub const itimerspec = extern struct {
11311241 it_interval: timespec,
1132 it_value: timespec
1242 it_value: timespec,
11331243};
11341244
1135pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {
1136 return syscall2(SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value));
1245pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
1246 return syscall2(SYS_timerfd_gettime, @intCast(usize, fd), @ptrToInt(curr_value));
11371247}
11381248
1139pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) usize {
1140 return syscall4(SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
1249pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
1250 return syscall4(SYS_timerfd_settime, @intCast(usize, fd), @intCast(usize, flags), @ptrToInt(new_value), @ptrToInt(old_value));
11411251}
11421252
11431253pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1144pub const _LINUX_CAPABILITY_U32S_1 = 1;
1254pub const _LINUX_CAPABILITY_U32S_1 = 1;
11451255
11461256pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1147pub const _LINUX_CAPABILITY_U32S_2 = 2;
1257pub const _LINUX_CAPABILITY_U32S_2 = 2;
11481258
11491259pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1150pub const _LINUX_CAPABILITY_U32S_3 = 2;
1260pub const _LINUX_CAPABILITY_U32S_3 = 2;
11511261
1152pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1153pub const VFS_CAP_REVISION_SHIFT = 24;
1154pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1262pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1263pub const VFS_CAP_REVISION_SHIFT = 24;
1264pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
11551265pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
11561266
11571267pub const VFS_CAP_REVISION_1 = 0x01000000;
1158pub const VFS_CAP_U32_1 = 1;
1159pub const XATTR_CAPS_SZ_1 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_1);
1268pub const VFS_CAP_U32_1 = 1;
1269pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
11601270
11611271pub const VFS_CAP_REVISION_2 = 0x02000000;
1162pub const VFS_CAP_U32_2 = 2;
1163pub const XATTR_CAPS_SZ_2 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_2);
1272pub const VFS_CAP_U32_2 = 2;
1273pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
11641274
1165pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1166pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1167pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
1275pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1276pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1277pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
11681278
11691279pub const vfs_cap_data = extern struct {
11701280 //all of these are mandated as little endian
......@@ -1175,49 +1285,48 @@ pub const vfs_cap_data = extern struct {
11751285 };
11761286
11771287 magic_etc: u32,
1178 data: [VFS_CAP_U32]Data,
1288 data: [VFS_CAP_U32]Data,
11791289};
11801290
1181
1182pub const CAP_CHOWN = 0;
1183pub const CAP_DAC_OVERRIDE = 1;
1184pub const CAP_DAC_READ_SEARCH = 2;
1185pub const CAP_FOWNER = 3;
1186pub const CAP_FSETID = 4;
1187pub const CAP_KILL = 5;
1188pub const CAP_SETGID = 6;
1189pub const CAP_SETUID = 7;
1190pub const CAP_SETPCAP = 8;
1191pub const CAP_LINUX_IMMUTABLE = 9;
1192pub const CAP_NET_BIND_SERVICE = 10;
1193pub const CAP_NET_BROADCAST = 11;
1194pub const CAP_NET_ADMIN = 12;
1195pub const CAP_NET_RAW = 13;
1196pub const CAP_IPC_LOCK = 14;
1197pub const CAP_IPC_OWNER = 15;
1198pub const CAP_SYS_MODULE = 16;
1199pub const CAP_SYS_RAWIO = 17;
1200pub const CAP_SYS_CHROOT = 18;
1201pub const CAP_SYS_PTRACE = 19;
1202pub const CAP_SYS_PACCT = 20;
1203pub const CAP_SYS_ADMIN = 21;
1204pub const CAP_SYS_BOOT = 22;
1205pub const CAP_SYS_NICE = 23;
1206pub const CAP_SYS_RESOURCE = 24;
1207pub const CAP_SYS_TIME = 25;
1208pub const CAP_SYS_TTY_CONFIG = 26;
1209pub const CAP_MKNOD = 27;
1210pub const CAP_LEASE = 28;
1211pub const CAP_AUDIT_WRITE = 29;
1212pub const CAP_AUDIT_CONTROL = 30;
1213pub const CAP_SETFCAP = 31;
1214pub const CAP_MAC_OVERRIDE = 32;
1215pub const CAP_MAC_ADMIN = 33;
1216pub const CAP_SYSLOG = 34;
1217pub const CAP_WAKE_ALARM = 35;
1218pub const CAP_BLOCK_SUSPEND = 36;
1219pub const CAP_AUDIT_READ = 37;
1220pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1291pub const CAP_CHOWN = 0;
1292pub const CAP_DAC_OVERRIDE = 1;
1293pub const CAP_DAC_READ_SEARCH = 2;
1294pub const CAP_FOWNER = 3;
1295pub const CAP_FSETID = 4;
1296pub const CAP_KILL = 5;
1297pub const CAP_SETGID = 6;
1298pub const CAP_SETUID = 7;
1299pub const CAP_SETPCAP = 8;
1300pub const CAP_LINUX_IMMUTABLE = 9;
1301pub const CAP_NET_BIND_SERVICE = 10;
1302pub const CAP_NET_BROADCAST = 11;
1303pub const CAP_NET_ADMIN = 12;
1304pub const CAP_NET_RAW = 13;
1305pub const CAP_IPC_LOCK = 14;
1306pub const CAP_IPC_OWNER = 15;
1307pub const CAP_SYS_MODULE = 16;
1308pub const CAP_SYS_RAWIO = 17;
1309pub const CAP_SYS_CHROOT = 18;
1310pub const CAP_SYS_PTRACE = 19;
1311pub const CAP_SYS_PACCT = 20;
1312pub const CAP_SYS_ADMIN = 21;
1313pub const CAP_SYS_BOOT = 22;
1314pub const CAP_SYS_NICE = 23;
1315pub const CAP_SYS_RESOURCE = 24;
1316pub const CAP_SYS_TIME = 25;
1317pub const CAP_SYS_TTY_CONFIG = 26;
1318pub const CAP_MKNOD = 27;
1319pub const CAP_LEASE = 28;
1320pub const CAP_AUDIT_WRITE = 29;
1321pub const CAP_AUDIT_CONTROL = 30;
1322pub const CAP_SETFCAP = 31;
1323pub const CAP_MAC_OVERRIDE = 32;
1324pub const CAP_MAC_ADMIN = 33;
1325pub const CAP_SYSLOG = 34;
1326pub const CAP_WAKE_ALARM = 35;
1327pub const CAP_BLOCK_SUSPEND = 36;
1328pub const CAP_AUDIT_READ = 37;
1329pub const CAP_LAST_CAP = CAP_AUDIT_READ;
12211330
12221331pub fn cap_valid(u8: x) bool {
12231332 return x >= 0 and x <= CAP_LAST_CAP;
......@@ -1232,8 +1341,8 @@ pub fn CAP_TO_INDEX(cap: u8) u8 {
12321341}
12331342
12341343pub const cap_t = extern struct {
1235 hdrp: &cap_user_header_t,
1236 datap: &cap_user_data_t,
1344 hdrp: *cap_user_header_t,
1345 datap: *cap_user_data_t,
12371346};
12381347
12391348pub const cap_user_header_t = extern struct {
......@@ -1248,20 +1357,18 @@ pub const cap_user_data_t = extern struct {
12481357};
12491358
12501359pub fn unshare(flags: usize) usize {
1251 return syscall1(SYS_unshare, usize(flags));
1360 return syscall1(SYS_unshare, @intCast(usize, flags));
12521361}
12531362
1254pub fn capget(hdrp: &cap_user_header_t, datap: &cap_user_data_t) usize {
1363pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize {
12551364 return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
12561365}
12571366
1258pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize {
1367pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
12591368 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
12601369}
12611370
1262test "import linux test" {
1263 // TODO lazy analysis should prevent this test from being compiled on windows, but
1264 // it is still compiled on windows
1371test "import" {
12651372 if (builtin.os == builtin.Os.linux) {
12661373 _ = @import("test.zig");
12671374 }
std/os/linux/test.zig+15-9
......@@ -1,7 +1,12 @@
11const std = @import("../../index.zig");
2const builtin = @import("builtin");
23const linux = std.os.linux;
34const assert = std.debug.assert;
45
6test "getpid" {
7 assert(linux.getpid() != 0);
8}
9
510test "timer" {
611 const epoll_fd = linux.epoll_create();
712 var err = linux.getErrno(epoll_fd);
......@@ -10,29 +15,30 @@ test "timer" {
1015 const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0);
1116 assert(linux.getErrno(timer_fd) == 0);
1217
13 const time_interval = linux.timespec {
18 const time_interval = linux.timespec{
1419 .tv_sec = 0,
15 .tv_nsec = 2000000
20 .tv_nsec = 2000000,
1621 };
1722
18 const new_time = linux.itimerspec {
23 const new_time = linux.itimerspec{
1924 .it_interval = time_interval,
20 .it_value = time_interval
25 .it_value = time_interval,
2126 };
2227
23 err = linux.timerfd_settime(i32(timer_fd), 0, &new_time, null);
28 err = linux.timerfd_settime(@intCast(i32, timer_fd), 0, &new_time, null);
2429 assert(err == 0);
2530
26 var event = linux.epoll_event {
31 var event = linux.epoll_event{
2732 .events = linux.EPOLLIN | linux.EPOLLOUT | linux.EPOLLET,
28 .data = linux.epoll_data { .ptr = 0 },
33 .data = linux.epoll_data{ .ptr = 0 },
2934 };
3035
31 err = linux.epoll_ctl(i32(epoll_fd), linux.EPOLL_CTL_ADD, i32(timer_fd), &event);
36 err = linux.epoll_ctl(@intCast(i32, epoll_fd), linux.EPOLL_CTL_ADD, @intCast(i32, timer_fd), &event);
3237 assert(err == 0);
3338
3439 const events_one: linux.epoll_event = undefined;
3540 var events = []linux.epoll_event{events_one} ** 8;
3641
37 err = linux.epoll_wait(i32(epoll_fd), &events[0], 8, -1);
42 // TODO implicit cast from *[N]T to [*]T
43 err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1);
3844}
std/os/linux/vdso.zig created+91
......@@ -0,0 +1,91 @@
1const std = @import("../../index.zig");
2const elf = std.elf;
3const linux = std.os.linux;
4const cstr = std.cstr;
5const mem = std.mem;
6
7pub fn lookup(vername: []const u8, name: []const u8) usize {
8 const vdso_addr = std.os.linux_aux_raw[std.elf.AT_SYSINFO_EHDR];
9 if (vdso_addr == 0) return 0;
10
11 const eh = @intToPtr(*elf.Ehdr, vdso_addr);
12 var ph_addr: usize = vdso_addr + eh.e_phoff;
13 const ph = @intToPtr(*elf.Phdr, ph_addr);
14
15 var maybe_dynv: ?[*]usize = null;
16 var base: usize = @maxValue(usize);
17 {
18 var i: usize = 0;
19 while (i < eh.e_phnum) : ({
20 i += 1;
21 ph_addr += eh.e_phentsize;
22 }) {
23 const this_ph = @intToPtr(*elf.Phdr, ph_addr);
24 switch (this_ph.p_type) {
25 elf.PT_LOAD => base = vdso_addr + this_ph.p_offset - this_ph.p_vaddr,
26 elf.PT_DYNAMIC => maybe_dynv = @intToPtr([*]usize, vdso_addr + this_ph.p_offset),
27 else => {},
28 }
29 }
30 }
31 const dynv = maybe_dynv orelse return 0;
32 if (base == @maxValue(usize)) return 0;
33
34 var maybe_strings: ?[*]u8 = null;
35 var maybe_syms: ?[*]elf.Sym = null;
36 var maybe_hashtab: ?[*]linux.Elf_Symndx = null;
37 var maybe_versym: ?[*]u16 = null;
38 var maybe_verdef: ?*elf.Verdef = null;
39
40 {
41 var i: usize = 0;
42 while (dynv[i] != 0) : (i += 2) {
43 const p = base + dynv[i + 1];
44 switch (dynv[i]) {
45 elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
46 elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
47 elf.DT_HASH => maybe_hashtab = @intToPtr([*]linux.Elf_Symndx, p),
48 elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p),
49 elf.DT_VERDEF => maybe_verdef = @intToPtr(*elf.Verdef, p),
50 else => {},
51 }
52 }
53 }
54
55 const strings = maybe_strings orelse return 0;
56 const syms = maybe_syms orelse return 0;
57 const hashtab = maybe_hashtab orelse return 0;
58 if (maybe_verdef == null) maybe_versym = null;
59
60 const OK_TYPES = (1 << elf.STT_NOTYPE | 1 << elf.STT_OBJECT | 1 << elf.STT_FUNC | 1 << elf.STT_COMMON);
61 const OK_BINDS = (1 << elf.STB_GLOBAL | 1 << elf.STB_WEAK | 1 << elf.STB_GNU_UNIQUE);
62
63 var i: usize = 0;
64 while (i < hashtab[1]) : (i += 1) {
65 if (0 == (u32(1) << @intCast(u5, syms[i].st_info & 0xf) & OK_TYPES)) continue;
66 if (0 == (u32(1) << @intCast(u5, syms[i].st_info >> 4) & OK_BINDS)) continue;
67 if (0 == syms[i].st_shndx) continue;
68 if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue;
69 if (maybe_versym) |versym| {
70 if (!checkver(maybe_verdef.?, versym[i], vername, strings))
71 continue;
72 }
73 return base + syms[i].st_value;
74 }
75
76 return 0;
77}
78
79fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool {
80 var def = def_arg;
81 const vsym = @bitCast(u32, vsym_arg) & 0x7fff;
82 while (true) {
83 if (0 == (def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)
84 break;
85 if (def.vd_next == 0)
86 return false;
87 def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
88 }
89 const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
90 return mem.eql(u8, vername, cstr.toSliceConst(strings + aux.vda_name));
91}
std/os/linux/x86_64.zig+86-53
......@@ -330,26 +330,26 @@ pub const SYS_userfaultfd = 323;
330330pub const SYS_membarrier = 324;
331331pub const SYS_mlock2 = 325;
332332
333pub const O_CREAT = 0o100;
334pub const O_EXCL = 0o200;
335pub const O_NOCTTY = 0o400;
336pub const O_TRUNC = 0o1000;
337pub const O_APPEND = 0o2000;
338pub const O_NONBLOCK = 0o4000;
339pub const O_DSYNC = 0o10000;
340pub const O_SYNC = 0o4010000;
341pub const O_RSYNC = 0o4010000;
333pub const O_CREAT = 0o100;
334pub const O_EXCL = 0o200;
335pub const O_NOCTTY = 0o400;
336pub const O_TRUNC = 0o1000;
337pub const O_APPEND = 0o2000;
338pub const O_NONBLOCK = 0o4000;
339pub const O_DSYNC = 0o10000;
340pub const O_SYNC = 0o4010000;
341pub const O_RSYNC = 0o4010000;
342342pub const O_DIRECTORY = 0o200000;
343pub const O_NOFOLLOW = 0o400000;
344pub const O_CLOEXEC = 0o2000000;
343pub const O_NOFOLLOW = 0o400000;
344pub const O_CLOEXEC = 0o2000000;
345345
346pub const O_ASYNC = 0o20000;
347pub const O_DIRECT = 0o40000;
348pub const O_LARGEFILE = 0;
349pub const O_NOATIME = 0o1000000;
350pub const O_PATH = 0o10000000;
346pub const O_ASYNC = 0o20000;
347pub const O_DIRECT = 0o40000;
348pub const O_LARGEFILE = 0;
349pub const O_NOATIME = 0o1000000;
350pub const O_PATH = 0o10000000;
351351pub const O_TMPFILE = 0o20200000;
352pub const O_NDELAY = O_NONBLOCK;
352pub const O_NDELAY = O_NONBLOCK;
353353
354354pub const F_DUPFD = 0;
355355pub const F_GETFD = 1;
......@@ -371,93 +371,115 @@ pub const F_GETOWN_EX = 16;
371371
372372pub const F_GETOWNER_UIDS = 17;
373373
374pub const VDSO_USEFUL = true;
375pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
376pub const VDSO_CGT_VER = "LINUX_2.6";
377pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
378pub const VDSO_GETCPU_VER = "LINUX_2.6";
379
374380pub fn syscall0(number: usize) usize {
375381 return asm volatile ("syscall"
376382 : [ret] "={rax}" (-> usize)
377383 : [number] "{rax}" (number)
378 : "rcx", "r11");
384 : "rcx", "r11"
385 );
379386}
380387
381388pub fn syscall1(number: usize, arg1: usize) usize {
382389 return asm volatile ("syscall"
383390 : [ret] "={rax}" (-> usize)
384391 : [number] "{rax}" (number),
385 [arg1] "{rdi}" (arg1)
386 : "rcx", "r11");
392 [arg1] "{rdi}" (arg1)
393 : "rcx", "r11"
394 );
387395}
388396
389397pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
390398 return asm volatile ("syscall"
391399 : [ret] "={rax}" (-> usize)
392400 : [number] "{rax}" (number),
393 [arg1] "{rdi}" (arg1),
394 [arg2] "{rsi}" (arg2)
395 : "rcx", "r11");
401 [arg1] "{rdi}" (arg1),
402 [arg2] "{rsi}" (arg2)
403 : "rcx", "r11"
404 );
396405}
397406
398407pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
399408 return asm volatile ("syscall"
400409 : [ret] "={rax}" (-> usize)
401410 : [number] "{rax}" (number),
402 [arg1] "{rdi}" (arg1),
403 [arg2] "{rsi}" (arg2),
404 [arg3] "{rdx}" (arg3)
405 : "rcx", "r11");
411 [arg1] "{rdi}" (arg1),
412 [arg2] "{rsi}" (arg2),
413 [arg3] "{rdx}" (arg3)
414 : "rcx", "r11"
415 );
406416}
407417
408418pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
409419 return asm volatile ("syscall"
410420 : [ret] "={rax}" (-> usize)
411421 : [number] "{rax}" (number),
412 [arg1] "{rdi}" (arg1),
413 [arg2] "{rsi}" (arg2),
414 [arg3] "{rdx}" (arg3),
415 [arg4] "{r10}" (arg4)
416 : "rcx", "r11");
422 [arg1] "{rdi}" (arg1),
423 [arg2] "{rsi}" (arg2),
424 [arg3] "{rdx}" (arg3),
425 [arg4] "{r10}" (arg4)
426 : "rcx", "r11"
427 );
417428}
418429
419430pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
420431 return asm volatile ("syscall"
421432 : [ret] "={rax}" (-> usize)
422433 : [number] "{rax}" (number),
423 [arg1] "{rdi}" (arg1),
424 [arg2] "{rsi}" (arg2),
425 [arg3] "{rdx}" (arg3),
426 [arg4] "{r10}" (arg4),
427 [arg5] "{r8}" (arg5)
428 : "rcx", "r11");
434 [arg1] "{rdi}" (arg1),
435 [arg2] "{rsi}" (arg2),
436 [arg3] "{rdx}" (arg3),
437 [arg4] "{r10}" (arg4),
438 [arg5] "{r8}" (arg5)
439 : "rcx", "r11"
440 );
429441}
430442
431pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
432 arg5: usize, arg6: usize) usize
433{
443pub fn syscall6(
444 number: usize,
445 arg1: usize,
446 arg2: usize,
447 arg3: usize,
448 arg4: usize,
449 arg5: usize,
450 arg6: usize,
451) usize {
434452 return asm volatile ("syscall"
435453 : [ret] "={rax}" (-> usize)
436454 : [number] "{rax}" (number),
437 [arg1] "{rdi}" (arg1),
438 [arg2] "{rsi}" (arg2),
439 [arg3] "{rdx}" (arg3),
440 [arg4] "{r10}" (arg4),
441 [arg5] "{r8}" (arg5),
442 [arg6] "{r9}" (arg6)
443 : "rcx", "r11");
455 [arg1] "{rdi}" (arg1),
456 [arg2] "{rsi}" (arg2),
457 [arg3] "{rdx}" (arg3),
458 [arg4] "{r10}" (arg4),
459 [arg5] "{r8}" (arg5),
460 [arg6] "{r9}" (arg6)
461 : "rcx", "r11"
462 );
444463}
445464
465/// This matches the libc clone function.
466pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
467
446468pub nakedcc fn restore_rt() void {
447469 return asm volatile ("syscall"
448470 :
449471 : [number] "{rax}" (usize(SYS_rt_sigreturn))
450 : "rcx", "r11");
472 : "rcx", "r11"
473 );
451474}
452475
453
454476pub const msghdr = extern struct {
455 msg_name: &u8,
477 msg_name: *u8,
456478 msg_namelen: socklen_t,
457 msg_iov: &iovec,
479 msg_iov: *iovec,
458480 msg_iovlen: i32,
459481 __pad1: i32,
460 msg_control: &u8,
482 msg_control: *u8,
461483 msg_controllen: socklen_t,
462484 __pad2: socklen_t,
463485 msg_flags: i32,
......@@ -489,6 +511,16 @@ pub const timespec = extern struct {
489511 tv_nsec: isize,
490512};
491513
514pub const timeval = extern struct {
515 tv_sec: isize,
516 tv_usec: isize,
517};
518
519pub const timezone = extern struct {
520 tz_minuteswest: i32,
521 tz_dsttime: i32,
522};
523
492524pub const dirent = extern struct {
493525 d_ino: usize,
494526 d_off: usize,
......@@ -496,3 +528,4 @@ pub const dirent = extern struct {
496528 d_name: u8, // field address is the address of first byte of name
497529};
498530
531pub const Elf_Symndx = u32;
std/os/path.zig+100-95
......@@ -32,7 +32,7 @@ pub fn isSep(byte: u8) bool {
3232
3333/// Naively combines a series of paths with the native path seperator.
3434/// Allocates memory for the result, which must be freed by the caller.
35pub fn join(allocator: &Allocator, paths: ...) ![]u8 {
35pub fn join(allocator: *Allocator, paths: ...) ![]u8 {
3636 if (is_windows) {
3737 return joinWindows(allocator, paths);
3838 } else {
......@@ -40,11 +40,11 @@ pub fn join(allocator: &Allocator, paths: ...) ![]u8 {
4040 }
4141}
4242
43pub fn joinWindows(allocator: &Allocator, paths: ...) ![]u8 {
43pub fn joinWindows(allocator: *Allocator, paths: ...) ![]u8 {
4444 return mem.join(allocator, sep_windows, paths);
4545}
4646
47pub fn joinPosix(allocator: &Allocator, paths: ...) ![]u8 {
47pub fn joinPosix(allocator: *Allocator, paths: ...) ![]u8 {
4848 return mem.join(allocator, sep_posix, paths);
4949}
5050
......@@ -55,9 +55,7 @@ test "os.path.join" {
5555 assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\", "a", "b\\", "c"), "c:\\a\\b\\c"));
5656 assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\", "b\\", "c"), "c:\\a\\b\\c"));
5757
58 assert(mem.eql(u8, try joinWindows(debug.global_allocator,
59 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig"),
60 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig"));
58 assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig"), "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig"));
6159
6260 assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b", "c"), "/a/b/c"));
6361 assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b/", "c"), "/a/b/c"));
......@@ -65,8 +63,7 @@ test "os.path.join" {
6563 assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c"));
6664 assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/", "b/", "c"), "/a/b/c"));
6765
68 assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/home/andy/dev/zig/build/lib/zig/std", "io.zig"),
69 "/home/andy/dev/zig/build/lib/zig/std/io.zig"));
66 assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/home/andy/dev/zig/build/lib/zig/std", "io.zig"), "/home/andy/dev/zig/build/lib/zig/std/io.zig"));
7067}
7168
7269pub fn isAbsolute(path: []const u8) bool {
......@@ -151,22 +148,22 @@ pub const WindowsPath = struct {
151148
152149pub fn windowsParsePath(path: []const u8) WindowsPath {
153150 if (path.len >= 2 and path[1] == ':') {
154 return WindowsPath {
151 return WindowsPath{
155152 .is_abs = isAbsoluteWindows(path),
156153 .kind = WindowsPath.Kind.Drive,
157154 .disk_designator = path[0..2],
158155 };
159156 }
160157 if (path.len >= 1 and (path[0] == '/' or path[0] == '\\') and
161 (path.len == 1 or (path[1] != '/' and path[1] != '\\')))
158 (path.len == 1 or (path[1] != '/' and path[1] != '\\')))
162159 {
163 return WindowsPath {
160 return WindowsPath{
164161 .is_abs = true,
165162 .kind = WindowsPath.Kind.None,
166163 .disk_designator = path[0..0],
167164 };
168165 }
169 const relative_path = WindowsPath {
166 const relative_path = WindowsPath{
170167 .kind = WindowsPath.Kind.None,
171168 .disk_designator = []u8{},
172169 .is_abs = false,
......@@ -178,16 +175,16 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
178175 // TODO when I combined these together with `inline for` the compiler crashed
179176 {
180177 const this_sep = '/';
181 const two_sep = []u8{this_sep, this_sep};
178 const two_sep = []u8{ this_sep, this_sep };
182179 if (mem.startsWith(u8, path, two_sep)) {
183180 if (path[2] == this_sep) {
184181 return relative_path;
185182 }
186183
187184 var it = mem.split(path, []u8{this_sep});
188 _ = (it.next() ?? return relative_path);
189 _ = (it.next() ?? return relative_path);
190 return WindowsPath {
185 _ = (it.next() orelse return relative_path);
186 _ = (it.next() orelse return relative_path);
187 return WindowsPath{
191188 .is_abs = isAbsoluteWindows(path),
192189 .kind = WindowsPath.Kind.NetworkShare,
193190 .disk_designator = path[0..it.index],
......@@ -196,16 +193,16 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
196193 }
197194 {
198195 const this_sep = '\\';
199 const two_sep = []u8{this_sep, this_sep};
196 const two_sep = []u8{ this_sep, this_sep };
200197 if (mem.startsWith(u8, path, two_sep)) {
201198 if (path[2] == this_sep) {
202199 return relative_path;
203200 }
204201
205202 var it = mem.split(path, []u8{this_sep});
206 _ = (it.next() ?? return relative_path);
207 _ = (it.next() ?? return relative_path);
208 return WindowsPath {
203 _ = (it.next() orelse return relative_path);
204 _ = (it.next() orelse return relative_path);
205 return WindowsPath{
209206 .is_abs = isAbsoluteWindows(path),
210207 .kind = WindowsPath.Kind.NetworkShare,
211208 .disk_designator = path[0..it.index],
......@@ -268,7 +265,7 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
268265 var it2 = mem.split(ns2, []u8{sep2});
269266
270267 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
271 return asciiEqlIgnoreCase(??it1.next(), ??it2.next());
268 return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
272269}
273270
274271fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool {
......@@ -289,14 +286,14 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8
289286 var it2 = mem.split(p2, []u8{sep2});
290287
291288 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
292 return asciiEqlIgnoreCase(??it1.next(), ??it2.next()) and asciiEqlIgnoreCase(??it1.next(), ??it2.next());
289 return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);
293290 },
294291 }
295292}
296293
297294fn asciiUpper(byte: u8) u8 {
298295 return switch (byte) {
299 'a' ... 'z' => 'A' + (byte - 'a'),
296 'a'...'z' => 'A' + (byte - 'a'),
300297 else => byte,
301298 };
302299}
......@@ -313,7 +310,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
313310}
314311
315312/// Converts the command line arguments into a slice and calls `resolveSlice`.
316pub fn resolve(allocator: &Allocator, args: ...) ![]u8 {
313pub fn resolve(allocator: *Allocator, args: ...) ![]u8 {
317314 var paths: [args.len][]const u8 = undefined;
318315 comptime var arg_i = 0;
319316 inline while (arg_i < args.len) : (arg_i += 1) {
......@@ -323,7 +320,7 @@ pub fn resolve(allocator: &Allocator, args: ...) ![]u8 {
323320}
324321
325322/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
326pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) ![]u8 {
323pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 {
327324 if (is_windows) {
328325 return resolveWindows(allocator, paths);
329326 } else {
......@@ -337,7 +334,7 @@ pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) ![]u8 {
337334/// If all paths are relative it uses the current working directory as a starting point.
338335/// Each drive has its own current working directory.
339336/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
340pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
337pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
341338 if (paths.len == 0) {
342339 assert(is_windows); // resolveWindows called on non windows can't use getCwd
343340 return os.getCwd(allocator);
......@@ -372,7 +369,6 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
372369 max_size += p.len + 1;
373370 }
374371
375
376372 // if we will result with a disk designator, loop again to determine
377373 // which is the last time the disk designator is absolutely specified, if any
378374 // and count up the max bytes for paths related to this disk designator
......@@ -386,8 +382,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
386382 const parsed = windowsParsePath(p);
387383 if (parsed.kind != WindowsPath.Kind.None) {
388384 if (parsed.kind == have_drive_kind) {
389 correct_disk_designator = compareDiskDesignators(have_drive_kind,
390 result_disk_designator, parsed.disk_designator);
385 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
391386 } else {
392387 continue;
393388 }
......@@ -404,7 +399,6 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
404399 }
405400 }
406401
407
408402 // Allocate result and fill in the disk designator, calling getCwd if we have to.
409403 var result: []u8 = undefined;
410404 var result_index: usize = 0;
......@@ -420,8 +414,8 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
420414 WindowsPath.Kind.NetworkShare => {
421415 result = try allocator.alloc(u8, max_size);
422416 var it = mem.split(paths[first_index], "/\\");
423 const server_name = ??it.next();
424 const other_name = ??it.next();
417 const server_name = it.next().?;
418 const other_name = it.next().?;
425419
426420 result[result_index] = '\\';
427421 result_index += 1;
......@@ -433,7 +427,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
433427 result_index += 1;
434428 mem.copy(u8, result[result_index..], other_name);
435429 result_index += other_name.len;
436
430
437431 result_disk_designator = result[0..result_index];
438432 },
439433 WindowsPath.Kind.None => {
......@@ -478,8 +472,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
478472
479473 if (parsed.kind != WindowsPath.Kind.None) {
480474 if (parsed.kind == have_drive_kind) {
481 correct_disk_designator = compareDiskDesignators(have_drive_kind,
482 result_disk_designator, parsed.disk_designator);
475 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
483476 } else {
484477 continue;
485478 }
......@@ -520,7 +513,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) ![]u8 {
520513/// It resolves "." and "..".
521514/// The result does not have a trailing path separator.
522515/// If all paths are relative it uses the current working directory as a starting point.
523pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) ![]u8 {
516pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
524517 if (paths.len == 0) {
525518 assert(!is_windows); // resolvePosix called on windows can't use getCwd
526519 return os.getCwd(allocator);
......@@ -591,7 +584,7 @@ test "os.path.resolve" {
591584 }
592585 assert(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd));
593586 } else {
594 assert(mem.eql(u8, testResolvePosix([][]const u8{"a/b/c/", "../../.."}), cwd));
587 assert(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd));
595588 assert(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd));
596589 }
597590}
......@@ -601,16 +594,15 @@ test "os.path.resolveWindows" {
601594 const cwd = try os.getCwd(debug.global_allocator);
602595 const parsed_cwd = windowsParsePath(cwd);
603596 {
604 const result = testResolveWindows([][]const u8{"/usr/local", "lib\\zig\\std\\array_list.zig"});
605 const expected = try join(debug.global_allocator,
606 parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig");
597 const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
598 const expected = try join(debug.global_allocator, parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig");
607599 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
608600 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
609601 }
610602 assert(mem.eql(u8, result, expected));
611603 }
612604 {
613 const result = testResolveWindows([][]const u8{"usr/local", "lib\\zig"});
605 const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });
614606 const expected = try join(debug.global_allocator, cwd, "usr\\local\\lib\\zig");
615607 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
616608 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
......@@ -619,33 +611,32 @@ test "os.path.resolveWindows" {
619611 }
620612 }
621613
622 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:\\a\\b\\c", "/hi", "ok"}), "C:\\hi\\ok"));
623 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/blah\\blah", "d:/games", "c:../a"}), "C:\\blah\\a"));
624 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/blah\\blah", "d:/games", "C:../a"}), "C:\\blah\\a"));
625 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/ignore", "d:\\a/b\\c/d", "\\e.exe"}), "D:\\e.exe"));
626 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/ignore", "c:/some/file"}), "C:\\some\\file"));
627 assert(mem.eql(u8, testResolveWindows([][]const u8{"d:/ignore", "d:some/dir//"}), "D:\\ignore\\some\\dir"));
628 assert(mem.eql(u8, testResolveWindows([][]const u8{"//server/share", "..", "relative\\"}), "\\\\server\\share\\relative"));
629 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/", "//"}), "C:\\"));
630 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/", "//dir"}), "C:\\dir"));
631 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/", "//server/share"}), "\\\\server\\share\\"));
632 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/", "//server//share"}), "\\\\server\\share\\"));
633 assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/", "///some//dir"}), "C:\\some\\dir"));
634 assert(mem.eql(u8, testResolveWindows([][]const u8{"C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js"}),
635 "C:\\foo\\tmp.3\\cycles\\root.js"));
614 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok"));
615 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a"));
616 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a"));
617 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe"));
618 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file"));
619 assert(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir"));
620 assert(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative"));
621 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\"));
622 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir"));
623 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\"));
624 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\"));
625 assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir"));
626 assert(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js"));
636627}
637628
638629test "os.path.resolvePosix" {
639 assert(mem.eql(u8, testResolvePosix([][]const u8{"/a/b", "c"}), "/a/b/c"));
640 assert(mem.eql(u8, testResolvePosix([][]const u8{"/a/b", "c", "//d", "e///"}), "/d/e"));
641 assert(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c", "..", "../"}), "/a"));
642 assert(mem.eql(u8, testResolvePosix([][]const u8{"/", "..", ".."}), "/"));
630 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c"));
631 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e"));
632 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a"));
633 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/"));
643634 assert(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c"));
644635
645 assert(mem.eql(u8, testResolvePosix([][]const u8{"/var/lib", "../", "file/"}), "/var/file"));
646 assert(mem.eql(u8, testResolvePosix([][]const u8{"/var/lib", "/../", "file/"}), "/file"));
647 assert(mem.eql(u8, testResolvePosix([][]const u8{"/some/dir", ".", "/absolute/"}), "/absolute"));
648 assert(mem.eql(u8, testResolvePosix([][]const u8{"/foo/tmp.3/", "../tmp.3/cycles/root.js"}), "/foo/tmp.3/cycles/root.js"));
636 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file"));
637 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file"));
638 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute"));
639 assert(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js"));
649640}
650641
651642fn testResolveWindows(paths: []const []const u8) []u8 {
......@@ -656,7 +647,9 @@ fn testResolvePosix(paths: []const []const u8) []u8 {
656647 return resolvePosix(debug.global_allocator, paths) catch unreachable;
657648}
658649
659pub fn dirname(path: []const u8) []const u8 {
650/// If the path is a file in the current directory (no directory component)
651/// then returns null
652pub fn dirname(path: []const u8) ?[]const u8 {
660653 if (is_windows) {
661654 return dirnameWindows(path);
662655 } else {
......@@ -664,9 +657,9 @@ pub fn dirname(path: []const u8) []const u8 {
664657 }
665658}
666659
667pub fn dirnameWindows(path: []const u8) []const u8 {
660pub fn dirnameWindows(path: []const u8) ?[]const u8 {
668661 if (path.len == 0)
669 return path[0..0];
662 return null;
670663
671664 const root_slice = diskDesignatorWindows(path);
672665 if (path.len == root_slice.len)
......@@ -678,13 +671,13 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
678671
679672 while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
680673 if (end_index == 0)
681 return path[0..0];
674 return null;
682675 end_index -= 1;
683676 }
684677
685678 while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
686679 if (end_index == 0)
687 return path[0..0];
680 return null;
688681 end_index -= 1;
689682 }
690683
......@@ -692,12 +685,15 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
692685 end_index += 1;
693686 }
694687
688 if (end_index == 0)
689 return null;
690
695691 return path[0..end_index];
696692}
697693
698pub fn dirnamePosix(path: []const u8) []const u8 {
694pub fn dirnamePosix(path: []const u8) ?[]const u8 {
699695 if (path.len == 0)
700 return path[0..0];
696 return null;
701697
702698 var end_index: usize = path.len - 1;
703699 while (path[end_index] == '/') {
......@@ -708,13 +704,16 @@ pub fn dirnamePosix(path: []const u8) []const u8 {
708704
709705 while (path[end_index] != '/') {
710706 if (end_index == 0)
711 return path[0..0];
707 return null;
712708 end_index -= 1;
713709 }
714710
715711 if (end_index == 0 and path[end_index] == '/')
716712 return path[0..1];
717713
714 if (end_index == 0)
715 return null;
716
718717 return path[0..end_index];
719718}
720719
......@@ -724,10 +723,10 @@ test "os.path.dirnamePosix" {
724723 testDirnamePosix("/a", "/");
725724 testDirnamePosix("/", "/");
726725 testDirnamePosix("////", "/");
727 testDirnamePosix("", "");
728 testDirnamePosix("a", "");
729 testDirnamePosix("a/", "");
730 testDirnamePosix("a//", "");
726 testDirnamePosix("", null);
727 testDirnamePosix("a", null);
728 testDirnamePosix("a/", null);
729 testDirnamePosix("a//", null);
731730}
732731
733732test "os.path.dirnameWindows" {
......@@ -749,7 +748,7 @@ test "os.path.dirnameWindows" {
749748 testDirnameWindows("c:foo\\bar", "c:foo");
750749 testDirnameWindows("c:foo\\bar\\", "c:foo");
751750 testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
752 testDirnameWindows("file:stream", "");
751 testDirnameWindows("file:stream", null);
753752 testDirnameWindows("dir\\file:stream", "dir");
754753 testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
755754 testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
......@@ -760,18 +759,26 @@ test "os.path.dirnameWindows" {
760759 testDirnameWindows("/a/b/", "/a");
761760 testDirnameWindows("/a/b", "/a");
762761 testDirnameWindows("/a", "/");
763 testDirnameWindows("", "");
762 testDirnameWindows("", null);
764763 testDirnameWindows("/", "/");
765764 testDirnameWindows("////", "/");
766 testDirnameWindows("foo", "");
765 testDirnameWindows("foo", null);
767766}
768767
769fn testDirnamePosix(input: []const u8, expected_output: []const u8) void {
770 assert(mem.eql(u8, dirnamePosix(input), expected_output));
768fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void {
769 if (dirnamePosix(input)) |output| {
770 assert(mem.eql(u8, output, expected_output.?));
771 } else {
772 assert(expected_output == null);
773 }
771774}
772775
773fn testDirnameWindows(input: []const u8, expected_output: []const u8) void {
774 assert(mem.eql(u8, dirnameWindows(input), expected_output));
776fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
777 if (dirnameWindows(input)) |output| {
778 assert(mem.eql(u8, output, expected_output.?));
779 } else {
780 assert(expected_output == null);
781 }
775782}
776783
777784pub fn basename(path: []const u8) []const u8 {
......@@ -800,7 +807,7 @@ pub fn basenamePosix(path: []const u8) []const u8 {
800807 start_index -= 1;
801808 }
802809
803 return path[start_index + 1..end_index];
810 return path[start_index + 1 .. end_index];
804811}
805812
806813pub fn basenameWindows(path: []const u8) []const u8 {
......@@ -832,7 +839,7 @@ pub fn basenameWindows(path: []const u8) []const u8 {
832839 start_index -= 1;
833840 }
834841
835 return path[start_index + 1..end_index];
842 return path[start_index + 1 .. end_index];
836843}
837844
838845test "os.path.basename" {
......@@ -890,7 +897,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
890897/// resolve to the same path (after calling `resolve` on each), a zero-length
891898/// string is returned.
892899/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
893pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
900pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
894901 if (is_windows) {
895902 return relativeWindows(allocator, from, to);
896903 } else {
......@@ -898,7 +905,7 @@ pub fn relative(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
898905 }
899906}
900907
901pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
908pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
902909 const resolved_from = try resolveWindows(allocator, [][]const u8{from});
903910 defer allocator.free(resolved_from);
904911
......@@ -930,7 +937,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
930937 var from_it = mem.split(resolved_from, "/\\");
931938 var to_it = mem.split(resolved_to, "/\\");
932939 while (true) {
933 const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest());
940 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
934941 const to_rest = to_it.rest();
935942 if (to_it.next()) |to_component| {
936943 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
......@@ -971,7 +978,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
971978 return []u8{};
972979}
973980
974pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) ![]u8 {
981pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
975982 const resolved_from = try resolvePosix(allocator, [][]const u8{from});
976983 defer allocator.free(resolved_from);
977984
......@@ -981,7 +988,7 @@ pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) ![
981988 var from_it = mem.split(resolved_from, "/");
982989 var to_it = mem.split(resolved_to, "/");
983990 while (true) {
984 const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest());
991 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
985992 const to_rest = to_it.rest();
986993 if (to_it.next()) |to_component| {
987994 if (mem.eql(u8, from_component, to_component))
......@@ -1006,7 +1013,7 @@ pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) ![
10061013 }
10071014 if (to_rest.len == 0) {
10081015 // shave off the trailing slash
1009 return result[0..result_index - 1];
1016 return result[0 .. result_index - 1];
10101017 }
10111018
10121019 mem.copy(u8, result[result_index..], to_rest);
......@@ -1070,7 +1077,7 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
10701077/// Expands all symbolic links and resolves references to `.`, `..`, and
10711078/// extra `/` characters in ::pathname.
10721079/// Caller must deallocate result.
1073pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {
1080pub fn real(allocator: *Allocator, pathname: []const u8) ![]u8 {
10741081 switch (builtin.os) {
10751082 Os.windows => {
10761083 const pathname_buf = try allocator.alloc(u8, pathname.len + 1);
......@@ -1079,9 +1086,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {
10791086 mem.copy(u8, pathname_buf, pathname);
10801087 pathname_buf[pathname.len] = 0;
10811088
1082 const h_file = windows.CreateFileA(pathname_buf.ptr,
1083 windows.GENERIC_READ, windows.FILE_SHARE_READ, null, windows.OPEN_EXISTING,
1084 windows.FILE_ATTRIBUTE_NORMAL, null);
1089 const h_file = windows.CreateFileA(pathname_buf.ptr, windows.GENERIC_READ, windows.FILE_SHARE_READ, null, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null);
10851090 if (h_file == windows.INVALID_HANDLE_VALUE) {
10861091 const err = windows.GetLastError();
10871092 return switch (err) {
......@@ -1161,7 +1166,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {
11611166 return allocator.shrink(u8, result_buf, cstr.len(result_buf.ptr));
11621167 },
11631168 Os.linux => {
1164 const fd = try os.posixOpen(allocator, pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0);
1169 const fd = try os.posixOpen(allocator, pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0);
11651170 defer os.close(fd);
11661171
11671172 var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;
std/os/test.zig+35-12
......@@ -6,13 +6,10 @@ const io = std.io;
66const a = std.debug.global_allocator;
77
88const builtin = @import("builtin");
9const AtomicRmwOp = builtin.AtomicRmwOp;
10const AtomicOrder = builtin.AtomicOrder;
911
1012test "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 }
1613 try os.makePath(a, "os_test_tmp/b/c");
1714 try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
1815 try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
......@@ -25,18 +22,44 @@ test "makePath, put some files in it, deleteTree" {
2522}
2623
2724test "access file" {
28 if (builtin.os == builtin.Os.windows) {
29 return;
30 }
31
3225 try os.makePath(a, "os_test_tmp");
33 if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
34 unreachable;
26 if (os.File.access(a, "os_test_tmp/file.txt")) |ok| {
27 @panic("expected error");
3528 } else |err| {
3629 assert(err == error.NotFound);
3730 }
3831
3932 try io.writeFile(a, "os_test_tmp/file.txt", "");
40 assert((try os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) == true);
33 try os.File.access(a, "os_test_tmp/file.txt");
4134 try os.deleteTree(a, "os_test_tmp");
4235}
36
37test "spawn threads" {
38 var shared_ctx: i32 = 1;
39
40 const thread1 = try std.os.spawnThread({}, start1);
41 const thread2 = try std.os.spawnThread(&shared_ctx, start2);
42 const thread3 = try std.os.spawnThread(&shared_ctx, start2);
43 const thread4 = try std.os.spawnThread(&shared_ctx, start2);
44
45 thread1.wait();
46 thread2.wait();
47 thread3.wait();
48 thread4.wait();
49
50 assert(shared_ctx == 4);
51}
52
53fn start1(ctx: void) u8 {
54 return 0;
55}
56
57fn start2(ctx: *i32) u8 {
58 _ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
59 return 0;
60}
61
62test "cpu count" {
63 const cpu_count = try std.os.cpuCount(a);
64 assert(cpu_count >= 1);
65}
std/os/time.zig created+282
......@@ -0,0 +1,282 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const debug = std.debug;
5
6const windows = std.os.windows;
7const linux = std.os.linux;
8const darwin = std.os.darwin;
9const posix = std.os.posix;
10
11pub const epoch = @import("epoch.zig");
12
13/// Sleep for the specified duration
14pub fn sleep(seconds: usize, nanoseconds: usize) void {
15 switch (builtin.os) {
16 Os.linux, Os.macosx, Os.ios => {
17 posixSleep(@intCast(u63, seconds), @intCast(u63, nanoseconds));
18 },
19 Os.windows => {
20 const ns_per_ms = ns_per_s / ms_per_s;
21 const milliseconds = seconds * ms_per_s + nanoseconds / ns_per_ms;
22 windows.Sleep(@intCast(windows.DWORD, milliseconds));
23 },
24 else => @compileError("Unsupported OS"),
25 }
26}
27
28pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
29 var req = posix.timespec{
30 .tv_sec = seconds,
31 .tv_nsec = nanoseconds,
32 };
33 var rem: posix.timespec = undefined;
34 while (true) {
35 const ret_val = posix.nanosleep(&req, &rem);
36 const err = posix.getErrno(ret_val);
37 if (err == 0) return;
38 switch (err) {
39 posix.EFAULT => unreachable,
40 posix.EINVAL => {
41 // Sometimes Darwin returns EINVAL for no reason.
42 // We treat it as a spurious wakeup.
43 return;
44 },
45 posix.EINTR => {
46 req = rem;
47 continue;
48 },
49 else => return,
50 }
51 }
52}
53
54/// Get the posix timestamp, UTC, in seconds
55pub fn timestamp() u64 {
56 return @divFloor(milliTimestamp(), ms_per_s);
57}
58
59/// Get the posix timestamp, UTC, in milliseconds
60pub const milliTimestamp = switch (builtin.os) {
61 Os.windows => milliTimestampWindows,
62 Os.linux => milliTimestampPosix,
63 Os.macosx, Os.ios => milliTimestampDarwin,
64 else => @compileError("Unsupported OS"),
65};
66
67fn milliTimestampWindows() u64 {
68 //FileTime has a granularity of 100 nanoseconds
69 // and uses the NTFS/Windows epoch
70 var ft: windows.FILETIME = undefined;
71 windows.GetSystemTimeAsFileTime(&ft);
72 const hns_per_ms = (ns_per_s / 100) / ms_per_s;
73 const epoch_adj = epoch.windows * ms_per_s;
74
75 const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
76 return @divFloor(ft64, hns_per_ms) - -epoch_adj;
77}
78
79fn milliTimestampDarwin() u64 {
80 //Sources suggest MacOS 10.12 has support for
81 // posix clock_gettime.
82 var tv: darwin.timeval = undefined;
83 var err = darwin.gettimeofday(&tv, null);
84 debug.assert(err == 0);
85 const sec_ms = @intCast(u64, tv.tv_sec) * ms_per_s;
86 const usec_ms = @divFloor(@intCast(u64, tv.tv_usec), us_per_s / ms_per_s);
87 return u64(sec_ms) + u64(usec_ms);
88}
89
90fn milliTimestampPosix() u64 {
91 //From what I can tell there's no reason clock_gettime
92 // should ever fail for us with CLOCK_REALTIME,
93 // seccomp aside.
94 var ts: posix.timespec = undefined;
95 const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts);
96 debug.assert(err == 0);
97 const sec_ms = @intCast(u64, ts.tv_sec) * ms_per_s;
98 const nsec_ms = @divFloor(@intCast(u64, ts.tv_nsec), ns_per_s / ms_per_s);
99 return sec_ms + nsec_ms;
100}
101
102/// Divisions of a second
103pub const ns_per_s = 1000000000;
104pub const us_per_s = 1000000;
105pub const ms_per_s = 1000;
106pub const cs_per_s = 100;
107
108/// Common time divisions
109pub const s_per_min = 60;
110pub const s_per_hour = s_per_min * 60;
111pub const s_per_day = s_per_hour * 24;
112pub const s_per_week = s_per_day * 7;
113
114/// A monotonic high-performance timer.
115/// Timer.start() must be called to initialize the struct, which captures
116/// the counter frequency on windows and darwin, records the resolution,
117/// and gives the user an oportunity to check for the existnece of
118/// monotonic clocks without forcing them to check for error on each read.
119/// .resolution is in nanoseconds on all platforms but .start_time's meaning
120/// depends on the OS. On Windows and Darwin it is a hardware counter
121/// value that requires calculation to convert to a meaninful unit.
122pub const Timer = struct {
123
124 //if we used resolution's value when performing the
125 // performance counter calc on windows/darwin, it would
126 // be less precise
127 frequency: switch (builtin.os) {
128 Os.windows => u64,
129 Os.macosx, Os.ios => darwin.mach_timebase_info_data,
130 else => void,
131 },
132 resolution: u64,
133 start_time: u64,
134
135 //At some point we may change our minds on RAW, but for now we're
136 // sticking with posix standard MONOTONIC. For more information, see:
137 // https://github.com/ziglang/zig/pull/933
138 //
139 //const monotonic_clock_id = switch(builtin.os) {
140 // Os.linux => linux.CLOCK_MONOTONIC_RAW,
141 // else => posix.CLOCK_MONOTONIC,
142 //};
143 const monotonic_clock_id = posix.CLOCK_MONOTONIC;
144 /// Initialize the timer structure.
145 //This gives us an oportunity to grab the counter frequency in windows.
146 //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
147 //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
148 // supported, or if the timespec pointer is out of bounds, which should be
149 // impossible here barring cosmic rays or other such occurances of
150 // incredibly bad luck.
151 //On Darwin: This cannot fail, as far as I am able to tell.
152 const TimerError = error{
153 TimerUnsupported,
154 Unexpected,
155 };
156 pub fn start() TimerError!Timer {
157 var self: Timer = undefined;
158
159 switch (builtin.os) {
160 Os.windows => {
161 var freq: i64 = undefined;
162 var err = windows.QueryPerformanceFrequency(&freq);
163 if (err == windows.FALSE) return error.TimerUnsupported;
164 self.frequency = @intCast(u64, freq);
165 self.resolution = @divFloor(ns_per_s, self.frequency);
166
167 var start_time: i64 = undefined;
168 err = windows.QueryPerformanceCounter(&start_time);
169 debug.assert(err != windows.FALSE);
170 self.start_time = @intCast(u64, start_time);
171 },
172 Os.linux => {
173 //On Linux, seccomp can do arbitrary things to our ability to call
174 // syscalls, including return any errno value it wants and
175 // inconsistently throwing errors. Since we can't account for
176 // abuses of seccomp in a reasonable way, we'll assume that if
177 // seccomp is going to block us it will at least do so consistently
178 var ts: posix.timespec = undefined;
179 var result = posix.clock_getres(monotonic_clock_id, &ts);
180 var errno = posix.getErrno(result);
181 switch (errno) {
182 0 => {},
183 posix.EINVAL => return error.TimerUnsupported,
184 else => return std.os.unexpectedErrorPosix(errno),
185 }
186 self.resolution = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
187
188 result = posix.clock_gettime(monotonic_clock_id, &ts);
189 errno = posix.getErrno(result);
190 if (errno != 0) return std.os.unexpectedErrorPosix(errno);
191 self.start_time = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
192 },
193 Os.macosx, Os.ios => {
194 darwin.mach_timebase_info(&self.frequency);
195 self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
196 self.start_time = darwin.mach_absolute_time();
197 },
198 else => @compileError("Unsupported OS"),
199 }
200 return self;
201 }
202
203 /// Reads the timer value since start or the last reset in nanoseconds
204 pub fn read(self: *Timer) u64 {
205 var clock = clockNative() - self.start_time;
206 return switch (builtin.os) {
207 Os.windows => @divFloor(clock * ns_per_s, self.frequency),
208 Os.linux => clock,
209 Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
210 else => @compileError("Unsupported OS"),
211 };
212 }
213
214 /// Resets the timer value to 0/now.
215 pub fn reset(self: *Timer) void {
216 self.start_time = clockNative();
217 }
218
219 /// Returns the current value of the timer in nanoseconds, then resets it
220 pub fn lap(self: *Timer) u64 {
221 var now = clockNative();
222 var lap_time = self.read();
223 self.start_time = now;
224 return lap_time;
225 }
226
227 const clockNative = switch (builtin.os) {
228 Os.windows => clockWindows,
229 Os.linux => clockLinux,
230 Os.macosx, Os.ios => clockDarwin,
231 else => @compileError("Unsupported OS"),
232 };
233
234 fn clockWindows() u64 {
235 var result: i64 = undefined;
236 var err = windows.QueryPerformanceCounter(&result);
237 debug.assert(err != windows.FALSE);
238 return @intCast(u64, result);
239 }
240
241 fn clockDarwin() u64 {
242 return darwin.mach_absolute_time();
243 }
244
245 fn clockLinux() u64 {
246 var ts: posix.timespec = undefined;
247 var result = posix.clock_gettime(monotonic_clock_id, &ts);
248 debug.assert(posix.getErrno(result) == 0);
249 return @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
250 }
251};
252
253test "os.time.sleep" {
254 sleep(0, 1);
255}
256
257test "os.time.timestamp" {
258 const ns_per_ms = (ns_per_s / ms_per_s);
259 const margin = 50;
260
261 const time_0 = milliTimestamp();
262 sleep(0, ns_per_ms);
263 const time_1 = milliTimestamp();
264 const interval = time_1 - time_0;
265 debug.assert(interval > 0 and interval < margin);
266}
267
268test "os.time.Timer" {
269 const ns_per_ms = (ns_per_s / ms_per_s);
270 const margin = ns_per_ms * 150;
271
272 var timer = try Timer.start();
273 sleep(0, 10 * ns_per_ms);
274 const time_0 = timer.read();
275 debug.assert(time_0 > 0 and time_0 < margin);
276
277 const time_1 = timer.lap();
278 debug.assert(time_1 >= time_0);
279
280 timer.reset();
281 debug.assert(timer.read() < time_1);
282}
std/os/windows/advapi32.zig created+35
......@@ -0,0 +1,35 @@
1use @import("index.zig");
2
3pub const PROV_RSA_FULL = 1;
4
5pub const REGSAM = ACCESS_MASK;
6pub const ACCESS_MASK = DWORD;
7pub const PHKEY = &HKEY;
8pub const HKEY = &HKEY__;
9pub const HKEY__ = extern struct {
10 unused: c_int,
11};
12pub const LSTATUS = LONG;
13
14pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
15 phProv: *HCRYPTPROV,
16 pszContainer: ?LPCSTR,
17 pszProvider: ?LPCSTR,
18 dwProvType: DWORD,
19 dwFlags: DWORD,
20) BOOL;
21
22pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL;
23
24pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;
25
26pub extern "advapi32" stdcallcc fn RegOpenKeyExW(hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM,
27 phkResult: &HKEY,) LSTATUS;
28
29pub extern "advapi32" stdcallcc fn RegQueryValueExW(hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,
30 lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,) LSTATUS;
31
32// RtlGenRandom is known as SystemFunction036 under advapi32
33// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
34pub extern "advapi32" stdcallcc fn SystemFunction036(output: [*]u8, length: usize) BOOL;
35pub const RtlGenRandom = SystemFunction036;
std/os/windows/error.zig+1188
......@@ -1,2379 +1,3567 @@
11/// The operation completed successfully.
22pub const SUCCESS = 0;
3
34/// Incorrect function.
45pub const INVALID_FUNCTION = 1;
6
57/// The system cannot find the file specified.
68pub const FILE_NOT_FOUND = 2;
9
710/// The system cannot find the path specified.
811pub const PATH_NOT_FOUND = 3;
12
913/// The system cannot open the file.
1014pub const TOO_MANY_OPEN_FILES = 4;
15
1116/// Access is denied.
1217pub const ACCESS_DENIED = 5;
18
1319/// The handle is invalid.
1420pub const INVALID_HANDLE = 6;
21
1522/// The storage control blocks were destroyed.
1623pub const ARENA_TRASHED = 7;
24
1725/// Not enough storage is available to process this command.
1826pub const NOT_ENOUGH_MEMORY = 8;
27
1928/// The storage control block address is invalid.
2029pub const INVALID_BLOCK = 9;
30
2131/// The environment is incorrect.
2232pub const BAD_ENVIRONMENT = 10;
33
2334/// An attempt was made to load a program with an incorrect format.
2435pub const BAD_FORMAT = 11;
36
2537/// The access code is invalid.
2638pub const INVALID_ACCESS = 12;
39
2740/// The data is invalid.
2841pub const INVALID_DATA = 13;
42
2943/// Not enough storage is available to complete this operation.
3044pub const OUTOFMEMORY = 14;
45
3146/// The system cannot find the drive specified.
3247pub const INVALID_DRIVE = 15;
48
3349/// The directory cannot be removed.
3450pub const CURRENT_DIRECTORY = 16;
51
3552/// The system cannot move the file to a different disk drive.
3653pub const NOT_SAME_DEVICE = 17;
54
3755/// There are no more files.
3856pub const NO_MORE_FILES = 18;
57
3958/// The media is write protected.
4059pub const WRITE_PROTECT = 19;
60
4161/// The system cannot find the device specified.
4262pub const BAD_UNIT = 20;
63
4364/// The device is not ready.
4465pub const NOT_READY = 21;
66
4567/// The device does not recognize the command.
4668pub const BAD_COMMAND = 22;
69
4770/// Data error (cyclic redundancy check).
4871pub const CRC = 23;
72
4973/// The program issued a command but the command length is incorrect.
5074pub const BAD_LENGTH = 24;
75
5176/// The drive cannot locate a specific area or track on the disk.
5277pub const SEEK = 25;
78
5379/// The specified disk or diskette cannot be accessed.
5480pub const NOT_DOS_DISK = 26;
81
5582/// The drive cannot find the sector requested.
5683pub const SECTOR_NOT_FOUND = 27;
84
5785/// The printer is out of paper.
5886pub const OUT_OF_PAPER = 28;
87
5988/// The system cannot write to the specified device.
6089pub const WRITE_FAULT = 29;
90
6191/// The system cannot read from the specified device.
6292pub const READ_FAULT = 30;
93
6394/// A device attached to the system is not functioning.
6495pub const GEN_FAILURE = 31;
96
6597/// The process cannot access the file because it is being used by another process.
6698pub const SHARING_VIOLATION = 32;
99
67100/// The process cannot access the file because another process has locked a portion of the file.
68101pub const LOCK_VIOLATION = 33;
102
69103/// The wrong diskette is in the drive. Insert %2 (Volume Serial Number: %3) into drive %1.
70104pub const WRONG_DISK = 34;
105
71106/// Too many files opened for sharing.
72107pub const SHARING_BUFFER_EXCEEDED = 36;
108
73109/// Reached the end of the file.
74110pub const HANDLE_EOF = 38;
111
75112/// The disk is full.
76113pub const HANDLE_DISK_FULL = 39;
114
77115/// The request is not supported.
78116pub const NOT_SUPPORTED = 50;
117
79118/// Windows cannot find the network path. Verify that the network path is correct and the destination computer is not busy or turned off. If Windows still cannot find the network path, contact your network administrator.
80119pub const REM_NOT_LIST = 51;
120
81121/// You were not connected because a duplicate name exists on the network. If joining a domain, go to System in Control Panel to change the computer name and try again. If joining a workgroup, choose another workgroup name.
82122pub const DUP_NAME = 52;
123
83124/// The network path was not found.
84125pub const BAD_NETPATH = 53;
126
85127/// The network is busy.
86128pub const NETWORK_BUSY = 54;
129
87130/// The specified network resource or device is no longer available.
88131pub const DEV_NOT_EXIST = 55;
132
89133/// The network BIOS command limit has been reached.
90134pub const TOO_MANY_CMDS = 56;
135
91136/// A network adapter hardware error occurred.
92137pub const ADAP_HDW_ERR = 57;
138
93139/// The specified server cannot perform the requested operation.
94140pub const BAD_NET_RESP = 58;
141
95142/// An unexpected network error occurred.
96143pub const UNEXP_NET_ERR = 59;
144
97145/// The remote adapter is not compatible.
98146pub const BAD_REM_ADAP = 60;
147
99148/// The printer queue is full.
100149pub const PRINTQ_FULL = 61;
150
101151/// Space to store the file waiting to be printed is not available on the server.
102152pub const NO_SPOOL_SPACE = 62;
153
103154/// Your file waiting to be printed was deleted.
104155pub const PRINT_CANCELLED = 63;
156
105157/// The specified network name is no longer available.
106158pub const NETNAME_DELETED = 64;
159
107160/// Network access is denied.
108161pub const NETWORK_ACCESS_DENIED = 65;
162
109163/// The network resource type is not correct.
110164pub const BAD_DEV_TYPE = 66;
165
111166/// The network name cannot be found.
112167pub const BAD_NET_NAME = 67;
168
113169/// The name limit for the local computer network adapter card was exceeded.
114170pub const TOO_MANY_NAMES = 68;
171
115172/// The network BIOS session limit was exceeded.
116173pub const TOO_MANY_SESS = 69;
174
117175/// The remote server has been paused or is in the process of being started.
118176pub const SHARING_PAUSED = 70;
177
119178/// No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept.
120179pub const REQ_NOT_ACCEP = 71;
180
121181/// The specified printer or disk device has been paused.
122182pub const REDIR_PAUSED = 72;
183
123184/// The file exists.
124185pub const FILE_EXISTS = 80;
186
125187/// The directory or file cannot be created.
126188pub const CANNOT_MAKE = 82;
189
127190/// Fail on INT 24.
128191pub const FAIL_I24 = 83;
192
129193/// Storage to process this request is not available.
130194pub const OUT_OF_STRUCTURES = 84;
195
131196/// The local device name is already in use.
132197pub const ALREADY_ASSIGNED = 85;
198
133199/// The specified network password is not correct.
134200pub const INVALID_PASSWORD = 86;
201
135202/// The parameter is incorrect.
136203pub const INVALID_PARAMETER = 87;
204
137205/// A write fault occurred on the network.
138206pub const NET_WRITE_FAULT = 88;
207
139208/// The system cannot start another process at this time.
140209pub const NO_PROC_SLOTS = 89;
210
141211/// Cannot create another system semaphore.
142212pub const TOO_MANY_SEMAPHORES = 100;
213
143214/// The exclusive semaphore is owned by another process.
144215pub const EXCL_SEM_ALREADY_OWNED = 101;
216
145217/// The semaphore is set and cannot be closed.
146218pub const SEM_IS_SET = 102;
219
147220/// The semaphore cannot be set again.
148221pub const TOO_MANY_SEM_REQUESTS = 103;
222
149223/// Cannot request exclusive semaphores at interrupt time.
150224pub const INVALID_AT_INTERRUPT_TIME = 104;
225
151226/// The previous ownership of this semaphore has ended.
152227pub const SEM_OWNER_DIED = 105;
228
153229/// Insert the diskette for drive %1.
154230pub const SEM_USER_LIMIT = 106;
231
155232/// The program stopped because an alternate diskette was not inserted.
156233pub const DISK_CHANGE = 107;
234
157235/// The disk is in use or locked by another process.
158236pub const DRIVE_LOCKED = 108;
237
159238/// The pipe has been ended.
160239pub const BROKEN_PIPE = 109;
240
161241/// The system cannot open the device or file specified.
162242pub const OPEN_FAILED = 110;
243
163244/// The file name is too long.
164245pub const BUFFER_OVERFLOW = 111;
246
165247/// There is not enough space on the disk.
166248pub const DISK_FULL = 112;
249
167250/// No more internal file identifiers available.
168251pub const NO_MORE_SEARCH_HANDLES = 113;
252
169253/// The target internal file identifier is incorrect.
170254pub const INVALID_TARGET_HANDLE = 114;
255
171256/// The IOCTL call made by the application program is not correct.
172257pub const INVALID_CATEGORY = 117;
258
173259/// The verify-on-write switch parameter value is not correct.
174260pub const INVALID_VERIFY_SWITCH = 118;
261
175262/// The system does not support the command requested.
176263pub const BAD_DRIVER_LEVEL = 119;
264
177265/// This function is not supported on this system.
178266pub const CALL_NOT_IMPLEMENTED = 120;
267
179268/// The semaphore timeout period has expired.
180269pub const SEM_TIMEOUT = 121;
270
181271/// The data area passed to a system call is too small.
182272pub const INSUFFICIENT_BUFFER = 122;
273
183274/// The filename, directory name, or volume label syntax is incorrect.
184275pub const INVALID_NAME = 123;
276
185277/// The system call level is not correct.
186278pub const INVALID_LEVEL = 124;
279
187280/// The disk has no volume label.
188281pub const NO_VOLUME_LABEL = 125;
282
189283/// The specified module could not be found.
190284pub const MOD_NOT_FOUND = 126;
285
191286/// The specified procedure could not be found.
192287pub const PROC_NOT_FOUND = 127;
288
193289/// There are no child processes to wait for.
194290pub const WAIT_NO_CHILDREN = 128;
291
195292/// The %1 application cannot be run in Win32 mode.
196293pub const CHILD_NOT_COMPLETE = 129;
294
197295/// Attempt to use a file handle to an open disk partition for an operation other than raw disk I/O.
198296pub const DIRECT_ACCESS_HANDLE = 130;
297
199298/// An attempt was made to move the file pointer before the beginning of the file.
200299pub const NEGATIVE_SEEK = 131;
300
201301/// The file pointer cannot be set on the specified device or file.
202302pub const SEEK_ON_DEVICE = 132;
303
203304/// A JOIN or SUBST command cannot be used for a drive that contains previously joined drives.
204305pub const IS_JOIN_TARGET = 133;
306
205307/// An attempt was made to use a JOIN or SUBST command on a drive that has already been joined.
206308pub const IS_JOINED = 134;
309
207310/// An attempt was made to use a JOIN or SUBST command on a drive that has already been substituted.
208311pub const IS_SUBSTED = 135;
312
209313/// The system tried to delete the JOIN of a drive that is not joined.
210314pub const NOT_JOINED = 136;
315
211316/// The system tried to delete the substitution of a drive that is not substituted.
212317pub const NOT_SUBSTED = 137;
318
213319/// The system tried to join a drive to a directory on a joined drive.
214320pub const JOIN_TO_JOIN = 138;
321
215322/// The system tried to substitute a drive to a directory on a substituted drive.
216323pub const SUBST_TO_SUBST = 139;
324
217325/// The system tried to join a drive to a directory on a substituted drive.
218326pub const JOIN_TO_SUBST = 140;
327
219328/// The system tried to SUBST a drive to a directory on a joined drive.
220329pub const SUBST_TO_JOIN = 141;
330
221331/// The system cannot perform a JOIN or SUBST at this time.
222332pub const BUSY_DRIVE = 142;
333
223334/// The system cannot join or substitute a drive to or for a directory on the same drive.
224335pub const SAME_DRIVE = 143;
336
225337/// The directory is not a subdirectory of the root directory.
226338pub const DIR_NOT_ROOT = 144;
339
227340/// The directory is not empty.
228341pub const DIR_NOT_EMPTY = 145;
342
229343/// The path specified is being used in a substitute.
230344pub const IS_SUBST_PATH = 146;
345
231346/// Not enough resources are available to process this command.
232347pub const IS_JOIN_PATH = 147;
348
233349/// The path specified cannot be used at this time.
234350pub const PATH_BUSY = 148;
351
235352/// An attempt was made to join or substitute a drive for which a directory on the drive is the target of a previous substitute.
236353pub const IS_SUBST_TARGET = 149;
354
237355/// System trace information was not specified in your CONFIG.SYS file, or tracing is disallowed.
238356pub const SYSTEM_TRACE = 150;
357
239358/// The number of specified semaphore events for DosMuxSemWait is not correct.
240359pub const INVALID_EVENT_COUNT = 151;
360
241361/// DosMuxSemWait did not execute; too many semaphores are already set.
242362pub const TOO_MANY_MUXWAITERS = 152;
363
243364/// The DosMuxSemWait list is not correct.
244365pub const INVALID_LIST_FORMAT = 153;
366
245367/// The volume label you entered exceeds the label character limit of the target file system.
246368pub const LABEL_TOO_LONG = 154;
369
247370/// Cannot create another thread.
248371pub const TOO_MANY_TCBS = 155;
372
249373/// The recipient process has refused the signal.
250374pub const SIGNAL_REFUSED = 156;
375
251376/// The segment is already discarded and cannot be locked.
252377pub const DISCARDED = 157;
378
253379/// The segment is already unlocked.
254380pub const NOT_LOCKED = 158;
381
255382/// The address for the thread ID is not correct.
256383pub const BAD_THREADID_ADDR = 159;
384
257385/// One or more arguments are not correct.
258386pub const BAD_ARGUMENTS = 160;
387
259388/// The specified path is invalid.
260389pub const BAD_PATHNAME = 161;
390
261391/// A signal is already pending.
262392pub const SIGNAL_PENDING = 162;
393
263394/// No more threads can be created in the system.
264395pub const MAX_THRDS_REACHED = 164;
396
265397/// Unable to lock a region of a file.
266398pub const LOCK_FAILED = 167;
399
267400/// The requested resource is in use.
268401pub const BUSY = 170;
402
269403/// Device's command support detection is in progress.
270404pub const DEVICE_SUPPORT_IN_PROGRESS = 171;
405
271406/// A lock request was not outstanding for the supplied cancel region.
272407pub const CANCEL_VIOLATION = 173;
408
273409/// The file system does not support atomic changes to the lock type.
274410pub const ATOMIC_LOCKS_NOT_SUPPORTED = 174;
411
275412/// The system detected a segment number that was not correct.
276413pub const INVALID_SEGMENT_NUMBER = 180;
414
277415/// The operating system cannot run %1.
278416pub const INVALID_ORDINAL = 182;
417
279418/// Cannot create a file when that file already exists.
280419pub const ALREADY_EXISTS = 183;
420
281421/// The flag passed is not correct.
282422pub const INVALID_FLAG_NUMBER = 186;
423
283424/// The specified system semaphore name was not found.
284425pub const SEM_NOT_FOUND = 187;
426
285427/// The operating system cannot run %1.
286428pub const INVALID_STARTING_CODESEG = 188;
429
287430/// The operating system cannot run %1.
288431pub const INVALID_STACKSEG = 189;
432
289433/// The operating system cannot run %1.
290434pub const INVALID_MODULETYPE = 190;
435
291436/// Cannot run %1 in Win32 mode.
292437pub const INVALID_EXE_SIGNATURE = 191;
438
293439/// The operating system cannot run %1.
294440pub const EXE_MARKED_INVALID = 192;
441
295442/// %1 is not a valid Win32 application.
296443pub const BAD_EXE_FORMAT = 193;
444
297445/// The operating system cannot run %1.
298446pub const ITERATED_DATA_EXCEEDS_64k = 194;
447
299448/// The operating system cannot run %1.
300449pub const INVALID_MINALLOCSIZE = 195;
450
301451/// The operating system cannot run this application program.
302452pub const DYNLINK_FROM_INVALID_RING = 196;
453
303454/// The operating system is not presently configured to run this application.
304455pub const IOPL_NOT_ENABLED = 197;
456
305457/// The operating system cannot run %1.
306458pub const INVALID_SEGDPL = 198;
459
307460/// The operating system cannot run this application program.
308461pub const AUTODATASEG_EXCEEDS_64k = 199;
462
309463/// The code segment cannot be greater than or equal to 64K.
310464pub const RING2SEG_MUST_BE_MOVABLE = 200;
465
311466/// The operating system cannot run %1.
312467pub const RELOC_CHAIN_XEEDS_SEGLIM = 201;
468
313469/// The operating system cannot run %1.
314470pub const INFLOOP_IN_RELOC_CHAIN = 202;
471
315472/// The system could not find the environment option that was entered.
316473pub const ENVVAR_NOT_FOUND = 203;
474
317475/// No process in the command subtree has a signal handler.
318476pub const NO_SIGNAL_SENT = 205;
477
319478/// The filename or extension is too long.
320479pub const FILENAME_EXCED_RANGE = 206;
480
321481/// The ring 2 stack is in use.
322482pub const RING2_STACK_IN_USE = 207;
483
323484/// The global filename characters, * or ?, are entered incorrectly or too many global filename characters are specified.
324485pub const META_EXPANSION_TOO_LONG = 208;
486
325487/// The signal being posted is not correct.
326488pub const INVALID_SIGNAL_NUMBER = 209;
489
327490/// The signal handler cannot be set.
328491pub const THREAD_1_INACTIVE = 210;
492
329493/// The segment is locked and cannot be reallocated.
330494pub const LOCKED = 212;
495
331496/// Too many dynamic-link modules are attached to this program or dynamic-link module.
332497pub const TOO_MANY_MODULES = 214;
498
333499/// Cannot nest calls to LoadModule.
334500pub const NESTING_NOT_ALLOWED = 215;
501
335502/// This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher.
336503pub const EXE_MACHINE_TYPE_MISMATCH = 216;
504
337505/// The image file %1 is signed, unable to modify.
338506pub const EXE_CANNOT_MODIFY_SIGNED_BINARY = 217;
507
339508/// The image file %1 is strong signed, unable to modify.
340509pub const EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY = 218;
510
341511/// This file is checked out or locked for editing by another user.
342512pub const FILE_CHECKED_OUT = 220;
513
343514/// The file must be checked out before saving changes.
344515pub const CHECKOUT_REQUIRED = 221;
516
345517/// The file type being saved or retrieved has been blocked.
346518pub const BAD_FILE_TYPE = 222;
519
347520/// The file size exceeds the limit allowed and cannot be saved.
348521pub const FILE_TOO_LARGE = 223;
522
349523/// Access Denied. Before opening files in this location, you must first add the web site to your trusted sites list, browse to the web site, and select the option to login automatically.
350524pub const FORMS_AUTH_REQUIRED = 224;
525
351526/// Operation did not complete successfully because the file contains a virus or potentially unwanted software.
352527pub const VIRUS_INFECTED = 225;
528
353529/// This file contains a virus or potentially unwanted software and cannot be opened. Due to the nature of this virus or potentially unwanted software, the file has been removed from this location.
354530pub const VIRUS_DELETED = 226;
531
355532/// The pipe is local.
356533pub const PIPE_LOCAL = 229;
534
357535/// The pipe state is invalid.
358536pub const BAD_PIPE = 230;
537
359538/// All pipe instances are busy.
360539pub const PIPE_BUSY = 231;
540
361541/// The pipe is being closed.
362542pub const NO_DATA = 232;
543
363544/// No process is on the other end of the pipe.
364545pub const PIPE_NOT_CONNECTED = 233;
546
365547/// More data is available.
366548pub const MORE_DATA = 234;
549
367550/// The session was canceled.
368551pub const VC_DISCONNECTED = 240;
552
369553/// The specified extended attribute name was invalid.
370554pub const INVALID_EA_NAME = 254;
555
371556/// The extended attributes are inconsistent.
372557pub const EA_LIST_INCONSISTENT = 255;
558
373559/// The wait operation timed out.
374560pub const IMEOUT = 258;
561
375562/// No more data is available.
376563pub const NO_MORE_ITEMS = 259;
564
377565/// The copy functions cannot be used.
378566pub const CANNOT_COPY = 266;
567
379568/// The directory name is invalid.
380569pub const DIRECTORY = 267;
570
381571/// The extended attributes did not fit in the buffer.
382572pub const EAS_DIDNT_FIT = 275;
573
383574/// The extended attribute file on the mounted file system is corrupt.
384575pub const EA_FILE_CORRUPT = 276;
576
385577/// The extended attribute table file is full.
386578pub const EA_TABLE_FULL = 277;
579
387580/// The specified extended attribute handle is invalid.
388581pub const INVALID_EA_HANDLE = 278;
582
389583/// The mounted file system does not support extended attributes.
390584pub const EAS_NOT_SUPPORTED = 282;
585
391586/// Attempt to release mutex not owned by caller.
392587pub const NOT_OWNER = 288;
588
393589/// Too many posts were made to a semaphore.
394590pub const TOO_MANY_POSTS = 298;
591
395592/// Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
396593pub const PARTIAL_COPY = 299;
594
397595/// The oplock request is denied.
398596pub const OPLOCK_NOT_GRANTED = 300;
597
399598/// An invalid oplock acknowledgment was received by the system.
400599pub const INVALID_OPLOCK_PROTOCOL = 301;
600
401601/// The volume is too fragmented to complete this operation.
402602pub const DISK_TOO_FRAGMENTED = 302;
603
403604/// The file cannot be opened because it is in the process of being deleted.
404605pub const DELETE_PENDING = 303;
606
405607/// Short name settings may not be changed on this volume due to the global registry setting.
406608pub const INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 304;
609
407610/// Short names are not enabled on this volume.
408611pub const SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 305;
612
409613/// The security stream for the given volume is in an inconsistent state. Please run CHKDSK on the volume.
410614pub const SECURITY_STREAM_IS_INCONSISTENT = 306;
615
411616/// A requested file lock operation cannot be processed due to an invalid byte range.
412617pub const INVALID_LOCK_RANGE = 307;
618
413619/// The subsystem needed to support the image type is not present.
414620pub const IMAGE_SUBSYSTEM_NOT_PRESENT = 308;
621
415622/// The specified file already has a notification GUID associated with it.
416623pub const NOTIFICATION_GUID_ALREADY_DEFINED = 309;
624
417625/// An invalid exception handler routine has been detected.
418626pub const INVALID_EXCEPTION_HANDLER = 310;
627
419628/// Duplicate privileges were specified for the token.
420629pub const DUPLICATE_PRIVILEGES = 311;
630
421631/// No ranges for the specified operation were able to be processed.
422632pub const NO_RANGES_PROCESSED = 312;
633
423634/// Operation is not allowed on a file system internal file.
424635pub const NOT_ALLOWED_ON_SYSTEM_FILE = 313;
636
425637/// The physical resources of this disk have been exhausted.
426638pub const DISK_RESOURCES_EXHAUSTED = 314;
639
427640/// The token representing the data is invalid.
428641pub const INVALID_TOKEN = 315;
642
429643/// The device does not support the command feature.
430644pub const DEVICE_FEATURE_NOT_SUPPORTED = 316;
645
431646/// The system cannot find message text for message number 0x%1 in the message file for %2.
432647pub const MR_MID_NOT_FOUND = 317;
648
433649/// The scope specified was not found.
434650pub const SCOPE_NOT_FOUND = 318;
651
435652/// The Central Access Policy specified is not defined on the target machine.
436653pub const UNDEFINED_SCOPE = 319;
654
437655/// The Central Access Policy obtained from Active Directory is invalid.
438656pub const INVALID_CAP = 320;
657
439658/// The device is unreachable.
440659pub const DEVICE_UNREACHABLE = 321;
660
441661/// The target device has insufficient resources to complete the operation.
442662pub const DEVICE_NO_RESOURCES = 322;
663
443664/// A data integrity checksum error occurred. Data in the file stream is corrupt.
444665pub const DATA_CHECKSUM_ERROR = 323;
666
445667/// An attempt was made to modify both a KERNEL and normal Extended Attribute (EA) in the same operation.
446668pub const INTERMIXED_KERNEL_EA_OPERATION = 324;
669
447670/// Device does not support file-level TRIM.
448671pub const FILE_LEVEL_TRIM_NOT_SUPPORTED = 326;
672
449673/// The command specified a data offset that does not align to the device's granularity/alignment.
450674pub const OFFSET_ALIGNMENT_VIOLATION = 327;
675
451676/// The command specified an invalid field in its parameter list.
452677pub const INVALID_FIELD_IN_PARAMETER_LIST = 328;
678
453679/// An operation is currently in progress with the device.
454680pub const OPERATION_IN_PROGRESS = 329;
681
455682/// An attempt was made to send down the command via an invalid path to the target device.
456683pub const BAD_DEVICE_PATH = 330;
684
457685/// The command specified a number of descriptors that exceeded the maximum supported by the device.
458686pub const TOO_MANY_DESCRIPTORS = 331;
687
459688/// Scrub is disabled on the specified file.
460689pub const SCRUB_DATA_DISABLED = 332;
690
461691/// The storage device does not provide redundancy.
462692pub const NOT_REDUNDANT_STORAGE = 333;
693
463694/// An operation is not supported on a resident file.
464695pub const RESIDENT_FILE_NOT_SUPPORTED = 334;
696
465697/// An operation is not supported on a compressed file.
466698pub const COMPRESSED_FILE_NOT_SUPPORTED = 335;
699
467700/// An operation is not supported on a directory.
468701pub const DIRECTORY_NOT_SUPPORTED = 336;
702
469703/// The specified copy of the requested data could not be read.
470704pub const NOT_READ_FROM_COPY = 337;
705
471706/// No action was taken as a system reboot is required.
472707pub const FAIL_NOACTION_REBOOT = 350;
708
473709/// The shutdown operation failed.
474710pub const FAIL_SHUTDOWN = 351;
711
475712/// The restart operation failed.
476713pub const FAIL_RESTART = 352;
714
477715/// The maximum number of sessions has been reached.
478716pub const MAX_SESSIONS_REACHED = 353;
717
479718/// The thread is already in background processing mode.
480719pub const THREAD_MODE_ALREADY_BACKGROUND = 400;
720
481721/// The thread is not in background processing mode.
482722pub const THREAD_MODE_NOT_BACKGROUND = 401;
723
483724/// The process is already in background processing mode.
484725pub const PROCESS_MODE_ALREADY_BACKGROUND = 402;
726
485727/// The process is not in background processing mode.
486728pub const PROCESS_MODE_NOT_BACKGROUND = 403;
729
487730/// Attempt to access invalid address.
488731pub const INVALID_ADDRESS = 487;
732
489733/// User profile cannot be loaded.
490734pub const USER_PROFILE_LOAD = 500;
735
491736/// Arithmetic result exceeded 32 bits.
492737pub const ARITHMETIC_OVERFLOW = 534;
738
493739/// There is a process on other end of the pipe.
494740pub const PIPE_CONNECTED = 535;
741
495742/// Waiting for a process to open the other end of the pipe.
496743pub const PIPE_LISTENING = 536;
744
497745/// Application verifier has found an error in the current process.
498746pub const VERIFIER_STOP = 537;
747
499748/// An error occurred in the ABIOS subsystem.
500749pub const ABIOS_ERROR = 538;
750
501751/// A warning occurred in the WX86 subsystem.
502752pub const WX86_WARNING = 539;
753
503754/// An error occurred in the WX86 subsystem.
504755pub const WX86_ERROR = 540;
756
505757/// An attempt was made to cancel or set a timer that has an associated APC and the subject thread is not the thread that originally set the timer with an associated APC routine.
506758pub const TIMER_NOT_CANCELED = 541;
759
507760/// Unwind exception code.
508761pub const UNWIND = 542;
762
509763/// An invalid or unaligned stack was encountered during an unwind operation.
510764pub const BAD_STACK = 543;
765
511766/// An invalid unwind target was encountered during an unwind operation.
512767pub const INVALID_UNWIND_TARGET = 544;
768
513769/// Invalid Object Attributes specified to NtCreatePort or invalid Port Attributes specified to NtConnectPort
514770pub const INVALID_PORT_ATTRIBUTES = 545;
771
515772/// Length of message passed to NtRequestPort or NtRequestWaitReplyPort was longer than the maximum message allowed by the port.
516773pub const PORT_MESSAGE_TOO_LONG = 546;
774
517775/// An attempt was made to lower a quota limit below the current usage.
518776pub const INVALID_QUOTA_LOWER = 547;
777
519778/// An attempt was made to attach to a device that was already attached to another device.
520779pub const DEVICE_ALREADY_ATTACHED = 548;
780
521781/// An attempt was made to execute an instruction at an unaligned address and the host system does not support unaligned instruction references.
522782pub const INSTRUCTION_MISALIGNMENT = 549;
783
523784/// Profiling not started.
524785pub const PROFILING_NOT_STARTED = 550;
786
525787/// Profiling not stopped.
526788pub const PROFILING_NOT_STOPPED = 551;
789
527790/// The passed ACL did not contain the minimum required information.
528791pub const COULD_NOT_INTERPRET = 552;
792
529793/// The number of active profiling objects is at the maximum and no more may be started.
530794pub const PROFILING_AT_LIMIT = 553;
795
531796/// Used to indicate that an operation cannot continue without blocking for I/O.
532797pub const CANT_WAIT = 554;
798
533799/// Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process.
534800pub const CANT_TERMINATE_SELF = 555;
801
535802/// If an MM error is returned which is not defined in the standard FsRtl filter, it is converted to one of the following errors which is guaranteed to be in the filter. In this case information is lost, however, the filter correctly handles the exception.
536803pub const UNEXPECTED_MM_CREATE_ERR = 556;
804
537805/// If an MM error is returned which is not defined in the standard FsRtl filter, it is converted to one of the following errors which is guaranteed to be in the filter. In this case information is lost, however, the filter correctly handles the exception.
538806pub const UNEXPECTED_MM_MAP_ERROR = 557;
807
539808/// If an MM error is returned which is not defined in the standard FsRtl filter, it is converted to one of the following errors which is guaranteed to be in the filter. In this case information is lost, however, the filter correctly handles the exception.
540809pub const UNEXPECTED_MM_EXTEND_ERR = 558;
810
541811/// A malformed function table was encountered during an unwind operation.
542812pub const BAD_FUNCTION_TABLE = 559;
813
543814/// Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. This causes the protection attempt to fail, which may cause a file creation attempt to fail.
544815pub const NO_GUID_TRANSLATION = 560;
816
545817/// Indicates that an attempt was made to grow an LDT by setting its size, or that the size was not an even number of selectors.
546818pub const INVALID_LDT_SIZE = 561;
819
547820/// Indicates that the starting value for the LDT information was not an integral multiple of the selector size.
548821pub const INVALID_LDT_OFFSET = 563;
822
549823/// Indicates that the user supplied an invalid descriptor when trying to set up Ldt descriptors.
550824pub const INVALID_LDT_DESCRIPTOR = 564;
825
551826/// Indicates a process has too many threads to perform the requested action. For example, assignment of a primary token may only be performed when a process has zero or one threads.
552827pub const TOO_MANY_THREADS = 565;
828
553829/// An attempt was made to operate on a thread within a specific process, but the thread specified is not in the process specified.
554830pub const THREAD_NOT_IN_PROCESS = 566;
831
555832/// Page file quota was exceeded.
556833pub const PAGEFILE_QUOTA_EXCEEDED = 567;
834
557835/// The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role.
558836pub const LOGON_SERVER_CONFLICT = 568;
837
559838/// The SAM database on a Windows Server is significantly out of synchronization with the copy on the Domain Controller. A complete synchronization is required.
560839pub const SYNCHRONIZATION_REQUIRED = 569;
840
561841/// The NtCreateFile API failed. This error should never be returned to an application, it is a place holder for the Windows Lan Manager Redirector to use in its internal error mapping routines.
562842pub const NET_OPEN_FAILED = 570;
843
563844/// {Privilege Failed} The I/O permissions for the process could not be changed.
564845pub const IO_PRIVILEGE_FAILED = 571;
846
565847/// {Application Exit by CTRL+C} The application terminated as a result of a CTRL+C.
566848pub const CONTROL_C_EXIT = 572;
849
567850/// {Missing System File} The required system file %hs is bad or missing.
568851pub const MISSING_SYSTEMFILE = 573;
852
569853/// {Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx.
570854pub const UNHANDLED_EXCEPTION = 574;
855
571856/// {Application Error} The application was unable to start correctly (0x%lx). Click OK to close the application.
572857pub const APP_INIT_FAILURE = 575;
858
573859/// {Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld.
574860pub const PAGEFILE_CREATE_FAILED = 576;
861
575862/// Windows cannot verify the digital signature for this file. A recent hardware or software change might have installed a file that is signed incorrectly or damaged, or that might be malicious software from an unknown source.
576863pub const INVALID_IMAGE_HASH = 577;
864
577865/// {No Paging File Specified} No paging file was specified in the system configuration.
578866pub const NO_PAGEFILE = 578;
867
579868/// {EXCEPTION} A real-mode application issued a floating-point instruction and floating-point hardware is not present.
580869pub const ILLEGAL_FLOAT_CONTEXT = 579;
870
581871/// An event pair synchronization operation was performed using the thread specific client/server event pair object, but no event pair object was associated with the thread.
582872pub const NO_EVENT_PAIR = 580;
873
583874/// A Windows Server has an incorrect configuration.
584875pub const DOMAIN_CTRLR_CONFIG_ERROR = 581;
876
585877/// An illegal character was encountered. For a multi-byte character set this includes a lead byte without a succeeding trail byte. For the Unicode character set this includes the characters 0xFFFF and 0xFFFE.
586878pub const ILLEGAL_CHARACTER = 582;
879
587880/// The Unicode character is not defined in the Unicode character set installed on the system.
588881pub const UNDEFINED_CHARACTER = 583;
882
589883/// The paging file cannot be created on a floppy diskette.
590884pub const FLOPPY_VOLUME = 584;
885
591886/// The system BIOS failed to connect a system interrupt to the device or bus for which the device is connected.
592887pub const BIOS_FAILED_TO_CONNECT_INTERRUPT = 585;
888
593889/// This operation is only allowed for the Primary Domain Controller of the domain.
594890pub const BACKUP_CONTROLLER = 586;
891
595892/// An attempt was made to acquire a mutant such that its maximum count would have been exceeded.
596893pub const MUTANT_LIMIT_EXCEEDED = 587;
894
597895/// A volume has been accessed for which a file system driver is required that has not yet been loaded.
598896pub const FS_DRIVER_REQUIRED = 588;
897
599898/// {Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable.
600899pub const CANNOT_LOAD_REGISTRY_FILE = 589;
900
601901/// {Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. You may choose OK to terminate the process, or Cancel to ignore the error.
602902pub const DEBUG_ATTACH_FAILED = 590;
903
603904/// {Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
604905pub const SYSTEM_PROCESS_TERMINATED = 591;
906
605907/// {Data Not Accepted} The TDI client could not handle the data received during an indication.
606908pub const DATA_NOT_ACCEPTED = 592;
909
607910/// NTVDM encountered a hard error.
608911pub const VDM_HARD_ERROR = 593;
912
609913/// {Cancel Timeout} The driver %hs failed to complete a cancelled I/O request in the allotted time.
610914pub const DRIVER_CANCEL_TIMEOUT = 594;
915
611916/// {Reply Message Mismatch} An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message.
612917pub const REPLY_MESSAGE_MISMATCH = 595;
918
613919/// {Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. This error may be caused by a failure of your computer hardware or network connection. Please try to save this file elsewhere.
614920pub const LOST_WRITEBEHIND_DATA = 596;
921
615922/// The parameter(s) passed to the server in the client/server shared memory window were invalid. Too much data may have been put in the shared memory window.
616923pub const CLIENT_SERVER_PARAMETERS_INVALID = 597;
924
617925/// The stream is not a tiny stream.
618926pub const NOT_TINY_STREAM = 598;
927
619928/// The request must be handled by the stack overflow code.
620929pub const STACK_OVERFLOW_READ = 599;
930
621931/// Internal OFS status codes indicating how an allocation operation is handled. Either it is retried after the containing onode is moved or the extent stream is converted to a large stream.
622932pub const CONVERT_TO_LARGE = 600;
933
623934/// The attempt to find the object found an object matching by ID on the volume but it is out of the scope of the handle used for the operation.
624935pub const FOUND_OUT_OF_SCOPE = 601;
936
625937/// The bucket array must be grown. Retry transaction after doing so.
626938pub const ALLOCATE_BUCKET = 602;
939
627940/// The user/kernel marshalling buffer has overflowed.
628941pub const MARSHALL_OVERFLOW = 603;
942
629943/// The supplied variant structure contains invalid data.
630944pub const INVALID_VARIANT = 604;
945
631946/// The specified buffer contains ill-formed data.
632947pub const BAD_COMPRESSION_BUFFER = 605;
948
633949/// {Audit Failed} An attempt to generate a security audit failed.
634950pub const AUDIT_FAILED = 606;
951
635952/// The timer resolution was not previously set by the current process.
636953pub const TIMER_RESOLUTION_NOT_SET = 607;
954
637955/// There is insufficient account information to log you on.
638956pub const INSUFFICIENT_LOGON_INFO = 608;
957
639958/// {Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. The stack pointer has been left in an inconsistent state. The entrypoint should be declared as WINAPI or STDCALL. Select YES to fail the DLL load. Select NO to continue execution. Selecting NO may cause the application to operate incorrectly.
640959pub const BAD_DLL_ENTRYPOINT = 609;
960
641961/// {Invalid Service Callback Entrypoint} The %hs service is not written correctly. The stack pointer has been left in an inconsistent state. The callback entrypoint should be declared as WINAPI or STDCALL. Selecting OK will cause the service to continue operation. However, the service process may operate incorrectly.
642962pub const BAD_SERVICE_ENTRYPOINT = 610;
963
643964/// There is an IP address conflict with another system on the network.
644965pub const IP_ADDRESS_CONFLICT1 = 611;
966
645967/// There is an IP address conflict with another system on the network.
646968pub const IP_ADDRESS_CONFLICT2 = 612;
969
647970/// {Low On Registry Space} The system has reached the maximum size allowed for the system part of the registry. Additional storage requests will be ignored.
648971pub const REGISTRY_QUOTA_LIMIT = 613;
972
649973/// A callback return system service cannot be executed when no callback is active.
650974pub const NO_CALLBACK_ACTIVE = 614;
975
651976/// The password provided is too short to meet the policy of your user account. Please choose a longer password.
652977pub const PWD_TOO_SHORT = 615;
978
653979/// The policy of your user account does not allow you to change passwords too frequently. This is done to prevent users from changing back to a familiar, but potentially discovered, password. If you feel your password has been compromised then please contact your administrator immediately to have a new one assigned.
654980pub const PWD_TOO_RECENT = 616;
981
655982/// You have attempted to change your password to one that you have used in the past. The policy of your user account does not allow this. Please select a password that you have not previously used.
656983pub const PWD_HISTORY_CONFLICT = 617;
984
657985/// The specified compression format is unsupported.
658986pub const UNSUPPORTED_COMPRESSION = 618;
987
659988/// The specified hardware profile configuration is invalid.
660989pub const INVALID_HW_PROFILE = 619;
990
661991/// The specified Plug and Play registry device path is invalid.
662992pub const INVALID_PLUGPLAY_DEVICE_PATH = 620;
993
663994/// The specified quota list is internally inconsistent with its descriptor.
664995pub const QUOTA_LIST_INCONSISTENT = 621;
996
665997/// {Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shutdown in 1 hour. To restore access to this installation of Windows, please upgrade this installation using a licensed distribution of this product.
666998pub const EVALUATION_EXPIRATION = 622;
999
6671000/// {Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. The relocation occurred because the DLL %hs occupied an address range reserved for Windows system DLLs. The vendor supplying the DLL should be contacted for a new DLL.
6681001pub const ILLEGAL_DLL_RELOCATION = 623;
1002
6691003/// {DLL Initialization Failed} The application failed to initialize because the window station is shutting down.
6701004pub const DLL_INIT_FAILED_LOGOFF = 624;
1005
6711006/// The validation process needs to continue on to the next step.
6721007pub const VALIDATE_CONTINUE = 625;
1008
6731009/// There are no more matches for the current index enumeration.
6741010pub const NO_MORE_MATCHES = 626;
1011
6751012/// The range could not be added to the range list because of a conflict.
6761013pub const RANGE_LIST_CONFLICT = 627;
1014
6771015/// The server process is running under a SID different than that required by client.
6781016pub const SERVER_SID_MISMATCH = 628;
1017
6791018/// A group marked use for deny only cannot be enabled.
6801019pub const CANT_ENABLE_DENY_ONLY = 629;
1020
6811021/// {EXCEPTION} Multiple floating point faults.
6821022pub const FLOAT_MULTIPLE_FAULTS = 630;
1023
6831024/// {EXCEPTION} Multiple floating point traps.
6841025pub const FLOAT_MULTIPLE_TRAPS = 631;
1026
6851027/// The requested interface is not supported.
6861028pub const NOINTERFACE = 632;
1029
6871030/// {System Standby Failed} The driver %hs does not support standby mode. Updating this driver may allow the system to go to standby mode.
6881031pub const DRIVER_FAILED_SLEEP = 633;
1032
6891033/// The system file %1 has become corrupt and has been replaced.
6901034pub const CORRUPT_SYSTEM_FILE = 634;
1035
6911036/// {Virtual Memory Minimum Too Low} Your system is low on virtual memory. Windows is increasing the size of your virtual memory paging file. During this process, memory requests for some applications may be denied. For more information, see Help.
6921037pub const COMMITMENT_MINIMUM = 635;
1038
6931039/// A device was removed so enumeration must be restarted.
6941040pub const PNP_RESTART_ENUMERATION = 636;
1041
6951042/// {Fatal System Error} The system image %s is not properly signed. The file has been replaced with the signed file. The system has been shut down.
6961043pub const SYSTEM_IMAGE_BAD_SIGNATURE = 637;
1044
6971045/// Device will not start without a reboot.
6981046pub const PNP_REBOOT_REQUIRED = 638;
1047
6991048/// There is not enough power to complete the requested operation.
7001049pub const INSUFFICIENT_POWER = 639;
1050
7011051/// ERROR_MULTIPLE_FAULT_VIOLATION
7021052pub const MULTIPLE_FAULT_VIOLATION = 640;
1053
7031054/// The system is in the process of shutting down.
7041055pub const SYSTEM_SHUTDOWN = 641;
1056
7051057/// An attempt to remove a processes DebugPort was made, but a port was not already associated with the process.
7061058pub const PORT_NOT_SET = 642;
1059
7071060/// This version of Windows is not compatible with the behavior version of directory forest, domain or domain controller.
7081061pub const DS_VERSION_CHECK_FAILURE = 643;
1062
7091063/// The specified range could not be found in the range list.
7101064pub const RANGE_NOT_FOUND = 644;
1065
7111066/// The driver was not loaded because the system is booting into safe mode.
7121067pub const NOT_SAFE_MODE_DRIVER = 646;
1068
7131069/// The driver was not loaded because it failed its initialization call.
7141070pub const FAILED_DRIVER_ENTRY = 647;
1071
7151072/// The "%hs" encountered an error while applying power or reading the device configuration. This may be caused by a failure of your hardware or by a poor connection.
7161073pub const DEVICE_ENUMERATION_ERROR = 648;
1074
7171075/// The create operation failed because the name contained at least one mount point which resolves to a volume to which the specified device object is not attached.
7181076pub const MOUNT_POINT_NOT_RESOLVED = 649;
1077
7191078/// The device object parameter is either not a valid device object or is not attached to the volume specified by the file name.
7201079pub const INVALID_DEVICE_OBJECT_PARAMETER = 650;
1080
7211081/// A Machine Check Error has occurred. Please check the system eventlog for additional information.
7221082pub const MCA_OCCURED = 651;
1083
7231084/// There was error [%2] processing the driver database.
7241085pub const DRIVER_DATABASE_ERROR = 652;
1086
7251087/// System hive size has exceeded its limit.
7261088pub const SYSTEM_HIVE_TOO_LARGE = 653;
1089
7271090/// The driver could not be loaded because a previous version of the driver is still in memory.
7281091pub const DRIVER_FAILED_PRIOR_UNLOAD = 654;
1092
7291093/// {Volume Shadow Copy Service} Please wait while the Volume Shadow Copy Service prepares volume %hs for hibernation.
7301094pub const VOLSNAP_PREPARE_HIBERNATE = 655;
1095
7311096/// The system has failed to hibernate (The error code is %hs). Hibernation will be disabled until the system is restarted.
7321097pub const HIBERNATION_FAILURE = 656;
1098
7331099/// The password provided is too long to meet the policy of your user account. Please choose a shorter password.
7341100pub const PWD_TOO_LONG = 657;
1101
7351102/// The requested operation could not be completed due to a file system limitation.
7361103pub const FILE_SYSTEM_LIMITATION = 665;
1104
7371105/// An assertion failure has occurred.
7381106pub const ASSERTION_FAILURE = 668;
1107
7391108/// An error occurred in the ACPI subsystem.
7401109pub const ACPI_ERROR = 669;
1110
7411111/// WOW Assertion Error.
7421112pub const WOW_ASSERTION = 670;
1113
7431114/// A device is missing in the system BIOS MPS table. This device will not be used. Please contact your system vendor for system BIOS update.
7441115pub const PNP_BAD_MPS_TABLE = 671;
1116
7451117/// A translator failed to translate resources.
7461118pub const PNP_TRANSLATION_FAILED = 672;
1119
7471120/// A IRQ translator failed to translate resources.
7481121pub const PNP_IRQ_TRANSLATION_FAILED = 673;
1122
7491123/// Driver %2 returned invalid ID for a child device (%3).
7501124pub const PNP_INVALID_ID = 674;
1125
7511126/// {Kernel Debugger Awakened} the system debugger was awakened by an interrupt.
7521127pub const WAKE_SYSTEM_DEBUGGER = 675;
1128
7531129/// {Handles Closed} Handles to objects have been automatically closed as a result of the requested operation.
7541130pub const HANDLES_CLOSED = 676;
1131
7551132/// {Too Much Information} The specified access control list (ACL) contained more information than was expected.
7561133pub const EXTRANEOUS_INFORMATION = 677;
1134
7571135/// This warning level status indicates that the transaction state already exists for the registry sub-tree, but that a transaction commit was previously aborted. The commit has NOT been completed, but has not been rolled back either (so it may still be committed if desired).
7581136pub const RXACT_COMMIT_NECESSARY = 678;
1137
7591138/// {Media Changed} The media may have changed.
7601139pub const MEDIA_CHECK = 679;
1140
7611141/// {GUID Substitution} During the translation of a global identifier (GUID) to a Windows security ID (SID), no administratively-defined GUID prefix was found. A substitute prefix was used, which will not compromise system security. However, this may provide a more restrictive access than intended.
7621142pub const GUID_SUBSTITUTION_MADE = 680;
1143
7631144/// The create operation stopped after reaching a symbolic link.
7641145pub const STOPPED_ON_SYMLINK = 681;
1146
7651147/// A long jump has been executed.
7661148pub const LONGJUMP = 682;
1149
7671150/// The Plug and Play query operation was not successful.
7681151pub const PLUGPLAY_QUERY_VETOED = 683;
1152
7691153/// A frame consolidation has been executed.
7701154pub const UNWIND_CONSOLIDATE = 684;
1155
7711156/// {Registry Hive Recovered} Registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost.
7721157pub const REGISTRY_HIVE_RECOVERED = 685;
1158
7731159/// The application is attempting to run executable code from the module %hs. This may be insecure. An alternative, %hs, is available. Should the application use the secure module %hs?
7741160pub const DLL_MIGHT_BE_INSECURE = 686;
1161
7751162/// The application is loading executable code from the module %hs. This is secure, but may be incompatible with previous releases of the operating system. An alternative, %hs, is available. Should the application use the secure module %hs?
7761163pub const DLL_MIGHT_BE_INCOMPATIBLE = 687;
1164
7771165/// Debugger did not handle the exception.
7781166pub const DBG_EXCEPTION_NOT_HANDLED = 688;
1167
7791168/// Debugger will reply later.
7801169pub const DBG_REPLY_LATER = 689;
1170
7811171/// Debugger cannot provide handle.
7821172pub const DBG_UNABLE_TO_PROVIDE_HANDLE = 690;
1173
7831174/// Debugger terminated thread.
7841175pub const DBG_TERMINATE_THREAD = 691;
1176
7851177/// Debugger terminated process.
7861178pub const DBG_TERMINATE_PROCESS = 692;
1179
7871180/// Debugger got control C.
7881181pub const DBG_CONTROL_C = 693;
1182
7891183/// Debugger printed exception on control C.
7901184pub const DBG_PRINTEXCEPTION_C = 694;
1185
7911186/// Debugger received RIP exception.
7921187pub const DBG_RIPEXCEPTION = 695;
1188
7931189/// Debugger received control break.
7941190pub const DBG_CONTROL_BREAK = 696;
1191
7951192/// Debugger command communication exception.
7961193pub const DBG_COMMAND_EXCEPTION = 697;
1194
7971195/// {Object Exists} An attempt was made to create an object and the object name already existed.
7981196pub const OBJECT_NAME_EXISTS = 698;
1197
7991198/// {Thread Suspended} A thread termination occurred while the thread was suspended. The thread was resumed, and termination proceeded.
8001199pub const THREAD_WAS_SUSPENDED = 699;
1200
8011201/// {Image Relocated} An image file could not be mapped at the address specified in the image file. Local fixups must be performed on this image.
8021202pub const IMAGE_NOT_AT_BASE = 700;
1203
8031204/// This informational level status indicates that a specified registry sub-tree transaction state did not yet exist and had to be created.
8041205pub const RXACT_STATE_CREATED = 701;
1206
8051207/// {Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. An exception is raised so a debugger can load, unload or track symbols and breakpoints within these 16-bit segments.
8061208pub const SEGMENT_NOTIFICATION = 702;
1209
8071210/// {Invalid Current Directory} The process cannot switch to the startup current directory %hs. Select OK to set current directory to %hs, or select CANCEL to exit.
8081211pub const BAD_CURRENT_DIRECTORY = 703;
1212
8091213/// {Redundant Read} To satisfy a read request, the NT fault-tolerant file system successfully read the requested data from a redundant copy. This was done because the file system encountered a failure on a member of the fault-tolerant volume, but was unable to reassign the failing area of the device.
8101214pub const FT_READ_RECOVERY_FROM_BACKUP = 704;
1215
8111216/// {Redundant Write} To satisfy a write request, the NT fault-tolerant file system successfully wrote a redundant copy of the information. This was done because the file system encountered a failure on a member of the fault-tolerant volume, but was not able to reassign the failing area of the device.
8121217pub const FT_WRITE_RECOVERY = 705;
1218
8131219/// {Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine. Select OK to continue, or CANCEL to fail the DLL load.
8141220pub const IMAGE_MACHINE_TYPE_MISMATCH = 706;
1221
8151222/// {Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later.
8161223pub const RECEIVE_PARTIAL = 707;
1224
8171225/// {Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system.
8181226pub const RECEIVE_EXPEDITED = 708;
1227
8191228/// {Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later.
8201229pub const RECEIVE_PARTIAL_EXPEDITED = 709;
1230
8211231/// {TDI Event Done} The TDI indication has completed successfully.
8221232pub const EVENT_DONE = 710;
1233
8231234/// {TDI Event Pending} The TDI indication has entered the pending state.
8241235pub const EVENT_PENDING = 711;
1236
8251237/// Checking file system on %wZ.
8261238pub const CHECKING_FILE_SYSTEM = 712;
1239
8271240/// {Fatal Application Exit} %hs.
8281241pub const FATAL_APP_EXIT = 713;
1242
8291243/// The specified registry key is referenced by a predefined handle.
8301244pub const PREDEFINED_HANDLE = 714;
1245
8311246/// {Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process.
8321247pub const WAS_UNLOCKED = 715;
1248
8331249/// %hs
8341250pub const SERVICE_NOTIFICATION = 716;
1251
8351252/// {Page Locked} One of the pages to lock was already locked.
8361253pub const WAS_LOCKED = 717;
1254
8371255/// Application popup: %1 : %2
8381256pub const LOG_HARD_ERROR = 718;
1257
8391258/// ERROR_ALREADY_WIN32
8401259pub const ALREADY_WIN32 = 719;
1260
8411261/// {Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine.
8421262pub const IMAGE_MACHINE_TYPE_MISMATCH_EXE = 720;
1263
8431264/// A yield execution was performed and no thread was available to run.
8441265pub const NO_YIELD_PERFORMED = 721;
1266
8451267/// The resumable flag to a timer API was ignored.
8461268pub const TIMER_RESUME_IGNORED = 722;
1269
8471270/// The arbiter has deferred arbitration of these resources to its parent.
8481271pub const ARBITRATION_UNHANDLED = 723;
1272
8491273/// The inserted CardBus device cannot be started because of a configuration error on "%hs".
8501274pub const CARDBUS_NOT_SUPPORTED = 724;
1275
8511276/// The CPUs in this multiprocessor system are not all the same revision level. To use all processors the operating system restricts itself to the features of the least capable processor in the system. Should problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported.
8521277pub const MP_PROCESSOR_MISMATCH = 725;
1278
8531279/// The system was put into hibernation.
8541280pub const HIBERNATED = 726;
1281
8551282/// The system was resumed from hibernation.
8561283pub const RESUME_HIBERNATION = 727;
1284
8571285/// Windows has detected that the system firmware (BIOS) was updated [previous firmware date = %2, current firmware date %3].
8581286pub const FIRMWARE_UPDATED = 728;
1287
8591288/// A device driver is leaking locked I/O pages causing system degradation. The system has automatically enabled tracking code in order to try and catch the culprit.
8601289pub const DRIVERS_LEAKING_LOCKED_PAGES = 729;
1290
8611291/// The system has awoken.
8621292pub const WAKE_SYSTEM = 730;
1293
8631294/// ERROR_WAIT_1
8641295pub const WAIT_1 = 731;
1296
8651297/// ERROR_WAIT_2
8661298pub const WAIT_2 = 732;
1299
8671300/// ERROR_WAIT_3
8681301pub const WAIT_3 = 733;
1302
8691303/// ERROR_WAIT_63
8701304pub const WAIT_63 = 734;
1305
8711306/// ERROR_ABANDONED_WAIT_0
8721307pub const ABANDONED_WAIT_0 = 735;
1308
8731309/// ERROR_ABANDONED_WAIT_63
8741310pub const ABANDONED_WAIT_63 = 736;
1311
8751312/// ERROR_USER_APC
8761313pub const USER_APC = 737;
1314
8771315/// ERROR_KERNEL_APC
8781316pub const KERNEL_APC = 738;
1317
8791318/// ERROR_ALERTED
8801319pub const ALERTED = 739;
1320
8811321/// The requested operation requires elevation.
8821322pub const ELEVATION_REQUIRED = 740;
1323
8831324/// A reparse should be performed by the Object Manager since the name of the file resulted in a symbolic link.
8841325pub const REPARSE = 741;
1326
8851327/// An open/create operation completed while an oplock break is underway.
8861328pub const OPLOCK_BREAK_IN_PROGRESS = 742;
1329
8871330/// A new volume has been mounted by a file system.
8881331pub const VOLUME_MOUNTED = 743;
1332
8891333/// This success level status indicates that the transaction state already exists for the registry sub-tree, but that a transaction commit was previously aborted. The commit has now been completed.
8901334pub const RXACT_COMMITTED = 744;
1335
8911336/// This indicates that a notify change request has been completed due to closing the handle which made the notify change request.
8921337pub const NOTIFY_CLEANUP = 745;
1338
8931339/// {Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. The computer WAS able to connect on a secondary transport.
8941340pub const PRIMARY_TRANSPORT_CONNECT_FAILED = 746;
1341
8951342/// Page fault was a transition fault.
8961343pub const PAGE_FAULT_TRANSITION = 747;
1344
8971345/// Page fault was a demand zero fault.
8981346pub const PAGE_FAULT_DEMAND_ZERO = 748;
1347
8991348/// Page fault was a demand zero fault.
9001349pub const PAGE_FAULT_COPY_ON_WRITE = 749;
1350
9011351/// Page fault was a demand zero fault.
9021352pub const PAGE_FAULT_GUARD_PAGE = 750;
1353
9031354/// Page fault was satisfied by reading from a secondary storage device.
9041355pub const PAGE_FAULT_PAGING_FILE = 751;
1356
9051357/// Cached page was locked during operation.
9061358pub const CACHE_PAGE_LOCKED = 752;
1359
9071360/// Crash dump exists in paging file.
9081361pub const CRASH_DUMP = 753;
1362
9091363/// Specified buffer contains all zeros.
9101364pub const BUFFER_ALL_ZEROS = 754;
1365
9111366/// A reparse should be performed by the Object Manager since the name of the file resulted in a symbolic link.
9121367pub const REPARSE_OBJECT = 755;
1368
9131369/// The device has succeeded a query-stop and its resource requirements have changed.
9141370pub const RESOURCE_REQUIREMENTS_CHANGED = 756;
1371
9151372/// The translator has translated these resources into the global space and no further translations should be performed.
9161373pub const TRANSLATION_COMPLETE = 757;
1374
9171375/// A process being terminated has no threads to terminate.
9181376pub const NOTHING_TO_TERMINATE = 758;
1377
9191378/// The specified process is not part of a job.
9201379pub const PROCESS_NOT_IN_JOB = 759;
1380
9211381/// The specified process is part of a job.
9221382pub const PROCESS_IN_JOB = 760;
1383
9231384/// {Volume Shadow Copy Service} The system is now ready for hibernation.
9241385pub const VOLSNAP_HIBERNATE_READY = 761;
1386
9251387/// A file system or file system filter driver has successfully completed an FsFilter operation.
9261388pub const FSFILTER_OP_COMPLETED_SUCCESSFULLY = 762;
1389
9271390/// The specified interrupt vector was already connected.
9281391pub const INTERRUPT_VECTOR_ALREADY_CONNECTED = 763;
1392
9291393/// The specified interrupt vector is still connected.
9301394pub const INTERRUPT_STILL_CONNECTED = 764;
1395
9311396/// An operation is blocked waiting for an oplock.
9321397pub const WAIT_FOR_OPLOCK = 765;
1398
9331399/// Debugger handled exception.
9341400pub const DBG_EXCEPTION_HANDLED = 766;
1401
9351402/// Debugger continued.
9361403pub const DBG_CONTINUE = 767;
1404
9371405/// An exception occurred in a user mode callback and the kernel callback frame should be removed.
9381406pub const CALLBACK_POP_STACK = 768;
1407
9391408/// Compression is disabled for this volume.
9401409pub const COMPRESSION_DISABLED = 769;
1410
9411411/// The data provider cannot fetch backwards through a result set.
9421412pub const CANTFETCHBACKWARDS = 770;
1413
9431414/// The data provider cannot scroll backwards through a result set.
9441415pub const CANTSCROLLBACKWARDS = 771;
1416
9451417/// The data provider requires that previously fetched data is released before asking for more data.
9461418pub const ROWSNOTRELEASED = 772;
1419
9471420/// The data provider was not able to interpret the flags set for a column binding in an accessor.
9481421pub const BAD_ACCESSOR_FLAGS = 773;
1422
9491423/// One or more errors occurred while processing the request.
9501424pub const ERRORS_ENCOUNTERED = 774;
1425
9511426/// The implementation is not capable of performing the request.
9521427pub const NOT_CAPABLE = 775;
1428
9531429/// The client of a component requested an operation which is not valid given the state of the component instance.
9541430pub const REQUEST_OUT_OF_SEQUENCE = 776;
1431
9551432/// A version number could not be parsed.
9561433pub const VERSION_PARSE_ERROR = 777;
1434
9571435/// The iterator's start position is invalid.
9581436pub const BADSTARTPOSITION = 778;
1437
9591438/// The hardware has reported an uncorrectable memory error.
9601439pub const MEMORY_HARDWARE = 779;
1440
9611441/// The attempted operation required self healing to be enabled.
9621442pub const DISK_REPAIR_DISABLED = 780;
1443
9631444/// The Desktop heap encountered an error while allocating session memory. There is more information in the system event log.
9641445pub const INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 781;
1446
9651447/// The system power state is transitioning from %2 to %3.
9661448pub const SYSTEM_POWERSTATE_TRANSITION = 782;
1449
9671450/// The system power state is transitioning from %2 to %3 but could enter %4.
9681451pub const SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 783;
1452
9691453/// A thread is getting dispatched with MCA EXCEPTION because of MCA.
9701454pub const MCA_EXCEPTION = 784;
1455
9711456/// Access to %1 is monitored by policy rule %2.
9721457pub const ACCESS_AUDIT_BY_POLICY = 785;
1458
9731459/// Access to %1 has been restricted by your Administrator by policy rule %2.
9741460pub const ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 786;
1461
9751462/// A valid hibernation file has been invalidated and should be abandoned.
9761463pub const ABANDON_HIBERFILE = 787;
1464
9771465/// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error may be caused by network connectivity issues. Please try to save this file elsewhere.
9781466pub const LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 788;
1467
9791468/// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error was returned by the server on which the file exists. Please try to save this file elsewhere.
9801469pub const LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 789;
1470
9811471/// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error may be caused if the device has been removed or the media is write-protected.
9821472pub const LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 790;
1473
9831474/// The resources required for this device conflict with the MCFG table.
9841475pub const BAD_MCFG_TABLE = 791;
1476
9851477/// The volume repair could not be performed while it is online. Please schedule to take the volume offline so that it can be repaired.
9861478pub const DISK_REPAIR_REDIRECTED = 792;
1479
9871480/// The volume repair was not successful.
9881481pub const DISK_REPAIR_UNSUCCESSFUL = 793;
1482
9891483/// One of the volume corruption logs is full. Further corruptions that may be detected won't be logged.
9901484pub const CORRUPT_LOG_OVERFULL = 794;
1485
9911486/// One of the volume corruption logs is internally corrupted and needs to be recreated. The volume may contain undetected corruptions and must be scanned.
9921487pub const CORRUPT_LOG_CORRUPTED = 795;
1488
9931489/// One of the volume corruption logs is unavailable for being operated on.
9941490pub const CORRUPT_LOG_UNAVAILABLE = 796;
1491
9951492/// One of the volume corruption logs was deleted while still having corruption records in them. The volume contains detected corruptions and must be scanned.
9961493pub const CORRUPT_LOG_DELETED_FULL = 797;
1494
9971495/// One of the volume corruption logs was cleared by chkdsk and no longer contains real corruptions.
9981496pub const CORRUPT_LOG_CLEARED = 798;
1497
9991498/// Orphaned files exist on the volume but could not be recovered because no more new names could be created in the recovery directory. Files must be moved from the recovery directory.
10001499pub const ORPHAN_NAME_EXHAUSTED = 799;
1500
10011501/// The oplock that was associated with this handle is now associated with a different handle.
10021502pub const OPLOCK_SWITCHED_TO_NEW_HANDLE = 800;
1503
10031504/// An oplock of the requested level cannot be granted. An oplock of a lower level may be available.
10041505pub const CANNOT_GRANT_REQUESTED_OPLOCK = 801;
1506
10051507/// The operation did not complete successfully because it would cause an oplock to be broken. The caller has requested that existing oplocks not be broken.
10061508pub const CANNOT_BREAK_OPLOCK = 802;
1509
10071510/// The handle with which this oplock was associated has been closed. The oplock is now broken.
10081511pub const OPLOCK_HANDLE_CLOSED = 803;
1512
10091513/// The specified access control entry (ACE) does not contain a condition.
10101514pub const NO_ACE_CONDITION = 804;
1515
10111516/// The specified access control entry (ACE) contains an invalid condition.
10121517pub const INVALID_ACE_CONDITION = 805;
1518
10131519/// Access to the specified file handle has been revoked.
10141520pub const FILE_HANDLE_REVOKED = 806;
1521
10151522/// An image file was mapped at a different address from the one specified in the image file but fixups will still be automatically performed on the image.
10161523pub const IMAGE_AT_DIFFERENT_BASE = 807;
1524
10171525/// Access to the extended attribute was denied.
10181526pub const EA_ACCESS_DENIED = 994;
1527
10191528/// The I/O operation has been aborted because of either a thread exit or an application request.
10201529pub const OPERATION_ABORTED = 995;
1530
10211531/// Overlapped I/O event is not in a signaled state.
10221532pub const IO_INCOMPLETE = 996;
1533
10231534/// Overlapped I/O operation is in progress.
10241535pub const IO_PENDING = 997;
1536
10251537/// Invalid access to memory location.
10261538pub const NOACCESS = 998;
1539
10271540/// Error performing inpage operation.
10281541pub const SWAPERROR = 999;
1542
10291543/// Recursion too deep; the stack overflowed.
10301544pub const STACK_OVERFLOW = 1001;
1545
10311546/// The window cannot act on the sent message.
10321547pub const INVALID_MESSAGE = 1002;
1548
10331549/// Cannot complete this function.
10341550pub const CAN_NOT_COMPLETE = 1003;
1551
10351552/// Invalid flags.
10361553pub const INVALID_FLAGS = 1004;
1554
10371555/// The volume does not contain a recognized file system. Please make sure that all required file system drivers are loaded and that the volume is not corrupted.
10381556pub const UNRECOGNIZED_VOLUME = 1005;
1557
10391558/// The volume for a file has been externally altered so that the opened file is no longer valid.
10401559pub const FILE_INVALID = 1006;
1560
10411561/// The requested operation cannot be performed in full-screen mode.
10421562pub const FULLSCREEN_MODE = 1007;
1563
10431564/// An attempt was made to reference a token that does not exist.
10441565pub const NO_TOKEN = 1008;
1566
10451567/// The configuration registry database is corrupt.
10461568pub const BADDB = 1009;
1569
10471570/// The configuration registry key is invalid.
10481571pub const BADKEY = 1010;
1572
10491573/// The configuration registry key could not be opened.
10501574pub const CANTOPEN = 1011;
1575
10511576/// The configuration registry key could not be read.
10521577pub const CANTREAD = 1012;
1578
10531579/// The configuration registry key could not be written.
10541580pub const CANTWRITE = 1013;
1581
10551582/// One of the files in the registry database had to be recovered by use of a log or alternate copy. The recovery was successful.
10561583pub const REGISTRY_RECOVERED = 1014;
1584
10571585/// The registry is corrupted. The structure of one of the files containing registry data is corrupted, or the system's memory image of the file is corrupted, or the file could not be recovered because the alternate copy or log was absent or corrupted.
10581586pub const REGISTRY_CORRUPT = 1015;
1587
10591588/// An I/O operation initiated by the registry failed unrecoverably. The registry could not read in, or write out, or flush, one of the files that contain the system's image of the registry.
10601589pub const REGISTRY_IO_FAILED = 1016;
1590
10611591/// The system has attempted to load or restore a file into the registry, but the specified file is not in a registry file format.
10621592pub const NOT_REGISTRY_FILE = 1017;
1593
10631594/// Illegal operation attempted on a registry key that has been marked for deletion.
10641595pub const KEY_DELETED = 1018;
1596
10651597/// System could not allocate the required space in a registry log.
10661598pub const NO_LOG_SPACE = 1019;
1599
10671600/// Cannot create a symbolic link in a registry key that already has subkeys or values.
10681601pub const KEY_HAS_CHILDREN = 1020;
1602
10691603/// Cannot create a stable subkey under a volatile parent key.
10701604pub const CHILD_MUST_BE_VOLATILE = 1021;
1605
10711606/// A notify change request is being completed and the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.
10721607pub const NOTIFY_ENUM_DIR = 1022;
1608
10731609/// A stop control has been sent to a service that other running services are dependent on.
10741610pub const DEPENDENT_SERVICES_RUNNING = 1051;
1611
10751612/// The requested control is not valid for this service.
10761613pub const INVALID_SERVICE_CONTROL = 1052;
1614
10771615/// The service did not respond to the start or control request in a timely fashion.
10781616pub const SERVICE_REQUEST_TIMEOUT = 1053;
1617
10791618/// A thread could not be created for the service.
10801619pub const SERVICE_NO_THREAD = 1054;
1620
10811621/// The service database is locked.
10821622pub const SERVICE_DATABASE_LOCKED = 1055;
1623
10831624/// An instance of the service is already running.
10841625pub const SERVICE_ALREADY_RUNNING = 1056;
1626
10851627/// The account name is invalid or does not exist, or the password is invalid for the account name specified.
10861628pub const INVALID_SERVICE_ACCOUNT = 1057;
1629
10871630/// The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.
10881631pub const SERVICE_DISABLED = 1058;
1632
10891633/// Circular service dependency was specified.
10901634pub const CIRCULAR_DEPENDENCY = 1059;
1635
10911636/// The specified service does not exist as an installed service.
10921637pub const SERVICE_DOES_NOT_EXIST = 1060;
1638
10931639/// The service cannot accept control messages at this time.
10941640pub const SERVICE_CANNOT_ACCEPT_CTRL = 1061;
1641
10951642/// The service has not been started.
10961643pub const SERVICE_NOT_ACTIVE = 1062;
1644
10971645/// The service process could not connect to the service controller.
10981646pub const FAILED_SERVICE_CONTROLLER_CONNECT = 1063;
1647
10991648/// An exception occurred in the service when handling the control request.
11001649pub const EXCEPTION_IN_SERVICE = 1064;
1650
11011651/// The database specified does not exist.
11021652pub const DATABASE_DOES_NOT_EXIST = 1065;
1653
11031654/// The service has returned a service-specific error code.
11041655pub const SERVICE_SPECIFIC_ERROR = 1066;
1656
11051657/// The process terminated unexpectedly.
11061658pub const PROCESS_ABORTED = 1067;
1659
11071660/// The dependency service or group failed to start.
11081661pub const SERVICE_DEPENDENCY_FAIL = 1068;
1662
11091663/// The service did not start due to a logon failure.
11101664pub const SERVICE_LOGON_FAILED = 1069;
1665
11111666/// After starting, the service hung in a start-pending state.
11121667pub const SERVICE_START_HANG = 1070;
1668
11131669/// The specified service database lock is invalid.
11141670pub const INVALID_SERVICE_LOCK = 1071;
1671
11151672/// The specified service has been marked for deletion.
11161673pub const SERVICE_MARKED_FOR_DELETE = 1072;
1674
11171675/// The specified service already exists.
11181676pub const SERVICE_EXISTS = 1073;
1677
11191678/// The system is currently running with the last-known-good configuration.
11201679pub const ALREADY_RUNNING_LKG = 1074;
1680
11211681/// The dependency service does not exist or has been marked for deletion.
11221682pub const SERVICE_DEPENDENCY_DELETED = 1075;
1683
11231684/// The current boot has already been accepted for use as the last-known-good control set.
11241685pub const BOOT_ALREADY_ACCEPTED = 1076;
1686
11251687/// No attempts to start the service have been made since the last boot.
11261688pub const SERVICE_NEVER_STARTED = 1077;
1689
11271690/// The name is already in use as either a service name or a service display name.
11281691pub const DUPLICATE_SERVICE_NAME = 1078;
1692
11291693/// The account specified for this service is different from the account specified for other services running in the same process.
11301694pub const DIFFERENT_SERVICE_ACCOUNT = 1079;
1695
11311696/// Failure actions can only be set for Win32 services, not for drivers.
11321697pub const CANNOT_DETECT_DRIVER_FAILURE = 1080;
1698
11331699/// This service runs in the same process as the service control manager. Therefore, the service control manager cannot take action if this service's process terminates unexpectedly.
11341700pub const CANNOT_DETECT_PROCESS_ABORT = 1081;
1701
11351702/// No recovery program has been configured for this service.
11361703pub const NO_RECOVERY_PROGRAM = 1082;
1704
11371705/// The executable program that this service is configured to run in does not implement the service.
11381706pub const SERVICE_NOT_IN_EXE = 1083;
1707
11391708/// This service cannot be started in Safe Mode.
11401709pub const NOT_SAFEBOOT_SERVICE = 1084;
1710
11411711/// The physical end of the tape has been reached.
11421712pub const END_OF_MEDIA = 1100;
1713
11431714/// A tape access reached a filemark.
11441715pub const FILEMARK_DETECTED = 1101;
1716
11451717/// The beginning of the tape or a partition was encountered.
11461718pub const BEGINNING_OF_MEDIA = 1102;
1719
11471720/// A tape access reached the end of a set of files.
11481721pub const SETMARK_DETECTED = 1103;
1722
11491723/// No more data is on the tape.
11501724pub const NO_DATA_DETECTED = 1104;
1725
11511726/// Tape could not be partitioned.
11521727pub const PARTITION_FAILURE = 1105;
1728
11531729/// When accessing a new tape of a multivolume partition, the current block size is incorrect.
11541730pub const INVALID_BLOCK_LENGTH = 1106;
1731
11551732/// Tape partition information could not be found when loading a tape.
11561733pub const DEVICE_NOT_PARTITIONED = 1107;
1734
11571735/// Unable to lock the media eject mechanism.
11581736pub const UNABLE_TO_LOCK_MEDIA = 1108;
1737
11591738/// Unable to unload the media.
11601739pub const UNABLE_TO_UNLOAD_MEDIA = 1109;
1740
11611741/// The media in the drive may have changed.
11621742pub const MEDIA_CHANGED = 1110;
1743
11631744/// The I/O bus was reset.
11641745pub const BUS_RESET = 1111;
1746
11651747/// No media in drive.
11661748pub const NO_MEDIA_IN_DRIVE = 1112;
1749
11671750/// No mapping for the Unicode character exists in the target multi-byte code page.
11681751pub const NO_UNICODE_TRANSLATION = 1113;
1752
11691753/// A dynamic link library (DLL) initialization routine failed.
11701754pub const DLL_INIT_FAILED = 1114;
1755
11711756/// A system shutdown is in progress.
11721757pub const SHUTDOWN_IN_PROGRESS = 1115;
1758
11731759/// Unable to abort the system shutdown because no shutdown was in progress.
11741760pub const NO_SHUTDOWN_IN_PROGRESS = 1116;
1761
11751762/// The request could not be performed because of an I/O device error.
11761763pub const IO_DEVICE = 1117;
1764
11771765/// No serial device was successfully initialized. The serial driver will unload.
11781766pub const SERIAL_NO_DEVICE = 1118;
1767
11791768/// Unable to open a device that was sharing an interrupt request (IRQ) with other devices. At least one other device that uses that IRQ was already opened.
11801769pub const IRQ_BUSY = 1119;
1770
11811771/// A serial I/O operation was completed by another write to the serial port. The IOCTL_SERIAL_XOFF_COUNTER reached zero.)
11821772pub const MORE_WRITES = 1120;
1773
11831774/// A serial I/O operation completed because the timeout period expired. The IOCTL_SERIAL_XOFF_COUNTER did not reach zero.)
11841775pub const COUNTER_TIMEOUT = 1121;
1776
11851777/// No ID address mark was found on the floppy disk.
11861778pub const FLOPPY_ID_MARK_NOT_FOUND = 1122;
1779
11871780/// Mismatch between the floppy disk sector ID field and the floppy disk controller track address.
11881781pub const FLOPPY_WRONG_CYLINDER = 1123;
1782
11891783/// The floppy disk controller reported an error that is not recognized by the floppy disk driver.
11901784pub const FLOPPY_UNKNOWN_ERROR = 1124;
1785
11911786/// The floppy disk controller returned inconsistent results in its registers.
11921787pub const FLOPPY_BAD_REGISTERS = 1125;
1788
11931789/// While accessing the hard disk, a recalibrate operation failed, even after retries.
11941790pub const DISK_RECALIBRATE_FAILED = 1126;
1791
11951792/// While accessing the hard disk, a disk operation failed even after retries.
11961793pub const DISK_OPERATION_FAILED = 1127;
1794
11971795/// While accessing the hard disk, a disk controller reset was needed, but even that failed.
11981796pub const DISK_RESET_FAILED = 1128;
1797
11991798/// Physical end of tape encountered.
12001799pub const EOM_OVERFLOW = 1129;
1800
12011801/// Not enough server storage is available to process this command.
12021802pub const NOT_ENOUGH_SERVER_MEMORY = 1130;
1803
12031804/// A potential deadlock condition has been detected.
12041805pub const POSSIBLE_DEADLOCK = 1131;
1806
12051807/// The base address or the file offset specified does not have the proper alignment.
12061808pub const MAPPED_ALIGNMENT = 1132;
1809
12071810/// An attempt to change the system power state was vetoed by another application or driver.
12081811pub const SET_POWER_STATE_VETOED = 1140;
1812
12091813/// The system BIOS failed an attempt to change the system power state.
12101814pub const SET_POWER_STATE_FAILED = 1141;
1815
12111816/// An attempt was made to create more links on a file than the file system supports.
12121817pub const TOO_MANY_LINKS = 1142;
1818
12131819/// The specified program requires a newer version of Windows.
12141820pub const OLD_WIN_VERSION = 1150;
1821
12151822/// The specified program is not a Windows or MS-DOS program.
12161823pub const APP_WRONG_OS = 1151;
1824
12171825/// Cannot start more than one instance of the specified program.
12181826pub const SINGLE_INSTANCE_APP = 1152;
1827
12191828/// The specified program was written for an earlier version of Windows.
12201829pub const RMODE_APP = 1153;
1830
12211831/// One of the library files needed to run this application is damaged.
12221832pub const INVALID_DLL = 1154;
1833
12231834/// No application is associated with the specified file for this operation.
12241835pub const NO_ASSOCIATION = 1155;
1836
12251837/// An error occurred in sending the command to the application.
12261838pub const DDE_FAIL = 1156;
1839
12271840/// One of the library files needed to run this application cannot be found.
12281841pub const DLL_NOT_FOUND = 1157;
1842
12291843/// The current process has used all of its system allowance of handles for Window Manager objects.
12301844pub const NO_MORE_USER_HANDLES = 1158;
1845
12311846/// The message can be used only with synchronous operations.
12321847pub const MESSAGE_SYNC_ONLY = 1159;
1848
12331849/// The indicated source element has no media.
12341850pub const SOURCE_ELEMENT_EMPTY = 1160;
1851
12351852/// The indicated destination element already contains media.
12361853pub const DESTINATION_ELEMENT_FULL = 1161;
1854
12371855/// The indicated element does not exist.
12381856pub const ILLEGAL_ELEMENT_ADDRESS = 1162;
1857
12391858/// The indicated element is part of a magazine that is not present.
12401859pub const MAGAZINE_NOT_PRESENT = 1163;
1860
12411861/// The indicated device requires reinitialization due to hardware errors.
12421862pub const DEVICE_REINITIALIZATION_NEEDED = 1164;
1863
12431864/// The device has indicated that cleaning is required before further operations are attempted.
12441865pub const DEVICE_REQUIRES_CLEANING = 1165;
1866
12451867/// The device has indicated that its door is open.
12461868pub const DEVICE_DOOR_OPEN = 1166;
1869
12471870/// The device is not connected.
12481871pub const DEVICE_NOT_CONNECTED = 1167;
1872
12491873/// Element not found.
12501874pub const NOT_FOUND = 1168;
1875
12511876/// There was no match for the specified key in the index.
12521877pub const NO_MATCH = 1169;
1878
12531879/// The property set specified does not exist on the object.
12541880pub const SET_NOT_FOUND = 1170;
1881
12551882/// The point passed to GetMouseMovePoints is not in the buffer.
12561883pub const POINT_NOT_FOUND = 1171;
1884
12571885/// The tracking (workstation) service is not running.
12581886pub const NO_TRACKING_SERVICE = 1172;
1887
12591888/// The Volume ID could not be found.
12601889pub const NO_VOLUME_ID = 1173;
1890
12611891/// Unable to remove the file to be replaced.
12621892pub const UNABLE_TO_REMOVE_REPLACED = 1175;
1893
12631894/// Unable to move the replacement file to the file to be replaced. The file to be replaced has retained its original name.
12641895pub const UNABLE_TO_MOVE_REPLACEMENT = 1176;
1896
12651897/// Unable to move the replacement file to the file to be replaced. The file to be replaced has been renamed using the backup name.
12661898pub const UNABLE_TO_MOVE_REPLACEMENT_2 = 1177;
1899
12671900/// The volume change journal is being deleted.
12681901pub const JOURNAL_DELETE_IN_PROGRESS = 1178;
1902
12691903/// The volume change journal is not active.
12701904pub const JOURNAL_NOT_ACTIVE = 1179;
1905
12711906/// A file was found, but it may not be the correct file.
12721907pub const POTENTIAL_FILE_FOUND = 1180;
1908
12731909/// The journal entry has been deleted from the journal.
12741910pub const JOURNAL_ENTRY_DELETED = 1181;
1911
12751912/// A system shutdown has already been scheduled.
12761913pub const SHUTDOWN_IS_SCHEDULED = 1190;
1914
12771915/// The system shutdown cannot be initiated because there are other users logged on to the computer.
12781916pub const SHUTDOWN_USERS_LOGGED_ON = 1191;
1917
12791918/// The specified device name is invalid.
12801919pub const BAD_DEVICE = 1200;
1920
12811921/// The device is not currently connected but it is a remembered connection.
12821922pub const CONNECTION_UNAVAIL = 1201;
1923
12831924/// The local device name has a remembered connection to another network resource.
12841925pub const DEVICE_ALREADY_REMEMBERED = 1202;
1926
12851927/// The network path was either typed incorrectly, does not exist, or the network provider is not currently available. Please try retyping the path or contact your network administrator.
12861928pub const NO_NET_OR_BAD_PATH = 1203;
1929
12871930/// The specified network provider name is invalid.
12881931pub const BAD_PROVIDER = 1204;
1932
12891933/// Unable to open the network connection profile.
12901934pub const CANNOT_OPEN_PROFILE = 1205;
1935
12911936/// The network connection profile is corrupted.
12921937pub const BAD_PROFILE = 1206;
1938
12931939/// Cannot enumerate a noncontainer.
12941940pub const NOT_CONTAINER = 1207;
1941
12951942/// An extended error has occurred.
12961943pub const EXTENDED_ERROR = 1208;
1944
12971945/// The format of the specified group name is invalid.
12981946pub const INVALID_GROUPNAME = 1209;
1947
12991948/// The format of the specified computer name is invalid.
13001949pub const INVALID_COMPUTERNAME = 1210;
1950
13011951/// The format of the specified event name is invalid.
13021952pub const INVALID_EVENTNAME = 1211;
1953
13031954/// The format of the specified domain name is invalid.
13041955pub const INVALID_DOMAINNAME = 1212;
1956
13051957/// The format of the specified service name is invalid.
13061958pub const INVALID_SERVICENAME = 1213;
1959
13071960/// The format of the specified network name is invalid.
13081961pub const INVALID_NETNAME = 1214;
1962
13091963/// The format of the specified share name is invalid.
13101964pub const INVALID_SHARENAME = 1215;
1965
13111966/// The format of the specified password is invalid.
13121967pub const INVALID_PASSWORDNAME = 1216;
1968
13131969/// The format of the specified message name is invalid.
13141970pub const INVALID_MESSAGENAME = 1217;
1971
13151972/// The format of the specified message destination is invalid.
13161973pub const INVALID_MESSAGEDEST = 1218;
1974
13171975/// Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
13181976pub const SESSION_CREDENTIAL_CONFLICT = 1219;
1977
13191978/// An attempt was made to establish a session to a network server, but there are already too many sessions established to that server.
13201979pub const REMOTE_SESSION_LIMIT_EXCEEDED = 1220;
1980
13211981/// The workgroup or domain name is already in use by another computer on the network.
13221982pub const DUP_DOMAINNAME = 1221;
1983
13231984/// The network is not present or not started.
13241985pub const NO_NETWORK = 1222;
1986
13251987/// The operation was canceled by the user.
13261988pub const CANCELLED = 1223;
1989
13271990/// The requested operation cannot be performed on a file with a user-mapped section open.
13281991pub const USER_MAPPED_FILE = 1224;
1992
13291993/// The remote computer refused the network connection.
13301994pub const CONNECTION_REFUSED = 1225;
1995
13311996/// The network connection was gracefully closed.
13321997pub const GRACEFUL_DISCONNECT = 1226;
1998
13331999/// The network transport endpoint already has an address associated with it.
13342000pub const ADDRESS_ALREADY_ASSOCIATED = 1227;
2001
13352002/// An address has not yet been associated with the network endpoint.
13362003pub const ADDRESS_NOT_ASSOCIATED = 1228;
2004
13372005/// An operation was attempted on a nonexistent network connection.
13382006pub const CONNECTION_INVALID = 1229;
2007
13392008/// An invalid operation was attempted on an active network connection.
13402009pub const CONNECTION_ACTIVE = 1230;
2010
13412011/// The network location cannot be reached. For information about network troubleshooting, see Windows Help.
13422012pub const NETWORK_UNREACHABLE = 1231;
2013
13432014/// The network location cannot be reached. For information about network troubleshooting, see Windows Help.
13442015pub const HOST_UNREACHABLE = 1232;
2016
13452017/// The network location cannot be reached. For information about network troubleshooting, see Windows Help.
13462018pub const PROTOCOL_UNREACHABLE = 1233;
2019
13472020/// No service is operating at the destination network endpoint on the remote system.
13482021pub const PORT_UNREACHABLE = 1234;
2022
13492023/// The request was aborted.
13502024pub const REQUEST_ABORTED = 1235;
2025
13512026/// The network connection was aborted by the local system.
13522027pub const CONNECTION_ABORTED = 1236;
2028
13532029/// The operation could not be completed. A retry should be performed.
13542030pub const RETRY = 1237;
2031
13552032/// A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached.
13562033pub const CONNECTION_COUNT_LIMIT = 1238;
2034
13572035/// Attempting to log in during an unauthorized time of day for this account.
13582036pub const LOGIN_TIME_RESTRICTION = 1239;
2037
13592038/// The account is not authorized to log in from this station.
13602039pub const LOGIN_WKSTA_RESTRICTION = 1240;
2040
13612041/// The network address could not be used for the operation requested.
13622042pub const INCORRECT_ADDRESS = 1241;
2043
13632044/// The service is already registered.
13642045pub const ALREADY_REGISTERED = 1242;
2046
13652047/// The specified service does not exist.
13662048pub const SERVICE_NOT_FOUND = 1243;
2049
13672050/// The operation being requested was not performed because the user has not been authenticated.
13682051pub const NOT_AUTHENTICATED = 1244;
2052
13692053/// The operation being requested was not performed because the user has not logged on to the network. The specified service does not exist.
13702054pub const NOT_LOGGED_ON = 1245;
2055
13712056/// Continue with work in progress.
13722057pub const CONTINUE = 1246;
2058
13732059/// An attempt was made to perform an initialization operation when initialization has already been completed.
13742060pub const ALREADY_INITIALIZED = 1247;
2061
13752062/// No more local devices.
13762063pub const NO_MORE_DEVICES = 1248;
2064
13772065/// The specified site does not exist.
13782066pub const NO_SUCH_SITE = 1249;
2067
13792068/// A domain controller with the specified name already exists.
13802069pub const DOMAIN_CONTROLLER_EXISTS = 1250;
2070
13812071/// This operation is supported only when you are connected to the server.
13822072pub const ONLY_IF_CONNECTED = 1251;
2073
13832074/// The group policy framework should call the extension even if there are no changes.
13842075pub const OVERRIDE_NOCHANGES = 1252;
2076
13852077/// The specified user does not have a valid profile.
13862078pub const BAD_USER_PROFILE = 1253;
2079
13872080/// This operation is not supported on a computer running Windows Server 2003 for Small Business Server.
13882081pub const NOT_SUPPORTED_ON_SBS = 1254;
2082
13892083/// The server machine is shutting down.
13902084pub const SERVER_SHUTDOWN_IN_PROGRESS = 1255;
2085
13912086/// The remote system is not available. For information about network troubleshooting, see Windows Help.
13922087pub const HOST_DOWN = 1256;
2088
13932089/// The security identifier provided is not from an account domain.
13942090pub const NON_ACCOUNT_SID = 1257;
2091
13952092/// The security identifier provided does not have a domain component.
13962093pub const NON_DOMAIN_SID = 1258;
2094
13972095/// AppHelp dialog canceled thus preventing the application from starting.
13982096pub const APPHELP_BLOCK = 1259;
2097
13992098/// This program is blocked by group policy. For more information, contact your system administrator.
14002099pub const ACCESS_DISABLED_BY_POLICY = 1260;
2100
14012101/// A program attempt to use an invalid register value. Normally caused by an uninitialized register. This error is Itanium specific.
14022102pub const REG_NAT_CONSUMPTION = 1261;
2103
14032104/// The share is currently offline or does not exist.
14042105pub const CSCSHARE_OFFLINE = 1262;
2106
14052107/// The Kerberos protocol encountered an error while validating the KDC certificate during smartcard logon. There is more information in the system event log.
14062108pub const PKINIT_FAILURE = 1263;
2109
14072110/// The Kerberos protocol encountered an error while attempting to utilize the smartcard subsystem.
14082111pub const SMARTCARD_SUBSYSTEM_FAILURE = 1264;
2112
14092113/// The system cannot contact a domain controller to service the authentication request. Please try again later.
14102114pub const DOWNGRADE_DETECTED = 1265;
2115
14112116/// The machine is locked and cannot be shut down without the force option.
14122117pub const MACHINE_LOCKED = 1271;
2118
14132119/// An application-defined callback gave invalid data when called.
14142120pub const CALLBACK_SUPPLIED_INVALID_DATA = 1273;
2121
14152122/// The group policy framework should call the extension in the synchronous foreground policy refresh.
14162123pub const SYNC_FOREGROUND_REFRESH_REQUIRED = 1274;
2124
14172125/// This driver has been blocked from loading.
14182126pub const DRIVER_BLOCKED = 1275;
2127
14192128/// A dynamic link library (DLL) referenced a module that was neither a DLL nor the process's executable image.
14202129pub const INVALID_IMPORT_OF_NON_DLL = 1276;
2130
14212131/// Windows cannot open this program since it has been disabled.
14222132pub const ACCESS_DISABLED_WEBBLADE = 1277;
2133
14232134/// Windows cannot open this program because the license enforcement system has been tampered with or become corrupted.
14242135pub const ACCESS_DISABLED_WEBBLADE_TAMPER = 1278;
2136
14252137/// A transaction recover failed.
14262138pub const RECOVERY_FAILURE = 1279;
2139
14272140/// The current thread has already been converted to a fiber.
14282141pub const ALREADY_FIBER = 1280;
2142
14292143/// The current thread has already been converted from a fiber.
14302144pub const ALREADY_THREAD = 1281;
2145
14312146/// The system detected an overrun of a stack-based buffer in this application. This overrun could potentially allow a malicious user to gain control of this application.
14322147pub const STACK_BUFFER_OVERRUN = 1282;
2148
14332149/// Data present in one of the parameters is more than the function can operate on.
14342150pub const PARAMETER_QUOTA_EXCEEDED = 1283;
2151
14352152/// An attempt to do an operation on a debug object failed because the object is in the process of being deleted.
14362153pub const DEBUGGER_INACTIVE = 1284;
2154
14372155/// An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed.
14382156pub const DELAY_LOAD_FAILED = 1285;
2157
14392158/// %1 is a 16-bit application. You do not have permissions to execute 16-bit applications. Check your permissions with your system administrator.
14402159pub const VDM_DISALLOWED = 1286;
2160
14412161/// Insufficient information exists to identify the cause of failure.
14422162pub const UNIDENTIFIED_ERROR = 1287;
2163
14432164/// The parameter passed to a C runtime function is incorrect.
14442165pub const INVALID_CRUNTIME_PARAMETER = 1288;
2166
14452167/// The operation occurred beyond the valid data length of the file.
14462168pub const BEYOND_VDL = 1289;
2169
14472170/// The service start failed since one or more services in the same process have an incompatible service SID type setting. A service with restricted service SID type can only coexist in the same process with other services with a restricted SID type. If the service SID type for this service was just configured, the hosting process must be restarted in order to start this service.
14482171/// On Windows Server 2003 and Windows XP, an unrestricted service cannot coexist in the same process with other services. The service with the unrestricted service SID type must be moved to an owned process in order to start this service.
14492172pub const INCOMPATIBLE_SERVICE_SID_TYPE = 1290;
2173
14502174/// The process hosting the driver for this device has been terminated.
14512175pub const DRIVER_PROCESS_TERMINATED = 1291;
2176
14522177/// An operation attempted to exceed an implementation-defined limit.
14532178pub const IMPLEMENTATION_LIMIT = 1292;
2179
14542180/// Either the target process, or the target thread's containing process, is a protected process.
14552181pub const PROCESS_IS_PROTECTED = 1293;
2182
14562183/// The service notification client is lagging too far behind the current state of services in the machine.
14572184pub const SERVICE_NOTIFY_CLIENT_LAGGING = 1294;
2185
14582186/// The requested file operation failed because the storage quota was exceeded. To free up disk space, move files to a different location or delete unnecessary files. For more information, contact your system administrator.
14592187pub const DISK_QUOTA_EXCEEDED = 1295;
2188
14602189/// The requested file operation failed because the storage policy blocks that type of file. For more information, contact your system administrator.
14612190pub const CONTENT_BLOCKED = 1296;
2191
14622192/// A privilege that the service requires to function properly does not exist in the service account configuration. You may use the Services Microsoft Management Console (MMC) snap-in (services.msc) and the Local Security Settings MMC snap-in (secpol.msc) to view the service configuration and the account configuration.
14632193pub const INCOMPATIBLE_SERVICE_PRIVILEGE = 1297;
2194
14642195/// A thread involved in this operation appears to be unresponsive.
14652196pub const APP_HANG = 1298;
2197
14662198/// Indicates a particular Security ID may not be assigned as the label of an object.
14672199pub const INVALID_LABEL = 1299;
2200
14682201/// Not all privileges or groups referenced are assigned to the caller.
14692202pub const NOT_ALL_ASSIGNED = 1300;
2203
14702204/// Some mapping between account names and security IDs was not done.
14712205pub const SOME_NOT_MAPPED = 1301;
2206
14722207/// No system quota limits are specifically set for this account.
14732208pub const NO_QUOTAS_FOR_ACCOUNT = 1302;
2209
14742210/// No encryption key is available. A well-known encryption key was returned.
14752211pub const LOCAL_USER_SESSION_KEY = 1303;
2212
14762213/// The password is too complex to be converted to a LAN Manager password. The LAN Manager password returned is a NULL string.
14772214pub const NULL_LM_PASSWORD = 1304;
2215
14782216/// The revision level is unknown.
14792217pub const UNKNOWN_REVISION = 1305;
2218
14802219/// Indicates two revision levels are incompatible.
14812220pub const REVISION_MISMATCH = 1306;
2221
14822222/// This security ID may not be assigned as the owner of this object.
14832223pub const INVALID_OWNER = 1307;
2224
14842225/// This security ID may not be assigned as the primary group of an object.
14852226pub const INVALID_PRIMARY_GROUP = 1308;
2227
14862228/// An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client.
14872229pub const NO_IMPERSONATION_TOKEN = 1309;
2230
14882231/// The group may not be disabled.
14892232pub const CANT_DISABLE_MANDATORY = 1310;
2233
14902234/// There are currently no logon servers available to service the logon request.
14912235pub const NO_LOGON_SERVERS = 1311;
2236
14922237/// A specified logon session does not exist. It may already have been terminated.
14932238pub const NO_SUCH_LOGON_SESSION = 1312;
2239
14942240/// A specified privilege does not exist.
14952241pub const NO_SUCH_PRIVILEGE = 1313;
2242
14962243/// A required privilege is not held by the client.
14972244pub const PRIVILEGE_NOT_HELD = 1314;
2245
14982246/// The name provided is not a properly formed account name.
14992247pub const INVALID_ACCOUNT_NAME = 1315;
2248
15002249/// The specified account already exists.
15012250pub const USER_EXISTS = 1316;
2251
15022252/// The specified account does not exist.
15032253pub const NO_SUCH_USER = 1317;
2254
15042255/// The specified group already exists.
15052256pub const GROUP_EXISTS = 1318;
2257
15062258/// The specified group does not exist.
15072259pub const NO_SUCH_GROUP = 1319;
2260
15082261/// Either the specified user account is already a member of the specified group, or the specified group cannot be deleted because it contains a member.
15092262pub const MEMBER_IN_GROUP = 1320;
2263
15102264/// The specified user account is not a member of the specified group account.
15112265pub const MEMBER_NOT_IN_GROUP = 1321;
2266
15122267/// This operation is disallowed as it could result in an administration account being disabled, deleted or unable to log on.
15132268pub const LAST_ADMIN = 1322;
2269
15142270/// Unable to update the password. The value provided as the current password is incorrect.
15152271pub const WRONG_PASSWORD = 1323;
2272
15162273/// Unable to update the password. The value provided for the new password contains values that are not allowed in passwords.
15172274pub const ILL_FORMED_PASSWORD = 1324;
2275
15182276/// Unable to update the password. The value provided for the new password does not meet the length, complexity, or history requirements of the domain.
15192277pub const PASSWORD_RESTRICTION = 1325;
2278
15202279/// The user name or password is incorrect.
15212280pub const LOGON_FAILURE = 1326;
2281
15222282/// Account restrictions are preventing this user from signing in. For example: blank passwords aren't allowed, sign-in times are limited, or a policy restriction has been enforced.
15232283pub const ACCOUNT_RESTRICTION = 1327;
2284
15242285/// Your account has time restrictions that keep you from signing in right now.
15252286pub const INVALID_LOGON_HOURS = 1328;
2287
15262288/// This user isn't allowed to sign in to this computer.
15272289pub const INVALID_WORKSTATION = 1329;
2290
15282291/// The password for this account has expired.
15292292pub const PASSWORD_EXPIRED = 1330;
2293
15302294/// This user can't sign in because this account is currently disabled.
15312295pub const ACCOUNT_DISABLED = 1331;
2296
15322297/// No mapping between account names and security IDs was done.
15332298pub const NONE_MAPPED = 1332;
2299
15342300/// Too many local user identifiers (LUIDs) were requested at one time.
15352301pub const TOO_MANY_LUIDS_REQUESTED = 1333;
2302
15362303/// No more local user identifiers (LUIDs) are available.
15372304pub const LUIDS_EXHAUSTED = 1334;
2305
15382306/// The subauthority part of a security ID is invalid for this particular use.
15392307pub const INVALID_SUB_AUTHORITY = 1335;
2308
15402309/// The access control list (ACL) structure is invalid.
15412310pub const INVALID_ACL = 1336;
2311
15422312/// The security ID structure is invalid.
15432313pub const INVALID_SID = 1337;
2314
15442315/// The security descriptor structure is invalid.
15452316pub const INVALID_SECURITY_DESCR = 1338;
2317
15462318/// The inherited access control list (ACL) or access control entry (ACE) could not be built.
15472319pub const BAD_INHERITANCE_ACL = 1340;
2320
15482321/// The server is currently disabled.
15492322pub const SERVER_DISABLED = 1341;
2323
15502324/// The server is currently enabled.
15512325pub const SERVER_NOT_DISABLED = 1342;
2326
15522327/// The value provided was an invalid value for an identifier authority.
15532328pub const INVALID_ID_AUTHORITY = 1343;
2329
15542330/// No more memory is available for security information updates.
15552331pub const ALLOTTED_SPACE_EXCEEDED = 1344;
2332
15562333/// The specified attributes are invalid, or incompatible with the attributes for the group as a whole.
15572334pub const INVALID_GROUP_ATTRIBUTES = 1345;
2335
15582336/// Either a required impersonation level was not provided, or the provided impersonation level is invalid.
15592337pub const BAD_IMPERSONATION_LEVEL = 1346;
2338
15602339/// Cannot open an anonymous level security token.
15612340pub const CANT_OPEN_ANONYMOUS = 1347;
2341
15622342/// The validation information class requested was invalid.
15632343pub const BAD_VALIDATION_CLASS = 1348;
2344
15642345/// The type of the token is inappropriate for its attempted use.
15652346pub const BAD_TOKEN_TYPE = 1349;
2347
15662348/// Unable to perform a security operation on an object that has no associated security.
15672349pub const NO_SECURITY_ON_OBJECT = 1350;
2350
15682351/// Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied.
15692352pub const CANT_ACCESS_DOMAIN_INFO = 1351;
2353
15702354/// The security account manager (SAM) or local security authority (LSA) server was in the wrong state to perform the security operation.
15712355pub const INVALID_SERVER_STATE = 1352;
2356
15722357/// The domain was in the wrong state to perform the security operation.
15732358pub const INVALID_DOMAIN_STATE = 1353;
2359
15742360/// This operation is only allowed for the Primary Domain Controller of the domain.
15752361pub const INVALID_DOMAIN_ROLE = 1354;
2362
15762363/// The specified domain either does not exist or could not be contacted.
15772364pub const NO_SUCH_DOMAIN = 1355;
2365
15782366/// The specified domain already exists.
15792367pub const DOMAIN_EXISTS = 1356;
2368
15802369/// An attempt was made to exceed the limit on the number of domains per server.
15812370pub const DOMAIN_LIMIT_EXCEEDED = 1357;
2371
15822372/// Unable to complete the requested operation because of either a catastrophic media failure or a data structure corruption on the disk.
15832373pub const INTERNAL_DB_CORRUPTION = 1358;
2374
15842375/// An internal error occurred.
15852376pub const INTERNAL_ERROR = 1359;
2377
15862378/// Generic access types were contained in an access mask which should already be mapped to nongeneric types.
15872379pub const GENERIC_NOT_MAPPED = 1360;
2380
15882381/// A security descriptor is not in the right format (absolute or self-relative).
15892382pub const BAD_DESCRIPTOR_FORMAT = 1361;
2383
15902384/// The requested action is restricted for use by logon processes only. The calling process has not registered as a logon process.
15912385pub const NOT_LOGON_PROCESS = 1362;
2386
15922387/// Cannot start a new logon session with an ID that is already in use.
15932388pub const LOGON_SESSION_EXISTS = 1363;
2389
15942390/// A specified authentication package is unknown.
15952391pub const NO_SUCH_PACKAGE = 1364;
2392
15962393/// The logon session is not in a state that is consistent with the requested operation.
15972394pub const BAD_LOGON_SESSION_STATE = 1365;
2395
15982396/// The logon session ID is already in use.
15992397pub const LOGON_SESSION_COLLISION = 1366;
2398
16002399/// A logon request contained an invalid logon type value.
16012400pub const INVALID_LOGON_TYPE = 1367;
2401
16022402/// Unable to impersonate using a named pipe until data has been read from that pipe.
16032403pub const CANNOT_IMPERSONATE = 1368;
2404
16042405/// The transaction state of a registry subtree is incompatible with the requested operation.
16052406pub const RXACT_INVALID_STATE = 1369;
2407
16062408/// An internal security database corruption has been encountered.
16072409pub const RXACT_COMMIT_FAILURE = 1370;
2410
16082411/// Cannot perform this operation on built-in accounts.
16092412pub const SPECIAL_ACCOUNT = 1371;
2413
16102414/// Cannot perform this operation on this built-in special group.
16112415pub const SPECIAL_GROUP = 1372;
2416
16122417/// Cannot perform this operation on this built-in special user.
16132418pub const SPECIAL_USER = 1373;
2419
16142420/// The user cannot be removed from a group because the group is currently the user's primary group.
16152421pub const MEMBERS_PRIMARY_GROUP = 1374;
2422
16162423/// The token is already in use as a primary token.
16172424pub const TOKEN_ALREADY_IN_USE = 1375;
2425
16182426/// The specified local group does not exist.
16192427pub const NO_SUCH_ALIAS = 1376;
2428
16202429/// The specified account name is not a member of the group.
16212430pub const MEMBER_NOT_IN_ALIAS = 1377;
2431
16222432/// The specified account name is already a member of the group.
16232433pub const MEMBER_IN_ALIAS = 1378;
2434
16242435/// The specified local group already exists.
16252436pub const ALIAS_EXISTS = 1379;
2437
16262438/// Logon failure: the user has not been granted the requested logon type at this computer.
16272439pub const LOGON_NOT_GRANTED = 1380;
2440
16282441/// The maximum number of secrets that may be stored in a single system has been exceeded.
16292442pub const TOO_MANY_SECRETS = 1381;
2443
16302444/// The length of a secret exceeds the maximum length allowed.
16312445pub const SECRET_TOO_LONG = 1382;
2446
16322447/// The local security authority database contains an internal inconsistency.
16332448pub const INTERNAL_DB_ERROR = 1383;
2449
16342450/// During a logon attempt, the user's security context accumulated too many security IDs.
16352451pub const TOO_MANY_CONTEXT_IDS = 1384;
2452
16362453/// Logon failure: the user has not been granted the requested logon type at this computer.
16372454pub const LOGON_TYPE_NOT_GRANTED = 1385;
2455
16382456/// A cross-encrypted password is necessary to change a user password.
16392457pub const NT_CROSS_ENCRYPTION_REQUIRED = 1386;
2458
16402459/// A member could not be added to or removed from the local group because the member does not exist.
16412460pub const NO_SUCH_MEMBER = 1387;
2461
16422462/// A new member could not be added to a local group because the member has the wrong account type.
16432463pub const INVALID_MEMBER = 1388;
2464
16442465/// Too many security IDs have been specified.
16452466pub const TOO_MANY_SIDS = 1389;
2467
16462468/// A cross-encrypted password is necessary to change this user password.
16472469pub const LM_CROSS_ENCRYPTION_REQUIRED = 1390;
2470
16482471/// Indicates an ACL contains no inheritable components.
16492472pub const NO_INHERITANCE = 1391;
2473
16502474/// The file or directory is corrupted and unreadable.
16512475pub const FILE_CORRUPT = 1392;
2476
16522477/// The disk structure is corrupted and unreadable.
16532478pub const DISK_CORRUPT = 1393;
2479
16542480/// There is no user session key for the specified logon session.
16552481pub const NO_USER_SESSION_KEY = 1394;
2482
16562483/// The service being accessed is licensed for a particular number of connections. No more connections can be made to the service at this time because there are already as many connections as the service can accept.
16572484pub const LICENSE_QUOTA_EXCEEDED = 1395;
2485
16582486/// The target account name is incorrect.
16592487pub const WRONG_TARGET_NAME = 1396;
2488
16602489/// Mutual Authentication failed. The server's password is out of date at the domain controller.
16612490pub const MUTUAL_AUTH_FAILED = 1397;
2491
16622492/// There is a time and/or date difference between the client and server.
16632493pub const TIME_SKEW = 1398;
2494
16642495/// This operation cannot be performed on the current domain.
16652496pub const CURRENT_DOMAIN_NOT_ALLOWED = 1399;
2497
16662498/// Invalid window handle.
16672499pub const INVALID_WINDOW_HANDLE = 1400;
2500
16682501/// Invalid menu handle.
16692502pub const INVALID_MENU_HANDLE = 1401;
2503
16702504/// Invalid cursor handle.
16712505pub const INVALID_CURSOR_HANDLE = 1402;
2506
16722507/// Invalid accelerator table handle.
16732508pub const INVALID_ACCEL_HANDLE = 1403;
2509
16742510/// Invalid hook handle.
16752511pub const INVALID_HOOK_HANDLE = 1404;
2512
16762513/// Invalid handle to a multiple-window position structure.
16772514pub const INVALID_DWP_HANDLE = 1405;
2515
16782516/// Cannot create a top-level child window.
16792517pub const TLW_WITH_WSCHILD = 1406;
2518
16802519/// Cannot find window class.
16812520pub const CANNOT_FIND_WND_CLASS = 1407;
2521
16822522/// Invalid window; it belongs to other thread.
16832523pub const WINDOW_OF_OTHER_THREAD = 1408;
2524
16842525/// Hot key is already registered.
16852526pub const HOTKEY_ALREADY_REGISTERED = 1409;
2527
16862528/// Class already exists.
16872529pub const CLASS_ALREADY_EXISTS = 1410;
2530
16882531/// Class does not exist.
16892532pub const CLASS_DOES_NOT_EXIST = 1411;
2533
16902534/// Class still has open windows.
16912535pub const CLASS_HAS_WINDOWS = 1412;
2536
16922537/// Invalid index.
16932538pub const INVALID_INDEX = 1413;
2539
16942540/// Invalid icon handle.
16952541pub const INVALID_ICON_HANDLE = 1414;
2542
16962543/// Using private DIALOG window words.
16972544pub const PRIVATE_DIALOG_INDEX = 1415;
2545
16982546/// The list box identifier was not found.
16992547pub const LISTBOX_ID_NOT_FOUND = 1416;
2548
17002549/// No wildcards were found.
17012550pub const NO_WILDCARD_CHARACTERS = 1417;
2551
17022552/// Thread does not have a clipboard open.
17032553pub const CLIPBOARD_NOT_OPEN = 1418;
2554
17042555/// Hot key is not registered.
17052556pub const HOTKEY_NOT_REGISTERED = 1419;
2557
17062558/// The window is not a valid dialog window.
17072559pub const WINDOW_NOT_DIALOG = 1420;
2560
17082561/// Control ID not found.
17092562pub const CONTROL_ID_NOT_FOUND = 1421;
2563
17102564/// Invalid message for a combo box because it does not have an edit control.
17112565pub const INVALID_COMBOBOX_MESSAGE = 1422;
2566
17122567/// The window is not a combo box.
17132568pub const WINDOW_NOT_COMBOBOX = 1423;
2569
17142570/// Height must be less than 256.
17152571pub const INVALID_EDIT_HEIGHT = 1424;
2572
17162573/// Invalid device context (DC) handle.
17172574pub const DC_NOT_FOUND = 1425;
2575
17182576/// Invalid hook procedure type.
17192577pub const INVALID_HOOK_FILTER = 1426;
2578
17202579/// Invalid hook procedure.
17212580pub const INVALID_FILTER_PROC = 1427;
2581
17222582/// Cannot set nonlocal hook without a module handle.
17232583pub const HOOK_NEEDS_HMOD = 1428;
2584
17242585/// This hook procedure can only be set globally.
17252586pub const GLOBAL_ONLY_HOOK = 1429;
2587
17262588/// The journal hook procedure is already installed.
17272589pub const JOURNAL_HOOK_SET = 1430;
2590
17282591/// The hook procedure is not installed.
17292592pub const HOOK_NOT_INSTALLED = 1431;
2593
17302594/// Invalid message for single-selection list box.
17312595pub const INVALID_LB_MESSAGE = 1432;
2596
17322597/// LB_SETCOUNT sent to non-lazy list box.
17332598pub const SETCOUNT_ON_BAD_LB = 1433;
2599
17342600/// This list box does not support tab stops.
17352601pub const LB_WITHOUT_TABSTOPS = 1434;
2602
17362603/// Cannot destroy object created by another thread.
17372604pub const DESTROY_OBJECT_OF_OTHER_THREAD = 1435;
2605
17382606/// Child windows cannot have menus.
17392607pub const CHILD_WINDOW_MENU = 1436;
2608
17402609/// The window does not have a system menu.
17412610pub const NO_SYSTEM_MENU = 1437;
2611
17422612/// Invalid message box style.
17432613pub const INVALID_MSGBOX_STYLE = 1438;
2614
17442615/// Invalid system-wide (SPI_*) parameter.
17452616pub const INVALID_SPI_VALUE = 1439;
2617
17462618/// Screen already locked.
17472619pub const SCREEN_ALREADY_LOCKED = 1440;
2620
17482621/// All handles to windows in a multiple-window position structure must have the same parent.
17492622pub const HWNDS_HAVE_DIFF_PARENT = 1441;
2623
17502624/// The window is not a child window.
17512625pub const NOT_CHILD_WINDOW = 1442;
2626
17522627/// Invalid GW_* command.
17532628pub const INVALID_GW_COMMAND = 1443;
2629
17542630/// Invalid thread identifier.
17552631pub const INVALID_THREAD_ID = 1444;
2632
17562633/// Cannot process a message from a window that is not a multiple document interface (MDI) window.
17572634pub const NON_MDICHILD_WINDOW = 1445;
2635
17582636/// Popup menu already active.
17592637pub const POPUP_ALREADY_ACTIVE = 1446;
2638
17602639/// The window does not have scroll bars.
17612640pub const NO_SCROLLBARS = 1447;
2641
17622642/// Scroll bar range cannot be greater than MAXLONG.
17632643pub const INVALID_SCROLLBAR_RANGE = 1448;
2644
17642645/// Cannot show or remove the window in the way specified.
17652646pub const INVALID_SHOWWIN_COMMAND = 1449;
2647
17662648/// Insufficient system resources exist to complete the requested service.
17672649pub const NO_SYSTEM_RESOURCES = 1450;
2650
17682651/// Insufficient system resources exist to complete the requested service.
17692652pub const NONPAGED_SYSTEM_RESOURCES = 1451;
2653
17702654/// Insufficient system resources exist to complete the requested service.
17712655pub const PAGED_SYSTEM_RESOURCES = 1452;
2656
17722657/// Insufficient quota to complete the requested service.
17732658pub const WORKING_SET_QUOTA = 1453;
2659
17742660/// Insufficient quota to complete the requested service.
17752661pub const PAGEFILE_QUOTA = 1454;
2662
17762663/// The paging file is too small for this operation to complete.
17772664pub const COMMITMENT_LIMIT = 1455;
2665
17782666/// A menu item was not found.
17792667pub const MENU_ITEM_NOT_FOUND = 1456;
2668
17802669/// Invalid keyboard layout handle.
17812670pub const INVALID_KEYBOARD_HANDLE = 1457;
2671
17822672/// Hook type not allowed.
17832673pub const HOOK_TYPE_NOT_ALLOWED = 1458;
2674
17842675/// This operation requires an interactive window station.
17852676pub const REQUIRES_INTERACTIVE_WINDOWSTATION = 1459;
2677
17862678/// This operation returned because the timeout period expired.
17872679pub const TIMEOUT = 1460;
2680
17882681/// Invalid monitor handle.
17892682pub const INVALID_MONITOR_HANDLE = 1461;
2683
17902684/// Incorrect size argument.
17912685pub const INCORRECT_SIZE = 1462;
2686
17922687/// The symbolic link cannot be followed because its type is disabled.
17932688pub const SYMLINK_CLASS_DISABLED = 1463;
2689
17942690/// This application does not support the current operation on symbolic links.
17952691pub const SYMLINK_NOT_SUPPORTED = 1464;
2692
17962693/// Windows was unable to parse the requested XML data.
17972694pub const XML_PARSE_ERROR = 1465;
2695
17982696/// An error was encountered while processing an XML digital signature.
17992697pub const XMLDSIG_ERROR = 1466;
2698
18002699/// This application must be restarted.
18012700pub const RESTART_APPLICATION = 1467;
2701
18022702/// The caller made the connection request in the wrong routing compartment.
18032703pub const WRONG_COMPARTMENT = 1468;
2704
18042705/// There was an AuthIP failure when attempting to connect to the remote host.
18052706pub const AUTHIP_FAILURE = 1469;
2707
18062708/// Insufficient NVRAM resources exist to complete the requested service. A reboot might be required.
18072709pub const NO_NVRAM_RESOURCES = 1470;
2710
18082711/// Unable to finish the requested operation because the specified process is not a GUI process.
18092712pub const NOT_GUI_PROCESS = 1471;
2713
18102714/// The event log file is corrupted.
18112715pub const EVENTLOG_FILE_CORRUPT = 1500;
2716
18122717/// No event log file could be opened, so the event logging service did not start.
18132718pub const EVENTLOG_CANT_START = 1501;
2719
18142720/// The event log file is full.
18152721pub const LOG_FILE_FULL = 1502;
2722
18162723/// The event log file has changed between read operations.
18172724pub const EVENTLOG_FILE_CHANGED = 1503;
2725
18182726/// The specified task name is invalid.
18192727pub const INVALID_TASK_NAME = 1550;
2728
18202729/// The specified task index is invalid.
18212730pub const INVALID_TASK_INDEX = 1551;
2731
18222732/// The specified thread is already joining a task.
18232733pub const THREAD_ALREADY_IN_TASK = 1552;
2734
18242735/// The Windows Installer Service could not be accessed. This can occur if the Windows Installer is not correctly installed. Contact your support personnel for assistance.
18252736pub const INSTALL_SERVICE_FAILURE = 1601;
2737
18262738/// User cancelled installation.
18272739pub const INSTALL_USEREXIT = 1602;
2740
18282741/// Fatal error during installation.
18292742pub const INSTALL_FAILURE = 1603;
2743
18302744/// Installation suspended, incomplete.
18312745pub const INSTALL_SUSPEND = 1604;
2746
18322747/// This action is only valid for products that are currently installed.
18332748pub const UNKNOWN_PRODUCT = 1605;
2749
18342750/// Feature ID not registered.
18352751pub const UNKNOWN_FEATURE = 1606;
2752
18362753/// Component ID not registered.
18372754pub const UNKNOWN_COMPONENT = 1607;
2755
18382756/// Unknown property.
18392757pub const UNKNOWN_PROPERTY = 1608;
2758
18402759/// Handle is in an invalid state.
18412760pub const INVALID_HANDLE_STATE = 1609;
2761
18422762/// The configuration data for this product is corrupt. Contact your support personnel.
18432763pub const BAD_CONFIGURATION = 1610;
2764
18442765/// Component qualifier not present.
18452766pub const INDEX_ABSENT = 1611;
2767
18462768/// The installation source for this product is not available. Verify that the source exists and that you can access it.
18472769pub const INSTALL_SOURCE_ABSENT = 1612;
2770
18482771/// This installation package cannot be installed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.
18492772pub const INSTALL_PACKAGE_VERSION = 1613;
2773
18502774/// Product is uninstalled.
18512775pub const PRODUCT_UNINSTALLED = 1614;
2776
18522777/// SQL query syntax invalid or unsupported.
18532778pub const BAD_QUERY_SYNTAX = 1615;
2779
18542780/// Record field does not exist.
18552781pub const INVALID_FIELD = 1616;
2782
18562783/// The device has been removed.
18572784pub const DEVICE_REMOVED = 1617;
2785
18582786/// Another installation is already in progress. Complete that installation before proceeding with this install.
18592787pub const INSTALL_ALREADY_RUNNING = 1618;
2788
18602789/// This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package.
18612790pub const INSTALL_PACKAGE_OPEN_FAILED = 1619;
2791
18622792/// This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer package.
18632793pub const INSTALL_PACKAGE_INVALID = 1620;
2794
18642795/// There was an error starting the Windows Installer service user interface. Contact your support personnel.
18652796pub const INSTALL_UI_FAILURE = 1621;
2797
18662798/// Error opening installation log file. Verify that the specified log file location exists and that you can write to it.
18672799pub const INSTALL_LOG_FAILURE = 1622;
2800
18682801/// The language of this installation package is not supported by your system.
18692802pub const INSTALL_LANGUAGE_UNSUPPORTED = 1623;
2803
18702804/// Error applying transforms. Verify that the specified transform paths are valid.
18712805pub const INSTALL_TRANSFORM_FAILURE = 1624;
2806
18722807/// This installation is forbidden by system policy. Contact your system administrator.
18732808pub const INSTALL_PACKAGE_REJECTED = 1625;
2809
18742810/// Function could not be executed.
18752811pub const FUNCTION_NOT_CALLED = 1626;
2812
18762813/// Function failed during execution.
18772814pub const FUNCTION_FAILED = 1627;
2815
18782816/// Invalid or unknown table specified.
18792817pub const INVALID_TABLE = 1628;
2818
18802819/// Data supplied is of wrong type.
18812820pub const DATATYPE_MISMATCH = 1629;
2821
18822822/// Data of this type is not supported.
18832823pub const UNSUPPORTED_TYPE = 1630;
2824
18842825/// The Windows Installer service failed to start. Contact your support personnel.
18852826pub const CREATE_FAILED = 1631;
2827
18862828/// The Temp folder is on a drive that is full or is inaccessible. Free up space on the drive or verify that you have write permission on the Temp folder.
18872829pub const INSTALL_TEMP_UNWRITABLE = 1632;
2830
18882831/// This installation package is not supported by this processor type. Contact your product vendor.
18892832pub const INSTALL_PLATFORM_UNSUPPORTED = 1633;
2833
18902834/// Component not used on this computer.
18912835pub const INSTALL_NOTUSED = 1634;
2836
18922837/// This update package could not be opened. Verify that the update package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer update package.
18932838pub const PATCH_PACKAGE_OPEN_FAILED = 1635;
2839
18942840/// This update package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer update package.
18952841pub const PATCH_PACKAGE_INVALID = 1636;
2842
18962843/// This update package cannot be processed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.
18972844pub const PATCH_PACKAGE_UNSUPPORTED = 1637;
2845
18982846/// Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs on the Control Panel.
18992847pub const PRODUCT_VERSION = 1638;
2848
19002849/// Invalid command line argument. Consult the Windows Installer SDK for detailed command line help.
19012850pub const INVALID_COMMAND_LINE = 1639;
2851
19022852/// Only administrators have permission to add, remove, or configure server software during a Terminal services remote session. If you want to install or configure software on the server, contact your network administrator.
19032853pub const INSTALL_REMOTE_DISALLOWED = 1640;
2854
19042855/// The requested operation completed successfully. The system will be restarted so the changes can take effect.
19052856pub const SUCCESS_REBOOT_INITIATED = 1641;
2857
19062858/// The upgrade cannot be installed by the Windows Installer service because the program to be upgraded may be missing, or the upgrade may update a different version of the program. Verify that the program to be upgraded exists on your computer and that you have the correct upgrade.
19072859pub const PATCH_TARGET_NOT_FOUND = 1642;
2860
19082861/// The update package is not permitted by software restriction policy.
19092862pub const PATCH_PACKAGE_REJECTED = 1643;
2863
19102864/// One or more customizations are not permitted by software restriction policy.
19112865pub const INSTALL_TRANSFORM_REJECTED = 1644;
2866
19122867/// The Windows Installer does not permit installation from a Remote Desktop Connection.
19132868pub const INSTALL_REMOTE_PROHIBITED = 1645;
2869
19142870/// Uninstallation of the update package is not supported.
19152871pub const PATCH_REMOVAL_UNSUPPORTED = 1646;
2872
19162873/// The update is not applied to this product.
19172874pub const UNKNOWN_PATCH = 1647;
2875
19182876/// No valid sequence could be found for the set of updates.
19192877pub const PATCH_NO_SEQUENCE = 1648;
2878
19202879/// Update removal was disallowed by policy.
19212880pub const PATCH_REMOVAL_DISALLOWED = 1649;
2881
19222882/// The XML update data is invalid.
19232883pub const INVALID_PATCH_XML = 1650;
2884
19242885/// Windows Installer does not permit updating of managed advertised products. At least one feature of the product must be installed before applying the update.
19252886pub const PATCH_MANAGED_ADVERTISED_PRODUCT = 1651;
2887
19262888/// The Windows Installer service is not accessible in Safe Mode. Please try again when your computer is not in Safe Mode or you can use System Restore to return your machine to a previous good state.
19272889pub const INSTALL_SERVICE_SAFEBOOT = 1652;
2890
19282891/// A fail fast exception occurred. Exception handlers will not be invoked and the process will be terminated immediately.
19292892pub const FAIL_FAST_EXCEPTION = 1653;
2893
19302894/// The app that you are trying to run is not supported on this version of Windows.
19312895pub const INSTALL_REJECTED = 1654;
2896
19322897/// The string binding is invalid.
19332898pub const RPC_S_INVALID_STRING_BINDING = 1700;
2899
19342900/// The binding handle is not the correct type.
19352901pub const RPC_S_WRONG_KIND_OF_BINDING = 1701;
2902
19362903/// The binding handle is invalid.
19372904pub const RPC_S_INVALID_BINDING = 1702;
2905
19382906/// The RPC protocol sequence is not supported.
19392907pub const RPC_S_PROTSEQ_NOT_SUPPORTED = 1703;
2908
19402909/// The RPC protocol sequence is invalid.
19412910pub const RPC_S_INVALID_RPC_PROTSEQ = 1704;
2911
19422912/// The string universal unique identifier (UUID) is invalid.
19432913pub const RPC_S_INVALID_STRING_UUID = 1705;
2914
19442915/// The endpoint format is invalid.
19452916pub const RPC_S_INVALID_ENDPOINT_FORMAT = 1706;
2917
19462918/// The network address is invalid.
19472919pub const RPC_S_INVALID_NET_ADDR = 1707;
2920
19482921/// No endpoint was found.
19492922pub const RPC_S_NO_ENDPOINT_FOUND = 1708;
2923
19502924/// The timeout value is invalid.
19512925pub const RPC_S_INVALID_TIMEOUT = 1709;
2926
19522927/// The object universal unique identifier (UUID) was not found.
19532928pub const RPC_S_OBJECT_NOT_FOUND = 1710;
2929
19542930/// The object universal unique identifier (UUID) has already been registered.
19552931pub const RPC_S_ALREADY_REGISTERED = 1711;
2932
19562933/// The type universal unique identifier (UUID) has already been registered.
19572934pub const RPC_S_TYPE_ALREADY_REGISTERED = 1712;
2935
19582936/// The RPC server is already listening.
19592937pub const RPC_S_ALREADY_LISTENING = 1713;
2938
19602939/// No protocol sequences have been registered.
19612940pub const RPC_S_NO_PROTSEQS_REGISTERED = 1714;
2941
19622942/// The RPC server is not listening.
19632943pub const RPC_S_NOT_LISTENING = 1715;
2944
19642945/// The manager type is unknown.
19652946pub const RPC_S_UNKNOWN_MGR_TYPE = 1716;
2947
19662948/// The interface is unknown.
19672949pub const RPC_S_UNKNOWN_IF = 1717;
2950
19682951/// There are no bindings.
19692952pub const RPC_S_NO_BINDINGS = 1718;
2953
19702954/// There are no protocol sequences.
19712955pub const RPC_S_NO_PROTSEQS = 1719;
2956
19722957/// The endpoint cannot be created.
19732958pub const RPC_S_CANT_CREATE_ENDPOINT = 1720;
2959
19742960/// Not enough resources are available to complete this operation.
19752961pub const RPC_S_OUT_OF_RESOURCES = 1721;
2962
19762963/// The RPC server is unavailable.
19772964pub const RPC_S_SERVER_UNAVAILABLE = 1722;
2965
19782966/// The RPC server is too busy to complete this operation.
19792967pub const RPC_S_SERVER_TOO_BUSY = 1723;
2968
19802969/// The network options are invalid.
19812970pub const RPC_S_INVALID_NETWORK_OPTIONS = 1724;
2971
19822972/// There are no remote procedure calls active on this thread.
19832973pub const RPC_S_NO_CALL_ACTIVE = 1725;
2974
19842975/// The remote procedure call failed.
19852976pub const RPC_S_CALL_FAILED = 1726;
2977
19862978/// The remote procedure call failed and did not execute.
19872979pub const RPC_S_CALL_FAILED_DNE = 1727;
2980
19882981/// A remote procedure call (RPC) protocol error occurred.
19892982pub const RPC_S_PROTOCOL_ERROR = 1728;
2983
19902984/// Access to the HTTP proxy is denied.
19912985pub const RPC_S_PROXY_ACCESS_DENIED = 1729;
2986
19922987/// The transfer syntax is not supported by the RPC server.
19932988pub const RPC_S_UNSUPPORTED_TRANS_SYN = 1730;
2989
19942990/// The universal unique identifier (UUID) type is not supported.
19952991pub const RPC_S_UNSUPPORTED_TYPE = 1732;
2992
19962993/// The tag is invalid.
19972994pub const RPC_S_INVALID_TAG = 1733;
2995
19982996/// The array bounds are invalid.
19992997pub const RPC_S_INVALID_BOUND = 1734;
2998
20002999/// The binding does not contain an entry name.
20013000pub const RPC_S_NO_ENTRY_NAME = 1735;
3001
20023002/// The name syntax is invalid.
20033003pub const RPC_S_INVALID_NAME_SYNTAX = 1736;
3004
20043005/// The name syntax is not supported.
20053006pub const RPC_S_UNSUPPORTED_NAME_SYNTAX = 1737;
3007
20063008/// No network address is available to use to construct a universal unique identifier (UUID).
20073009pub const RPC_S_UUID_NO_ADDRESS = 1739;
3010
20083011/// The endpoint is a duplicate.
20093012pub const RPC_S_DUPLICATE_ENDPOINT = 1740;
3013
20103014/// The authentication type is unknown.
20113015pub const RPC_S_UNKNOWN_AUTHN_TYPE = 1741;
3016
20123017/// The maximum number of calls is too small.
20133018pub const RPC_S_MAX_CALLS_TOO_SMALL = 1742;
3019
20143020/// The string is too long.
20153021pub const RPC_S_STRING_TOO_LONG = 1743;
3022
20163023/// The RPC protocol sequence was not found.
20173024pub const RPC_S_PROTSEQ_NOT_FOUND = 1744;
3025
20183026/// The procedure number is out of range.
20193027pub const RPC_S_PROCNUM_OUT_OF_RANGE = 1745;
3028
20203029/// The binding does not contain any authentication information.
20213030pub const RPC_S_BINDING_HAS_NO_AUTH = 1746;
3031
20223032/// The authentication service is unknown.
20233033pub const RPC_S_UNKNOWN_AUTHN_SERVICE = 1747;
3034
20243035/// The authentication level is unknown.
20253036pub const RPC_S_UNKNOWN_AUTHN_LEVEL = 1748;
3037
20263038/// The security context is invalid.
20273039pub const RPC_S_INVALID_AUTH_IDENTITY = 1749;
3040
20283041/// The authorization service is unknown.
20293042pub const RPC_S_UNKNOWN_AUTHZ_SERVICE = 1750;
3043
20303044/// The entry is invalid.
20313045pub const EPT_S_INVALID_ENTRY = 1751;
3046
20323047/// The server endpoint cannot perform the operation.
20333048pub const EPT_S_CANT_PERFORM_OP = 1752;
3049
20343050/// There are no more endpoints available from the endpoint mapper.
20353051pub const EPT_S_NOT_REGISTERED = 1753;
3052
20363053/// No interfaces have been exported.
20373054pub const RPC_S_NOTHING_TO_EXPORT = 1754;
3055
20383056/// The entry name is incomplete.
20393057pub const RPC_S_INCOMPLETE_NAME = 1755;
3058
20403059/// The version option is invalid.
20413060pub const RPC_S_INVALID_VERS_OPTION = 1756;
3061
20423062/// There are no more members.
20433063pub const RPC_S_NO_MORE_MEMBERS = 1757;
3064
20443065/// There is nothing to unexport.
20453066pub const RPC_S_NOT_ALL_OBJS_UNEXPORTED = 1758;
3067
20463068/// The interface was not found.
20473069pub const RPC_S_INTERFACE_NOT_FOUND = 1759;
3070
20483071/// The entry already exists.
20493072pub const RPC_S_ENTRY_ALREADY_EXISTS = 1760;
3073
20503074/// The entry is not found.
20513075pub const RPC_S_ENTRY_NOT_FOUND = 1761;
3076
20523077/// The name service is unavailable.
20533078pub const RPC_S_NAME_SERVICE_UNAVAILABLE = 1762;
3079
20543080/// The network address family is invalid.
20553081pub const RPC_S_INVALID_NAF_ID = 1763;
3082
20563083/// The requested operation is not supported.
20573084pub const RPC_S_CANNOT_SUPPORT = 1764;
3085
20583086/// No security context is available to allow impersonation.
20593087pub const RPC_S_NO_CONTEXT_AVAILABLE = 1765;
3088
20603089/// An internal error occurred in a remote procedure call (RPC).
20613090pub const RPC_S_INTERNAL_ERROR = 1766;
3091
20623092/// The RPC server attempted an integer division by zero.
20633093pub const RPC_S_ZERO_DIVIDE = 1767;
3094
20643095/// An addressing error occurred in the RPC server.
20653096pub const RPC_S_ADDRESS_ERROR = 1768;
3097
20663098/// A floating-point operation at the RPC server caused a division by zero.
20673099pub const RPC_S_FP_DIV_ZERO = 1769;
3100
20683101/// A floating-point underflow occurred at the RPC server.
20693102pub const RPC_S_FP_UNDERFLOW = 1770;
3103
20703104/// A floating-point overflow occurred at the RPC server.
20713105pub const RPC_S_FP_OVERFLOW = 1771;
3106
20723107/// The list of RPC servers available for the binding of auto handles has been exhausted.
20733108pub const RPC_X_NO_MORE_ENTRIES = 1772;
3109
20743110/// Unable to open the character translation table file.
20753111pub const RPC_X_SS_CHAR_TRANS_OPEN_FAIL = 1773;
3112
20763113/// The file containing the character translation table has fewer than 512 bytes.
20773114pub const RPC_X_SS_CHAR_TRANS_SHORT_FILE = 1774;
3115
20783116/// A null context handle was passed from the client to the host during a remote procedure call.
20793117pub const RPC_X_SS_IN_NULL_CONTEXT = 1775;
3118
20803119/// The context handle changed during a remote procedure call.
20813120pub const RPC_X_SS_CONTEXT_DAMAGED = 1777;
3121
20823122/// The binding handles passed to a remote procedure call do not match.
20833123pub const RPC_X_SS_HANDLES_MISMATCH = 1778;
3124
20843125/// The stub is unable to get the remote procedure call handle.
20853126pub const RPC_X_SS_CANNOT_GET_CALL_HANDLE = 1779;
3127
20863128/// A null reference pointer was passed to the stub.
20873129pub const RPC_X_NULL_REF_POINTER = 1780;
3130
20883131/// The enumeration value is out of range.
20893132pub const RPC_X_ENUM_VALUE_OUT_OF_RANGE = 1781;
3133
20903134/// The byte count is too small.
20913135pub const RPC_X_BYTE_COUNT_TOO_SMALL = 1782;
3136
20923137/// The stub received bad data.
20933138pub const RPC_X_BAD_STUB_DATA = 1783;
3139
20943140/// The supplied user buffer is not valid for the requested operation.
20953141pub const INVALID_USER_BUFFER = 1784;
3142
20963143/// The disk media is not recognized. It may not be formatted.
20973144pub const UNRECOGNIZED_MEDIA = 1785;
3145
20983146/// The workstation does not have a trust secret.
20993147pub const NO_TRUST_LSA_SECRET = 1786;
3148
21003149/// The security database on the server does not have a computer account for this workstation trust relationship.
21013150pub const NO_TRUST_SAM_ACCOUNT = 1787;
3151
21023152/// The trust relationship between the primary domain and the trusted domain failed.
21033153pub const TRUSTED_DOMAIN_FAILURE = 1788;
3154
21043155/// The trust relationship between this workstation and the primary domain failed.
21053156pub const TRUSTED_RELATIONSHIP_FAILURE = 1789;
3157
21063158/// The network logon failed.
21073159pub const TRUST_FAILURE = 1790;
3160
21083161/// A remote procedure call is already in progress for this thread.
21093162pub const RPC_S_CALL_IN_PROGRESS = 1791;
3163
21103164/// An attempt was made to logon, but the network logon service was not started.
21113165pub const NETLOGON_NOT_STARTED = 1792;
3166
21123167/// The user's account has expired.
21133168pub const ACCOUNT_EXPIRED = 1793;
3169
21143170/// The redirector is in use and cannot be unloaded.
21153171pub const REDIRECTOR_HAS_OPEN_HANDLES = 1794;
3172
21163173/// The specified printer driver is already installed.
21173174pub const PRINTER_DRIVER_ALREADY_INSTALLED = 1795;
3175
21183176/// The specified port is unknown.
21193177pub const UNKNOWN_PORT = 1796;
3178
21203179/// The printer driver is unknown.
21213180pub const UNKNOWN_PRINTER_DRIVER = 1797;
3181
21223182/// The print processor is unknown.
21233183pub const UNKNOWN_PRINTPROCESSOR = 1798;
3184
21243185/// The specified separator file is invalid.
21253186pub const INVALID_SEPARATOR_FILE = 1799;
3187
21263188/// The specified priority is invalid.
21273189pub const INVALID_PRIORITY = 1800;
3190
21283191/// The printer name is invalid.
21293192pub const INVALID_PRINTER_NAME = 1801;
3193
21303194/// The printer already exists.
21313195pub const PRINTER_ALREADY_EXISTS = 1802;
3196
21323197/// The printer command is invalid.
21333198pub const INVALID_PRINTER_COMMAND = 1803;
3199
21343200/// The specified datatype is invalid.
21353201pub const INVALID_DATATYPE = 1804;
3202
21363203/// The environment specified is invalid.
21373204pub const INVALID_ENVIRONMENT = 1805;
3205
21383206/// There are no more bindings.
21393207pub const RPC_S_NO_MORE_BINDINGS = 1806;
3208
21403209/// The account used is an interdomain trust account. Use your global user account or local user account to access this server.
21413210pub const NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 1807;
3211
21423212/// The account used is a computer account. Use your global user account or local user account to access this server.
21433213pub const NOLOGON_WORKSTATION_TRUST_ACCOUNT = 1808;
3214
21443215/// The account used is a server trust account. Use your global user account or local user account to access this server.
21453216pub const NOLOGON_SERVER_TRUST_ACCOUNT = 1809;
3217
21463218/// The name or security ID (SID) of the domain specified is inconsistent with the trust information for that domain.
21473219pub const DOMAIN_TRUST_INCONSISTENT = 1810;
3220
21483221/// The server is in use and cannot be unloaded.
21493222pub const SERVER_HAS_OPEN_HANDLES = 1811;
3223
21503224/// The specified image file did not contain a resource section.
21513225pub const RESOURCE_DATA_NOT_FOUND = 1812;
3226
21523227/// The specified resource type cannot be found in the image file.
21533228pub const RESOURCE_TYPE_NOT_FOUND = 1813;
3229
21543230/// The specified resource name cannot be found in the image file.
21553231pub const RESOURCE_NAME_NOT_FOUND = 1814;
3232
21563233/// The specified resource language ID cannot be found in the image file.
21573234pub const RESOURCE_LANG_NOT_FOUND = 1815;
3235
21583236/// Not enough quota is available to process this command.
21593237pub const NOT_ENOUGH_QUOTA = 1816;
3238
21603239/// No interfaces have been registered.
21613240pub const RPC_S_NO_INTERFACES = 1817;
3241
21623242/// The remote procedure call was cancelled.
21633243pub const RPC_S_CALL_CANCELLED = 1818;
3244
21643245/// The binding handle does not contain all required information.
21653246pub const RPC_S_BINDING_INCOMPLETE = 1819;
3247
21663248/// A communications failure occurred during a remote procedure call.
21673249pub const RPC_S_COMM_FAILURE = 1820;
3250
21683251/// The requested authentication level is not supported.
21693252pub const RPC_S_UNSUPPORTED_AUTHN_LEVEL = 1821;
3253
21703254/// No principal name registered.
21713255pub const RPC_S_NO_PRINC_NAME = 1822;
3256
21723257/// The error specified is not a valid Windows RPC error code.
21733258pub const RPC_S_NOT_RPC_ERROR = 1823;
3259
21743260/// A UUID that is valid only on this computer has been allocated.
21753261pub const RPC_S_UUID_LOCAL_ONLY = 1824;
3262
21763263/// A security package specific error occurred.
21773264pub const RPC_S_SEC_PKG_ERROR = 1825;
3265
21783266/// Thread is not canceled.
21793267pub const RPC_S_NOT_CANCELLED = 1826;
3268
21803269/// Invalid operation on the encoding/decoding handle.
21813270pub const RPC_X_INVALID_ES_ACTION = 1827;
3271
21823272/// Incompatible version of the serializing package.
21833273pub const RPC_X_WRONG_ES_VERSION = 1828;
3274
21843275/// Incompatible version of the RPC stub.
21853276pub const RPC_X_WRONG_STUB_VERSION = 1829;
3277
21863278/// The RPC pipe object is invalid or corrupted.
21873279pub const RPC_X_INVALID_PIPE_OBJECT = 1830;
3280
21883281/// An invalid operation was attempted on an RPC pipe object.
21893282pub const RPC_X_WRONG_PIPE_ORDER = 1831;
3283
21903284/// Unsupported RPC pipe version.
21913285pub const RPC_X_WRONG_PIPE_VERSION = 1832;
3286
21923287/// HTTP proxy server rejected the connection because the cookie authentication failed.
21933288pub const RPC_S_COOKIE_AUTH_FAILED = 1833;
3289
21943290/// The group member was not found.
21953291pub const RPC_S_GROUP_MEMBER_NOT_FOUND = 1898;
3292
21963293/// The endpoint mapper database entry could not be created.
21973294pub const EPT_S_CANT_CREATE = 1899;
3295
21983296/// The object universal unique identifier (UUID) is the nil UUID.
21993297pub const RPC_S_INVALID_OBJECT = 1900;
3298
22003299/// The specified time is invalid.
22013300pub const INVALID_TIME = 1901;
3301
22023302/// The specified form name is invalid.
22033303pub const INVALID_FORM_NAME = 1902;
3304
22043305/// The specified form size is invalid.
22053306pub const INVALID_FORM_SIZE = 1903;
3307
22063308/// The specified printer handle is already being waited on.
22073309pub const ALREADY_WAITING = 1904;
3310
22083311/// The specified printer has been deleted.
22093312pub const PRINTER_DELETED = 1905;
3313
22103314/// The state of the printer is invalid.
22113315pub const INVALID_PRINTER_STATE = 1906;
3316
22123317/// The user's password must be changed before signing in.
22133318pub const PASSWORD_MUST_CHANGE = 1907;
3319
22143320/// Could not find the domain controller for this domain.
22153321pub const DOMAIN_CONTROLLER_NOT_FOUND = 1908;
3322
22163323/// The referenced account is currently locked out and may not be logged on to.
22173324pub const ACCOUNT_LOCKED_OUT = 1909;
3325
22183326/// The object exporter specified was not found.
22193327pub const OR_INVALID_OXID = 1910;
3328
22203329/// The object specified was not found.
22213330pub const OR_INVALID_OID = 1911;
3331
22223332/// The object resolver set specified was not found.
22233333pub const OR_INVALID_SET = 1912;
3334
22243335/// Some data remains to be sent in the request buffer.
22253336pub const RPC_S_SEND_INCOMPLETE = 1913;
3337
22263338/// Invalid asynchronous remote procedure call handle.
22273339pub const RPC_S_INVALID_ASYNC_HANDLE = 1914;
3340
22283341/// Invalid asynchronous RPC call handle for this operation.
22293342pub const RPC_S_INVALID_ASYNC_CALL = 1915;
3343
22303344/// The RPC pipe object has already been closed.
22313345pub const RPC_X_PIPE_CLOSED = 1916;
3346
22323347/// The RPC call completed before all pipes were processed.
22333348pub const RPC_X_PIPE_DISCIPLINE_ERROR = 1917;
3349
22343350/// No more data is available from the RPC pipe.
22353351pub const RPC_X_PIPE_EMPTY = 1918;
3352
22363353/// No site name is available for this machine.
22373354pub const NO_SITENAME = 1919;
3355
22383356/// The file cannot be accessed by the system.
22393357pub const CANT_ACCESS_FILE = 1920;
3358
22403359/// The name of the file cannot be resolved by the system.
22413360pub const CANT_RESOLVE_FILENAME = 1921;
3361
22423362/// The entry is not of the expected type.
22433363pub const RPC_S_ENTRY_TYPE_MISMATCH = 1922;
3364
22443365/// Not all object UUIDs could be exported to the specified entry.
22453366pub const RPC_S_NOT_ALL_OBJS_EXPORTED = 1923;
3367
22463368/// Interface could not be exported to the specified entry.
22473369pub const RPC_S_INTERFACE_NOT_EXPORTED = 1924;
3370
22483371/// The specified profile entry could not be added.
22493372pub const RPC_S_PROFILE_NOT_ADDED = 1925;
3373
22503374/// The specified profile element could not be added.
22513375pub const RPC_S_PRF_ELT_NOT_ADDED = 1926;
3376
22523377/// The specified profile element could not be removed.
22533378pub const RPC_S_PRF_ELT_NOT_REMOVED = 1927;
3379
22543380/// The group element could not be added.
22553381pub const RPC_S_GRP_ELT_NOT_ADDED = 1928;
3382
22563383/// The group element could not be removed.
22573384pub const RPC_S_GRP_ELT_NOT_REMOVED = 1929;
3385
22583386/// The printer driver is not compatible with a policy enabled on your computer that blocks NT 4.0 drivers.
22593387pub const KM_DRIVER_BLOCKED = 1930;
3388
22603389/// The context has expired and can no longer be used.
22613390pub const CONTEXT_EXPIRED = 1931;
3391
22623392/// The current user's delegated trust creation quota has been exceeded.
22633393pub const PER_USER_TRUST_QUOTA_EXCEEDED = 1932;
3394
22643395/// The total delegated trust creation quota has been exceeded.
22653396pub const ALL_USER_TRUST_QUOTA_EXCEEDED = 1933;
3397
22663398/// The current user's delegated trust deletion quota has been exceeded.
22673399pub const USER_DELETE_TRUST_QUOTA_EXCEEDED = 1934;
3400
22683401/// The computer you are signing into is protected by an authentication firewall. The specified account is not allowed to authenticate to the computer.
22693402pub const AUTHENTICATION_FIREWALL_FAILED = 1935;
3403
22703404/// Remote connections to the Print Spooler are blocked by a policy set on your machine.
22713405pub const REMOTE_PRINT_CONNECTIONS_BLOCKED = 1936;
3406
22723407/// Authentication failed because NTLM authentication has been disabled.
22733408pub const NTLM_BLOCKED = 1937;
3409
22743410/// Logon Failure: EAS policy requires that the user change their password before this operation can be performed.
22753411pub const PASSWORD_CHANGE_REQUIRED = 1938;
3412
22763413/// The pixel format is invalid.
22773414pub const INVALID_PIXEL_FORMAT = 2000;
3415
22783416/// The specified driver is invalid.
22793417pub const BAD_DRIVER = 2001;
3418
22803419/// The window style or class attribute is invalid for this operation.
22813420pub const INVALID_WINDOW_STYLE = 2002;
3421
22823422/// The requested metafile operation is not supported.
22833423pub const METAFILE_NOT_SUPPORTED = 2003;
3424
22843425/// The requested transformation operation is not supported.
22853426pub const TRANSFORM_NOT_SUPPORTED = 2004;
3427
22863428/// The requested clipping operation is not supported.
22873429pub const CLIPPING_NOT_SUPPORTED = 2005;
3430
22883431/// The specified color management module is invalid.
22893432pub const INVALID_CMM = 2010;
3433
22903434/// The specified color profile is invalid.
22913435pub const INVALID_PROFILE = 2011;
3436
22923437/// The specified tag was not found.
22933438pub const TAG_NOT_FOUND = 2012;
3439
22943440/// A required tag is not present.
22953441pub const TAG_NOT_PRESENT = 2013;
3442
22963443/// The specified tag is already present.
22973444pub const DUPLICATE_TAG = 2014;
3445
22983446/// The specified color profile is not associated with the specified device.
22993447pub const PROFILE_NOT_ASSOCIATED_WITH_DEVICE = 2015;
3448
23003449/// The specified color profile was not found.
23013450pub const PROFILE_NOT_FOUND = 2016;
3451
23023452/// The specified color space is invalid.
23033453pub const INVALID_COLORSPACE = 2017;
3454
23043455/// Image Color Management is not enabled.
23053456pub const ICM_NOT_ENABLED = 2018;
3457
23063458/// There was an error while deleting the color transform.
23073459pub const DELETING_ICM_XFORM = 2019;
3460
23083461/// The specified color transform is invalid.
23093462pub const INVALID_TRANSFORM = 2020;
3463
23103464/// The specified transform does not match the bitmap's color space.
23113465pub const COLORSPACE_MISMATCH = 2021;
3466
23123467/// The specified named color index is not present in the profile.
23133468pub const INVALID_COLORINDEX = 2022;
3469
23143470/// The specified profile is intended for a device of a different type than the specified device.
23153471pub const PROFILE_DOES_NOT_MATCH_DEVICE = 2023;
3472
23163473/// The network connection was made successfully, but the user had to be prompted for a password other than the one originally specified.
23173474pub const CONNECTED_OTHER_PASSWORD = 2108;
3475
23183476/// The network connection was made successfully using default credentials.
23193477pub const CONNECTED_OTHER_PASSWORD_DEFAULT = 2109;
3478
23203479/// The specified username is invalid.
23213480pub const BAD_USERNAME = 2202;
3481
23223482/// This network connection does not exist.
23233483pub const NOT_CONNECTED = 2250;
3484
23243485/// This network connection has files open or requests pending.
23253486pub const OPEN_FILES = 2401;
3487
23263488/// Active connections still exist.
23273489pub const ACTIVE_CONNECTIONS = 2402;
3490
23283491/// The device is in use by an active process and cannot be disconnected.
23293492pub const DEVICE_IN_USE = 2404;
3493
23303494/// The specified print monitor is unknown.
23313495pub const UNKNOWN_PRINT_MONITOR = 3000;
3496
23323497/// The specified printer driver is currently in use.
23333498pub const PRINTER_DRIVER_IN_USE = 3001;
3499
23343500/// The spool file was not found.
23353501pub const SPOOL_FILE_NOT_FOUND = 3002;
3502
23363503/// A StartDocPrinter call was not issued.
23373504pub const SPL_NO_STARTDOC = 3003;
3505
23383506/// An AddJob call was not issued.
23393507pub const SPL_NO_ADDJOB = 3004;
3508
23403509/// The specified print processor has already been installed.
23413510pub const PRINT_PROCESSOR_ALREADY_INSTALLED = 3005;
3511
23423512/// The specified print monitor has already been installed.
23433513pub const PRINT_MONITOR_ALREADY_INSTALLED = 3006;
3514
23443515/// The specified print monitor does not have the required functions.
23453516pub const INVALID_PRINT_MONITOR = 3007;
3517
23463518/// The specified print monitor is currently in use.
23473519pub const PRINT_MONITOR_IN_USE = 3008;
3520
23483521/// The requested operation is not allowed when there are jobs queued to the printer.
23493522pub const PRINTER_HAS_JOBS_QUEUED = 3009;
3523
23503524/// The requested operation is successful. Changes will not be effective until the system is rebooted.
23513525pub const SUCCESS_REBOOT_REQUIRED = 3010;
3526
23523527/// The requested operation is successful. Changes will not be effective until the service is restarted.
23533528pub const SUCCESS_RESTART_REQUIRED = 3011;
3529
23543530/// No printers were found.
23553531pub const PRINTER_NOT_FOUND = 3012;
3532
23563533/// The printer driver is known to be unreliable.
23573534pub const PRINTER_DRIVER_WARNED = 3013;
3535
23583536/// The printer driver is known to harm the system.
23593537pub const PRINTER_DRIVER_BLOCKED = 3014;
3538
23603539/// The specified printer driver package is currently in use.
23613540pub const PRINTER_DRIVER_PACKAGE_IN_USE = 3015;
3541
23623542/// Unable to find a core driver package that is required by the printer driver package.
23633543pub const CORE_DRIVER_PACKAGE_NOT_FOUND = 3016;
3544
23643545/// The requested operation failed. A system reboot is required to roll back changes made.
23653546pub const FAIL_REBOOT_REQUIRED = 3017;
3547
23663548/// The requested operation failed. A system reboot has been initiated to roll back changes made.
23673549pub const FAIL_REBOOT_INITIATED = 3018;
3550
23683551/// The specified printer driver was not found on the system and needs to be downloaded.
23693552pub const PRINTER_DRIVER_DOWNLOAD_NEEDED = 3019;
3553
23703554/// The requested print job has failed to print. A print system update requires the job to be resubmitted.
23713555pub const PRINT_JOB_RESTART_REQUIRED = 3020;
3556
23723557/// The printer driver does not contain a valid manifest, or contains too many manifests.
23733558pub const INVALID_PRINTER_DRIVER_MANIFEST = 3021;
3559
23743560/// The specified printer cannot be shared.
23753561pub const PRINTER_NOT_SHAREABLE = 3022;
3562
23763563/// The operation was paused.
23773564pub const REQUEST_PAUSED = 3050;
3565
23783566/// Reissue the given operation as a cached IO operation.
23793567pub const IO_REISSUE_AS_CACHED = 3950;
std/os/windows/index.zig+189-149
......@@ -1,112 +1,18 @@
1pub const ERROR = @import("error.zig");
2
3pub extern "advapi32" stdcallcc fn CryptAcquireContextA(phProv: &HCRYPTPROV, pszContainer: ?LPCSTR,
4 pszProvider: ?LPCSTR, dwProvType: DWORD, dwFlags: DWORD) BOOL;
5
6pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL;
7
8pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) BOOL;
9
10
11pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
12
13pub extern "kernel32" stdcallcc fn CreateDirectoryA(lpPathName: LPCSTR,
14 lpSecurityAttributes: ?&SECURITY_ATTRIBUTES) BOOL;
15
16pub extern "kernel32" stdcallcc fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD,
17 dwShareMode: DWORD, lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD,
18 dwFlagsAndAttributes: DWORD, hTemplateFile: ?HANDLE) HANDLE;
19
20pub extern "kernel32" stdcallcc fn CreatePipe(hReadPipe: &HANDLE, hWritePipe: &HANDLE,
21 lpPipeAttributes: &const SECURITY_ATTRIBUTES, nSize: DWORD) BOOL;
22
23pub extern "kernel32" stdcallcc fn CreateProcessA(lpApplicationName: ?LPCSTR, lpCommandLine: LPSTR,
24 lpProcessAttributes: ?&SECURITY_ATTRIBUTES, lpThreadAttributes: ?&SECURITY_ATTRIBUTES, bInheritHandles: BOOL,
25 dwCreationFlags: DWORD, lpEnvironment: ?&c_void, lpCurrentDirectory: ?LPCSTR, lpStartupInfo: &STARTUPINFOA,
26 lpProcessInformation: &PROCESS_INFORMATION) BOOL;
27
28pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(lpSymlinkFileName: LPCSTR, lpTargetFileName: LPCSTR,
29 dwFlags: DWORD) BOOLEAN;
30
31pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
32
33pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
34
35pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: LPCH) BOOL;
36
37pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
38
39pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) BOOL;
40
41pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
42
43pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?LPCH;
44
45pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
46
47pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) BOOL;
48
49pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: &LARGE_INTEGER) BOOL;
50
51pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
52
53pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
54
55pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE,
56 in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, out_lpFileInformation: &c_void,
57 in_dwBufferSize: DWORD) BOOL;
58
59pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR,
60 cchFilePath: DWORD, dwFlags: DWORD) DWORD;
61
62pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
63
64pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
65pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
66pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void, dwBytes: SIZE_T) ?&c_void;
67pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: &const c_void) SIZE_T;
68pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: &const c_void) BOOL;
69pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
70pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
71
72pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
73
74pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?&c_void;
75
76pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void) BOOL;
77
78pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
79 dwFlags: DWORD) BOOL;
80
81pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
82
83pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,
84 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
85 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;
86
87pub extern "kernel32" stdcallcc fn SetFilePointerEx(in_fFile: HANDLE, in_liDistanceToMove: LARGE_INTEGER,
88 out_opt_ldNewFilePointer: ?&LARGE_INTEGER, in_dwMoveMethod: DWORD) BOOL;
89
90pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
91
92pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
1const std = @import("../../index.zig");
2const assert = std.debug.assert;
933
94pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
4pub use @import("advapi32.zig");
5pub use @import("kernel32.zig");
6pub use @import("ole32.zig");
7pub use @import("shell32.zig");
8pub use @import("shlwapi.zig");
9pub use @import("user32.zig");
9510
96pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
11test "import" {
12 _ = @import("util.zig");
13}
9714
98pub extern "kernel32" stdcallcc fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &const c_void,
99 in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD,
100 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;
101
102//TODO: call unicode versions instead of relying on ANSI code page
103pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
104
105pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
106
107pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
108
109pub const PROV_RSA_FULL = 1;
15pub const ERROR = @import("error.zig");
11016
11117pub const BOOL = c_int;
11218pub const BOOLEAN = BYTE;
......@@ -114,27 +20,29 @@ pub const BYTE = u8;
11420pub const CHAR = u8;
11521pub const DWORD = u32;
11622pub const FLOAT = f32;
117pub const HANDLE = &c_void;
23pub const HANDLE = *c_void;
11824pub const HCRYPTPROV = ULONG_PTR;
119pub const HINSTANCE = &@OpaqueType();
120pub const HMODULE = &@OpaqueType();
25pub const HINSTANCE = *@OpaqueType();
26pub const HMODULE = *@OpaqueType();
12127pub const INT = c_int;
122pub const LPBYTE = &BYTE;
123pub const LPCH = &CHAR;
124pub const LPCSTR = &const CHAR;
125pub const LPCTSTR = &const TCHAR;
126pub const LPCVOID = &const c_void;
127pub const LPDWORD = &DWORD;
128pub const LPSTR = &CHAR;
28pub const LPBYTE = *BYTE;
29pub const LPCH = *CHAR;
30pub const LPCSTR = [*]const CHAR;
31pub const LPCTSTR = [*]const TCHAR;
32pub const LPCVOID = *const c_void;
33pub const LPDWORD = *DWORD;
34pub const LPSTR = [*]CHAR;
12935pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
130pub const LPVOID = &c_void;
131pub const LPWSTR = &WCHAR;
132pub const PVOID = &c_void;
133pub const PWSTR = &WCHAR;
36pub const LPVOID = *c_void;
37pub const LPWSTR = [*]WCHAR;
38pub const LPCWSTR = [*]const WCHAR;
39pub const PVOID = *c_void;
40pub const PWSTR = [*]WCHAR;
13441pub const SIZE_T = usize;
13542pub const TCHAR = if (UNICODE) WCHAR else u8;
13643pub const UINT = c_uint;
13744pub const ULONG_PTR = usize;
45pub const DWORD_PTR = ULONG_PTR;
13846pub const UNICODE = false;
13947pub const WCHAR = u16;
14048pub const WORD = u16;
......@@ -154,69 +62,72 @@ pub const STD_ERROR_HANDLE = @maxValue(DWORD) - 12 + 1;
15462
15563pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, @maxValue(usize));
15664
65pub const INVALID_FILE_ATTRIBUTES = DWORD(@maxValue(DWORD));
66
15767pub const OVERLAPPED = extern struct {
15868 Internal: ULONG_PTR,
15969 InternalHigh: ULONG_PTR,
16070 Pointer: PVOID,
16171 hEvent: HANDLE,
16272};
163pub const LPOVERLAPPED = &OVERLAPPED;
73pub const LPOVERLAPPED = *OVERLAPPED;
16474
16575pub const MAX_PATH = 260;
16676
16777// TODO issue #305
16878pub const FILE_INFO_BY_HANDLE_CLASS = u32;
169pub const FileBasicInfo = 0;
170pub const FileStandardInfo = 1;
171pub const FileNameInfo = 2;
172pub const FileRenameInfo = 3;
173pub const FileDispositionInfo = 4;
174pub const FileAllocationInfo = 5;
175pub const FileEndOfFileInfo = 6;
176pub const FileStreamInfo = 7;
177pub const FileCompressionInfo = 8;
178pub const FileAttributeTagInfo = 9;
179pub const FileIdBothDirectoryInfo = 10;
180pub const FileIdBothDirectoryRestartInfo = 11;
181pub const FileIoPriorityHintInfo = 12;
182pub const FileRemoteProtocolInfo = 13;
183pub const FileFullDirectoryInfo = 14;
184pub const FileFullDirectoryRestartInfo = 15;
185pub const FileStorageInfo = 16;
186pub const FileAlignmentInfo = 17;
187pub const FileIdInfo = 18;
188pub const FileIdExtdDirectoryInfo = 19;
189pub const FileIdExtdDirectoryRestartInfo = 20;
79pub const FileBasicInfo = 0;
80pub const FileStandardInfo = 1;
81pub const FileNameInfo = 2;
82pub const FileRenameInfo = 3;
83pub const FileDispositionInfo = 4;
84pub const FileAllocationInfo = 5;
85pub const FileEndOfFileInfo = 6;
86pub const FileStreamInfo = 7;
87pub const FileCompressionInfo = 8;
88pub const FileAttributeTagInfo = 9;
89pub const FileIdBothDirectoryInfo = 10;
90pub const FileIdBothDirectoryRestartInfo = 11;
91pub const FileIoPriorityHintInfo = 12;
92pub const FileRemoteProtocolInfo = 13;
93pub const FileFullDirectoryInfo = 14;
94pub const FileFullDirectoryRestartInfo = 15;
95pub const FileStorageInfo = 16;
96pub const FileAlignmentInfo = 17;
97pub const FileIdInfo = 18;
98pub const FileIdExtdDirectoryInfo = 19;
99pub const FileIdExtdDirectoryRestartInfo = 20;
190100
191101pub const FILE_NAME_INFO = extern struct {
192102 FileNameLength: DWORD,
193103 FileName: [1]WCHAR,
194104};
195105
196
197106/// Return the normalized drive name. This is the default.
198107pub const FILE_NAME_NORMALIZED = 0x0;
108
199109/// Return the opened file name (not normalized).
200110pub const FILE_NAME_OPENED = 0x8;
201111
202112/// Return the path with the drive letter. This is the default.
203113pub const VOLUME_NAME_DOS = 0x0;
114
204115/// Return the path with a volume GUID path instead of the drive name.
205116pub const VOLUME_NAME_GUID = 0x1;
117
206118/// Return the path with no drive information.
207119pub const VOLUME_NAME_NONE = 0x4;
120
208121/// Return the path with the volume device path.
209122pub const VOLUME_NAME_NT = 0x2;
210123
211
212124pub const SECURITY_ATTRIBUTES = extern struct {
213125 nLength: DWORD,
214 lpSecurityDescriptor: ?&c_void,
126 lpSecurityDescriptor: ?*c_void,
215127 bInheritHandle: BOOL,
216128};
217pub const PSECURITY_ATTRIBUTES = &SECURITY_ATTRIBUTES;
218pub const LPSECURITY_ATTRIBUTES = &SECURITY_ATTRIBUTES;
219
129pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
130pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
220131
221132pub const GENERIC_READ = 0x80000000;
222133pub const GENERIC_WRITE = 0x40000000;
......@@ -233,15 +144,25 @@ pub const OPEN_ALWAYS = 4;
233144pub const OPEN_EXISTING = 3;
234145pub const TRUNCATE_EXISTING = 5;
235146
236
237147pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
148pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
149pub const FILE_ATTRIBUTE_DEVICE = 0x40;
150pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
238151pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
239152pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
153pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
240154pub const FILE_ATTRIBUTE_NORMAL = 0x80;
155pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
156pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
241157pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
242158pub const FILE_ATTRIBUTE_READONLY = 0x1;
159pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
160pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
161pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
162pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
243163pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
244164pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
165pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
245166
246167pub const PROCESS_INFORMATION = extern struct {
247168 hProcess: HANDLE,
......@@ -310,3 +231,122 @@ pub const FILE_END = 2;
310231pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
311232pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
312233pub const HEAP_NO_SERIALIZE = 0x00000001;
234
235pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
236pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
237
238pub const WIN32_FIND_DATAA = extern struct {
239 dwFileAttributes: DWORD,
240 ftCreationTime: FILETIME,
241 ftLastAccessTime: FILETIME,
242 ftLastWriteTime: FILETIME,
243 nFileSizeHigh: DWORD,
244 nFileSizeLow: DWORD,
245 dwReserved0: DWORD,
246 dwReserved1: DWORD,
247 cFileName: [260]CHAR,
248 cAlternateFileName: [14]CHAR,
249};
250
251pub const FILETIME = extern struct {
252 dwLowDateTime: DWORD,
253 dwHighDateTime: DWORD,
254};
255
256pub const SYSTEM_INFO = extern struct {
257 anon1: extern union {
258 dwOemId: DWORD,
259 anon2: extern struct {
260 wProcessorArchitecture: WORD,
261 wReserved: WORD,
262 },
263 },
264 dwPageSize: DWORD,
265 lpMinimumApplicationAddress: LPVOID,
266 lpMaximumApplicationAddress: LPVOID,
267 dwActiveProcessorMask: DWORD_PTR,
268 dwNumberOfProcessors: DWORD,
269 dwProcessorType: DWORD,
270 dwAllocationGranularity: DWORD,
271 wProcessorLevel: WORD,
272 wProcessorRevision: WORD,
273};
274
275pub const HRESULT = c_long;
276
277pub const KNOWNFOLDERID = GUID;
278pub const GUID = extern struct {
279 Data1: c_ulong,
280 Data2: c_ushort,
281 Data3: c_ushort,
282 Data4: [8]u8,
283
284 pub fn parse(str: []const u8) GUID {
285 var guid: GUID = undefined;
286 var index: usize = 0;
287 assert(str[index] == '{');
288 index += 1;
289
290 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index..index + 8], 16) catch unreachable;
291 index += 8;
292
293 assert(str[index] == '-');
294 index += 1;
295
296 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable;
297 index += 4;
298
299 assert(str[index] == '-');
300 index += 1;
301
302 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable;
303 index += 4;
304
305 assert(str[index] == '-');
306 index += 1;
307
308 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;
309 index += 2;
310 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;
311 index += 2;
312
313 assert(str[index] == '-');
314 index += 1;
315
316 var i: usize = 2;
317 while (i < guid.Data4.len) : (i += 1) {
318 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;
319 index += 2;
320 }
321
322 assert(str[index] == '}');
323 index += 1;
324 return guid;
325 }
326};
327
328pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
329
330pub const KF_FLAG_DEFAULT = 0;
331pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
332pub const KF_FLAG_CREATE = 32768;
333pub const KF_FLAG_DONT_VERIFY = 16384;
334pub const KF_FLAG_DONT_UNEXPAND = 8192;
335pub const KF_FLAG_NO_ALIAS = 4096;
336pub const KF_FLAG_INIT = 2048;
337pub const KF_FLAG_DEFAULT_PATH = 1024;
338pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
339pub const KF_FLAG_SIMPLE_IDLIST = 256;
340pub const KF_FLAG_ALIAS_ONLY = -2147483648;
341
342pub const S_OK = 0;
343pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
344pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
345pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
346pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
347pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
348pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
349pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
350pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
351pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
352pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
std/os/windows/kernel32.zig created+162
......@@ -0,0 +1,162 @@
1use @import("index.zig");
2
3pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
4
5pub extern "kernel32" stdcallcc fn CreateDirectoryA(
6 lpPathName: LPCSTR,
7 lpSecurityAttributes: ?*SECURITY_ATTRIBUTES,
8) BOOL;
9
10pub extern "kernel32" stdcallcc fn CreateFileA(
11 lpFileName: LPCSTR,
12 dwDesiredAccess: DWORD,
13 dwShareMode: DWORD,
14 lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
15 dwCreationDisposition: DWORD,
16 dwFlagsAndAttributes: DWORD,
17 hTemplateFile: ?HANDLE,
18) HANDLE;
19
20pub extern "kernel32" stdcallcc fn CreatePipe(
21 hReadPipe: *HANDLE,
22 hWritePipe: *HANDLE,
23 lpPipeAttributes: *const SECURITY_ATTRIBUTES,
24 nSize: DWORD,
25) BOOL;
26
27pub extern "kernel32" stdcallcc fn CreateProcessA(
28 lpApplicationName: ?LPCSTR,
29 lpCommandLine: LPSTR,
30 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
31 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
32 bInheritHandles: BOOL,
33 dwCreationFlags: DWORD,
34 lpEnvironment: ?*c_void,
35 lpCurrentDirectory: ?LPCSTR,
36 lpStartupInfo: *STARTUPINFOA,
37 lpProcessInformation: *PROCESS_INFORMATION,
38) BOOL;
39
40pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(
41 lpSymlinkFileName: LPCSTR,
42 lpTargetFileName: LPCSTR,
43 dwFlags: DWORD,
44) BOOLEAN;
45
46pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;
47
48pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;
49
50pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
51
52pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
53
54pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
55pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
56pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
57
58pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
59
60pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
61
62pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
63
64pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
65
66pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
67
68pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
69
70pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
71
72pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
73
74pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
75
76pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
77
78pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
79
80pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
81 in_hFile: HANDLE,
82 in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
83 out_lpFileInformation: *c_void,
84 in_dwBufferSize: DWORD,
85) BOOL;
86
87pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
88 hFile: HANDLE,
89 lpszFilePath: LPSTR,
90 cchFilePath: DWORD,
91 dwFlags: DWORD,
92) DWORD;
93
94pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
95pub extern "kernel32" stdcallcc fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) BOOL;
96
97pub extern "kernel32" stdcallcc fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) void;
98pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
99
100pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
101pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
102pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
103pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
104pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
105pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
106pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
107
108pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
109
110pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
111
112pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
113
114pub extern "kernel32" stdcallcc fn MoveFileExA(
115 lpExistingFileName: LPCSTR,
116 lpNewFileName: LPCSTR,
117 dwFlags: DWORD,
118) BOOL;
119
120pub extern "kernel32" stdcallcc fn PostQueuedCompletionStatus(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: ULONG_PTR, lpOverlapped: ?*OVERLAPPED) BOOL;
121
122pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *LARGE_INTEGER) BOOL;
123
124pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
125
126pub extern "kernel32" stdcallcc fn ReadFile(
127 in_hFile: HANDLE,
128 out_lpBuffer: *c_void,
129 in_nNumberOfBytesToRead: DWORD,
130 out_lpNumberOfBytesRead: *DWORD,
131 in_out_lpOverlapped: ?*OVERLAPPED,
132) BOOL;
133
134pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
135
136pub extern "kernel32" stdcallcc fn SetFilePointerEx(
137 in_fFile: HANDLE,
138 in_liDistanceToMove: LARGE_INTEGER,
139 out_opt_ldNewFilePointer: ?*LARGE_INTEGER,
140 in_dwMoveMethod: DWORD,
141) BOOL;
142
143pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
144
145pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
146
147pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
148
149pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
150
151pub extern "kernel32" stdcallcc fn WriteFile(
152 in_hFile: HANDLE,
153 in_lpBuffer: *const c_void,
154 in_nNumberOfBytesToWrite: DWORD,
155 out_lpNumberOfBytesWritten: ?*DWORD,
156 in_out_lpOverlapped: ?*OVERLAPPED,
157) BOOL;
158
159//TODO: call unicode versions instead of relying on ANSI code page
160pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
161
162pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
std/os/windows/ole32.zig created+18
......@@ -0,0 +1,18 @@
1use @import("index.zig");
2
3pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
4pub extern "ole32.dll" stdcallcc fn CoUninitialize() void;
5pub extern "ole32.dll" stdcallcc fn CoGetCurrentProcess() DWORD;
6pub extern "ole32.dll" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;
7
8
9pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
10pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
11pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
12pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
13pub const COINIT = extern enum {
14 COINIT_APARTMENTTHREADED = 2,
15 COINIT_MULTITHREADED = 0,
16 COINIT_DISABLE_OLE1DDE = 4,
17 COINIT_SPEED_OVER_MEMORY = 8,
18};
std/os/windows/shell32.zig created+4
......@@ -0,0 +1,4 @@
1use @import("index.zig");
2
3pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
4
std/os/windows/shlwapi.zig created+4
......@@ -0,0 +1,4 @@
1use @import("index.zig");
2
3pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
4
std/os/windows/user32.zig created+4
......@@ -0,0 +1,4 @@
1use @import("index.zig");
2
3pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
4
std/os/windows/util.zig+110-25
......@@ -7,7 +7,7 @@ const mem = std.mem;
77const BufMap = std.BufMap;
88const cstr = std.cstr;
99
10pub const WaitError = error {
10pub const WaitError = error{
1111 WaitAbandoned,
1212 WaitTimeOut,
1313 Unexpected,
......@@ -33,7 +33,7 @@ pub fn windowsClose(handle: windows.HANDLE) void {
3333 assert(windows.CloseHandle(handle) != 0);
3434}
3535
36pub const WriteError = error {
36pub const WriteError = error{
3737 SystemResources,
3838 OperationAborted,
3939 IoPending,
......@@ -42,7 +42,7 @@ pub const WriteError = error {
4242};
4343
4444pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
45 if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
45 if (windows.WriteFile(handle, @ptrCast(*const c_void, bytes.ptr), @intCast(u32, bytes.len), null, null) == 0) {
4646 const err = windows.GetLastError();
4747 return switch (err) {
4848 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
......@@ -68,20 +68,23 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
6868 const size = @sizeOf(windows.FILE_NAME_INFO);
6969 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
7070
71 if (windows.GetFileInformationByHandleEx(handle, windows.FileNameInfo,
72 @ptrCast(&c_void, &name_info_bytes[0]), u32(name_info_bytes.len)) == 0)
73 {
71 if (windows.GetFileInformationByHandleEx(
72 handle,
73 windows.FileNameInfo,
74 @ptrCast(*c_void, &name_info_bytes[0]),
75 @intCast(u32, name_info_bytes.len),
76 ) == 0) {
7477 return true;
7578 }
7679
77 const name_info = @ptrCast(&const windows.FILE_NAME_INFO, &name_info_bytes[0]);
78 const name_bytes = name_info_bytes[size..size + usize(name_info.FileNameLength)];
79 const name_wide = ([]u16)(name_bytes);
80 return mem.indexOf(u16, name_wide, []u16{'m','s','y','s','-'}) != null or
81 mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null;
80 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
81 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
82 const name_wide = @bytesToSlice(u16, name_bytes);
83 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
84 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
8285}
8386
84pub const OpenError = error {
87pub const OpenError = error{
8588 SharingViolation,
8689 PathAlreadyExists,
8790 FileNotFound,
......@@ -92,15 +95,18 @@ pub const OpenError = error {
9295};
9396
9497/// `file_path` needs to be copied in memory to add a null terminating byte, hence the allocator.
95pub fn windowsOpen(allocator: &mem.Allocator, file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,
96 creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD)
97 OpenError!windows.HANDLE
98{
98pub fn windowsOpen(
99 allocator: *mem.Allocator,
100 file_path: []const u8,
101 desired_access: windows.DWORD,
102 share_mode: windows.DWORD,
103 creation_disposition: windows.DWORD,
104 flags_and_attrs: windows.DWORD,
105) OpenError!windows.HANDLE {
99106 const path_with_null = try cstr.addNullByte(allocator, file_path);
100107 defer allocator.free(path_with_null);
101108
102 const result = windows.CreateFileA(path_with_null.ptr, desired_access, share_mode, null, creation_disposition,
103 flags_and_attrs, null);
109 const result = windows.CreateFileA(path_with_null.ptr, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
104110
105111 if (result == windows.INVALID_HANDLE_VALUE) {
106112 const err = windows.GetLastError();
......@@ -118,7 +124,7 @@ pub fn windowsOpen(allocator: &mem.Allocator, file_path: []const u8, desired_acc
118124}
119125
120126/// Caller must free result.
121pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) ![]u8 {
127pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u8 {
122128 // count bytes needed
123129 const bytes_needed = x: {
124130 var bytes_needed: usize = 1; // 1 for the final null byte
......@@ -149,25 +155,104 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
149155 return result;
150156}
151157
152pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) !windows.HMODULE {
158pub fn windowsLoadDll(allocator: *mem.Allocator, dll_path: []const u8) !windows.HMODULE {
153159 const padded_buff = try cstr.addNullByte(allocator, dll_path);
154160 defer allocator.free(padded_buff);
155 return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
161 return windows.LoadLibraryA(padded_buff.ptr) orelse error.DllNotFound;
156162}
157163
158164pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
159 assert(windows.FreeLibrary(hModule)!= 0);
165 assert(windows.FreeLibrary(hModule) != 0);
160166}
161167
162
163168test "InvalidDll" {
164 if (builtin.os != builtin.Os.windows) return;
169 if (builtin.os != builtin.Os.windows) return error.SkipZigTest;
165170
166171 const DllName = "asdf.dll";
167172 const allocator = std.debug.global_allocator;
168 const handle = os.windowsLoadDll(allocator, DllName) catch |err| {
173 const handle = os.windowsLoadDll(allocator, DllName) catch |err| {
169174 assert(err == error.DllNotFound);
170175 return;
171176 };
172177}
173178
179pub fn windowsFindFirstFile(
180 allocator: *mem.Allocator,
181 dir_path: []const u8,
182 find_file_data: *windows.WIN32_FIND_DATAA,
183) !windows.HANDLE {
184 const wild_and_null = []u8{ '\\', '*', 0 };
185 const path_with_wild_and_null = try allocator.alloc(u8, dir_path.len + wild_and_null.len);
186 defer allocator.free(path_with_wild_and_null);
187
188 mem.copy(u8, path_with_wild_and_null, dir_path);
189 mem.copy(u8, path_with_wild_and_null[dir_path.len..], wild_and_null);
190
191 const handle = windows.FindFirstFileA(path_with_wild_and_null.ptr, find_file_data);
192
193 if (handle == windows.INVALID_HANDLE_VALUE) {
194 const err = windows.GetLastError();
195 switch (err) {
196 windows.ERROR.FILE_NOT_FOUND,
197 windows.ERROR.PATH_NOT_FOUND,
198 => return error.PathNotFound,
199 else => return os.unexpectedErrorWindows(err),
200 }
201 }
202
203 return handle;
204}
205
206/// Returns `true` if there was another file, `false` otherwise.
207pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAA) !bool {
208 if (windows.FindNextFileA(handle, find_file_data) == 0) {
209 const err = windows.GetLastError();
210 return switch (err) {
211 windows.ERROR.NO_MORE_FILES => false,
212 else => os.unexpectedErrorWindows(err),
213 };
214 }
215 return true;
216}
217
218pub const WindowsCreateIoCompletionPortError = error{Unexpected};
219
220pub fn windowsCreateIoCompletionPort(file_handle: windows.HANDLE, existing_completion_port: ?windows.HANDLE, completion_key: usize, concurrent_thread_count: windows.DWORD) !windows.HANDLE {
221 const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
222 const err = windows.GetLastError();
223 switch (err) {
224 else => return os.unexpectedErrorWindows(err),
225 }
226 };
227 return handle;
228}
229
230pub const WindowsPostQueuedCompletionStatusError = error{Unexpected};
231
232pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void {
233 if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
234 const err = windows.GetLastError();
235 switch (err) {
236 else => return os.unexpectedErrorWindows(err),
237 }
238 }
239}
240
241pub const WindowsWaitResult = error{
242 Normal,
243 Aborted,
244};
245
246pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult {
247 if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) {
248 if (std.debug.runtime_safety) {
249 const err = windows.GetLastError();
250 if (err != windows.ERROR.ABANDONED_WAIT_0) {
251 std.debug.warn("err: {}\n", err);
252 }
253 assert(err == windows.ERROR.ABANDONED_WAIT_0);
254 }
255 return WindowsWaitResult.Aborted;
256 }
257 return WindowsWaitResult.Normal;
258}
std/os/zen.zig+69-55
......@@ -6,26 +6,26 @@ const assert = std.debug.assert;
66//////////////////////////
77
88pub const Message = struct {
9 sender: MailboxId,
9 sender: MailboxId,
1010 receiver: MailboxId,
1111 code: usize,
1212 args: [5]usize,
1313 payload: ?[]const u8,
1414
15 pub fn from(mailbox_id: &const MailboxId) Message {
16 return Message {
17 .sender = MailboxId.Undefined,
18 .receiver = *mailbox_id,
15 pub fn from(mailbox_id: *const MailboxId) Message {
16 return Message{
17 .sender = MailboxId.Undefined,
18 .receiver = mailbox_id.*,
1919 .code = undefined,
2020 .args = undefined,
2121 .payload = null,
2222 };
2323 }
2424
25 pub fn to(mailbox_id: &const MailboxId, msg_code: usize, args: ...) Message {
25 pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message {
2626 var message = Message {
2727 .sender = MailboxId.This,
28 .receiver = *mailbox_id,
28 .receiver = mailbox_id.*,
2929 .code = msg_code,
3030 .args = undefined,
3131 .payload = null,
......@@ -40,14 +40,14 @@ pub const Message = struct {
4040 return message;
4141 }
4242
43 pub fn as(self: &const Message, sender: &const MailboxId) Message {
44 var message = *self;
45 message.sender = *sender;
43 pub fn as(self: *const Message, sender: *const MailboxId) Message {
44 var message = self.*;
45 message.sender = sender.*;
4646 return message;
4747 }
4848
49 pub fn withPayload(self: &const Message, payload: []const u8) Message {
50 var message = *self;
49 pub fn withPayload(self: *const Message, payload: []const u8) Message {
50 var message = self.*;
5151 message.payload = payload;
5252 return message;
5353 }
......@@ -57,27 +57,25 @@ pub const MailboxId = union(enum) {
5757 Undefined,
5858 This,
5959 Kernel,
60 Port: u16,
60 Port: u16,
6161 Thread: u16,
6262};
6363
64
6564//////////////////////////////////////
6665//// Ports reserved for servers ////
6766//////////////////////////////////////
6867
6968pub const Server = struct {
70 pub const Keyboard = MailboxId { .Port = 0 };
71 pub const Terminal = MailboxId { .Port = 1 };
69 pub const Keyboard = MailboxId{ .Port = 0 };
70 pub const Terminal = MailboxId{ .Port = 1 };
7271};
7372
74
7573////////////////////////
7674//// POSIX things ////
7775////////////////////////
7876
7977// Standard streams.
80pub const STDIN_FILENO = 0;
78pub const STDIN_FILENO = 0;
8179pub const STDOUT_FILENO = 1;
8280pub const STDERR_FILENO = 2;
8381
......@@ -86,7 +84,7 @@ pub const getErrno = @import("linux/index.zig").getErrno;
8684use @import("linux/errno.zig");
8785
8886// TODO: implement this correctly.
89pub fn read(fd: i32, buf: &u8, count: usize) usize {
87pub fn read(fd: i32, buf: *u8, count: usize) usize {
9088 switch (fd) {
9189 STDIN_FILENO => {
9290 var i: usize = 0;
......@@ -95,7 +93,7 @@ pub fn read(fd: i32, buf: &u8, count: usize) usize {
9593
9694 // FIXME: we should be certain that we are receiving from Keyboard.
9795 var message = Message.from(MailboxId.This);
98 receive(&message);
96 receive(message.*);
9997
10098 buf[i] = u8(message.args[0]);
10199 }
......@@ -106,7 +104,7 @@ pub fn read(fd: i32, buf: &u8, count: usize) usize {
106104}
107105
108106// TODO: implement this correctly.
109pub fn write(fd: i32, buf: &const u8, count: usize) usize {
107pub fn write(fd: i32, buf: *const u8, count: usize) usize {
110108 switch (fd) {
111109 STDOUT_FILENO, STDERR_FILENO => {
112110 send(Message.to(Server.Terminal, 1)
......@@ -117,7 +115,6 @@ pub fn write(fd: i32, buf: &const u8, count: usize) usize {
117115 return count;
118116}
119117
120
121118///////////////////////////
122119//// Syscall numbers ////
123120///////////////////////////
......@@ -133,7 +130,6 @@ pub const Syscall = enum(usize) {
133130 createThread = 7,
134131};
135132
136
137133////////////////////
138134//// Syscalls ////
139135////////////////////
......@@ -143,15 +139,15 @@ pub fn exit(status: i32) noreturn {
143139 unreachable;
144140}
145141
146pub fn send(message: &const Message) void {
142pub fn send(message: *const Message) void {
147143 _ = syscall1(Syscall.send, @ptrToInt(message));
148144}
149145
150pub fn receive(destination: &Message) void {
146pub fn receive(destination: *Message) void {
151147 _ = syscall1(Syscall.receive, @ptrToInt(destination));
152148}
153149
154pub fn subscribeIRQ(irq: u8, mailbox_id: &const MailboxId) void {
150pub fn subscribeIRQ(irq: u8, mailbox_id: *const MailboxId) void {
155151 _ = syscall2(Syscall.subscribeIRQ, irq, @ptrToInt(mailbox_id));
156152}
157153
......@@ -167,7 +163,7 @@ pub fn map(v_addr: usize, p_addr: usize, size: usize, writable: bool) bool {
167163 return syscall4(Syscall.map, v_addr, p_addr, size, usize(writable)) != 0;
168164}
169165
170pub fn createThread(function: fn()void) u16 {
166pub fn createThread(function: fn () void) u16 {
171167 return u16(syscall1(Syscall.createThread, @ptrToInt(function)));
172168}
173169
......@@ -178,66 +174,84 @@ pub fn createThread(function: fn()void) u16 {
178174inline fn syscall0(number: Syscall) usize {
179175 return asm volatile ("int $0x80"
180176 : [ret] "={eax}" (-> usize)
181 : [number] "{eax}" (number));
177 : [number] "{eax}" (number)
178 );
182179}
183180
184181inline fn syscall1(number: Syscall, arg1: usize) usize {
185182 return asm volatile ("int $0x80"
186183 : [ret] "={eax}" (-> usize)
187184 : [number] "{eax}" (number),
188 [arg1] "{ecx}" (arg1));
185 [arg1] "{ecx}" (arg1)
186 );
189187}
190188
191189inline fn syscall2(number: Syscall, arg1: usize, arg2: usize) usize {
192190 return asm volatile ("int $0x80"
193191 : [ret] "={eax}" (-> usize)
194192 : [number] "{eax}" (number),
195 [arg1] "{ecx}" (arg1),
196 [arg2] "{edx}" (arg2));
193 [arg1] "{ecx}" (arg1),
194 [arg2] "{edx}" (arg2)
195 );
197196}
198197
199198inline fn syscall3(number: Syscall, arg1: usize, arg2: usize, arg3: usize) usize {
200199 return asm volatile ("int $0x80"
201200 : [ret] "={eax}" (-> usize)
202201 : [number] "{eax}" (number),
203 [arg1] "{ecx}" (arg1),
204 [arg2] "{edx}" (arg2),
205 [arg3] "{ebx}" (arg3));
202 [arg1] "{ecx}" (arg1),
203 [arg2] "{edx}" (arg2),
204 [arg3] "{ebx}" (arg3)
205 );
206206}
207207
208208inline fn syscall4(number: Syscall, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
209209 return asm volatile ("int $0x80"
210210 : [ret] "={eax}" (-> usize)
211211 : [number] "{eax}" (number),
212 [arg1] "{ecx}" (arg1),
213 [arg2] "{edx}" (arg2),
214 [arg3] "{ebx}" (arg3),
215 [arg4] "{esi}" (arg4));
212 [arg1] "{ecx}" (arg1),
213 [arg2] "{edx}" (arg2),
214 [arg3] "{ebx}" (arg3),
215 [arg4] "{esi}" (arg4)
216 );
216217}
217218
218inline fn syscall5(number: Syscall, arg1: usize, arg2: usize, arg3: usize,
219 arg4: usize, arg5: usize) usize
220{
219inline fn syscall5(
220 number: Syscall,
221 arg1: usize,
222 arg2: usize,
223 arg3: usize,
224 arg4: usize,
225 arg5: usize,
226) usize {
221227 return asm volatile ("int $0x80"
222228 : [ret] "={eax}" (-> usize)
223229 : [number] "{eax}" (number),
224 [arg1] "{ecx}" (arg1),
225 [arg2] "{edx}" (arg2),
226 [arg3] "{ebx}" (arg3),
227 [arg4] "{esi}" (arg4),
228 [arg5] "{edi}" (arg5));
230 [arg1] "{ecx}" (arg1),
231 [arg2] "{edx}" (arg2),
232 [arg3] "{ebx}" (arg3),
233 [arg4] "{esi}" (arg4),
234 [arg5] "{edi}" (arg5)
235 );
229236}
230237
231inline fn syscall6(number: Syscall, arg1: usize, arg2: usize, arg3: usize,
232 arg4: usize, arg5: usize, arg6: usize) usize
233{
238inline fn syscall6(
239 number: Syscall,
240 arg1: usize,
241 arg2: usize,
242 arg3: usize,
243 arg4: usize,
244 arg5: usize,
245 arg6: usize,
246) usize {
234247 return asm volatile ("int $0x80"
235248 : [ret] "={eax}" (-> usize)
236249 : [number] "{eax}" (number),
237 [arg1] "{ecx}" (arg1),
238 [arg2] "{edx}" (arg2),
239 [arg3] "{ebx}" (arg3),
240 [arg4] "{esi}" (arg4),
241 [arg5] "{edi}" (arg5),
242 [arg6] "{ebp}" (arg6));
250 [arg1] "{ecx}" (arg1),
251 [arg2] "{edx}" (arg2),
252 [arg3] "{ebx}" (arg3),
253 [arg4] "{esi}" (arg4),
254 [arg5] "{edi}" (arg5),
255 [arg6] "{ebp}" (arg6)
256 );
243257}
std/rand/index.zig+109-78
......@@ -19,6 +19,7 @@ const builtin = @import("builtin");
1919const assert = std.debug.assert;
2020const mem = std.mem;
2121const math = std.math;
22const ziggurat = @import("ziggurat.zig");
2223
2324// When you need fast unbiased random numbers
2425pub const DefaultPrng = Xoroshiro128;
......@@ -27,15 +28,15 @@ pub const DefaultPrng = Xoroshiro128;
2728pub const DefaultCsprng = Isaac64;
2829
2930pub const Random = struct {
30 fillFn: fn(r: &Random, buf: []u8) void,
31 fillFn: fn (r: *Random, buf: []u8) void,
3132
32 /// Read random bytes into the specified buffer until fill.
33 pub fn bytes(r: &Random, buf: []u8) void {
33 /// Read random bytes into the specified buffer until full.
34 pub fn bytes(r: *Random, buf: []u8) void {
3435 r.fillFn(r, buf);
3536 }
3637
3738 /// Return a random integer/boolean type.
38 pub fn scalar(r: &Random, comptime T: type) T {
39 pub fn scalar(r: *Random, comptime T: type) T {
3940 var rand_bytes: [@sizeOf(T)]u8 = undefined;
4041 r.bytes(rand_bytes[0..]);
4142
......@@ -47,28 +48,28 @@ pub const Random = struct {
4748 }
4849 }
4950
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);
51 /// Return a random integer with even distribution between `start`
52 /// inclusive and `end` exclusive. `start` must be less than `end`.
53 pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
54 assert(start < end);
5455 if (T.is_signed) {
5556 const uint = @IntType(false, T.bit_count);
5657 if (start >= 0 and end >= 0) {
57 return T(r.range(uint, uint(start), uint(end)));
58 return @intCast(T, r.range(uint, @intCast(uint, start), @intCast(uint, end)));
5859 } else if (start < 0 and end < 0) {
5960 // Can't overflow because the range is over signed ints
6061 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
6162 } else if (start < 0 and end >= 0) {
62 const end_uint = uint(end);
63 const end_uint = @intCast(uint, end);
6364 const total_range = math.absCast(start) + end_uint;
6465 const value = r.range(uint, 0, total_range);
6566 const result = if (value < end_uint) x: {
66 break :x T(value);
67 break :x @intCast(T, value);
6768 } else if (value == end_uint) x: {
6869 break :x start;
6970 } else x: {
7071 // Can't overflow because the range is over signed ints
71 break :x math.negateCast(value - end_uint) catch unreachable;
72 break :x math.negateCast(value - end_uint) catch unreachable;
7273 };
7374 return result;
7475 } else {
......@@ -91,7 +92,7 @@ pub const Random = struct {
9192 }
9293
9394 /// Return a floating point value evenly distributed in the range [0, 1).
94 pub fn float(r: &Random, comptime T: type) T {
95 pub fn float(r: *Random, comptime T: type) T {
9596 // Generate a uniform value between [1, 2) and scale down to [0, 1).
9697 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
9798 switch (T) {
......@@ -109,19 +110,32 @@ pub const Random = struct {
109110 }
110111 }
111112
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");
113 /// Return a floating point value normally distributed with mean = 0, stddev = 1.
114 ///
115 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
116 pub fn floatNorm(r: *Random, comptime T: type) T {
117 const value = ziggurat.next_f64(r, ziggurat.NormDist);
118 switch (T) {
119 f32 => return @floatCast(f32, value),
120 f64 => return value,
121 else => @compileError("unknown floating point type"),
122 }
116123 }
117124
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");
125 /// Return an exponentially distributed float with a rate parameter of 1.
126 ///
127 /// To use a different rate parameter, use: floatExp(...) / desiredRate.
128 pub fn floatExp(r: *Random, comptime T: type) T {
129 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
130 switch (T) {
131 f32 => return @floatCast(f32, value),
132 f64 => return value,
133 else => @compileError("unknown floating point type"),
134 }
121135 }
122136
123137 /// Shuffle a slice into a random order.
124 pub fn shuffle(r: &Random, comptime T: type, buf: []T) void {
138 pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {
125139 if (buf.len < 2) {
126140 return;
127141 }
......@@ -142,10 +156,10 @@ const SplitMix64 = struct {
142156 s: u64,
143157
144158 pub fn init(seed: u64) SplitMix64 {
145 return SplitMix64 { .s = seed };
159 return SplitMix64{ .s = seed };
146160 }
147161
148 pub fn next(self: &SplitMix64) u64 {
162 pub fn next(self: *SplitMix64) u64 {
149163 self.s +%= 0x9e3779b97f4a7c15;
150164
151165 var z = self.s;
......@@ -158,7 +172,7 @@ const SplitMix64 = struct {
158172test "splitmix64 sequence" {
159173 var r = SplitMix64.init(0xaeecf86f7878dd75);
160174
161 const seq = []const u64 {
175 const seq = []const u64{
162176 0x5dbd39db0178eb44,
163177 0xa9900fb66b397da3,
164178 0x5c1a28b1aeebcf5c,
......@@ -184,8 +198,8 @@ pub const Pcg = struct {
184198 i: u64,
185199
186200 pub fn init(init_s: u64) Pcg {
187 var pcg = Pcg {
188 .random = Random { .fillFn = fill },
201 var pcg = Pcg{
202 .random = Random{ .fillFn = fill },
189203 .s = undefined,
190204 .i = undefined,
191205 };
......@@ -194,23 +208,23 @@ pub const Pcg = struct {
194208 return pcg;
195209 }
196210
197 fn next(self: &Pcg) u32 {
211 fn next(self: *Pcg) u32 {
198212 const l = self.s;
199213 self.s = l *% default_multiplier +% (self.i | 1);
200214
201215 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
202 const rot = u32(l >> 59);
216 const rot = @intCast(u32, l >> 59);
203217
204 return (xor_s >> u5(rot)) | (xor_s << u5((0 -% rot) & 31));
218 return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
205219 }
206220
207 fn seed(self: &Pcg, init_s: u64) void {
221 fn seed(self: *Pcg, init_s: u64) void {
208222 // Pcg requires 128-bits of seed.
209223 var gen = SplitMix64.init(init_s);
210224 self.seedTwo(gen.next(), gen.next());
211225 }
212226
213 fn seedTwo(self: &Pcg, init_s: u64, init_i: u64) void {
227 fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
214228 self.s = 0;
215229 self.i = (init_s << 1) | 1;
216230 self.s = self.s *% default_multiplier +% self.i;
......@@ -218,7 +232,7 @@ pub const Pcg = struct {
218232 self.s = self.s *% default_multiplier +% self.i;
219233 }
220234
221 fn fill(r: &Random, buf: []u8) void {
235 fn fill(r: *Random, buf: []u8) void {
222236 const self = @fieldParentPtr(Pcg, "random", r);
223237
224238 var i: usize = 0;
......@@ -251,7 +265,7 @@ test "pcg sequence" {
251265 const s1: u64 = 0x84e9c579ef59bbf7;
252266 r.seedTwo(s0, s1);
253267
254 const seq = []const u32 {
268 const seq = []const u32{
255269 2881561918,
256270 3063928540,
257271 1199791034,
......@@ -274,8 +288,8 @@ pub const Xoroshiro128 = struct {
274288 s: [2]u64,
275289
276290 pub fn init(init_s: u64) Xoroshiro128 {
277 var x = Xoroshiro128 {
278 .random = Random { .fillFn = fill },
291 var x = Xoroshiro128{
292 .random = Random{ .fillFn = fill },
279293 .s = undefined,
280294 };
281295
......@@ -283,7 +297,7 @@ pub const Xoroshiro128 = struct {
283297 return x;
284298 }
285299
286 fn next(self: &Xoroshiro128) u64 {
300 fn next(self: *Xoroshiro128) u64 {
287301 const s0 = self.s[0];
288302 var s1 = self.s[1];
289303 const r = s0 +% s1;
......@@ -296,19 +310,19 @@ pub const Xoroshiro128 = struct {
296310 }
297311
298312 // Skip 2^64 places ahead in the sequence
299 fn jump(self: &Xoroshiro128) void {
313 fn jump(self: *Xoroshiro128) void {
300314 var s0: u64 = 0;
301315 var s1: u64 = 0;
302316
303 const table = []const u64 {
317 const table = []const u64{
304318 0xbeac0467eba5facb,
305 0xd86b048b86aa9922
319 0xd86b048b86aa9922,
306320 };
307321
308322 inline for (table) |entry| {
309323 var b: usize = 0;
310324 while (b < 64) : (b += 1) {
311 if ((entry & (u64(1) << u6(b))) != 0) {
325 if ((entry & (u64(1) << @intCast(u6, b))) != 0) {
312326 s0 ^= self.s[0];
313327 s1 ^= self.s[1];
314328 }
......@@ -320,7 +334,7 @@ pub const Xoroshiro128 = struct {
320334 self.s[1] = s1;
321335 }
322336
323 fn seed(self: &Xoroshiro128, init_s: u64) void {
337 fn seed(self: *Xoroshiro128, init_s: u64) void {
324338 // Xoroshiro requires 128-bits of seed.
325339 var gen = SplitMix64.init(init_s);
326340
......@@ -328,7 +342,7 @@ pub const Xoroshiro128 = struct {
328342 self.s[1] = gen.next();
329343 }
330344
331 fn fill(r: &Random, buf: []u8) void {
345 fn fill(r: *Random, buf: []u8) void {
332346 const self = @fieldParentPtr(Xoroshiro128, "random", r);
333347
334348 var i: usize = 0;
......@@ -360,7 +374,7 @@ test "xoroshiro sequence" {
360374 r.s[0] = 0xaeecf86f7878dd75;
361375 r.s[1] = 0x01cd153642e72622;
362376
363 const seq1 = []const u64 {
377 const seq1 = []const u64{
364378 0xb0ba0da5bb600397,
365379 0x18a08afde614dccc,
366380 0xa2635b956a31b929,
......@@ -373,10 +387,9 @@ test "xoroshiro sequence" {
373387 std.debug.assert(s == r.next());
374388 }
375389
376
377390 r.jump();
378391
379 const seq2 = []const u64 {
392 const seq2 = []const u64{
380393 0x95344a13556d3e22,
381394 0xb4fb32dafa4d00df,
382395 0xb2011d9ccdcfe2dd,
......@@ -407,8 +420,8 @@ pub const Isaac64 = struct {
407420 i: usize,
408421
409422 pub fn init(init_s: u64) Isaac64 {
410 var isaac = Isaac64 {
411 .random = Random { .fillFn = fill },
423 var isaac = Isaac64{
424 .random = Random{ .fillFn = fill },
412425 .r = undefined,
413426 .m = undefined,
414427 .a = undefined,
......@@ -422,7 +435,7 @@ pub const Isaac64 = struct {
422435 return isaac;
423436 }
424437
425 fn step(self: &Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
438 fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
426439 const x = self.m[base + m1];
427440 self.a = mix +% self.m[base + m2];
428441
......@@ -433,7 +446,7 @@ pub const Isaac64 = struct {
433446 self.r[self.r.len - 1 - base - m1] = self.b;
434447 }
435448
436 fn refill(self: &Isaac64) void {
449 fn refill(self: *Isaac64) void {
437450 const midpoint = self.r.len / 2;
438451
439452 self.c +%= 1;
......@@ -442,27 +455,27 @@ pub const Isaac64 = struct {
442455 {
443456 var i: usize = 0;
444457 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);
458 self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
459 self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
460 self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
461 self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
449462 }
450463 }
451464
452465 {
453466 var i: usize = 0;
454467 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);
468 self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
469 self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
470 self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
471 self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
459472 }
460473 }
461474
462475 self.i = 0;
463476 }
464477
465 fn next(self: &Isaac64) u64 {
478 fn next(self: *Isaac64) u64 {
466479 if (self.i >= self.r.len) {
467480 self.refill();
468481 }
......@@ -472,14 +485,14 @@ pub const Isaac64 = struct {
472485 return value;
473486 }
474487
475 fn seed(self: &Isaac64, init_s: u64, comptime rounds: usize) void {
488 fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
476489 // We ignore the multi-pass requirement since we don't currently expose full access to
477490 // seeding the self.m array completely.
478491 mem.set(u64, self.m[0..], 0);
479492 self.m[0] = init_s;
480493
481494 // prescrambled golden ratio constants
482 var a = []const u64 {
495 var a = []const u64{
483496 0x647c4677a2884b7c,
484497 0xb9f8b322c73ac862,
485498 0x8c0ea5053d4712a0,
......@@ -499,14 +512,30 @@ pub const Isaac64 = struct {
499512 a[x1] +%= self.m[j + x1];
500513 }
501514
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];
515 a[0] -%= a[4];
516 a[5] ^= a[7] >> 9;
517 a[7] +%= a[0];
518 a[1] -%= a[5];
519 a[6] ^= a[0] << 9;
520 a[0] +%= a[1];
521 a[2] -%= a[6];
522 a[7] ^= a[1] >> 23;
523 a[1] +%= a[2];
524 a[3] -%= a[7];
525 a[0] ^= a[2] << 15;
526 a[2] +%= a[3];
527 a[4] -%= a[0];
528 a[1] ^= a[3] >> 14;
529 a[3] +%= a[4];
530 a[5] -%= a[1];
531 a[2] ^= a[4] << 20;
532 a[4] +%= a[5];
533 a[6] -%= a[2];
534 a[3] ^= a[5] >> 17;
535 a[5] +%= a[6];
536 a[7] -%= a[3];
537 a[4] ^= a[6] << 14;
538 a[6] +%= a[7];
510539
511540 comptime var x2: usize = 0;
512541 inline while (x2 < 8) : (x2 += 1) {
......@@ -519,10 +548,10 @@ pub const Isaac64 = struct {
519548 self.a = 0;
520549 self.b = 0;
521550 self.c = 0;
522 self.i = self.r.len; // trigger refill on first value
551 self.i = self.r.len; // trigger refill on first value
523552 }
524553
525 fn fill(r: &Random, buf: []u8) void {
554 fn fill(r: *Random, buf: []u8) void {
526555 const self = @fieldParentPtr(Isaac64, "random", r);
527556
528557 var i: usize = 0;
......@@ -553,7 +582,7 @@ test "isaac64 sequence" {
553582 var r = Isaac64.init(0);
554583
555584 // from reference implementation
556 const seq = []const u64 {
585 const seq = []const u64{
557586 0xf67dfba498e4937c,
558587 0x84a5066a9204f380,
559588 0xfee34bd5f5514dbb,
......@@ -595,7 +624,7 @@ test "Random float" {
595624
596625test "Random scalar" {
597626 var prng = DefaultPrng.init(0);
598 const s = prng .random.scalar(u64);
627 const s = prng.random.scalar(u64);
599628}
600629
601630test "Random bytes" {
......@@ -607,8 +636,8 @@ test "Random bytes" {
607636test "Random shuffle" {
608637 var prng = DefaultPrng.init(0);
609638
610 var seq = []const u8 { 0, 1, 2, 3, 4 };
611 var seen = []bool {false} ** 5;
639 var seq = []const u8{ 0, 1, 2, 3, 4 };
640 var seen = []bool{false} ** 5;
612641
613642 var i: usize = 0;
614643 while (i < 1000) : (i += 1) {
......@@ -625,7 +654,8 @@ test "Random shuffle" {
625654
626655fn sumArray(s: []const u8) u32 {
627656 var r: u32 = 0;
628 for (s) |e| r += e;
657 for (s) |e|
658 r += e;
629659 return r;
630660}
631661
......@@ -634,16 +664,17 @@ test "Random range" {
634664 testRange(&prng.random, -4, 3);
635665 testRange(&prng.random, -4, -1);
636666 testRange(&prng.random, 10, 14);
667 // TODO: test that prng.random.range(1, 1) causes an assertion error
637668}
638669
639fn testRange(r: &Random, start: i32, end: i32) void {
640 const count = usize(end - start);
670fn testRange(r: *Random, start: i32, end: i32) void {
671 const count = @intCast(usize, end - start);
641672 var values_buffer = []bool{false} ** 20;
642673 const values = values_buffer[0..count];
643674 var i: usize = 0;
644675 while (i < count) {
645676 const value = r.range(i32, start, end);
646 const index = usize(value - start);
677 const index = @intCast(usize, value - start);
647678 if (!values[index]) {
648679 i += 1;
649680 values[index] = true;
std/rand/ziggurat.zig created+166
......@@ -0,0 +1,166 @@
1// Implements ZIGNOR [1].
2//
3// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*]
4// (https://www.doornik.com/research/ziggurat.pdf). Nuffield College, Oxford.
5//
6// rust/rand used as a reference;
7//
8// NOTE: This seems interesting but reference code is a bit hard to grok:
9// https://sbarral.github.io/etf.
10
11const std = @import("../index.zig");
12const math = std.math;
13const Random = std.rand.Random;
14
15pub fn next_f64(random: *Random, comptime tables: *const ZigTable) f64 {
16 while (true) {
17 // We manually construct a float from parts as we can avoid an extra random lookup here by
18 // using the unused exponent for the lookup table entry.
19 const bits = random.scalar(u64);
20 const i = usize(bits & 0xff);
21
22 const u = blk: {
23 if (tables.is_symmetric) {
24 // Generate a value in the range [2, 4) and scale into [-1, 1)
25 const repr = ((0x3ff + 1) << 52) | (bits >> 12);
26 break :blk @bitCast(f64, repr) - 3.0;
27 } else {
28 // Generate a value in the range [1, 2) and scale into (0, 1)
29 const repr = (0x3ff << 52) | (bits >> 12);
30 break :blk @bitCast(f64, repr) - (1.0 - math.f64_epsilon / 2.0);
31 }
32 };
33
34 const x = u * tables.x[i];
35 const test_x = if (tables.is_symmetric) math.fabs(x) else x;
36
37 // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i])
38 if (test_x < tables.x[i + 1]) {
39 return x;
40 }
41
42 if (i == 0) {
43 return tables.zero_case(random, u);
44 }
45
46 // equivalent to f1 + DRanU() * (f0 - f1) < 1
47 if (tables.f[i + 1] + (tables.f[i] - tables.f[i + 1]) * random.float(f64) < tables.pdf(x)) {
48 return x;
49 }
50 }
51}
52
53pub const ZigTable = struct {
54 r: f64,
55 x: [257]f64,
56 f: [257]f64,
57
58 // probability density function used as a fallback
59 pdf: fn (f64) f64,
60 // whether the distribution is symmetric
61 is_symmetric: bool,
62 // fallback calculation in the case we are in the 0 block
63 zero_case: fn (*Random, f64) f64,
64};
65
66// zigNorInit
67fn ZigTableGen(
68 comptime is_symmetric: bool,
69 comptime r: f64,
70 comptime v: f64,
71 comptime f: fn (f64) f64,
72 comptime f_inv: fn (f64) f64,
73 comptime zero_case: fn (*Random, f64) f64,
74) ZigTable {
75 var tables: ZigTable = undefined;
76
77 tables.is_symmetric = is_symmetric;
78 tables.r = r;
79 tables.pdf = f;
80 tables.zero_case = zero_case;
81
82 tables.x[0] = v / f(r);
83 tables.x[1] = r;
84
85 for (tables.x[2..256]) |*entry, i| {
86 const last = tables.x[2 + i - 1];
87 entry.* = f_inv(v / last + f(last));
88 }
89 tables.x[256] = 0;
90
91 for (tables.f[0..]) |*entry, i| {
92 entry.* = f(tables.x[i]);
93 }
94
95 return tables;
96}
97
98// N(0, 1)
99pub const NormDist = blk: {
100 @setEvalBranchQuota(30000);
101 break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
102};
103
104const norm_r = 3.6541528853610088;
105const norm_v = 0.00492867323399;
106
107fn norm_f(x: f64) f64 {
108 return math.exp(-x * x / 2.0);
109}
110fn norm_f_inv(y: f64) f64 {
111 return math.sqrt(-2.0 * math.ln(y));
112}
113fn norm_zero_case(random: *Random, u: f64) f64 {
114 var x: f64 = 1;
115 var y: f64 = 0;
116
117 while (-2.0 * y < x * x) {
118 x = math.ln(random.float(f64)) / norm_r;
119 y = math.ln(random.float(f64));
120 }
121
122 if (u < 0) {
123 return x - norm_r;
124 } else {
125 return norm_r - x;
126 }
127}
128
129test "ziggurant normal dist sanity" {
130 var prng = std.rand.DefaultPrng.init(0);
131 var i: usize = 0;
132 while (i < 1000) : (i += 1) {
133 _ = prng.random.floatNorm(f64);
134 }
135}
136
137// Exp(1)
138pub const ExpDist = blk: {
139 @setEvalBranchQuota(30000);
140 break :blk ZigTableGen(false, exp_r, exp_v, exp_f, exp_f_inv, exp_zero_case);
141};
142
143const exp_r = 7.69711747013104972;
144const exp_v = 0.0039496598225815571993;
145
146fn exp_f(x: f64) f64 {
147 return math.exp(-x);
148}
149fn exp_f_inv(y: f64) f64 {
150 return -math.ln(y);
151}
152fn exp_zero_case(random: *Random, _: f64) f64 {
153 return exp_r - math.ln(random.float(f64));
154}
155
156test "ziggurant exp dist sanity" {
157 var prng = std.rand.DefaultPrng.init(0);
158 var i: usize = 0;
159 while (i < 1000) : (i += 1) {
160 _ = prng.random.floatExp(f64);
161 }
162}
163
164test "ziggurat table gen" {
165 const table = NormDist;
166}
std/segmented_list.zig created+389
......@@ -0,0 +1,389 @@
1const std = @import("index.zig");
2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
4
5// Imagine that `fn at(self: &Self, index: usize) &T` is a customer asking for a box
6// from a warehouse, based on a flat array, boxes ordered from 0 to N - 1.
7// But the warehouse actually stores boxes in shelves of increasing powers of 2 sizes.
8// So when the customer requests a box index, we have to translate it to shelf index
9// and box index within that shelf. Illustration:
10//
11// customer indexes:
12// shelf 0: 0
13// shelf 1: 1 2
14// shelf 2: 3 4 5 6
15// shelf 3: 7 8 9 10 11 12 13 14
16// shelf 4: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
17// shelf 5: 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
18// ...
19//
20// warehouse indexes:
21// shelf 0: 0
22// shelf 1: 0 1
23// shelf 2: 0 1 2 3
24// shelf 3: 0 1 2 3 4 5 6 7
25// shelf 4: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
26// shelf 5: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
27// ...
28//
29// With this arrangement, here are the equations to get the shelf index and
30// box index based on customer box index:
31//
32// shelf_index = floor(log2(customer_index + 1))
33// shelf_count = ceil(log2(box_count + 1))
34// box_index = customer_index + 1 - 2 ** shelf
35// shelf_size = 2 ** shelf_index
36//
37// Now we complicate it a little bit further by adding a preallocated shelf, which must be
38// a power of 2:
39// prealloc=4
40//
41// customer indexes:
42// prealloc: 0 1 2 3
43// shelf 0: 4 5 6 7 8 9 10 11
44// shelf 1: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
45// shelf 2: 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
46// ...
47//
48// warehouse indexes:
49// prealloc: 0 1 2 3
50// shelf 0: 0 1 2 3 4 5 6 7
51// shelf 1: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
52// shelf 2: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
53// ...
54//
55// Now the equations are:
56//
57// shelf_index = floor(log2(customer_index + prealloc)) - log2(prealloc) - 1
58// shelf_count = ceil(log2(box_count + prealloc)) - log2(prealloc) - 1
59// box_index = customer_index + prealloc - 2 ** (log2(prealloc) + 1 + shelf)
60// shelf_size = prealloc * 2 ** (shelf_index + 1)
61
62/// This is a stack data structure where pointers to indexes have the same lifetime as the data structure
63/// itself, unlike ArrayList where push() invalidates all existing element pointers.
64/// The tradeoff is that elements are not guaranteed to be contiguous. For that, use ArrayList.
65/// Note however that most elements are contiguous, making this data structure cache-friendly.
66///
67/// Because it never has to copy elements from an old location to a new location, it does not require
68/// its elements to be copyable, and it avoids wasting memory when backed by an ArenaAllocator.
69/// Note that the push() and pop() convenience methods perform a copy, but you can instead use
70/// addOne(), at(), setCapacity(), and shrinkCapacity() to avoid copying items.
71///
72/// This data structure has O(1) push and O(1) pop.
73///
74/// It supports preallocated elements, making it especially well suited when the expected maximum
75/// size is small. `prealloc_item_count` must be 0, or a power of 2.
76pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
77 return struct {
78 const Self = this;
79 const prealloc_exp = blk: {
80 // we don't use the prealloc_exp constant when prealloc_item_count is 0.
81 assert(prealloc_item_count != 0);
82
83 const value = std.math.log2_int(usize, prealloc_item_count);
84 assert((1 << value) == prealloc_item_count); // prealloc_item_count must be a power of 2
85 break :blk @typeOf(1)(value);
86 };
87 const ShelfIndex = std.math.Log2Int(usize);
88
89 prealloc_segment: [prealloc_item_count]T,
90 dynamic_segments: [][*]T,
91 allocator: *Allocator,
92 len: usize,
93
94 pub const prealloc_count = prealloc_item_count;
95
96 /// Deinitialize with `deinit`
97 pub fn init(allocator: *Allocator) Self {
98 return Self{
99 .allocator = allocator,
100 .len = 0,
101 .prealloc_segment = undefined,
102 .dynamic_segments = [][*]T{},
103 };
104 }
105
106 pub fn deinit(self: *Self) void {
107 self.freeShelves(@intCast(ShelfIndex, self.dynamic_segments.len), 0);
108 self.allocator.free(self.dynamic_segments);
109 self.* = undefined;
110 }
111
112 pub fn at(self: *Self, i: usize) *T {
113 assert(i < self.len);
114 return self.uncheckedAt(i);
115 }
116
117 pub fn count(self: *const Self) usize {
118 return self.len;
119 }
120
121 pub fn push(self: *Self, item: *const T) !void {
122 const new_item_ptr = try self.addOne();
123 new_item_ptr.* = item.*;
124 }
125
126 pub fn pushMany(self: *Self, items: []const T) !void {
127 for (items) |item| {
128 try self.push(item);
129 }
130 }
131
132 pub fn pop(self: *Self) ?T {
133 if (self.len == 0) return null;
134
135 const index = self.len - 1;
136 const result = self.uncheckedAt(index).*;
137 self.len = index;
138 return result;
139 }
140
141 pub fn addOne(self: *Self) !*T {
142 const new_length = self.len + 1;
143 try self.growCapacity(new_length);
144 const result = self.uncheckedAt(self.len);
145 self.len = new_length;
146 return result;
147 }
148
149 /// Grows or shrinks capacity to match usage.
150 pub fn setCapacity(self: *Self, new_capacity: usize) !void {
151 if (new_capacity <= usize(1) << (prealloc_exp + self.dynamic_segments.len)) {
152 return self.shrinkCapacity(new_capacity);
153 } else {
154 return self.growCapacity(new_capacity);
155 }
156 }
157
158 /// Only grows capacity, or retains current capacity
159 pub fn growCapacity(self: *Self, new_capacity: usize) !void {
160 const new_cap_shelf_count = shelfCount(new_capacity);
161 const old_shelf_count = @intCast(ShelfIndex, self.dynamic_segments.len);
162 if (new_cap_shelf_count > old_shelf_count) {
163 self.dynamic_segments = try self.allocator.realloc([*]T, self.dynamic_segments, new_cap_shelf_count);
164 var i = old_shelf_count;
165 errdefer {
166 self.freeShelves(i, old_shelf_count);
167 self.dynamic_segments = self.allocator.shrink([*]T, self.dynamic_segments, old_shelf_count);
168 }
169 while (i < new_cap_shelf_count) : (i += 1) {
170 self.dynamic_segments[i] = (try self.allocator.alloc(T, shelfSize(i))).ptr;
171 }
172 }
173 }
174
175 /// Only shrinks capacity or retains current capacity
176 pub fn shrinkCapacity(self: *Self, new_capacity: usize) void {
177 if (new_capacity <= prealloc_item_count) {
178 const len = @intCast(ShelfIndex, self.dynamic_segments.len);
179 self.freeShelves(len, 0);
180 self.allocator.free(self.dynamic_segments);
181 self.dynamic_segments = [][*]T{};
182 return;
183 }
184
185 const new_cap_shelf_count = shelfCount(new_capacity);
186 const old_shelf_count = @intCast(ShelfIndex, self.dynamic_segments.len);
187 assert(new_cap_shelf_count <= old_shelf_count);
188 if (new_cap_shelf_count == old_shelf_count) {
189 return;
190 }
191
192 self.freeShelves(old_shelf_count, new_cap_shelf_count);
193 self.dynamic_segments = self.allocator.shrink([*]T, self.dynamic_segments, new_cap_shelf_count);
194 }
195
196 pub fn uncheckedAt(self: *Self, index: usize) *T {
197 if (index < prealloc_item_count) {
198 return &self.prealloc_segment[index];
199 }
200 const shelf_index = shelfIndex(index);
201 const box_index = boxIndex(index, shelf_index);
202 return &self.dynamic_segments[shelf_index][box_index];
203 }
204
205 fn shelfCount(box_count: usize) ShelfIndex {
206 if (prealloc_item_count == 0) {
207 return std.math.log2_int_ceil(usize, box_count + 1);
208 }
209 return std.math.log2_int_ceil(usize, box_count + prealloc_item_count) - prealloc_exp - 1;
210 }
211
212 fn shelfSize(shelf_index: ShelfIndex) usize {
213 if (prealloc_item_count == 0) {
214 return usize(1) << shelf_index;
215 }
216 return usize(1) << (shelf_index + (prealloc_exp + 1));
217 }
218
219 fn shelfIndex(list_index: usize) ShelfIndex {
220 if (prealloc_item_count == 0) {
221 return std.math.log2_int(usize, list_index + 1);
222 }
223 return std.math.log2_int(usize, list_index + prealloc_item_count) - prealloc_exp - 1;
224 }
225
226 fn boxIndex(list_index: usize, shelf_index: ShelfIndex) usize {
227 if (prealloc_item_count == 0) {
228 return (list_index + 1) - (usize(1) << shelf_index);
229 }
230 return list_index + prealloc_item_count - (usize(1) << ((prealloc_exp + 1) + shelf_index));
231 }
232
233 fn freeShelves(self: *Self, from_count: ShelfIndex, to_count: ShelfIndex) void {
234 var i = from_count;
235 while (i != to_count) {
236 i -= 1;
237 self.allocator.free(self.dynamic_segments[i][0..shelfSize(i)]);
238 }
239 }
240
241 pub const Iterator = struct {
242 list: *Self,
243 index: usize,
244 box_index: usize,
245 shelf_index: ShelfIndex,
246 shelf_size: usize,
247
248 pub fn next(it: *Iterator) ?*T {
249 if (it.index >= it.list.len) return null;
250 if (it.index < prealloc_item_count) {
251 const ptr = &it.list.prealloc_segment[it.index];
252 it.index += 1;
253 if (it.index == prealloc_item_count) {
254 it.box_index = 0;
255 it.shelf_index = 0;
256 it.shelf_size = prealloc_item_count * 2;
257 }
258 return ptr;
259 }
260
261 const ptr = &it.list.dynamic_segments[it.shelf_index][it.box_index];
262 it.index += 1;
263 it.box_index += 1;
264 if (it.box_index == it.shelf_size) {
265 it.shelf_index += 1;
266 it.box_index = 0;
267 it.shelf_size *= 2;
268 }
269 return ptr;
270 }
271
272 pub fn prev(it: *Iterator) ?*T {
273 if (it.index == 0) return null;
274
275 it.index -= 1;
276 if (it.index < prealloc_item_count) return &it.list.prealloc_segment[it.index];
277
278 if (it.box_index == 0) {
279 it.shelf_index -= 1;
280 it.shelf_size /= 2;
281 it.box_index = it.shelf_size - 1;
282 } else {
283 it.box_index -= 1;
284 }
285
286 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
287 }
288
289 pub fn peek(it: *Iterator) ?*T {
290 if (it.index >= it.list.len)
291 return null;
292 if (it.index < prealloc_item_count)
293 return &it.list.prealloc_segment[it.index];
294
295 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
296 }
297
298 pub fn set(it: *Iterator, index: usize) void {
299 it.index = index;
300 if (index < prealloc_item_count) return;
301 it.shelf_index = shelfIndex(index);
302 it.box_index = boxIndex(index, it.shelf_index);
303 it.shelf_size = shelfSize(it.shelf_index);
304 }
305 };
306
307 pub fn iterator(self: *Self, start_index: usize) Iterator {
308 var it = Iterator{
309 .list = self,
310 .index = undefined,
311 .shelf_index = undefined,
312 .box_index = undefined,
313 .shelf_size = undefined,
314 };
315 it.set(start_index);
316 return it;
317 }
318 };
319}
320
321test "std.SegmentedList" {
322 var da = std.heap.DirectAllocator.init();
323 defer da.deinit();
324 var a = &da.allocator;
325
326 try testSegmentedList(0, a);
327 try testSegmentedList(1, a);
328 try testSegmentedList(2, a);
329 try testSegmentedList(4, a);
330 try testSegmentedList(8, a);
331 try testSegmentedList(16, a);
332}
333
334fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
335 var list = SegmentedList(i32, prealloc).init(allocator);
336 defer list.deinit();
337
338 {
339 var i: usize = 0;
340 while (i < 100) : (i += 1) {
341 try list.push(@intCast(i32, i + 1));
342 assert(list.len == i + 1);
343 }
344 }
345
346 {
347 var i: usize = 0;
348 while (i < 100) : (i += 1) {
349 assert(list.at(i).* == @intCast(i32, i + 1));
350 }
351 }
352
353 {
354 var it = list.iterator(0);
355 var x: i32 = 0;
356 while (it.next()) |item| {
357 x += 1;
358 assert(item.* == x);
359 }
360 assert(x == 100);
361 while (it.prev()) |item| : (x -= 1) {
362 assert(item.* == x);
363 }
364 assert(x == 0);
365 }
366
367 assert(list.pop().? == 100);
368 assert(list.len == 99);
369
370 try list.pushMany([]i32{
371 1,
372 2,
373 3,
374 });
375 assert(list.len == 102);
376 assert(list.pop().? == 3);
377 assert(list.pop().? == 2);
378 assert(list.pop().? == 1);
379 assert(list.len == 99);
380
381 try list.pushMany([]const i32{});
382 assert(list.len == 99);
383
384 var i: i32 = 99;
385 while (list.pop()) |item| : (i -= 1) {
386 assert(item == i);
387 list.shrinkCapacity(list.len);
388 }
389}
std/sort.zig+268-188
......@@ -5,15 +5,18 @@ const math = std.math;
55const builtin = @import("builtin");
66
77/// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required).
8pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) void {
9 {var i: usize = 1; while (i < items.len) : (i += 1) {
10 const x = items[i];
11 var j: usize = i;
12 while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
13 items[j] = items[j - 1];
8pub fn insertionSort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void {
9 {
10 var i: usize = 1;
11 while (i < items.len) : (i += 1) {
12 const x = items[i];
13 var j: usize = i;
14 while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
15 items[j] = items[j - 1];
16 }
17 items[j] = x;
1418 }
15 items[j] = x;
16 }}
19 }
1720}
1821
1922const Range = struct {
......@@ -21,15 +24,17 @@ const Range = struct {
2124 end: usize,
2225
2326 fn init(start: usize, end: usize) Range {
24 return Range { .start = start, .end = end };
27 return Range{
28 .start = start,
29 .end = end,
30 };
2531 }
2632
27 fn length(self: &const Range) usize {
33 fn length(self: Range) usize {
2834 return self.end - self.start;
2935 }
3036};
3137
32
3338const Iterator = struct {
3439 size: usize,
3540 power_of_two: usize,
......@@ -42,7 +47,7 @@ const Iterator = struct {
4247 fn init(size2: usize, min_level: usize) Iterator {
4348 const power_of_two = math.floorPowerOfTwo(usize, size2);
4449 const denominator = power_of_two / min_level;
45 return Iterator {
50 return Iterator{
4651 .numerator = 0,
4752 .decimal = 0,
4853 .size = size2,
......@@ -53,12 +58,12 @@ const Iterator = struct {
5358 };
5459 }
5560
56 fn begin(self: &Iterator) void {
61 fn begin(self: *Iterator) void {
5762 self.numerator = 0;
5863 self.decimal = 0;
5964 }
6065
61 fn nextRange(self: &Iterator) Range {
66 fn nextRange(self: *Iterator) Range {
6267 const start = self.decimal;
6368
6469 self.decimal += self.decimal_step;
......@@ -68,14 +73,17 @@ const Iterator = struct {
6873 self.decimal += 1;
6974 }
7075
71 return Range {.start = start, .end = self.decimal};
76 return Range{
77 .start = start,
78 .end = self.decimal,
79 };
7280 }
7381
74 fn finished(self: &Iterator) bool {
82 fn finished(self: *Iterator) bool {
7583 return self.decimal >= self.size;
7684 }
7785
78 fn nextLevel(self: &Iterator) bool {
86 fn nextLevel(self: *Iterator) bool {
7987 self.decimal_step += self.decimal_step;
8088 self.numerator_step += self.numerator_step;
8189 if (self.numerator_step >= self.denominator) {
......@@ -86,7 +94,7 @@ const Iterator = struct {
8694 return (self.decimal_step < self.size);
8795 }
8896
89 fn length(self: &Iterator) usize {
97 fn length(self: *Iterator) usize {
9098 return self.decimal_step;
9199 }
92100};
......@@ -100,7 +108,7 @@ const Pull = struct {
100108
101109/// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required).
102110/// Currently implemented as block sort.
103pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) void {
111pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void {
104112 // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c
105113 var cache: [512]T = undefined;
106114
......@@ -123,7 +131,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
123131 // http://pages.ripco.net/~jgamble/nw.html
124132 var iterator = Iterator.init(items.len, 4);
125133 while (!iterator.finished()) {
126 var order = []u8{0, 1, 2, 3, 4, 5, 6, 7};
134 var order = []u8{ 0, 1, 2, 3, 4, 5, 6, 7 };
127135 const range = iterator.nextRange();
128136
129137 const sliced_items = items[range.start..];
......@@ -149,56 +157,56 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
149157 swap(T, sliced_items, lessThan, &order, 3, 5);
150158 swap(T, sliced_items, lessThan, &order, 3, 4);
151159 },
152 7 => {
153 swap(T, sliced_items, lessThan, &order, 1, 2);
154 swap(T, sliced_items, lessThan, &order, 3, 4);
155 swap(T, sliced_items, lessThan, &order, 5, 6);
156 swap(T, sliced_items, lessThan, &order, 0, 2);
157 swap(T, sliced_items, lessThan, &order, 3, 5);
158 swap(T, sliced_items, lessThan, &order, 4, 6);
159 swap(T, sliced_items, lessThan, &order, 0, 1);
160 swap(T, sliced_items, lessThan, &order, 4, 5);
161 swap(T, sliced_items, lessThan, &order, 2, 6);
162 swap(T, sliced_items, lessThan, &order, 0, 4);
163 swap(T, sliced_items, lessThan, &order, 1, 5);
164 swap(T, sliced_items, lessThan, &order, 0, 3);
165 swap(T, sliced_items, lessThan, &order, 2, 5);
166 swap(T, sliced_items, lessThan, &order, 1, 3);
167 swap(T, sliced_items, lessThan, &order, 2, 4);
168 swap(T, sliced_items, lessThan, &order, 2, 3);
169 },
170 6 => {
171 swap(T, sliced_items, lessThan, &order, 1, 2);
172 swap(T, sliced_items, lessThan, &order, 4, 5);
173 swap(T, sliced_items, lessThan, &order, 0, 2);
174 swap(T, sliced_items, lessThan, &order, 3, 5);
175 swap(T, sliced_items, lessThan, &order, 0, 1);
176 swap(T, sliced_items, lessThan, &order, 3, 4);
177 swap(T, sliced_items, lessThan, &order, 2, 5);
178 swap(T, sliced_items, lessThan, &order, 0, 3);
179 swap(T, sliced_items, lessThan, &order, 1, 4);
180 swap(T, sliced_items, lessThan, &order, 2, 4);
181 swap(T, sliced_items, lessThan, &order, 1, 3);
182 swap(T, sliced_items, lessThan, &order, 2, 3);
183 },
184 5 => {
185 swap(T, sliced_items, lessThan, &order, 0, 1);
186 swap(T, sliced_items, lessThan, &order, 3, 4);
187 swap(T, sliced_items, lessThan, &order, 2, 4);
188 swap(T, sliced_items, lessThan, &order, 2, 3);
189 swap(T, sliced_items, lessThan, &order, 1, 4);
190 swap(T, sliced_items, lessThan, &order, 0, 3);
191 swap(T, sliced_items, lessThan, &order, 0, 2);
192 swap(T, sliced_items, lessThan, &order, 1, 3);
193 swap(T, sliced_items, lessThan, &order, 1, 2);
194 },
195 4 => {
196 swap(T, sliced_items, lessThan, &order, 0, 1);
197 swap(T, sliced_items, lessThan, &order, 2, 3);
198 swap(T, sliced_items, lessThan, &order, 0, 2);
199 swap(T, sliced_items, lessThan, &order, 1, 3);
200 swap(T, sliced_items, lessThan, &order, 1, 2);
201 },
160 7 => {
161 swap(T, sliced_items, lessThan, &order, 1, 2);
162 swap(T, sliced_items, lessThan, &order, 3, 4);
163 swap(T, sliced_items, lessThan, &order, 5, 6);
164 swap(T, sliced_items, lessThan, &order, 0, 2);
165 swap(T, sliced_items, lessThan, &order, 3, 5);
166 swap(T, sliced_items, lessThan, &order, 4, 6);
167 swap(T, sliced_items, lessThan, &order, 0, 1);
168 swap(T, sliced_items, lessThan, &order, 4, 5);
169 swap(T, sliced_items, lessThan, &order, 2, 6);
170 swap(T, sliced_items, lessThan, &order, 0, 4);
171 swap(T, sliced_items, lessThan, &order, 1, 5);
172 swap(T, sliced_items, lessThan, &order, 0, 3);
173 swap(T, sliced_items, lessThan, &order, 2, 5);
174 swap(T, sliced_items, lessThan, &order, 1, 3);
175 swap(T, sliced_items, lessThan, &order, 2, 4);
176 swap(T, sliced_items, lessThan, &order, 2, 3);
177 },
178 6 => {
179 swap(T, sliced_items, lessThan, &order, 1, 2);
180 swap(T, sliced_items, lessThan, &order, 4, 5);
181 swap(T, sliced_items, lessThan, &order, 0, 2);
182 swap(T, sliced_items, lessThan, &order, 3, 5);
183 swap(T, sliced_items, lessThan, &order, 0, 1);
184 swap(T, sliced_items, lessThan, &order, 3, 4);
185 swap(T, sliced_items, lessThan, &order, 2, 5);
186 swap(T, sliced_items, lessThan, &order, 0, 3);
187 swap(T, sliced_items, lessThan, &order, 1, 4);
188 swap(T, sliced_items, lessThan, &order, 2, 4);
189 swap(T, sliced_items, lessThan, &order, 1, 3);
190 swap(T, sliced_items, lessThan, &order, 2, 3);
191 },
192 5 => {
193 swap(T, sliced_items, lessThan, &order, 0, 1);
194 swap(T, sliced_items, lessThan, &order, 3, 4);
195 swap(T, sliced_items, lessThan, &order, 2, 4);
196 swap(T, sliced_items, lessThan, &order, 2, 3);
197 swap(T, sliced_items, lessThan, &order, 1, 4);
198 swap(T, sliced_items, lessThan, &order, 0, 3);
199 swap(T, sliced_items, lessThan, &order, 0, 2);
200 swap(T, sliced_items, lessThan, &order, 1, 3);
201 swap(T, sliced_items, lessThan, &order, 1, 2);
202 },
203 4 => {
204 swap(T, sliced_items, lessThan, &order, 0, 1);
205 swap(T, sliced_items, lessThan, &order, 2, 3);
206 swap(T, sliced_items, lessThan, &order, 0, 2);
207 swap(T, sliced_items, lessThan, &order, 1, 3);
208 swap(T, sliced_items, lessThan, &order, 1, 2);
209 },
202210 else => {},
203211 }
204212 }
......@@ -240,7 +248,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
240248 // merge A2 and B2 into the cache
241249 if (lessThan(items[B2.end - 1], items[A2.start])) {
242250 // the two ranges are in reverse order, so copy them in reverse order into the cache
243 mem.copy(T, cache[A1.length() + B2.length()..], items[A2.start..A2.end]);
251 mem.copy(T, cache[A1.length() + B2.length() ..], items[A2.start..A2.end]);
244252 mem.copy(T, cache[A1.length()..], items[B2.start..B2.end]);
245253 } else if (lessThan(items[B2.start], items[A2.end - 1])) {
246254 // these two ranges weren't already in order, so merge them into the cache
......@@ -248,7 +256,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
248256 } else {
249257 // copy A2 and B2 into the cache in the same order
250258 mem.copy(T, cache[A1.length()..], items[A2.start..A2.end]);
251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);
259 mem.copy(T, cache[A1.length() + A2.length() ..], items[B2.start..B2.end]);
252260 }
253261 A2 = Range.init(A2.start, B2.end);
254262
......@@ -258,7 +266,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
258266
259267 if (lessThan(cache[B3.end - 1], cache[A3.start])) {
260268 // 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]);
269 mem.copy(T, items[A1.start + A2.length() ..], cache[A3.start..A3.end]);
262270 mem.copy(T, items[A1.start..], cache[B3.start..B3.end]);
263271 } else if (lessThan(cache[B3.start], cache[A3.end - 1])) {
264272 // these two ranges weren't already in order, so merge them back into the items
......@@ -266,14 +274,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
266274 } else {
267275 // copy A3 and B3 into the items in the same order
268276 mem.copy(T, items[A1.start..], cache[A3.start..A3.end]);
269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);
277 mem.copy(T, items[A1.start + A1.length() ..], cache[B3.start..B3.end]);
270278 }
271279 }
272280
273281 // we merged two levels at the same time, so we're done with this level already
274282 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275283 _ = iterator.nextLevel();
276
277284 } else {
278285 iterator.begin();
279286 while (!iterator.finished()) {
......@@ -301,9 +308,8 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
301308 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer
302309 // 7. sort the second internal buffer if it exists
303310 // 8. redistribute the two internal buffers back into the items
304
305311 var block_size: usize = math.sqrt(iterator.length());
306 var buffer_size = iterator.length()/block_size + 1;
312 var buffer_size = iterator.length() / block_size + 1;
307313
308314 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309315 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
......@@ -316,8 +322,18 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
316322 var start: usize = 0;
317323 var pull_index: usize = 0;
318324 var pull = []Pull{
319 Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),},
320 Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),},
325 Pull{
326 .from = 0,
327 .to = 0,
328 .count = 0,
329 .range = Range.init(0, 0),
330 },
331 Pull{
332 .from = 0,
333 .to = 0,
334 .count = 0,
335 .range = Range.init(0, 0),
336 },
321337 };
322338
323339 var buffer1 = Range.init(0, 0);
......@@ -355,7 +371,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
355371 // these values will be pulled out to the start of A
356372 last = A.start;
357373 count = 1;
358 while (count < find) : ({last = index; count += 1;}) {
374 while (count < find) : ({
375 last = index;
376 count += 1;
377 }) {
359378 index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);
360379 if (index == A.end) break;
361380 }
......@@ -363,7 +382,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
363382
364383 if (count >= buffer_size) {
365384 // 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 {
385 pull[pull_index] = Pull{
367386 .range = Range.init(A.start, B.end),
368387 .count = count,
369388 .from = index,
......@@ -398,7 +417,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
398417 } else if (pull_index == 0 and count > buffer1.length()) {
399418 // keep track of the largest buffer we were able to find
400419 buffer1 = Range.init(A.start, A.start + count);
401 pull[pull_index] = Pull {
420 pull[pull_index] = Pull{
402421 .range = Range.init(A.start, B.end),
403422 .count = count,
404423 .from = index,
......@@ -410,7 +429,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
410429 // these values will be pulled out to the end of B
411430 last = B.end - 1;
412431 count = 1;
413 while (count < find) : ({last = index - 1; count += 1;}) {
432 while (count < find) : ({
433 last = index - 1;
434 count += 1;
435 }) {
414436 index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);
415437 if (index == B.start) break;
416438 }
......@@ -418,7 +440,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
418440
419441 if (count >= buffer_size) {
420442 // 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 {
443 pull[pull_index] = Pull{
422444 .range = Range.init(A.start, B.end),
423445 .count = count,
424446 .from = index,
......@@ -457,7 +479,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
457479 } else if (pull_index == 0 and count > buffer1.length()) {
458480 // keep track of the largest buffer we were able to find
459481 buffer1 = Range.init(B.end - count, B.end);
460 pull[pull_index] = Pull {
482 pull[pull_index] = Pull{
461483 .range = Range.init(A.start, B.end),
462484 .count = count,
463485 .from = index,
......@@ -496,7 +518,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
496518
497519 // adjust block_size and buffer_size based on the values we were able to pull out
498520 buffer_size = buffer1.length();
499 block_size = iterator.length()/buffer_size + 1;
521 block_size = iterator.length() / buffer_size + 1;
500522
501523 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502524 // so this was originally here to test the math for adjusting block_size above
......@@ -547,7 +569,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
547569 // swap the first value of each A block with the value in buffer1
548570 var indexA = buffer1.start;
549571 index = firstA.end;
550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
572 while (index < blockA.end) : ({
573 indexA += 1;
574 index += block_size;
575 }) {
551576 mem.swap(T, &items[indexA], &items[index]);
552577 }
553578
......@@ -606,7 +631,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
606631 if (buffer2.length() > 0 or block_size <= cache.len) {
607632 // 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
608633 if (block_size <= cache.len) {
609 mem.copy(T, cache[0..], items[blockA.start..blockA.start + block_size]);
634 mem.copy(T, cache[0..], items[blockA.start .. blockA.start + block_size]);
610635 } else {
611636 blockSwap(T, items, blockA.start, buffer2.start, block_size);
612637 }
......@@ -617,7 +642,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
617642 blockSwap(T, items, B_split, blockA.start + block_size - B_remaining, B_remaining);
618643 } else {
619644 // 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);
645 mem.rotate(T, items[B_split .. blockA.start + block_size], blockA.start - B_split);
621646 }
622647
623648 // update the range for the remaining A blocks, and the range remaining from the B block after it was split
......@@ -626,9 +651,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
626651
627652 // if there are no more A blocks remaining, this step is finished!
628653 blockA.start += block_size;
629 if (blockA.length() == 0)
630 break;
631
654 if (blockA.length() == 0) break;
632655 } else if (blockB.length() < block_size) {
633656 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634657 // the cache is disabled here since it might contain the contents of the previous A block
......@@ -709,7 +732,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
709732}
710733
711734// 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 {
735fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessThan: fn (T, T) bool) void {
713736 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714737
715738 // this just repeatedly binary searches into B and rotates A into position.
......@@ -730,8 +753,8 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const
730753 // again, this is NOT a general-purpose solution – it only works well in this case!
731754 // kind of like how the O(n^2) insertion sort is used in some places
732755
733 var A = *A_arg;
734 var B = *B_arg;
756 var A = A_arg;
757 var B = B_arg;
735758
736759 while (true) {
737760 // find the first place in B where the first item in A needs to be inserted
......@@ -751,7 +774,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const
751774}
752775
753776// merge operation using an internal buffer
754fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, buffer: &const Range) void {
777fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn (T, T) bool, buffer: Range) void {
755778 // whenever we find a value to add to the final array, swap it with the value that's already in that spot
756779 // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order
757780 var A_count: usize = 0;
......@@ -787,9 +810,9 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
787810
788811// combine a linear search with a binary search to reduce the number of comparisons in situations
789812// where have some idea as to how many unique values there are and where the next value might be
790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
813fn findFirstForward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize {
791814 if (range.length() == 0) return range.start;
792 const skip = math.max(range.length()/unique, usize(1));
815 const skip = math.max(range.length() / unique, usize(1));
793816
794817 var index = range.start + skip;
795818 while (lessThan(items[index - 1], value)) : (index += skip) {
......@@ -801,9 +824,9 @@ fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const
801824 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802825}
803826
804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
827fn findFirstBackward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize {
805828 if (range.length() == 0) return range.start;
806 const skip = math.max(range.length()/unique, usize(1));
829 const skip = math.max(range.length() / unique, usize(1));
807830
808831 var index = range.end - skip;
809832 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
......@@ -815,9 +838,9 @@ fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &cons
815838 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816839}
817840
818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
841fn findLastForward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize {
819842 if (range.length() == 0) return range.start;
820 const skip = math.max(range.length()/unique, usize(1));
843 const skip = math.max(range.length() / unique, usize(1));
821844
822845 var index = range.start + skip;
823846 while (!lessThan(value, items[index - 1])) : (index += skip) {
......@@ -829,9 +852,9 @@ fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const
829852 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830853}
831854
832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
855fn findLastBackward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize {
833856 if (range.length() == 0) return range.start;
834 const skip = math.max(range.length()/unique, usize(1));
857 const skip = math.max(range.length() / unique, usize(1));
835858
836859 var index = range.end - skip;
837860 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
......@@ -843,12 +866,12 @@ fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const
843866 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844867}
845868
846fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool) usize {
869fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool) usize {
847870 var start = range.start;
848871 var end = range.end - 1;
849872 if (range.start >= range.end) return range.end;
850873 while (start < end) {
851 const mid = start + (end - start)/2;
874 const mid = start + (end - start) / 2;
852875 if (lessThan(items[mid], value)) {
853876 start = mid + 1;
854877 } else {
......@@ -861,12 +884,12 @@ fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Rang
861884 return start;
862885}
863886
864fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool) usize {
887fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool) usize {
865888 var start = range.start;
866889 var end = range.end - 1;
867890 if (range.start >= range.end) return range.end;
868891 while (start < end) {
869 const mid = start + (end - start)/2;
892 const mid = start + (end - start) / 2;
870893 if (!lessThan(value, items[mid])) {
871894 start = mid + 1;
872895 } else {
......@@ -879,7 +902,7 @@ fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range
879902 return start;
880903}
881904
882fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, into: []T) void {
905fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T) bool, into: []T) void {
883906 var A_index: usize = A.start;
884907 var B_index: usize = B.start;
885908 const A_last = A.end;
......@@ -909,7 +932,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
909932 }
910933}
911934
912fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, cache: []T) void {
935fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn (T, T) bool, cache: []T) void {
913936 // A fits into the cache, so use that instead of the internal buffer
914937 var A_index: usize = 0;
915938 var B_index: usize = B.start;
......@@ -937,29 +960,32 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
937960 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938961}
939962
940fn swap(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool, order: &[8]u8, x: usize, y: usize) void {
941 if (lessThan(items[y], items[x]) or
942 ((*order)[x] > (*order)[y] and !lessThan(items[x], items[y])))
943 {
963fn swap(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool, order: *[8]u8, x: usize, y: usize) void {
964 if (lessThan(items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(items[x], items[y]))) {
944965 mem.swap(T, &items[x], &items[y]);
945 mem.swap(u8, &(*order)[x], &(*order)[y]);
966 mem.swap(u8, &(order.*)[x], &(order.*)[y]);
946967 }
947968}
948969
949fn i32asc(lhs: &const i32, rhs: &const i32) bool {
950 return *lhs < *rhs;
951}
970// Use these to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`.
971pub fn asc(comptime T: type) fn (T, T) bool {
972 const impl = struct {
973 fn inner(a: T, b: T) bool {
974 return a < b;
975 }
976 };
952977
953fn i32desc(lhs: &const i32, rhs: &const i32) bool {
954 return *rhs < *lhs;
978 return impl.inner;
955979}
956980
957fn u8asc(lhs: &const u8, rhs: &const u8) bool {
958 return *lhs < *rhs;
959}
981pub fn desc(comptime T: type) fn (T, T) bool {
982 const impl = struct {
983 fn inner(a: T, b: T) bool {
984 return a > b;
985 }
986 };
960987
961fn u8desc(lhs: &const u8, rhs: &const u8) bool {
962 return *rhs < *lhs;
988 return impl.inner;
963989}
964990
965991test "stable sort" {
......@@ -967,44 +993,44 @@ test "stable sort" {
967993 comptime testStableSort();
968994}
969995fn testStableSort() void {
970 var expected = []IdAndValue {
971 IdAndValue{.id = 0, .value = 0},
972 IdAndValue{.id = 1, .value = 0},
973 IdAndValue{.id = 2, .value = 0},
974 IdAndValue{.id = 0, .value = 1},
975 IdAndValue{.id = 1, .value = 1},
976 IdAndValue{.id = 2, .value = 1},
977 IdAndValue{.id = 0, .value = 2},
978 IdAndValue{.id = 1, .value = 2},
979 IdAndValue{.id = 2, .value = 2},
996 var expected = []IdAndValue{
997 IdAndValue{ .id = 0, .value = 0 },
998 IdAndValue{ .id = 1, .value = 0 },
999 IdAndValue{ .id = 2, .value = 0 },
1000 IdAndValue{ .id = 0, .value = 1 },
1001 IdAndValue{ .id = 1, .value = 1 },
1002 IdAndValue{ .id = 2, .value = 1 },
1003 IdAndValue{ .id = 0, .value = 2 },
1004 IdAndValue{ .id = 1, .value = 2 },
1005 IdAndValue{ .id = 2, .value = 2 },
9801006 };
981 var cases = [][9]IdAndValue {
982 []IdAndValue {
983 IdAndValue{.id = 0, .value = 0},
984 IdAndValue{.id = 0, .value = 1},
985 IdAndValue{.id = 0, .value = 2},
986 IdAndValue{.id = 1, .value = 0},
987 IdAndValue{.id = 1, .value = 1},
988 IdAndValue{.id = 1, .value = 2},
989 IdAndValue{.id = 2, .value = 0},
990 IdAndValue{.id = 2, .value = 1},
991 IdAndValue{.id = 2, .value = 2},
1007 var cases = [][9]IdAndValue{
1008 []IdAndValue{
1009 IdAndValue{ .id = 0, .value = 0 },
1010 IdAndValue{ .id = 0, .value = 1 },
1011 IdAndValue{ .id = 0, .value = 2 },
1012 IdAndValue{ .id = 1, .value = 0 },
1013 IdAndValue{ .id = 1, .value = 1 },
1014 IdAndValue{ .id = 1, .value = 2 },
1015 IdAndValue{ .id = 2, .value = 0 },
1016 IdAndValue{ .id = 2, .value = 1 },
1017 IdAndValue{ .id = 2, .value = 2 },
9921018 },
993 []IdAndValue {
994 IdAndValue{.id = 0, .value = 2},
995 IdAndValue{.id = 0, .value = 1},
996 IdAndValue{.id = 0, .value = 0},
997 IdAndValue{.id = 1, .value = 2},
998 IdAndValue{.id = 1, .value = 1},
999 IdAndValue{.id = 1, .value = 0},
1000 IdAndValue{.id = 2, .value = 2},
1001 IdAndValue{.id = 2, .value = 1},
1002 IdAndValue{.id = 2, .value = 0},
1019 []IdAndValue{
1020 IdAndValue{ .id = 0, .value = 2 },
1021 IdAndValue{ .id = 0, .value = 1 },
1022 IdAndValue{ .id = 0, .value = 0 },
1023 IdAndValue{ .id = 1, .value = 2 },
1024 IdAndValue{ .id = 1, .value = 1 },
1025 IdAndValue{ .id = 1, .value = 0 },
1026 IdAndValue{ .id = 2, .value = 2 },
1027 IdAndValue{ .id = 2, .value = 1 },
1028 IdAndValue{ .id = 2, .value = 0 },
10031029 },
10041030 };
10051031 for (cases) |*case| {
1006 insertionSort(IdAndValue, (*case)[0..], cmpByValue);
1007 for (*case) |item, i| {
1032 insertionSort(IdAndValue, (case.*)[0..], cmpByValue);
1033 for (case.*) |item, i| {
10081034 assert(item.id == expected[i].id);
10091035 assert(item.value == expected[i].value);
10101036 }
......@@ -1014,68 +1040,122 @@ const IdAndValue = struct {
10141040 id: usize,
10151041 value: i32,
10161042};
1017fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) bool {
1018 return i32asc(a.value, b.value);
1043fn cmpByValue(a: IdAndValue, b: IdAndValue) bool {
1044 return asc(i32)(a.value, b.value);
10191045}
10201046
10211047test "std.sort" {
1022 const u8cases = [][]const []const u8 {
1023 [][]const u8{"", ""},
1024 [][]const u8{"a", "a"},
1025 [][]const u8{"az", "az"},
1026 [][]const u8{"za", "az"},
1027 [][]const u8{"asdf", "adfs"},
1028 [][]const u8{"one", "eno"},
1048 const u8cases = [][]const []const u8{
1049 [][]const u8{
1050 "",
1051 "",
1052 },
1053 [][]const u8{
1054 "a",
1055 "a",
1056 },
1057 [][]const u8{
1058 "az",
1059 "az",
1060 },
1061 [][]const u8{
1062 "za",
1063 "az",
1064 },
1065 [][]const u8{
1066 "asdf",
1067 "adfs",
1068 },
1069 [][]const u8{
1070 "one",
1071 "eno",
1072 },
10291073 };
10301074
10311075 for (u8cases) |case| {
10321076 var buf: [8]u8 = undefined;
10331077 const slice = buf[0..case[0].len];
10341078 mem.copy(u8, slice, case[0]);
1035 sort(u8, slice, u8asc);
1079 sort(u8, slice, asc(u8));
10361080 assert(mem.eql(u8, slice, case[1]));
10371081 }
10381082
1039 const i32cases = [][]const []const i32 {
1040 [][]const i32{[]i32{}, []i32{}},
1041 [][]const i32{[]i32{1}, []i32{1}},
1042 [][]const i32{[]i32{0, 1}, []i32{0, 1}},
1043 [][]const i32{[]i32{1, 0}, []i32{0, 1}},
1044 [][]const i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}},
1045 [][]const i32{[]i32{2, 1, 3}, []i32{1, 2, 3}},
1083 const i32cases = [][]const []const i32{
1084 [][]const i32{
1085 []i32{},
1086 []i32{},
1087 },
1088 [][]const i32{
1089 []i32{1},
1090 []i32{1},
1091 },
1092 [][]const i32{
1093 []i32{ 0, 1 },
1094 []i32{ 0, 1 },
1095 },
1096 [][]const i32{
1097 []i32{ 1, 0 },
1098 []i32{ 0, 1 },
1099 },
1100 [][]const i32{
1101 []i32{ 1, -1, 0 },
1102 []i32{ -1, 0, 1 },
1103 },
1104 [][]const i32{
1105 []i32{ 2, 1, 3 },
1106 []i32{ 1, 2, 3 },
1107 },
10461108 };
10471109
10481110 for (i32cases) |case| {
10491111 var buf: [8]i32 = undefined;
10501112 const slice = buf[0..case[0].len];
10511113 mem.copy(i32, slice, case[0]);
1052 sort(i32, slice, i32asc);
1114 sort(i32, slice, asc(i32));
10531115 assert(mem.eql(i32, slice, case[1]));
10541116 }
10551117}
10561118
10571119test "std.sort descending" {
1058 const rev_cases = [][]const []const i32 {
1059 [][]const i32{[]i32{}, []i32{}},
1060 [][]const i32{[]i32{1}, []i32{1}},
1061 [][]const i32{[]i32{0, 1}, []i32{1, 0}},
1062 [][]const i32{[]i32{1, 0}, []i32{1, 0}},
1063 [][]const i32{[]i32{1, -1, 0}, []i32{1, 0, -1}},
1064 [][]const i32{[]i32{2, 1, 3}, []i32{3, 2, 1}},
1120 const rev_cases = [][]const []const i32{
1121 [][]const i32{
1122 []i32{},
1123 []i32{},
1124 },
1125 [][]const i32{
1126 []i32{1},
1127 []i32{1},
1128 },
1129 [][]const i32{
1130 []i32{ 0, 1 },
1131 []i32{ 1, 0 },
1132 },
1133 [][]const i32{
1134 []i32{ 1, 0 },
1135 []i32{ 1, 0 },
1136 },
1137 [][]const i32{
1138 []i32{ 1, -1, 0 },
1139 []i32{ 1, 0, -1 },
1140 },
1141 [][]const i32{
1142 []i32{ 2, 1, 3 },
1143 []i32{ 3, 2, 1 },
1144 },
10651145 };
10661146
10671147 for (rev_cases) |case| {
10681148 var buf: [8]i32 = undefined;
10691149 const slice = buf[0..case[0].len];
10701150 mem.copy(i32, slice, case[0]);
1071 sort(i32, slice, i32desc);
1151 sort(i32, slice, desc(i32));
10721152 assert(mem.eql(i32, slice, case[1]));
10731153 }
10741154}
10751155
10761156test "another sort case" {
10771157 var arr = []i32{ 5, 3, 1, 2, 4 };
1078 sort(i32, arr[0..], i32asc);
1158 sort(i32, arr[0..], asc(i32));
10791159
10801160 assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }));
10811161}
......@@ -1091,7 +1171,7 @@ test "sort fuzz testing" {
10911171
10921172var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10931173
1094fn fuzzTest(rng: &std.rand.Random) void {
1174fn fuzzTest(rng: *std.rand.Random) void {
10951175 const array_size = rng.range(usize, 0, 1000);
10961176 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
10971177 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;
......@@ -1112,7 +1192,7 @@ fn fuzzTest(rng: &std.rand.Random) void {
11121192 }
11131193}
11141194
1115pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) T {
1195pub fn min(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) T {
11161196 var i: usize = 0;
11171197 var smallest = items[0];
11181198 for (items[1..]) |item| {
......@@ -1123,7 +1203,7 @@ pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const
11231203 return smallest;
11241204}
11251205
1126pub fn max(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) T {
1206pub fn max(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) T {
11271207 var i: usize = 0;
11281208 var biggest = items[0];
11291209 for (items[1..]) |item| {
std/special/bootstrap.zig+31-14
......@@ -5,7 +5,7 @@ const root = @import("@root");
55const std = @import("std");
66const builtin = @import("builtin");
77
8var argc_ptr: &usize = undefined;
8var argc_ptr: [*]usize = undefined;
99
1010comptime {
1111 const strong_linkage = builtin.GlobalLinkage.Strong;
......@@ -21,10 +21,14 @@ comptime {
2121nakedcc fn _start() noreturn {
2222 switch (builtin.arch) {
2323 builtin.Arch.x86_64 => {
24 argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
24 argc_ptr = asm ("lea (%%rsp), %[argc]"
25 : [argc] "=r" (-> [*]usize)
26 );
2527 },
2628 builtin.Arch.i386 => {
27 argc_ptr = asm("lea (%%esp), %[argc]": [argc] "=r" (-> &usize));
29 argc_ptr = asm ("lea (%%esp), %[argc]"
30 : [argc] "=r" (-> [*]usize)
31 );
2832 },
2933 else => @compileError("unsupported arch"),
3034 }
......@@ -39,25 +43,38 @@ extern fn WinMainCRTStartup() noreturn {
3943 std.os.windows.ExitProcess(callMain());
4044}
4145
46// TODO https://github.com/ziglang/zig/issues/265
4247fn posixCallMainAndExit() noreturn {
43 const argc = *argc_ptr;
44 const argv = @ptrCast(&&u8, &argc_ptr[1]);
45 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
48 const argc = argc_ptr[0];
49 const argv = @ptrCast([*][*]u8, argc_ptr + 1);
50
51 const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1);
52 var envp_count: usize = 0;
53 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
54 const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
55 if (builtin.os == builtin.Os.linux) {
56 const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1);
57 var i: usize = 0;
58 while (auxv[i] != 0) : (i += 2) {
59 if (auxv[i] < std.os.linux_aux_raw.len) std.os.linux_aux_raw[auxv[i]] = auxv[i + 1];
60 }
61 std.debug.assert(std.os.linux_aux_raw[std.elf.AT_PAGESZ] == std.os.page_size);
62 }
63
4664 std.os.posix.exit(callMainWithArgs(argc, argv, envp));
4765}
4866
49fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) u8 {
67fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
5068 std.os.ArgIteratorPosix.raw = argv[0..argc];
51
52 var env_count: usize = 0;
53 while (envp[env_count] != null) : (env_count += 1) {}
54 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
55
69 std.os.posix_environ_raw = envp;
5670 return callMain();
5771}
5872
59extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) i32 {
60 return callMainWithArgs(usize(c_argc), c_argv, c_envp);
73extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 {
74 var env_count: usize = 0;
75 while (c_envp[env_count] != null) : (env_count += 1) {}
76 const envp = @ptrCast([*][*]u8, c_envp)[0..env_count];
77 return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp);
6178}
6279
6380fn callMain() u8 {
std/special/bootstrap_lib.zig+7-4
......@@ -1,13 +1,16 @@
11// This file is included in the compilation unit when exporting a library on windows.
22
33const std = @import("std");
4const builtin = @import("builtin");
45
56comptime {
6 @export("_DllMainCRTStartup", _DllMainCRTStartup);
7 @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong);
78}
89
9stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD,
10 lpReserved: std.os.windows.LPVOID) std.os.windows.BOOL
11{
10stdcallcc fn _DllMainCRTStartup(
11 hinstDLL: std.os.windows.HINSTANCE,
12 fdwReason: std.os.windows.DWORD,
13 lpReserved: std.os.windows.LPVOID,
14) std.os.windows.BOOL {
1215 return std.os.windows.TRUE;
1316}
std/special/build_file_template.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const mode = b.standardReleaseOptions();
55 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");
66 exe.setBuildMode(mode);
std/special/build_runner.zig+17-16
......@@ -24,19 +24,18 @@ pub fn main() !void {
2424
2525 const allocator = &arena.allocator;
2626
27
2827 // skip my own exe name
2928 _ = arg_it.skip();
3029
31 const zig_exe = try unwrapArg(arg_it.next(allocator) ?? {
30 const zig_exe = try unwrapArg(arg_it.next(allocator) orelse {
3231 warn("Expected first argument to be path to zig compiler\n");
3332 return error.InvalidArgs;
3433 });
35 const build_root = try unwrapArg(arg_it.next(allocator) ?? {
34 const build_root = try unwrapArg(arg_it.next(allocator) orelse {
3635 warn("Expected second argument to be build root directory path\n");
3736 return error.InvalidArgs;
3837 });
39 const cache_root = try unwrapArg(arg_it.next(allocator) ?? {
38 const cache_root = try unwrapArg(arg_it.next(allocator) orelse {
4039 warn("Expected third argument to be cache root directory path\n");
4140 return error.InvalidArgs;
4241 });
......@@ -72,7 +71,7 @@ pub fn main() !void {
7271 }
7372 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
7473 const option_name = option_contents[0..name_end];
75 const option_value = option_contents[name_end + 1..];
74 const option_value = option_contents[name_end + 1 ..];
7675 if (builder.addUserInputOption(option_name, option_value))
7776 return usageAndErr(&builder, false, try stderr_stream);
7877 } else {
......@@ -85,12 +84,12 @@ pub fn main() !void {
8584 } else if (mem.eql(u8, arg, "--help")) {
8685 return usage(&builder, false, try stdout_stream);
8786 } else if (mem.eql(u8, arg, "--prefix")) {
88 prefix = try unwrapArg(arg_it.next(allocator) ?? {
87 prefix = try unwrapArg(arg_it.next(allocator) orelse {
8988 warn("Expected argument after --prefix\n\n");
9089 return usageAndErr(&builder, false, try stderr_stream);
9190 });
9291 } else if (mem.eql(u8, arg, "--search-prefix")) {
93 const search_prefix = try unwrapArg(arg_it.next(allocator) ?? {
92 const search_prefix = try unwrapArg(arg_it.next(allocator) orelse {
9493 warn("Expected argument after --search-prefix\n\n");
9594 return usageAndErr(&builder, false, try stderr_stream);
9695 });
......@@ -123,14 +122,17 @@ pub fn main() !void {
123122 return usageAndErr(&builder, true, try stderr_stream);
124123
125124 builder.make(targets.toSliceConst()) catch |err| {
126 if (err == error.InvalidStepName) {
127 return usageAndErr(&builder, true, try stderr_stream);
125 switch (err) {
126 error.InvalidStepName => {
127 return usageAndErr(&builder, true, try stderr_stream);
128 },
129 error.UncleanExit => os.exit(1),
130 else => return err,
128131 }
129 return err;
130132 };
131133}
132134
133fn runBuild(builder: &Builder) error!void {
135fn runBuild(builder: *Builder) error!void {
134136 switch (@typeId(@typeOf(root.build).ReturnType)) {
135137 builtin.TypeId.Void => root.build(builder),
136138 builtin.TypeId.ErrorUnion => try root.build(builder),
......@@ -138,7 +140,7 @@ fn runBuild(builder: &Builder) error!void {
138140 }
139141}
140142
141fn usage(builder: &Builder, already_ran_build: bool, out_stream: var) !void {
143fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
142144 // run the build script to collect the options
143145 if (!already_ran_build) {
144146 builder.setInstallPrefix(null);
......@@ -175,8 +177,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: var) !void {
175177 try out_stream.print(" (none)\n");
176178 } else {
177179 for (builder.available_options_list.toSliceConst()) |option| {
178 const name = try fmt.allocPrint(allocator,
179 " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
180 const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
180181 defer allocator.free(name);
181182 try out_stream.print("{s24} {}\n", name, option.description);
182183 }
......@@ -197,12 +198,12 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: var) !void {
197198 );
198199}
199200
200fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: var) error {
201fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) error {
201202 usage(builder, already_ran_build, out_stream) catch {};
202203 return error.InvalidArgs;
203204}
204205
205const UnwrapArgError = error {OutOfMemory};
206const UnwrapArgError = error{OutOfMemory};
206207
207208fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 {
208209 return arg catch |err| {
std/special/builtin.zig+296-26
......@@ -5,7 +5,7 @@ const builtin = @import("builtin");
55
66// Avoid dragging in the runtime safety mechanisms into this .o file,
77// unless we're trying to test this file.
8pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {
8pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
99 if (builtin.is_test) {
1010 @setCold(true);
1111 @import("std").debug.panic("{}", msg);
......@@ -14,39 +14,39 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn
1414 }
1515}
1616
17export fn memset(dest: ?&u8, c: u8, n: usize) ?&u8 {
17export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {
1818 @setRuntimeSafety(false);
1919
2020 var index: usize = 0;
2121 while (index != n) : (index += 1)
22 (??dest)[index] = c;
22 dest.?[index] = c;
2323
2424 return dest;
2525}
2626
27export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) ?&u8 {
27export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8 {
2828 @setRuntimeSafety(false);
2929
3030 var index: usize = 0;
3131 while (index != n) : (index += 1)
32 (??dest)[index] = (??src)[index];
32 dest.?[index] = src.?[index];
3333
3434 return dest;
3535}
3636
37export fn memmove(dest: ?&u8, src: ?&const u8, n: usize) ?&u8 {
37export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {
3838 @setRuntimeSafety(false);
3939
4040 if (@ptrToInt(dest) < @ptrToInt(src)) {
4141 var index: usize = 0;
4242 while (index != n) : (index += 1) {
43 (??dest)[index] = (??src)[index];
43 dest.?[index] = src.?[index];
4444 }
4545 } else {
4646 var index = n;
4747 while (index != 0) {
4848 index -= 1;
49 (??dest)[index] = (??src)[index];
49 dest.?[index] = src.?[index];
5050 }
5151 }
5252
......@@ -54,25 +54,75 @@ export fn memmove(dest: ?&u8, src: ?&const u8, n: usize) ?&u8 {
5454}
5555
5656comptime {
57 if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) {
57 if (builtin.mode != builtin.Mode.ReleaseFast and
58 builtin.mode != builtin.Mode.ReleaseSmall and
59 builtin.os != builtin.Os.windows)
60 {
5861 @export("__stack_chk_fail", __stack_chk_fail, builtin.GlobalLinkage.Strong);
5962 }
63 if (builtin.os == builtin.Os.linux and builtin.arch == builtin.Arch.x86_64) {
64 @export("clone", clone, builtin.GlobalLinkage.Strong);
65 }
6066}
6167extern fn __stack_chk_fail() noreturn {
6268 @panic("stack smashing detected");
6369}
6470
71// TODO we should be able to put this directly in std/linux/x86_64.zig but
72// it causes a segfault in release mode. this is a workaround of calling it
73// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.
74nakedcc fn clone() void {
75 asm volatile (
76 \\ xor %%eax,%%eax
77 \\ mov $56,%%al
78 \\ mov %%rdi,%%r11
79 \\ mov %%rdx,%%rdi
80 \\ mov %%r8,%%rdx
81 \\ mov %%r9,%%r8
82 \\ mov 8(%%rsp),%%r10
83 \\ mov %%r11,%%r9
84 \\ and $-16,%%rsi
85 \\ sub $8,%%rsi
86 \\ mov %%rcx,(%%rsi)
87 \\ syscall
88 \\ test %%eax,%%eax
89 \\ jnz 1f
90 \\ xor %%ebp,%%ebp
91 \\ pop %%rdi
92 \\ call *%%r9
93 \\ mov %%eax,%%edi
94 \\ xor %%eax,%%eax
95 \\ mov $60,%%al
96 \\ syscall
97 \\ hlt
98 \\1: ret
99 \\
100 );
101}
102
65103const math = @import("../math/index.zig");
66104
67export fn fmodf(x: f32, y: f32) f32 { return generic_fmod(f32, x, y); }
68export fn fmod(x: f64, y: f64) f64 { return generic_fmod(f64, x, y); }
105export fn fmodf(x: f32, y: f32) f32 {
106 return generic_fmod(f32, x, y);
107}
108export fn fmod(x: f64, y: f64) f64 {
109 return generic_fmod(f64, x, y);
110}
69111
70112// TODO add intrinsics for these (and probably the double version too)
71113// and have the math stuff use the intrinsic. same as @mod and @rem
72export fn floorf(x: f32) f32 { return math.floor(x); }
73export fn ceilf(x: f32) f32 { return math.ceil(x); }
74export fn floor(x: f64) f64 { return math.floor(x); }
75export fn ceil(x: f64) f64 { return math.ceil(x); }
114export fn floorf(x: f32) f32 {
115 return math.floor(x);
116}
117export fn ceilf(x: f32) f32 {
118 return math.ceil(x);
119}
120export fn floor(x: f64) f64 {
121 return math.floor(x);
122}
123export fn ceil(x: f64) f64 {
124 return math.ceil(x);
125}
76126
77127fn generic_fmod(comptime T: type, x: T, y: T) T {
78128 @setRuntimeSafety(false);
......@@ -85,9 +135,9 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
85135 const mask = if (T == f32) 0xff else 0x7ff;
86136 var ux = @bitCast(uint, x);
87137 var uy = @bitCast(uint, y);
88 var ex = i32((ux >> digits) & mask);
89 var ey = i32((uy >> digits) & mask);
90 const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1);
138 var ex = @intCast(i32, (ux >> digits) & mask);
139 var ey = @intCast(i32, (uy >> digits) & mask);
140 const sx = if (T == f32) @intCast(u32, ux & 0x80000000) else @intCast(i32, ux >> bits_minus_1);
91141 var i: uint = undefined;
92142
93143 if (uy << 1 == 0 or isNan(uint, uy) or ex == mask)
......@@ -102,16 +152,22 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
102152 // normalize x and y
103153 if (ex == 0) {
104154 i = ux << exp_bits;
105 while (i >> bits_minus_1 == 0) : (b: {ex -= 1; break :b i <<= 1;}) {}
106 ux <<= log2uint(@bitCast(u32, -ex + 1));
155 while (i >> bits_minus_1 == 0) : (b: {
156 ex -= 1;
157 i <<= 1;
158 }) {}
159 ux <<= @intCast(log2uint, @bitCast(u32, -ex + 1));
107160 } else {
108161 ux &= @maxValue(uint) >> exp_bits;
109162 ux |= 1 << digits;
110163 }
111164 if (ey == 0) {
112165 i = uy << exp_bits;
113 while (i >> bits_minus_1 == 0) : (b: {ey -= 1; break :b i <<= 1;}) {}
114 uy <<= log2uint(@bitCast(u32, -ey + 1));
166 while (i >> bits_minus_1 == 0) : (b: {
167 ey -= 1;
168 i <<= 1;
169 }) {}
170 uy <<= @intCast(log2uint, @bitCast(u32, -ey + 1));
115171 } else {
116172 uy &= @maxValue(uint) >> exp_bits;
117173 uy |= 1 << digits;
......@@ -133,25 +189,30 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
133189 return 0 * x;
134190 ux = i;
135191 }
136 while (ux >> digits == 0) : (b: {ux <<= 1; break :b ex -= 1;}) {}
192 while (ux >> digits == 0) : (b: {
193 ux <<= 1;
194 ex -= 1;
195 }) {}
137196
138197 // scale result up
139198 if (ex > 0) {
140199 ux -%= 1 << digits;
141200 ux |= uint(@bitCast(u32, ex)) << digits;
142201 } else {
143 ux >>= log2uint(@bitCast(u32, -ex + 1));
202 ux >>= @intCast(log2uint, @bitCast(u32, -ex + 1));
144203 }
145204 if (T == f32) {
146205 ux |= sx;
147206 } else {
148 ux |= uint(sx) << bits_minus_1;
207 ux |= @intCast(uint, sx) << bits_minus_1;
149208 }
150209 return @bitCast(T, ux);
151210}
152211
153212fn isNan(comptime T: type, bits: T) bool {
154 if (T == u32) {
213 if (T == u16) {
214 return (bits & 0x7fff) > 0x7c00;
215 } else if (T == u32) {
155216 return (bits & 0x7fffffff) > 0x7f800000;
156217 } else if (T == u64) {
157218 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
......@@ -159,3 +220,212 @@ fn isNan(comptime T: type, bits: T) bool {
159220 unreachable;
160221 }
161222}
223
224// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
225// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
226// potentially some edge cases remaining that are not handled in the same way.
227export fn sqrt(x: f64) f64 {
228 const tiny: f64 = 1.0e-300;
229 const sign: u32 = 0x80000000;
230 const u = @bitCast(u64, x);
231
232 var ix0 = @intCast(u32, u >> 32);
233 var ix1 = @intCast(u32, u & 0xFFFFFFFF);
234
235 // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
236 if (ix0 & 0x7FF00000 == 0x7FF00000) {
237 return x * x + x;
238 }
239
240 // sqrt(+-0) = +-0
241 if (x == 0.0) {
242 return x;
243 }
244 // sqrt(-ve) = snan
245 if (ix0 & sign != 0) {
246 return math.snan(f64);
247 }
248
249 // normalize x
250 var m = @intCast(i32, ix0 >> 20);
251 if (m == 0) {
252 // subnormal
253 while (ix0 == 0) {
254 m -= 21;
255 ix0 |= ix1 >> 11;
256 ix1 <<= 21;
257 }
258
259 // subnormal
260 var i: u32 = 0;
261 while (ix0 & 0x00100000 == 0) : (i += 1) {
262 ix0 <<= 1;
263 }
264 m -= @intCast(i32, i) - 1;
265 ix0 |= ix1 >> @intCast(u5, 32 - i);
266 ix1 <<= @intCast(u5, i);
267 }
268
269 // unbias exponent
270 m -= 1023;
271 ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
272 if (m & 1 != 0) {
273 ix0 += ix0 + (ix1 >> 31);
274 ix1 = ix1 +% ix1;
275 }
276 m >>= 1;
277
278 // sqrt(x) bit by bit
279 ix0 += ix0 + (ix1 >> 31);
280 ix1 = ix1 +% ix1;
281
282 var q: u32 = 0;
283 var q1: u32 = 0;
284 var s0: u32 = 0;
285 var s1: u32 = 0;
286 var r: u32 = 0x00200000;
287 var t: u32 = undefined;
288 var t1: u32 = undefined;
289
290 while (r != 0) {
291 t = s0 +% r;
292 if (t <= ix0) {
293 s0 = t + r;
294 ix0 -= t;
295 q += r;
296 }
297 ix0 = ix0 +% ix0 +% (ix1 >> 31);
298 ix1 = ix1 +% ix1;
299 r >>= 1;
300 }
301
302 r = sign;
303 while (r != 0) {
304 t = s1 +% r;
305 t = s0;
306 if (t < ix0 or (t == ix0 and t1 <= ix1)) {
307 s1 = t1 +% r;
308 if (t1 & sign == sign and s1 & sign == 0) {
309 s0 += 1;
310 }
311 ix0 -= t;
312 if (ix1 < t1) {
313 ix0 -= 1;
314 }
315 ix1 = ix1 -% t1;
316 q1 += r;
317 }
318 ix0 = ix0 +% ix0 +% (ix1 >> 31);
319 ix1 = ix1 +% ix1;
320 r >>= 1;
321 }
322
323 // rounding direction
324 if (ix0 | ix1 != 0) {
325 var z = 1.0 - tiny; // raise inexact
326 if (z >= 1.0) {
327 z = 1.0 + tiny;
328 if (q1 == 0xFFFFFFFF) {
329 q1 = 0;
330 q += 1;
331 } else if (z > 1.0) {
332 if (q1 == 0xFFFFFFFE) {
333 q += 1;
334 }
335 q1 += 2;
336 } else {
337 q1 += q1 & 1;
338 }
339 }
340 }
341
342 ix0 = (q >> 1) + 0x3FE00000;
343 ix1 = q1 >> 1;
344 if (q & 1 != 0) {
345 ix1 |= 0x80000000;
346 }
347
348 // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
349 // behaviour at least.
350 var iix0 = @intCast(i32, ix0);
351 iix0 = iix0 +% (m << 20);
352
353 const uz = (@intCast(u64, iix0) << 32) | ix1;
354 return @bitCast(f64, uz);
355}
356
357export fn sqrtf(x: f32) f32 {
358 const tiny: f32 = 1.0e-30;
359 const sign: i32 = @bitCast(i32, u32(0x80000000));
360 var ix: i32 = @bitCast(i32, x);
361
362 if ((ix & 0x7F800000) == 0x7F800000) {
363 return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
364 }
365
366 // zero
367 if (ix <= 0) {
368 if (ix & ~sign == 0) {
369 return x; // sqrt (+-0) = +-0
370 }
371 if (ix < 0) {
372 return math.snan(f32);
373 }
374 }
375
376 // normalize
377 var m = ix >> 23;
378 if (m == 0) {
379 // subnormal
380 var i: i32 = 0;
381 while (ix & 0x00800000 == 0) : (i += 1) {
382 ix <<= 1;
383 }
384 m -= i - 1;
385 }
386
387 m -= 127; // unbias exponent
388 ix = (ix & 0x007FFFFF) | 0x00800000;
389
390 if (m & 1 != 0) { // odd m, double x to even
391 ix += ix;
392 }
393
394 m >>= 1; // m = [m / 2]
395
396 // sqrt(x) bit by bit
397 ix += ix;
398 var q: i32 = 0; // q = sqrt(x)
399 var s: i32 = 0;
400 var r: i32 = 0x01000000; // r = moving bit right -> left
401
402 while (r != 0) {
403 const t = s + r;
404 if (t <= ix) {
405 s = t + r;
406 ix -= t;
407 q += r;
408 }
409 ix += ix;
410 r >>= 1;
411 }
412
413 // floating add to find rounding direction
414 if (ix != 0) {
415 var z = 1.0 - tiny; // inexact
416 if (z >= 1.0) {
417 z = 1.0 + tiny;
418 if (z > 1.0) {
419 q += 2;
420 } else {
421 if (q & 1 != 0) {
422 q += 1;
423 }
424 }
425 }
426 }
427
428 ix = (q >> 1) + 0x3f000000;
429 ix += m << 23;
430 return @bitCast(f32, ix);
431}
std/special/compiler_rt/comparetf2.zig+28-35
......@@ -1,4 +1,4 @@
1// TODO https://github.com/zig-lang/zig/issues/305
1// TODO https://github.com/ziglang/zig/issues/641
22// and then make the return types of some of these functions the enum instead of c_int
33const LE_LESS = c_int(-1);
44const LE_EQUAL = c_int(0);
......@@ -38,28 +38,25 @@ pub extern fn __letf2(a: f128, b: f128) c_int {
3838
3939 // If at least one of a and b is positive, we get the same result comparing
4040 // a and b as signed integers as we would with a floating-point compare.
41 return if ((aInt & bInt) >= 0)
42 if (aInt < bInt)
43 LE_LESS
44 else if (aInt == bInt)
45 LE_EQUAL
46 else
47 LE_GREATER
41 return if ((aInt & bInt) >= 0) if (aInt < bInt)
42 LE_LESS
43 else if (aInt == bInt)
44 LE_EQUAL
4845 else
49 // Otherwise, both are negative, so we need to flip the sense of the
50 // comparison to get the correct result. (This assumes a twos- or ones-
51 // complement integer representation; if integers are represented in a
52 // sign-magnitude representation, then this flip is incorrect).
53 if (aInt > bInt)
54 LE_LESS
55 else if (aInt == bInt)
56 LE_EQUAL
57 else
58 LE_GREATER
59 ;
46 LE_GREATER else
47 // Otherwise, both are negative, so we need to flip the sense of the
48 // comparison to get the correct result. (This assumes a twos- or ones-
49 // complement integer representation; if integers are represented in a
50 // sign-magnitude representation, then this flip is incorrect).
51 if (aInt > bInt)
52 LE_LESS
53 else if (aInt == bInt)
54 LE_EQUAL
55 else
56 LE_GREATER;
6057}
6158
62// TODO https://github.com/zig-lang/zig/issues/305
59// TODO https://github.com/ziglang/zig/issues/641
6360// and then make the return types of some of these functions the enum instead of c_int
6461const GE_LESS = c_int(-1);
6562const GE_EQUAL = c_int(0);
......@@ -76,21 +73,17 @@ pub extern fn __getf2(a: f128, b: f128) c_int {
7673
7774 if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
7875 if ((aAbs | bAbs) == 0) return GE_EQUAL;
79 return if ((aInt & bInt) >= 0)
80 if (aInt < bInt)
81 GE_LESS
82 else if (aInt == bInt)
83 GE_EQUAL
84 else
85 GE_GREATER
76 return if ((aInt & bInt) >= 0) if (aInt < bInt)
77 GE_LESS
78 else if (aInt == bInt)
79 GE_EQUAL
80 else
81 GE_GREATER else if (aInt > bInt)
82 GE_LESS
83 else if (aInt == bInt)
84 GE_EQUAL
8685 else
87 if (aInt > bInt)
88 GE_LESS
89 else if (aInt == bInt)
90 GE_EQUAL
91 else
92 GE_GREATER
93 ;
86 GE_GREATER;
9487}
9588
9689pub extern fn __unordtf2(a: f128, b: f128) c_int {
......@@ -98,5 +91,5 @@ pub extern fn __unordtf2(a: f128, b: f128) c_int {
9891
9992 const aAbs = @bitCast(rep_t, a) & absMask;
10093 const bAbs = @bitCast(rep_t, b) & absMask;
101 return c_int(aAbs > infRep or bAbs > infRep);
94 return @boolToInt(aAbs > infRep or bAbs > infRep);
10295}
std/special/compiler_rt/divti3.zig created+26
......@@ -0,0 +1,26 @@
1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
4
5pub extern fn __divti3(a: i128, b: i128) i128 {
6 @setRuntimeSafety(builtin.is_test);
7
8 const s_a = a >> (i128.bit_count - 1);
9 const s_b = b >> (i128.bit_count - 1);
10
11 const an = (a ^ s_a) -% s_a;
12 const bn = (b ^ s_b) -% s_b;
13
14 const r = udivmod(u128, @bitCast(u128, an), @bitCast(u128, bn), null);
15 const s = s_a ^ s_b;
16 return (@bitCast(i128, r) ^ s) -% s;
17}
18
19pub extern fn __divti3_windows_x86_64(a: *const i128, b: *const i128) void {
20 @setRuntimeSafety(builtin.is_test);
21 compiler_rt.setXmm0(i128, __divti3(a.*, b.*));
22}
23
24test "import divti3" {
25 _ = @import("divti3_test.zig");
26}
std/special/compiler_rt/divti3_test.zig created+21
......@@ -0,0 +1,21 @@
1const __divti3 = @import("divti3.zig").__divti3;
2const assert = @import("std").debug.assert;
3
4fn test__divti3(a: i128, b: i128, expected: i128) void {
5 const x = __divti3(a, b);
6 assert(x == expected);
7}
8
9test "divti3" {
10 test__divti3(0, 1, 0);
11 test__divti3(0, -1, 0);
12 test__divti3(2, 1, 2);
13 test__divti3(2, -1, -2);
14 test__divti3(-2, 1, -2);
15 test__divti3(-2, -1, 2);
16
17 test__divti3(@bitCast(i128, u128(0x8 << 124)), 1, @bitCast(i128, u128(0x8 << 124)));
18 test__divti3(@bitCast(i128, u128(0x8 << 124)), -1, @bitCast(i128, u128(0x8 << 124)));
19 test__divti3(@bitCast(i128, u128(0x8 << 124)), -2, @bitCast(i128, u128(0x4 << 124)));
20 test__divti3(@bitCast(i128, u128(0x8 << 124)), 2, @bitCast(i128, u128(0xc << 124)));
21}
std/special/compiler_rt/extendXfYf2.zig created+89
......@@ -0,0 +1,89 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const is_test = builtin.is_test;
4
5pub extern fn __extenddftf2(a: f64) f128 {
6 return extendXfYf2(f128, f64, a);
7}
8
9pub extern fn __extendsftf2(a: f32) f128 {
10 return extendXfYf2(f128, f32, a);
11}
12
13pub extern fn __extendhfsf2(a: u16) f32 {
14 return extendXfYf2(f32, f16, @bitCast(f16, a));
15}
16
17const CHAR_BIT = 8;
18
19inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
20 const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
21 const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
22 const srcSigBits = std.math.floatMantissaBits(src_t);
23 const dstSigBits = std.math.floatMantissaBits(dst_t);
24 const SrcShift = std.math.Log2Int(src_rep_t);
25 const DstShift = std.math.Log2Int(dst_rep_t);
26
27 // Various constants whose values follow from the type parameters.
28 // Any reasonable optimizer will fold and propagate all of these.
29 const srcBits = @sizeOf(src_t) * CHAR_BIT;
30 const srcExpBits = srcBits - srcSigBits - 1;
31 const srcInfExp = (1 << srcExpBits) - 1;
32 const srcExpBias = srcInfExp >> 1;
33
34 const srcMinNormal = 1 << srcSigBits;
35 const srcInfinity = srcInfExp << srcSigBits;
36 const srcSignMask = 1 << (srcSigBits + srcExpBits);
37 const srcAbsMask = srcSignMask - 1;
38 const srcQNaN = 1 << (srcSigBits - 1);
39 const srcNaNCode = srcQNaN - 1;
40
41 const dstBits = @sizeOf(dst_t) * CHAR_BIT;
42 const dstExpBits = dstBits - dstSigBits - 1;
43 const dstInfExp = (1 << dstExpBits) - 1;
44 const dstExpBias = dstInfExp >> 1;
45
46 const dstMinNormal: dst_rep_t = dst_rep_t(1) << dstSigBits;
47
48 // Break a into a sign and representation of the absolute value
49 const aRep: src_rep_t = @bitCast(src_rep_t, a);
50 const aAbs: src_rep_t = aRep & srcAbsMask;
51 const sign: src_rep_t = aRep & srcSignMask;
52 var absResult: dst_rep_t = undefined;
53
54 if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) {
55 // a is a normal number.
56 // Extend to the destination type by shifting the significand and
57 // exponent into the proper position and rebiasing the exponent.
58 absResult = dst_rep_t(aAbs) << (dstSigBits - srcSigBits);
59 absResult += (dstExpBias - srcExpBias) << dstSigBits;
60 } else if (aAbs >= srcInfinity) {
61 // a is NaN or infinity.
62 // Conjure the result by beginning with infinity, then setting the qNaN
63 // bit (if needed) and right-aligning the rest of the trailing NaN
64 // payload field.
65 absResult = dstInfExp << dstSigBits;
66 absResult |= dst_rep_t(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
67 absResult |= dst_rep_t(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
68 } else if (aAbs != 0) {
69 // a is denormal.
70 // renormalize the significand and clear the leading bit, then insert
71 // the correct adjusted exponent in the destination type.
72 const scale: u32 = @clz(aAbs) - @clz(src_rep_t(srcMinNormal));
73 absResult = dst_rep_t(aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
74 absResult ^= dstMinNormal;
75 const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1;
76 absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits;
77 } else {
78 // a is zero.
79 absResult = 0;
80 }
81
82 // Apply the signbit to (dst_t)abs(a).
83 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | dst_rep_t(sign) << (dstBits - srcBits);
84 return @bitCast(dst_t, result);
85}
86
87test "import extendXfYf2" {
88 _ = @import("extendXfYf2_test.zig");
89}
std/special/compiler_rt/extendXfYf2_test.zig created+155
......@@ -0,0 +1,155 @@
1const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
2const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
3const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;
4const assert = @import("std").debug.assert;
5
6fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void {
7 const x = __extenddftf2(a);
8
9 const rep = @bitCast(u128, x);
10 const hi = @intCast(u64, rep >> 64);
11 const lo = @truncate(u64, rep);
12
13 if (hi == expectedHi and lo == expectedLo)
14 return;
15
16 // test other possible NaN representation(signal NaN)
17 if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) {
18 if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
19 ((hi & 0xffffffffffff) > 0 or lo > 0))
20 {
21 return;
22 }
23 }
24
25 @panic("__extenddftf2 test failure");
26}
27
28fn test__extendhfsf2(a: u16, expected: u32) void {
29 const x = __extendhfsf2(a);
30 const rep = @bitCast(u32, x);
31
32 if (rep == expected) {
33 if (rep & 0x7fffffff > 0x7f800000) {
34 return; // NaN is always unequal.
35 }
36 if (x == @bitCast(f32, expected)) {
37 return;
38 }
39 }
40
41 @panic("__extendhfsf2 test failure");
42}
43
44fn test__extendsftf2(a: f32, expectedHi: u64, expectedLo: u64) void {
45 const x = __extendsftf2(a);
46
47 const rep = @bitCast(u128, x);
48 const hi = @intCast(u64, rep >> 64);
49 const lo = @truncate(u64, rep);
50
51 if (hi == expectedHi and lo == expectedLo)
52 return;
53
54 // test other possible NaN representation(signal NaN)
55 if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) {
56 if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
57 ((hi & 0xffffffffffff) > 0 or lo > 0))
58 {
59 return;
60 }
61 }
62
63 @panic("__extendsftf2 test failure");
64}
65
66test "extenddftf2" {
67 // qNaN
68 test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0);
69
70 // NaN
71 test__extenddftf2(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0);
72
73 // inf
74 test__extenddftf2(makeInf64(), 0x7fff000000000000, 0x0);
75
76 // zero
77 test__extenddftf2(0.0, 0x0, 0x0);
78
79 test__extenddftf2(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000);
80
81 test__extenddftf2(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000);
82
83 test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000);
84
85 test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000);
86}
87
88test "extendhfsf2" {
89 test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN
90 test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN
91 test__extendhfsf2(0x7c01, 0x7f802000); // sNaN
92
93 test__extendhfsf2(0, 0); // 0
94 test__extendhfsf2(0x8000, 0x80000000); // -0
95
96 test__extendhfsf2(0x7c00, 0x7f800000); // inf
97 test__extendhfsf2(0xfc00, 0xff800000); // -inf
98
99 test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24
100 test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24
101
102 test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24
103 test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24
104
105 test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14
106 test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14
107
108 test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504
109 test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504
110
111 test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10
112 test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10
113
114 test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3
115 test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3
116}
117
118test "extendsftf2" {
119 // qNaN
120 test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0);
121 // NaN
122 test__extendsftf2(makeNaN32(0x410000), 0x7fff820000000000, 0x0);
123 // inf
124 test__extendsftf2(makeInf32(), 0x7fff000000000000, 0x0);
125 // zero
126 test__extendsftf2(0.0, 0x0, 0x0);
127 test__extendsftf2(0x1.23456p+5, 0x4004234560000000, 0x0);
128 test__extendsftf2(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0);
129 test__extendsftf2(0x1.23456p+45, 0x402c234560000000, 0x0);
130 test__extendsftf2(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0);
131}
132
133fn makeQNaN64() f64 {
134 return @bitCast(f64, u64(0x7ff8000000000000));
135}
136
137fn makeInf64() f64 {
138 return @bitCast(f64, u64(0x7ff0000000000000));
139}
140
141fn makeNaN64(rand: u64) f64 {
142 return @bitCast(f64, 0x7ff0000000000000 | (rand & 0xfffffffffffff));
143}
144
145fn makeQNaN32() f32 {
146 return @bitCast(f32, u32(0x7fc00000));
147}
148
149fn makeNaN32(rand: u32) f32 {
150 return @bitCast(f32, 0x7f800000 | (rand & 0x7fffff));
151}
152
153fn makeInf32() f32 {
154 return @bitCast(f32, u32(0x7f800000));
155}
std/special/compiler_rt/fixuint.zig+6-14
......@@ -1,5 +1,5 @@
11const is_test = @import("builtin").is_test;
2const Log2Int = @import("../../math/index.zig").Log2Int;
2const Log2Int = @import("std").math.Log2Int;
33
44pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t {
55 @setRuntimeSafety(is_test);
......@@ -32,28 +32,20 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t
3232 const aAbs: rep_t = aRep & absMask;
3333
3434 const sign = if ((aRep & signBit) != 0) i32(-1) else i32(1);
35 const exponent = i32(aAbs >> significandBits) - exponentBias;
35 const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias;
3636 const significand: rep_t = (aAbs & significandMask) | implicitBit;
3737
3838 // If either the value or the exponent is negative, the result is zero.
39 if (sign == -1 or exponent < 0)
40 return 0;
39 if (sign == -1 or exponent < 0) return 0;
4140
4241 // If the value is too large for the integer type, saturate.
43 if (c_uint(exponent) >= fixuint_t.bit_count)
44 return ~fixuint_t(0);
42 if (@intCast(c_uint, exponent) >= fixuint_t.bit_count) return ~fixuint_t(0);
4543
4644 // If 0 <= exponent < significandBits, right shift to get the result.
4745 // Otherwise, shift left.
4846 if (exponent < significandBits) {
49 // TODO this is a workaround for the mysterious "integer cast truncated bits"
50 // happening on the next line
51 @setRuntimeSafety(false);
52 return fixuint_t(significand >> Log2Int(rep_t)(significandBits - exponent));
47 return @intCast(fixuint_t, significand >> @intCast(Log2Int(rep_t), significandBits - exponent));
5348 } else {
54 // TODO this is a workaround for the mysterious "integer cast truncated bits"
55 // happening on the next line
56 @setRuntimeSafety(false);
57 return fixuint_t(significand) << Log2Int(fixuint_t)(exponent - significandBits);
49 return @intCast(fixuint_t, significand) << @intCast(Log2Int(fixuint_t), exponent - significandBits);
5850 }
5951}
std/special/compiler_rt/fixunsdfdi.zig-1
......@@ -9,4 +9,3 @@ pub extern fn __fixunsdfdi(a: f64) u64 {
99test "import fixunsdfdi" {
1010 _ = @import("fixunsdfdi_test.zig");
1111}
12
std/special/compiler_rt/fixunsdfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunsdfdi(a: f64, expected: u64) void {
55 const x = __fixunsdfdi(a);
std/special/compiler_rt/fixunsdfsi.zig-1
......@@ -9,4 +9,3 @@ pub extern fn __fixunsdfsi(a: f64) u32 {
99test "import fixunsdfsi" {
1010 _ = @import("fixunsdfsi_test.zig");
1111}
12
std/special/compiler_rt/fixunsdfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunsdfsi(a: f64, expected: u32) void {
55 const x = __fixunsdfsi(a);
std/special/compiler_rt/fixunsdfti_test.zig+1-2
......@@ -1,5 +1,5 @@
11const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunsdfti(a: f64, expected: u128) void {
55 const x = __fixunsdfti(a);
......@@ -44,4 +44,3 @@ test "fixunsdfti" {
4444 test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0);
4545 test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0);
4646}
47
std/special/compiler_rt/fixunssfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunssfdi(a: f32, expected: u64) void {
55 const x = __fixunssfdi(a);
std/special/compiler_rt/fixunssfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunssfsi(a: f32, expected: u32) void {
55 const x = __fixunssfsi(a);
std/special/compiler_rt/fixunssfti.zig-1
......@@ -9,4 +9,3 @@ pub extern fn __fixunssfti(a: f32) u128 {
99test "import fixunssfti" {
1010 _ = @import("fixunssfti_test.zig");
1111}
12
std/special/compiler_rt/fixunssfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunssfti(a: f32, expected: u128) void {
55 const x = __fixunssfti(a);
std/special/compiler_rt/fixunstfdi_test.zig+11-12
......@@ -1,5 +1,5 @@
11const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunstfdi(a: f128, expected: u64) void {
55 const x = __fixunstfdi(a);
......@@ -36,15 +36,14 @@ test "fixunstfdi" {
3636 test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0);
3737 test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0);
3838
39 // TODO enable these tests when we can parse f128 float literals
40 //test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF);
41 //test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001);
42 //test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000);
43 //test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF);
44 //test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE);
45 //test__fixunstfdi(0x1.p+64, 0xFFFFFFFFFFFFFFFF);
46
47 //test__fixunstfdi(-0x1.0000000000000000p+63, 0);
48 //test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0);
49 //test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0);
39 test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF);
40 test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001);
41 test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000);
42 test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF);
43 test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE);
44 test__fixunstfdi(0x1.p+64, 0xFFFFFFFFFFFFFFFF);
45
46 test__fixunstfdi(-0x1.0000000000000000p+63, 0);
47 test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0);
48 test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0);
5049}
std/special/compiler_rt/fixunstfsi_test.zig+3-3
......@@ -1,5 +1,5 @@
11const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunstfsi(a: f128, expected: u32) void {
55 const x = __fixunstfsi(a);
......@@ -11,9 +11,9 @@ const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000));
1111test "fixunstfsi" {
1212 test__fixunstfsi(inf128, 0xffffffff);
1313 test__fixunstfsi(0, 0x0);
14 //TODO test__fixunstfsi(0x1.23456789abcdefp+5, 0x24);
14 test__fixunstfsi(0x1.23456789abcdefp+5, 0x24);
1515 test__fixunstfsi(0x1.23456789abcdefp-3, 0x0);
16 //TODO test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456);
16 test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456);
1717 test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff);
1818 test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff);
1919 test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0);
std/special/compiler_rt/fixunstfti.zig-1
......@@ -9,4 +9,3 @@ pub extern fn __fixunstfti(a: f128) u128 {
99test "import fixunstfti" {
1010 _ = @import("fixunstfti_test.zig");
1111}
12
std/special/compiler_rt/fixunstfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunstfti(a: f128, expected: u128) void {
55 const x = __fixunstfti(a);
std/special/compiler_rt/floattidf.zig created+69
......@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const DBL_MANT_DIG = 53;
5
6pub extern fn __floattidf(arg: i128) f64 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var ai = arg;
13 const N: u32 = 128;
14 const si = ai >> @intCast(u7, (N - 1));
15 ai = ((ai ^ si) -% si);
16 var a = @bitCast(u128, ai);
17
18 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
19 var e: i32 = sd - 1; // exponent
20 if (sd > DBL_MANT_DIG) {
21 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
22 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
23 // 12345678901234567890123456
24 // 1 = msb 1 bit
25 // P = bit DBL_MANT_DIG-1 bits to the right of 1
26 // Q = bit DBL_MANT_DIG bits to the right of 1
27 // R = "or" of all bits to the right of Q
28 switch (sd) {
29 DBL_MANT_DIG + 1 => {
30 a <<= 1;
31 },
32 DBL_MANT_DIG + 2 => {},
33 else => {
34 const shift1_amt = @intCast(i32, sd - (DBL_MANT_DIG + 2));
35 const shift1_amt_u7 = @intCast(u7, shift1_amt);
36
37 const shift2_amt = @intCast(i32, N + (DBL_MANT_DIG + 2)) - sd;
38 const shift2_amt_u7 = @intCast(u7, shift2_amt);
39
40 a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, @maxValue(u128)) >> shift2_amt_u7)) != 0);
41 },
42 }
43 // finish
44 a |= @boolToInt((a & 4) != 0); // Or P into R
45 a += 1; // round - this step may add a significant bit
46 a >>= 2; // dump Q and R
47 // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
48 if ((a & (u128(1) << DBL_MANT_DIG)) != 0) {
49 a >>= 1;
50 e += 1;
51 }
52 // a is now rounded to DBL_MANT_DIG bits
53 } else {
54 a <<= @intCast(u7, DBL_MANT_DIG - sd);
55 // a is now rounded to DBL_MANT_DIG bits
56 }
57
58 const s = @bitCast(u128, arg) >> (128 - 32);
59 const high: u64 = (@intCast(u64, s) & 0x80000000) | // sign
60 (@intCast(u32, (e + 1023)) << 20) | // exponent
61 (@truncate(u32, a >> 32) & 0x000fffff); // mantissa-high
62 const low: u64 = @truncate(u32, a); // mantissa-low
63
64 return @bitCast(f64, low | (high << 32));
65}
66
67test "import floattidf" {
68 _ = @import("floattidf_test.zig");
69}
std/special/compiler_rt/floattidf_test.zig created+84
......@@ -0,0 +1,84 @@
1const __floattidf = @import("floattidf.zig").__floattidf;
2const assert = @import("std").debug.assert;
3
4fn test__floattidf(a: i128, expected: f64) void {
5 const x = __floattidf(a);
6 assert(x == expected);
7}
8
9test "floattidf" {
10 test__floattidf(0, 0.0);
11
12 test__floattidf(1, 1.0);
13 test__floattidf(2, 2.0);
14 test__floattidf(20, 20.0);
15 test__floattidf(-1, -1.0);
16 test__floattidf(-2, -2.0);
17 test__floattidf(-20, -20.0);
18
19 test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
20 test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
21 test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
22 test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
23
24 test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
25 test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
26 test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
27 test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
28
29 test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
30 test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127);
31
32 test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
33
34 test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
35 test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
36 test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
37 test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
38 test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
39
40 test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
41 test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
42 test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
43 test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
44 test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
45
46 test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
47 test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
48 test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
49 test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
50 test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
51 test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
52 test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
53 test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
54 test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
55 test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
56 test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
57 test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
58 test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
59 test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
60 test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
61
62 test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
63 test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
64 test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
65 test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
66 test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
67 test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
68 test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
69 test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
70 test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
71 test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
72 test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
73 test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
74 test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
75 test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
76 test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
77}
78
79fn make_ti(high: u64, low: u64) i128 {
80 var result: u128 = high;
81 result <<= 64;
82 result |= low;
83 return @bitCast(i128, result);
84}
std/special/compiler_rt/floattisf.zig created+69
......@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const FLT_MANT_DIG = 24;
5
6pub extern fn __floattisf(arg: i128) f32 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var ai = arg;
13 const N: u32 = 128;
14 const si = ai >> @intCast(u7, (N - 1));
15 ai = ((ai ^ si) -% si);
16 var a = @bitCast(u128, ai);
17
18 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
19 var e: i32 = sd - 1; // exponent
20
21 if (sd > FLT_MANT_DIG) {
22 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
23 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
24 // 12345678901234567890123456
25 // 1 = msb 1 bit
26 // P = bit FLT_MANT_DIG-1 bits to the right of 1
27 // Q = bit FLT_MANT_DIG bits to the right of 1
28 // R = "or" of all bits to the right of Q
29 switch (sd) {
30 FLT_MANT_DIG + 1 => {
31 a <<= 1;
32 },
33 FLT_MANT_DIG + 2 => {},
34 else => {
35 const shift1_amt = @intCast(i32, sd - (FLT_MANT_DIG + 2));
36 const shift1_amt_u7 = @intCast(u7, shift1_amt);
37
38 const shift2_amt = @intCast(i32, N + (FLT_MANT_DIG + 2)) - sd;
39 const shift2_amt_u7 = @intCast(u7, shift2_amt);
40
41 a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, @maxValue(u128)) >> shift2_amt_u7)) != 0);
42 },
43 }
44 // finish
45 a |= @boolToInt((a & 4) != 0); // Or P into R
46 a += 1; // round - this step may add a significant bit
47 a >>= 2; // dump Q and R
48 // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
49 if ((a & (u128(1) << FLT_MANT_DIG)) != 0) {
50 a >>= 1;
51 e += 1;
52 }
53 // a is now rounded to FLT_MANT_DIG bits
54 } else {
55 a <<= @intCast(u7, FLT_MANT_DIG - sd);
56 // a is now rounded to FLT_MANT_DIG bits
57 }
58
59 const s = @bitCast(u128, arg) >> (128 - 32);
60 const r = (@intCast(u32, s) & 0x80000000) | // sign
61 (@intCast(u32, (e + 127)) << 23) | // exponent
62 (@truncate(u32, a) & 0x007fffff); // mantissa-high
63
64 return @bitCast(f32, r);
65}
66
67test "import floattisf" {
68 _ = @import("floattisf_test.zig");
69}
std/special/compiler_rt/floattisf_test.zig created+60
......@@ -0,0 +1,60 @@
1const __floattisf = @import("floattisf.zig").__floattisf;
2const assert = @import("std").debug.assert;
3
4fn test__floattisf(a: i128, expected: f32) void {
5 const x = __floattisf(a);
6 assert(x == expected);
7}
8
9test "floattisf" {
10 test__floattisf(0, 0.0);
11
12 test__floattisf(1, 1.0);
13 test__floattisf(2, 2.0);
14 test__floattisf(-1, -1.0);
15 test__floattisf(-2, -2.0);
16
17 test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
18 test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
19
20 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62);
21 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62);
22
23 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63);
24 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63);
25
26 test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
27
28 test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
29 test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
30 test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
31 test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
32 test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
33
34 test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
35 test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
36 test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
37 test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
38 test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
39
40 test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114);
41
42 test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114);
43 test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114);
44 test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114);
45 test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114);
46 test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114);
47
48 test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114);
49 test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114);
50 test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114);
51 test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114);
52 test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114);
53}
54
55fn make_ti(high: u64, low: u64) i128 {
56 var result: u128 = high;
57 result <<= 64;
58 result |= low;
59 return @bitCast(i128, result);
60}
std/special/compiler_rt/floattitf.zig created+69
......@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const LDBL_MANT_DIG = 113;
5
6pub extern fn __floattitf(arg: i128) f128 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var ai = arg;
13 const N: u32 = 128;
14 const si = ai >> @intCast(u7, (N - 1));
15 ai = ((ai ^ si) -% si);
16 var a = @bitCast(u128, ai);
17
18 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
19 var e: i32 = sd - 1; // exponent
20 if (sd > LDBL_MANT_DIG) {
21 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
22 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
23 // 12345678901234567890123456
24 // 1 = msb 1 bit
25 // P = bit LDBL_MANT_DIG-1 bits to the right of 1
26 // Q = bit LDBL_MANT_DIG bits to the right of 1
27 // R = "or" of all bits to the right of Q
28 switch (sd) {
29 LDBL_MANT_DIG + 1 => {
30 a <<= 1;
31 },
32 LDBL_MANT_DIG + 2 => {},
33 else => {
34 const shift1_amt = @intCast(i32, sd - (LDBL_MANT_DIG + 2));
35 const shift1_amt_u7 = @intCast(u7, shift1_amt);
36
37 const shift2_amt = @intCast(i32, N + (LDBL_MANT_DIG + 2)) - sd;
38 const shift2_amt_u7 = @intCast(u7, shift2_amt);
39
40 a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, @maxValue(u128)) >> shift2_amt_u7)) != 0);
41 },
42 }
43 // finish
44 a |= @boolToInt((a & 4) != 0); // Or P into R
45 a += 1; // round - this step may add a significant bit
46 a >>= 2; // dump Q and R
47 // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
48 if ((a & (u128(1) << LDBL_MANT_DIG)) != 0) {
49 a >>= 1;
50 e += 1;
51 }
52 // a is now rounded to LDBL_MANT_DIG bits
53 } else {
54 a <<= @intCast(u7, LDBL_MANT_DIG - sd);
55 // a is now rounded to LDBL_MANT_DIG bits
56 }
57
58 const s = @bitCast(u128, arg) >> (128 - 64);
59 const high: u128 = (@intCast(u64, s) & 0x8000000000000000) | // sign
60 (@intCast(u64, (e + 16383)) << 48) | // exponent
61 (@truncate(u64, a >> 64) & 0x0000ffffffffffff); // mantissa-high
62 const low = @truncate(u64, a); // mantissa-low
63
64 return @bitCast(f128, low | (high << 64));
65}
66
67test "import floattitf" {
68 _ = @import("floattitf_test.zig");
69}
std/special/compiler_rt/floattitf_test.zig created+96
......@@ -0,0 +1,96 @@
1const __floattitf = @import("floattitf.zig").__floattitf;
2const assert = @import("std").debug.assert;
3
4fn test__floattitf(a: i128, expected: f128) void {
5 const x = __floattitf(a);
6 assert(x == expected);
7}
8
9test "floattitf" {
10 test__floattitf(0, 0.0);
11
12 test__floattitf(1, 1.0);
13 test__floattitf(2, 2.0);
14 test__floattitf(20, 20.0);
15 test__floattitf(-1, -1.0);
16 test__floattitf(-2, -2.0);
17 test__floattitf(-20, -20.0);
18
19 test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
20 test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
21 test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
22 test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
23
24 test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
25 test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
26 test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
27 test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
28
29 test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
30 test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126);
31
32 test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
33
34 test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
35 test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
36 test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
37 test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
38 test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
39
40 test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
41 test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
42 test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
43 test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
44 test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
45
46 test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
47 test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
48 test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
49 test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
50 test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
51 test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
52 test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
53 test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
54 test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
55 test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
56 test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
57 test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
58 test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
59 test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
60 test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
61
62 test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
63 test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
64 test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
65 test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
66 test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
67 test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
68 test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
69 test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
70 test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
71 test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
72 test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
73 test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
74 test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
75 test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
76 test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
77
78 test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
79
80 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
81 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
82 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
83 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
84 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
85 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
86 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
87 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
88 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
89}
90
91fn make_ti(high: u64, low: u64) i128 {
92 var result: u128 = high;
93 result <<= 64;
94 result |= low;
95 return @bitCast(i128, result);
96}
std/special/compiler_rt/floatunditf.zig created+28
......@@ -0,0 +1,28 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3const std = @import("std");
4
5pub extern fn __floatunditf(a: u128) f128 {
6 @setRuntimeSafety(is_test);
7
8 if (a == 0) {
9 return 0;
10 }
11
12 const mantissa_bits = std.math.floatMantissaBits(f128);
13 const exponent_bits = std.math.floatExponentBits(f128);
14 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15 const implicit_bit = 1 << mantissa_bits;
16
17 const exp = (u128.bit_count - 1) - @clz(a);
18 const shift = mantissa_bits - @intCast(u7, exp);
19
20 var result: u128 align(16) = (a << shift) ^ implicit_bit;
21 result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits;
22
23 return @bitCast(f128, result);
24}
25
26test "import floatunditf" {
27 _ = @import("floatunditf_test.zig");
28}
std/special/compiler_rt/floatunditf_test.zig created+33
......@@ -0,0 +1,33 @@
1const __floatunditf = @import("floatunditf.zig").__floatunditf;
2const assert = @import("std").debug.assert;
3
4fn test__floatunditf(a: u128, expected_hi: u64, expected_lo: u64) void {
5 const x = __floatunditf(a);
6
7 const x_repr = @bitCast(u128, x);
8 const x_hi = @intCast(u64, x_repr >> 64);
9 const x_lo = @truncate(u64, x_repr);
10
11 if (x_hi == expected_hi and x_lo == expected_lo) {
12 return;
13 }
14 // nan repr
15 else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
16 if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
17 return;
18 }
19 }
20
21 @panic("__floatunditf test failure");
22}
23
24test "floatunditf" {
25 test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000);
26 test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000);
27 test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0);
28 test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000);
29 test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000);
30 test__floatunditf(0x2, 0x4000000000000000, 0x0);
31 test__floatunditf(0x1, 0x3fff000000000000, 0x0);
32 test__floatunditf(0x0, 0x0, 0x0);
33}
std/special/compiler_rt/floatunsitf.zig created+29
......@@ -0,0 +1,29 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3const std = @import("std");
4
5pub extern fn __floatunsitf(a: u64) f128 {
6 @setRuntimeSafety(is_test);
7
8 if (a == 0) {
9 return 0;
10 }
11
12 const mantissa_bits = std.math.floatMantissaBits(f128);
13 const exponent_bits = std.math.floatExponentBits(f128);
14 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15 const implicit_bit = 1 << mantissa_bits;
16
17 const exp = (u64.bit_count - 1) - @clz(a);
18 const shift = mantissa_bits - @intCast(u7, exp);
19
20 // TODO(#1148): @bitCast alignment error
21 var result align(16) = (@intCast(u128, a) << shift) ^ implicit_bit;
22 result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits;
23
24 return @bitCast(f128, result);
25}
26
27test "import floatunsitf" {
28 _ = @import("floatunsitf_test.zig");
29}
std/special/compiler_rt/floatunsitf_test.zig created+29
......@@ -0,0 +1,29 @@
1const __floatunsitf = @import("floatunsitf.zig").__floatunsitf;
2const assert = @import("std").debug.assert;
3
4fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void {
5 const x = __floatunsitf(a);
6
7 const x_repr = @bitCast(u128, x);
8 const x_hi = @intCast(u64, x_repr >> 64);
9 const x_lo = @truncate(u64, x_repr);
10
11 if (x_hi == expected_hi and x_lo == expected_lo) {
12 return;
13 }
14 // nan repr
15 else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
16 if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
17 return;
18 }
19 }
20
21 @panic("__floatunsitf test failure");
22}
23
24test "floatunsitf" {
25 test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0);
26 test__floatunsitf(0, 0x0, 0x0);
27 test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0);
28 test__floatunsitf(0x12345678, 0x401b234567800000, 0x0);
29}
std/special/compiler_rt/floatuntidf.zig created+60
......@@ -0,0 +1,60 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const DBL_MANT_DIG = 53;
5
6pub extern fn __floatuntidf(arg: u128) f64 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var a = arg;
13 const N: u32 = @sizeOf(u128) * 8;
14 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
15 var e: i32 = sd - 1; // exponent
16 if (sd > DBL_MANT_DIG) {
17 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
18 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
19 // 12345678901234567890123456
20 // 1 = msb 1 bit
21 // P = bit DBL_MANT_DIG-1 bits to the right of 1
22 // Q = bit DBL_MANT_DIG bits to the right of 1
23 // R = "or" of all bits to the right of Q
24 switch (sd) {
25 DBL_MANT_DIG + 1 => {
26 a <<= 1;
27 },
28 DBL_MANT_DIG + 2 => {},
29 else => {
30 const shift_amt = @bitCast(i32, N + (DBL_MANT_DIG + 2)) - sd;
31 const shift_amt_u7 = @intCast(u7, shift_amt);
32 a = (a >> @intCast(u7, sd - (DBL_MANT_DIG + 2))) |
33 @boolToInt((a & (u128(@maxValue(u128)) >> shift_amt_u7)) != 0);
34 },
35 }
36 // finish
37 a |= @boolToInt((a & 4) != 0); // Or P into R
38 a += 1; // round - this step may add a significant bit
39 a >>= 2; // dump Q and R
40 // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
41 if ((a & (u128(1) << DBL_MANT_DIG)) != 0) {
42 a >>= 1;
43 e += 1;
44 }
45 // a is now rounded to DBL_MANT_DIG bits
46 } else {
47 a <<= @intCast(u7, DBL_MANT_DIG - sd);
48 // a is now rounded to DBL_MANT_DIG bits
49 }
50
51 const high: u64 = @bitCast(u32, (e + 1023) << 20) | // exponent
52 (@truncate(u32, a >> 32) & 0x000FFFFF); // mantissa-high
53 const low = @truncate(u32, a); // mantissa-low
54
55 return @bitCast(f64, low | (high << 32));
56}
57
58test "import floatuntidf" {
59 _ = @import("floatuntidf_test.zig");
60}
std/special/compiler_rt/floatuntidf_test.zig created+81
......@@ -0,0 +1,81 @@
1const __floatuntidf = @import("floatuntidf.zig").__floatuntidf;
2const assert = @import("std").debug.assert;
3
4fn test__floatuntidf(a: u128, expected: f64) void {
5 const x = __floatuntidf(a);
6 assert(x == expected);
7}
8
9test "floatuntidf" {
10 test__floatuntidf(0, 0.0);
11
12 test__floatuntidf(1, 1.0);
13 test__floatuntidf(2, 2.0);
14 test__floatuntidf(20, 20.0);
15
16 test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
17 test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
18 test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
19 test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
20
21 test__floatuntidf(make_ti(0x8000008000000000, 0), 0x1.000001p+127);
22 test__floatuntidf(make_ti(0x8000000000000800, 0), 0x1.0000000000001p+127);
23 test__floatuntidf(make_ti(0x8000010000000000, 0), 0x1.000002p+127);
24 test__floatuntidf(make_ti(0x8000000000001000, 0), 0x1.0000000000002p+127);
25
26 test__floatuntidf(make_ti(0x8000000000000000, 0), 0x1.000000p+127);
27 test__floatuntidf(make_ti(0x8000000000000001, 0), 0x1.0000000000000002p+127);
28
29 test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
30
31 test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
32 test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
33 test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
34 test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
35 test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
36
37 test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
38 test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
39 test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
40 test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
41 test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
42
43 test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
44 test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
45 test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
46 test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
47 test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
48 test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
49 test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
50 test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
51 test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
52 test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
53 test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
54 test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
55 test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
56 test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
57 test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
58
59 test__floatuntidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
60 test__floatuntidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
61 test__floatuntidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
62 test__floatuntidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
63 test__floatuntidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
64 test__floatuntidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
65 test__floatuntidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
66 test__floatuntidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
67 test__floatuntidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
68 test__floatuntidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
69 test__floatuntidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
70 test__floatuntidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
71 test__floatuntidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
72 test__floatuntidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
73 test__floatuntidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
74}
75
76fn make_ti(high: u64, low: u64) u128 {
77 var result: u128 = high;
78 result <<= 64;
79 result |= low;
80 return result;
81}
std/special/compiler_rt/floatuntisf.zig created+59
......@@ -0,0 +1,59 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const FLT_MANT_DIG = 24;
5
6pub extern fn __floatuntisf(arg: u128) f32 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var a = arg;
13 const N: u32 = @sizeOf(u128) * 8;
14 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
15 var e: i32 = sd - 1; // exponent
16 if (sd > FLT_MANT_DIG) {
17 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
18 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
19 // 12345678901234567890123456
20 // 1 = msb 1 bit
21 // P = bit FLT_MANT_DIG-1 bits to the right of 1
22 // Q = bit FLT_MANT_DIG bits to the right of 1
23 // R = "or" of all bits to the right of Q
24 switch (sd) {
25 FLT_MANT_DIG + 1 => {
26 a <<= 1;
27 },
28 FLT_MANT_DIG + 2 => {},
29 else => {
30 const shift_amt = @bitCast(i32, N + (FLT_MANT_DIG + 2)) - sd;
31 const shift_amt_u7 = @intCast(u7, shift_amt);
32 a = (a >> @intCast(u7, sd - (FLT_MANT_DIG + 2))) |
33 @boolToInt((a & (u128(@maxValue(u128)) >> shift_amt_u7)) != 0);
34 },
35 }
36 // finish
37 a |= @boolToInt((a & 4) != 0); // Or P into R
38 a += 1; // round - this step may add a significant bit
39 a >>= 2; // dump Q and R
40 // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
41 if ((a & (u128(1) << FLT_MANT_DIG)) != 0) {
42 a >>= 1;
43 e += 1;
44 }
45 // a is now rounded to FLT_MANT_DIG bits
46 } else {
47 a <<= @intCast(u7, FLT_MANT_DIG - sd);
48 // a is now rounded to FLT_MANT_DIG bits
49 }
50
51 const high = @bitCast(u32, (e + 127) << 23); // exponent
52 const low = @truncate(u32, a) & 0x007fffff; // mantissa
53
54 return @bitCast(f32, high | low);
55}
56
57test "import floatuntisf" {
58 _ = @import("floatuntisf_test.zig");
59}
std/special/compiler_rt/floatuntisf_test.zig created+72
......@@ -0,0 +1,72 @@
1const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;
2const assert = @import("std").debug.assert;
3
4fn test__floatuntisf(a: u128, expected: f32) void {
5 const x = __floatuntisf(a);
6 assert(x == expected);
7}
8
9test "floatuntisf" {
10 test__floatuntisf(0, 0.0);
11
12 test__floatuntisf(1, 1.0);
13 test__floatuntisf(2, 2.0);
14 test__floatuntisf(20, 20.0);
15
16 test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
17 test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
18
19 test__floatuntisf(make_ti(0x8000008000000000, 0), 0x1.000001p+127);
20 test__floatuntisf(make_ti(0x8000000000000800, 0), 0x1.0p+127);
21 test__floatuntisf(make_ti(0x8000010000000000, 0), 0x1.000002p+127);
22
23 test__floatuntisf(make_ti(0x8000000000000000, 0), 0x1.000000p+127);
24
25 test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
26
27 test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
28 test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
29
30 test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
31
32 test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
33 test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
34 test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
35
36 test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64);
37 test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64);
38
39 test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
40
41 test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
42 test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
43 test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
44 test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
45 test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
46
47 test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
48 test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
49 test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
50 test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
51 test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
52
53 test__floatuntisf(make_ti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76);
54 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76);
55 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76);
56 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76);
57 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76);
58 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76);
59 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76);
60 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76);
61 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76);
62 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76);
63 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76);
64 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76);
65}
66
67fn make_ti(high: u64, low: u64) u128 {
68 var result: u128 = high;
69 result <<= 64;
70 result |= low;
71 return result;
72}
std/special/compiler_rt/floatuntitf.zig created+60
......@@ -0,0 +1,60 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const LDBL_MANT_DIG = 113;
5
6pub extern fn __floatuntitf(arg: u128) f128 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var a = arg;
13 const N: u32 = @sizeOf(u128) * 8;
14 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
15 var e: i32 = sd - 1; // exponent
16 if (sd > LDBL_MANT_DIG) {
17 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
18 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
19 // 12345678901234567890123456
20 // 1 = msb 1 bit
21 // P = bit LDBL_MANT_DIG-1 bits to the right of 1
22 // Q = bit LDBL_MANT_DIG bits to the right of 1
23 // R = "or" of all bits to the right of Q
24 switch (sd) {
25 LDBL_MANT_DIG + 1 => {
26 a <<= 1;
27 },
28 LDBL_MANT_DIG + 2 => {},
29 else => {
30 const shift_amt = @bitCast(i32, N + (LDBL_MANT_DIG + 2)) - sd;
31 const shift_amt_u7 = @intCast(u7, shift_amt);
32 a = (a >> @intCast(u7, sd - (LDBL_MANT_DIG + 2))) |
33 @boolToInt((a & (u128(@maxValue(u128)) >> shift_amt_u7)) != 0);
34 },
35 }
36 // finish
37 a |= @boolToInt((a & 4) != 0); // Or P into R
38 a += 1; // round - this step may add a significant bit
39 a >>= 2; // dump Q and R
40 // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
41 if ((a & (u128(1) << LDBL_MANT_DIG)) != 0) {
42 a >>= 1;
43 e += 1;
44 }
45 // a is now rounded to LDBL_MANT_DIG bits
46 } else {
47 a <<= @intCast(u7, LDBL_MANT_DIG - sd);
48 // a is now rounded to LDBL_MANT_DIG bits
49 }
50
51 const high: u128 = (@intCast(u64, (e + 16383)) << 48) | // exponent
52 (@truncate(u64, a >> 64) & 0x0000ffffffffffff); // mantissa-high
53 const low = @truncate(u64, a); // mantissa-low
54
55 return @bitCast(f128, low | (high << 64));
56}
57
58test "import floatuntitf" {
59 _ = @import("floatuntitf_test.zig");
60}
std/special/compiler_rt/floatuntitf_test.zig created+99
......@@ -0,0 +1,99 @@
1const __floatuntitf = @import("floatuntitf.zig").__floatuntitf;
2const assert = @import("std").debug.assert;
3
4fn test__floatuntitf(a: u128, expected: f128) void {
5 const x = __floatuntitf(a);
6 assert(x == expected);
7}
8
9test "floatuntitf" {
10 test__floatuntitf(0, 0.0);
11
12 test__floatuntitf(1, 1.0);
13 test__floatuntitf(2, 2.0);
14 test__floatuntitf(20, 20.0);
15
16 test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
17 test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
18 test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
19 test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
20 test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59);
21 test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60);
22 test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60);
23
24 test__floatuntitf(0x8000008000000000, 0x8.000008p+60);
25 test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60);
26 test__floatuntitf(0x8000010000000000, 0x8.00001p+60);
27 test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60);
28
29 test__floatuntitf(0x8000000000000000, 0x8p+60);
30 test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60);
31
32 test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
33
34 test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
35 test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
36 test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
37 test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
38 test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
39
40 test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
41 test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
42 test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
43 test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
44 test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
45
46 test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
47 test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
48 test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
49 test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
50 test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
51 test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
52 test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
53 test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
54 test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
55 test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
56 test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
57 test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
58 test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
59 test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
60 test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
61
62 test__floatuntitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
63 test__floatuntitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
64 test__floatuntitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
65 test__floatuntitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
66 test__floatuntitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
67 test__floatuntitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
68 test__floatuntitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
69 test__floatuntitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
70 test__floatuntitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
71 test__floatuntitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
72 test__floatuntitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
73 test__floatuntitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
74 test__floatuntitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
75 test__floatuntitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
76 test__floatuntitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
77
78 test__floatuntitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
79
80 test__floatuntitf(make_ti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127);
81 test__floatuntitf(make_ti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128);
82
83 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
84 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
85 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
86 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
87 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
88 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
89 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
90 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
91 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
92}
93
94fn make_ti(high: u64, low: u64) u128 {
95 var result: u128 = high;
96 result <<= 64;
97 result |= low;
98 return result;
99}
std/special/compiler_rt/index.zig+729-156
......@@ -15,10 +15,31 @@ comptime {
1515 @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);
1616 @export("__netf2", @import("comparetf2.zig").__letf2, linkage);
1717 @export("__gttf2", @import("comparetf2.zig").__getf2, linkage);
18 @export("__gnu_h2f_ieee", @import("extendXfYf2.zig").__extendhfsf2, linkage);
19 @export("__gnu_f2h_ieee", @import("truncXfYf2.zig").__truncsfhf2, linkage);
1820 }
1921
2022 @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
2123
24 @export("__floattitf", @import("floattitf.zig").__floattitf, linkage);
25 @export("__floattidf", @import("floattidf.zig").__floattidf, linkage);
26 @export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
27
28 @export("__floatunditf", @import("floatunditf.zig").__floatunditf, linkage);
29 @export("__floatunsitf", @import("floatunsitf.zig").__floatunsitf, linkage);
30
31 @export("__floatuntitf", @import("floatuntitf.zig").__floatuntitf, linkage);
32 @export("__floatuntidf", @import("floatuntidf.zig").__floatuntidf, linkage);
33 @export("__floatuntisf", @import("floatuntisf.zig").__floatuntisf, linkage);
34
35 @export("__extenddftf2", @import("extendXfYf2.zig").__extenddftf2, linkage);
36 @export("__extendsftf2", @import("extendXfYf2.zig").__extendsftf2, linkage);
37 @export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
38
39 @export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
40 @export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage);
41 @export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage);
42
2243 @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);
2344 @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);
2445 @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage);
......@@ -32,10 +53,6 @@ comptime {
3253 @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage);
3354
3455 @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage);
35 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
36
37 @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
38 @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
3956
4057 @export("__udivsi3", __udivsi3, linkage);
4158 @export("__udivdi3", __udivdi3, linkage);
......@@ -62,27 +79,50 @@ comptime {
6279 @export("__chkstk", __chkstk, strong_linkage);
6380 @export("___chkstk_ms", ___chkstk_ms, linkage);
6481 }
82 @export("__divti3", @import("divti3.zig").__divti3_windows_x86_64, linkage);
83 @export("__muloti4", @import("muloti4.zig").__muloti4_windows_x86_64, linkage);
84 @export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage);
85 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
86 @export("__umodti3", @import("umodti3.zig").__umodti3_windows_x86_64, linkage);
6587 },
6688 else => {},
6789 }
90 } else {
91 @export("__divti3", @import("divti3.zig").__divti3, linkage);
92 @export("__muloti4", @import("muloti4.zig").__muloti4, linkage);
93 @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
94 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
95 @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
6896 }
6997}
7098
71const assert = @import("../../index.zig").debug.assert;
99const std = @import("std");
100const assert = std.debug.assert;
72101
73102const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
74103
75104// Avoid dragging in the runtime safety mechanisms into this .o file,
76105// unless we're trying to test this file.
77pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {
106pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
78107 @setCold(true);
79108 if (is_test) {
80 @import("std").debug.panic("{}", msg);
109 std.debug.panic("{}", msg);
81110 } else {
82111 unreachable;
83112 }
84113}
85114
115pub fn setXmm0(comptime T: type, value: T) void {
116 comptime assert(builtin.arch == builtin.Arch.x86_64);
117 const aligned_value: T align(16) = value;
118 asm volatile (
119 \\movaps (%[ptr]), %%xmm0
120 :
121 : [ptr] "r" (&aligned_value)
122 : "xmm0"
123 );
124}
125
86126extern fn __udivdi3(a: u64, b: u64) u64 {
87127 @setRuntimeSafety(is_test);
88128 return __udivmoddi4(a, b, null);
......@@ -144,7 +184,8 @@ fn isArmArch() bool {
144184 builtin.Arch.armebv6t2,
145185 builtin.Arch.armebv5,
146186 builtin.Arch.armebv5te,
147 builtin.Arch.armebv4t => true,
187 builtin.Arch.armebv4t,
188 => true,
148189 else => false,
149190 };
150191}
......@@ -159,7 +200,10 @@ nakedcc fn __aeabi_uidivmod() void {
159200 \\ ldr r1, [sp]
160201 \\ add sp, sp, #4
161202 \\ pop { pc }
162 ::: "r2", "r1");
203 :
204 :
205 : "r2", "r1"
206 );
163207}
164208
165209// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
......@@ -265,39 +309,40 @@ nakedcc fn ___chkstk_ms() align(4) void {
265309 );
266310}
267311
268extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) u32 {
312extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 {
269313 @setRuntimeSafety(is_test);
270314
271315 const d = __udivsi3(a, b);
272 *rem = u32(i32(a) -% (i32(d) * i32(b)));
316 rem.* = @bitCast(u32, @bitCast(i32, a) -% (@bitCast(i32, d) * @bitCast(i32, b)));
273317 return d;
274318}
275319
276
277320extern fn __udivsi3(n: u32, d: u32) u32 {
278321 @setRuntimeSafety(is_test);
279322
280323 const n_uword_bits: c_uint = u32.bit_count;
281324 // special cases
282 if (d == 0)
283 return 0; // ?!
284 if (n == 0)
285 return 0;
325 if (d == 0) return 0; // ?!
326 if (n == 0) return 0;
286327 var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
287328 // 0 <= sr <= n_uword_bits - 1 or sr large
288 if (sr > n_uword_bits - 1) // d > r
329 if (sr > n_uword_bits - 1) {
330 // d > r
289331 return 0;
290 if (sr == n_uword_bits - 1) // d == 1
332 }
333 if (sr == n_uword_bits - 1) {
334 // d == 1
291335 return n;
336 }
292337 sr += 1;
293338 // 1 <= sr <= n_uword_bits - 1
294339 // Not a special case
295 var q: u32 = n << u5(n_uword_bits - sr);
296 var r: u32 = n >> u5(sr);
340 var q: u32 = n << @intCast(u5, n_uword_bits - sr);
341 var r: u32 = n >> @intCast(u5, sr);
297342 var carry: u32 = 0;
298343 while (sr > 0) : (sr -= 1) {
299344 // r:q = ((r:q) << 1) | carry
300 r = (r << 1) | (q >> u5(n_uword_bits - 1));
345 r = (r << 1) | (q >> @intCast(u5, n_uword_bits - 1));
301346 q = (q << 1) | carry;
302347 // carry = 0;
303348 // if (r.all >= d.all)
......@@ -305,8 +350,8 @@ extern fn __udivsi3(n: u32, d: u32) u32 {
305350 // r.all -= d.all;
306351 // carry = 1;
307352 // }
308 const s = i32(d -% r -% 1) >> u5(n_uword_bits - 1);
309 carry = u32(s & 1);
353 const s = @intCast(i32, d -% r -% 1) >> @intCast(u5, n_uword_bits - 1);
354 carry = @intCast(u32, s & 1);
310355 r -= d & @bitCast(u32, s);
311356 }
312357 q = (q << 1) | carry;
......@@ -327,139 +372,667 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
327372}
328373
329374test "test_udivsi3" {
330 const cases = [][3]u32 {
331 []u32{0x00000000, 0x00000001, 0x00000000},
332 []u32{0x00000000, 0x00000002, 0x00000000},
333 []u32{0x00000000, 0x00000003, 0x00000000},
334 []u32{0x00000000, 0x00000010, 0x00000000},
335 []u32{0x00000000, 0x078644FA, 0x00000000},
336 []u32{0x00000000, 0x0747AE14, 0x00000000},
337 []u32{0x00000000, 0x7FFFFFFF, 0x00000000},
338 []u32{0x00000000, 0x80000000, 0x00000000},
339 []u32{0x00000000, 0xFFFFFFFD, 0x00000000},
340 []u32{0x00000000, 0xFFFFFFFE, 0x00000000},
341 []u32{0x00000000, 0xFFFFFFFF, 0x00000000},
342 []u32{0x00000001, 0x00000001, 0x00000001},
343 []u32{0x00000001, 0x00000002, 0x00000000},
344 []u32{0x00000001, 0x00000003, 0x00000000},
345 []u32{0x00000001, 0x00000010, 0x00000000},
346 []u32{0x00000001, 0x078644FA, 0x00000000},
347 []u32{0x00000001, 0x0747AE14, 0x00000000},
348 []u32{0x00000001, 0x7FFFFFFF, 0x00000000},
349 []u32{0x00000001, 0x80000000, 0x00000000},
350 []u32{0x00000001, 0xFFFFFFFD, 0x00000000},
351 []u32{0x00000001, 0xFFFFFFFE, 0x00000000},
352 []u32{0x00000001, 0xFFFFFFFF, 0x00000000},
353 []u32{0x00000002, 0x00000001, 0x00000002},
354 []u32{0x00000002, 0x00000002, 0x00000001},
355 []u32{0x00000002, 0x00000003, 0x00000000},
356 []u32{0x00000002, 0x00000010, 0x00000000},
357 []u32{0x00000002, 0x078644FA, 0x00000000},
358 []u32{0x00000002, 0x0747AE14, 0x00000000},
359 []u32{0x00000002, 0x7FFFFFFF, 0x00000000},
360 []u32{0x00000002, 0x80000000, 0x00000000},
361 []u32{0x00000002, 0xFFFFFFFD, 0x00000000},
362 []u32{0x00000002, 0xFFFFFFFE, 0x00000000},
363 []u32{0x00000002, 0xFFFFFFFF, 0x00000000},
364 []u32{0x00000003, 0x00000001, 0x00000003},
365 []u32{0x00000003, 0x00000002, 0x00000001},
366 []u32{0x00000003, 0x00000003, 0x00000001},
367 []u32{0x00000003, 0x00000010, 0x00000000},
368 []u32{0x00000003, 0x078644FA, 0x00000000},
369 []u32{0x00000003, 0x0747AE14, 0x00000000},
370 []u32{0x00000003, 0x7FFFFFFF, 0x00000000},
371 []u32{0x00000003, 0x80000000, 0x00000000},
372 []u32{0x00000003, 0xFFFFFFFD, 0x00000000},
373 []u32{0x00000003, 0xFFFFFFFE, 0x00000000},
374 []u32{0x00000003, 0xFFFFFFFF, 0x00000000},
375 []u32{0x00000010, 0x00000001, 0x00000010},
376 []u32{0x00000010, 0x00000002, 0x00000008},
377 []u32{0x00000010, 0x00000003, 0x00000005},
378 []u32{0x00000010, 0x00000010, 0x00000001},
379 []u32{0x00000010, 0x078644FA, 0x00000000},
380 []u32{0x00000010, 0x0747AE14, 0x00000000},
381 []u32{0x00000010, 0x7FFFFFFF, 0x00000000},
382 []u32{0x00000010, 0x80000000, 0x00000000},
383 []u32{0x00000010, 0xFFFFFFFD, 0x00000000},
384 []u32{0x00000010, 0xFFFFFFFE, 0x00000000},
385 []u32{0x00000010, 0xFFFFFFFF, 0x00000000},
386 []u32{0x078644FA, 0x00000001, 0x078644FA},
387 []u32{0x078644FA, 0x00000002, 0x03C3227D},
388 []u32{0x078644FA, 0x00000003, 0x028216FE},
389 []u32{0x078644FA, 0x00000010, 0x0078644F},
390 []u32{0x078644FA, 0x078644FA, 0x00000001},
391 []u32{0x078644FA, 0x0747AE14, 0x00000001},
392 []u32{0x078644FA, 0x7FFFFFFF, 0x00000000},
393 []u32{0x078644FA, 0x80000000, 0x00000000},
394 []u32{0x078644FA, 0xFFFFFFFD, 0x00000000},
395 []u32{0x078644FA, 0xFFFFFFFE, 0x00000000},
396 []u32{0x078644FA, 0xFFFFFFFF, 0x00000000},
397 []u32{0x0747AE14, 0x00000001, 0x0747AE14},
398 []u32{0x0747AE14, 0x00000002, 0x03A3D70A},
399 []u32{0x0747AE14, 0x00000003, 0x026D3A06},
400 []u32{0x0747AE14, 0x00000010, 0x00747AE1},
401 []u32{0x0747AE14, 0x078644FA, 0x00000000},
402 []u32{0x0747AE14, 0x0747AE14, 0x00000001},
403 []u32{0x0747AE14, 0x7FFFFFFF, 0x00000000},
404 []u32{0x0747AE14, 0x80000000, 0x00000000},
405 []u32{0x0747AE14, 0xFFFFFFFD, 0x00000000},
406 []u32{0x0747AE14, 0xFFFFFFFE, 0x00000000},
407 []u32{0x0747AE14, 0xFFFFFFFF, 0x00000000},
408 []u32{0x7FFFFFFF, 0x00000001, 0x7FFFFFFF},
409 []u32{0x7FFFFFFF, 0x00000002, 0x3FFFFFFF},
410 []u32{0x7FFFFFFF, 0x00000003, 0x2AAAAAAA},
411 []u32{0x7FFFFFFF, 0x00000010, 0x07FFFFFF},
412 []u32{0x7FFFFFFF, 0x078644FA, 0x00000011},
413 []u32{0x7FFFFFFF, 0x0747AE14, 0x00000011},
414 []u32{0x7FFFFFFF, 0x7FFFFFFF, 0x00000001},
415 []u32{0x7FFFFFFF, 0x80000000, 0x00000000},
416 []u32{0x7FFFFFFF, 0xFFFFFFFD, 0x00000000},
417 []u32{0x7FFFFFFF, 0xFFFFFFFE, 0x00000000},
418 []u32{0x7FFFFFFF, 0xFFFFFFFF, 0x00000000},
419 []u32{0x80000000, 0x00000001, 0x80000000},
420 []u32{0x80000000, 0x00000002, 0x40000000},
421 []u32{0x80000000, 0x00000003, 0x2AAAAAAA},
422 []u32{0x80000000, 0x00000010, 0x08000000},
423 []u32{0x80000000, 0x078644FA, 0x00000011},
424 []u32{0x80000000, 0x0747AE14, 0x00000011},
425 []u32{0x80000000, 0x7FFFFFFF, 0x00000001},
426 []u32{0x80000000, 0x80000000, 0x00000001},
427 []u32{0x80000000, 0xFFFFFFFD, 0x00000000},
428 []u32{0x80000000, 0xFFFFFFFE, 0x00000000},
429 []u32{0x80000000, 0xFFFFFFFF, 0x00000000},
430 []u32{0xFFFFFFFD, 0x00000001, 0xFFFFFFFD},
431 []u32{0xFFFFFFFD, 0x00000002, 0x7FFFFFFE},
432 []u32{0xFFFFFFFD, 0x00000003, 0x55555554},
433 []u32{0xFFFFFFFD, 0x00000010, 0x0FFFFFFF},
434 []u32{0xFFFFFFFD, 0x078644FA, 0x00000022},
435 []u32{0xFFFFFFFD, 0x0747AE14, 0x00000023},
436 []u32{0xFFFFFFFD, 0x7FFFFFFF, 0x00000001},
437 []u32{0xFFFFFFFD, 0x80000000, 0x00000001},
438 []u32{0xFFFFFFFD, 0xFFFFFFFD, 0x00000001},
439 []u32{0xFFFFFFFD, 0xFFFFFFFE, 0x00000000},
440 []u32{0xFFFFFFFD, 0xFFFFFFFF, 0x00000000},
441 []u32{0xFFFFFFFE, 0x00000001, 0xFFFFFFFE},
442 []u32{0xFFFFFFFE, 0x00000002, 0x7FFFFFFF},
443 []u32{0xFFFFFFFE, 0x00000003, 0x55555554},
444 []u32{0xFFFFFFFE, 0x00000010, 0x0FFFFFFF},
445 []u32{0xFFFFFFFE, 0x078644FA, 0x00000022},
446 []u32{0xFFFFFFFE, 0x0747AE14, 0x00000023},
447 []u32{0xFFFFFFFE, 0x7FFFFFFF, 0x00000002},
448 []u32{0xFFFFFFFE, 0x80000000, 0x00000001},
449 []u32{0xFFFFFFFE, 0xFFFFFFFD, 0x00000001},
450 []u32{0xFFFFFFFE, 0xFFFFFFFE, 0x00000001},
451 []u32{0xFFFFFFFE, 0xFFFFFFFF, 0x00000000},
452 []u32{0xFFFFFFFF, 0x00000001, 0xFFFFFFFF},
453 []u32{0xFFFFFFFF, 0x00000002, 0x7FFFFFFF},
454 []u32{0xFFFFFFFF, 0x00000003, 0x55555555},
455 []u32{0xFFFFFFFF, 0x00000010, 0x0FFFFFFF},
456 []u32{0xFFFFFFFF, 0x078644FA, 0x00000022},
457 []u32{0xFFFFFFFF, 0x0747AE14, 0x00000023},
458 []u32{0xFFFFFFFF, 0x7FFFFFFF, 0x00000002},
459 []u32{0xFFFFFFFF, 0x80000000, 0x00000001},
460 []u32{0xFFFFFFFF, 0xFFFFFFFD, 0x00000001},
461 []u32{0xFFFFFFFF, 0xFFFFFFFE, 0x00000001},
462 []u32{0xFFFFFFFF, 0xFFFFFFFF, 0x00000001},
375 const cases = [][3]u32{
376 []u32{
377 0x00000000,
378 0x00000001,
379 0x00000000,
380 },
381 []u32{
382 0x00000000,
383 0x00000002,
384 0x00000000,
385 },
386 []u32{
387 0x00000000,
388 0x00000003,
389 0x00000000,
390 },
391 []u32{
392 0x00000000,
393 0x00000010,
394 0x00000000,
395 },
396 []u32{
397 0x00000000,
398 0x078644FA,
399 0x00000000,
400 },
401 []u32{
402 0x00000000,
403 0x0747AE14,
404 0x00000000,
405 },
406 []u32{
407 0x00000000,
408 0x7FFFFFFF,
409 0x00000000,
410 },
411 []u32{
412 0x00000000,
413 0x80000000,
414 0x00000000,
415 },
416 []u32{
417 0x00000000,
418 0xFFFFFFFD,
419 0x00000000,
420 },
421 []u32{
422 0x00000000,
423 0xFFFFFFFE,
424 0x00000000,
425 },
426 []u32{
427 0x00000000,
428 0xFFFFFFFF,
429 0x00000000,
430 },
431 []u32{
432 0x00000001,
433 0x00000001,
434 0x00000001,
435 },
436 []u32{
437 0x00000001,
438 0x00000002,
439 0x00000000,
440 },
441 []u32{
442 0x00000001,
443 0x00000003,
444 0x00000000,
445 },
446 []u32{
447 0x00000001,
448 0x00000010,
449 0x00000000,
450 },
451 []u32{
452 0x00000001,
453 0x078644FA,
454 0x00000000,
455 },
456 []u32{
457 0x00000001,
458 0x0747AE14,
459 0x00000000,
460 },
461 []u32{
462 0x00000001,
463 0x7FFFFFFF,
464 0x00000000,
465 },
466 []u32{
467 0x00000001,
468 0x80000000,
469 0x00000000,
470 },
471 []u32{
472 0x00000001,
473 0xFFFFFFFD,
474 0x00000000,
475 },
476 []u32{
477 0x00000001,
478 0xFFFFFFFE,
479 0x00000000,
480 },
481 []u32{
482 0x00000001,
483 0xFFFFFFFF,
484 0x00000000,
485 },
486 []u32{
487 0x00000002,
488 0x00000001,
489 0x00000002,
490 },
491 []u32{
492 0x00000002,
493 0x00000002,
494 0x00000001,
495 },
496 []u32{
497 0x00000002,
498 0x00000003,
499 0x00000000,
500 },
501 []u32{
502 0x00000002,
503 0x00000010,
504 0x00000000,
505 },
506 []u32{
507 0x00000002,
508 0x078644FA,
509 0x00000000,
510 },
511 []u32{
512 0x00000002,
513 0x0747AE14,
514 0x00000000,
515 },
516 []u32{
517 0x00000002,
518 0x7FFFFFFF,
519 0x00000000,
520 },
521 []u32{
522 0x00000002,
523 0x80000000,
524 0x00000000,
525 },
526 []u32{
527 0x00000002,
528 0xFFFFFFFD,
529 0x00000000,
530 },
531 []u32{
532 0x00000002,
533 0xFFFFFFFE,
534 0x00000000,
535 },
536 []u32{
537 0x00000002,
538 0xFFFFFFFF,
539 0x00000000,
540 },
541 []u32{
542 0x00000003,
543 0x00000001,
544 0x00000003,
545 },
546 []u32{
547 0x00000003,
548 0x00000002,
549 0x00000001,
550 },
551 []u32{
552 0x00000003,
553 0x00000003,
554 0x00000001,
555 },
556 []u32{
557 0x00000003,
558 0x00000010,
559 0x00000000,
560 },
561 []u32{
562 0x00000003,
563 0x078644FA,
564 0x00000000,
565 },
566 []u32{
567 0x00000003,
568 0x0747AE14,
569 0x00000000,
570 },
571 []u32{
572 0x00000003,
573 0x7FFFFFFF,
574 0x00000000,
575 },
576 []u32{
577 0x00000003,
578 0x80000000,
579 0x00000000,
580 },
581 []u32{
582 0x00000003,
583 0xFFFFFFFD,
584 0x00000000,
585 },
586 []u32{
587 0x00000003,
588 0xFFFFFFFE,
589 0x00000000,
590 },
591 []u32{
592 0x00000003,
593 0xFFFFFFFF,
594 0x00000000,
595 },
596 []u32{
597 0x00000010,
598 0x00000001,
599 0x00000010,
600 },
601 []u32{
602 0x00000010,
603 0x00000002,
604 0x00000008,
605 },
606 []u32{
607 0x00000010,
608 0x00000003,
609 0x00000005,
610 },
611 []u32{
612 0x00000010,
613 0x00000010,
614 0x00000001,
615 },
616 []u32{
617 0x00000010,
618 0x078644FA,
619 0x00000000,
620 },
621 []u32{
622 0x00000010,
623 0x0747AE14,
624 0x00000000,
625 },
626 []u32{
627 0x00000010,
628 0x7FFFFFFF,
629 0x00000000,
630 },
631 []u32{
632 0x00000010,
633 0x80000000,
634 0x00000000,
635 },
636 []u32{
637 0x00000010,
638 0xFFFFFFFD,
639 0x00000000,
640 },
641 []u32{
642 0x00000010,
643 0xFFFFFFFE,
644 0x00000000,
645 },
646 []u32{
647 0x00000010,
648 0xFFFFFFFF,
649 0x00000000,
650 },
651 []u32{
652 0x078644FA,
653 0x00000001,
654 0x078644FA,
655 },
656 []u32{
657 0x078644FA,
658 0x00000002,
659 0x03C3227D,
660 },
661 []u32{
662 0x078644FA,
663 0x00000003,
664 0x028216FE,
665 },
666 []u32{
667 0x078644FA,
668 0x00000010,
669 0x0078644F,
670 },
671 []u32{
672 0x078644FA,
673 0x078644FA,
674 0x00000001,
675 },
676 []u32{
677 0x078644FA,
678 0x0747AE14,
679 0x00000001,
680 },
681 []u32{
682 0x078644FA,
683 0x7FFFFFFF,
684 0x00000000,
685 },
686 []u32{
687 0x078644FA,
688 0x80000000,
689 0x00000000,
690 },
691 []u32{
692 0x078644FA,
693 0xFFFFFFFD,
694 0x00000000,
695 },
696 []u32{
697 0x078644FA,
698 0xFFFFFFFE,
699 0x00000000,
700 },
701 []u32{
702 0x078644FA,
703 0xFFFFFFFF,
704 0x00000000,
705 },
706 []u32{
707 0x0747AE14,
708 0x00000001,
709 0x0747AE14,
710 },
711 []u32{
712 0x0747AE14,
713 0x00000002,
714 0x03A3D70A,
715 },
716 []u32{
717 0x0747AE14,
718 0x00000003,
719 0x026D3A06,
720 },
721 []u32{
722 0x0747AE14,
723 0x00000010,
724 0x00747AE1,
725 },
726 []u32{
727 0x0747AE14,
728 0x078644FA,
729 0x00000000,
730 },
731 []u32{
732 0x0747AE14,
733 0x0747AE14,
734 0x00000001,
735 },
736 []u32{
737 0x0747AE14,
738 0x7FFFFFFF,
739 0x00000000,
740 },
741 []u32{
742 0x0747AE14,
743 0x80000000,
744 0x00000000,
745 },
746 []u32{
747 0x0747AE14,
748 0xFFFFFFFD,
749 0x00000000,
750 },
751 []u32{
752 0x0747AE14,
753 0xFFFFFFFE,
754 0x00000000,
755 },
756 []u32{
757 0x0747AE14,
758 0xFFFFFFFF,
759 0x00000000,
760 },
761 []u32{
762 0x7FFFFFFF,
763 0x00000001,
764 0x7FFFFFFF,
765 },
766 []u32{
767 0x7FFFFFFF,
768 0x00000002,
769 0x3FFFFFFF,
770 },
771 []u32{
772 0x7FFFFFFF,
773 0x00000003,
774 0x2AAAAAAA,
775 },
776 []u32{
777 0x7FFFFFFF,
778 0x00000010,
779 0x07FFFFFF,
780 },
781 []u32{
782 0x7FFFFFFF,
783 0x078644FA,
784 0x00000011,
785 },
786 []u32{
787 0x7FFFFFFF,
788 0x0747AE14,
789 0x00000011,
790 },
791 []u32{
792 0x7FFFFFFF,
793 0x7FFFFFFF,
794 0x00000001,
795 },
796 []u32{
797 0x7FFFFFFF,
798 0x80000000,
799 0x00000000,
800 },
801 []u32{
802 0x7FFFFFFF,
803 0xFFFFFFFD,
804 0x00000000,
805 },
806 []u32{
807 0x7FFFFFFF,
808 0xFFFFFFFE,
809 0x00000000,
810 },
811 []u32{
812 0x7FFFFFFF,
813 0xFFFFFFFF,
814 0x00000000,
815 },
816 []u32{
817 0x80000000,
818 0x00000001,
819 0x80000000,
820 },
821 []u32{
822 0x80000000,
823 0x00000002,
824 0x40000000,
825 },
826 []u32{
827 0x80000000,
828 0x00000003,
829 0x2AAAAAAA,
830 },
831 []u32{
832 0x80000000,
833 0x00000010,
834 0x08000000,
835 },
836 []u32{
837 0x80000000,
838 0x078644FA,
839 0x00000011,
840 },
841 []u32{
842 0x80000000,
843 0x0747AE14,
844 0x00000011,
845 },
846 []u32{
847 0x80000000,
848 0x7FFFFFFF,
849 0x00000001,
850 },
851 []u32{
852 0x80000000,
853 0x80000000,
854 0x00000001,
855 },
856 []u32{
857 0x80000000,
858 0xFFFFFFFD,
859 0x00000000,
860 },
861 []u32{
862 0x80000000,
863 0xFFFFFFFE,
864 0x00000000,
865 },
866 []u32{
867 0x80000000,
868 0xFFFFFFFF,
869 0x00000000,
870 },
871 []u32{
872 0xFFFFFFFD,
873 0x00000001,
874 0xFFFFFFFD,
875 },
876 []u32{
877 0xFFFFFFFD,
878 0x00000002,
879 0x7FFFFFFE,
880 },
881 []u32{
882 0xFFFFFFFD,
883 0x00000003,
884 0x55555554,
885 },
886 []u32{
887 0xFFFFFFFD,
888 0x00000010,
889 0x0FFFFFFF,
890 },
891 []u32{
892 0xFFFFFFFD,
893 0x078644FA,
894 0x00000022,
895 },
896 []u32{
897 0xFFFFFFFD,
898 0x0747AE14,
899 0x00000023,
900 },
901 []u32{
902 0xFFFFFFFD,
903 0x7FFFFFFF,
904 0x00000001,
905 },
906 []u32{
907 0xFFFFFFFD,
908 0x80000000,
909 0x00000001,
910 },
911 []u32{
912 0xFFFFFFFD,
913 0xFFFFFFFD,
914 0x00000001,
915 },
916 []u32{
917 0xFFFFFFFD,
918 0xFFFFFFFE,
919 0x00000000,
920 },
921 []u32{
922 0xFFFFFFFD,
923 0xFFFFFFFF,
924 0x00000000,
925 },
926 []u32{
927 0xFFFFFFFE,
928 0x00000001,
929 0xFFFFFFFE,
930 },
931 []u32{
932 0xFFFFFFFE,
933 0x00000002,
934 0x7FFFFFFF,
935 },
936 []u32{
937 0xFFFFFFFE,
938 0x00000003,
939 0x55555554,
940 },
941 []u32{
942 0xFFFFFFFE,
943 0x00000010,
944 0x0FFFFFFF,
945 },
946 []u32{
947 0xFFFFFFFE,
948 0x078644FA,
949 0x00000022,
950 },
951 []u32{
952 0xFFFFFFFE,
953 0x0747AE14,
954 0x00000023,
955 },
956 []u32{
957 0xFFFFFFFE,
958 0x7FFFFFFF,
959 0x00000002,
960 },
961 []u32{
962 0xFFFFFFFE,
963 0x80000000,
964 0x00000001,
965 },
966 []u32{
967 0xFFFFFFFE,
968 0xFFFFFFFD,
969 0x00000001,
970 },
971 []u32{
972 0xFFFFFFFE,
973 0xFFFFFFFE,
974 0x00000001,
975 },
976 []u32{
977 0xFFFFFFFE,
978 0xFFFFFFFF,
979 0x00000000,
980 },
981 []u32{
982 0xFFFFFFFF,
983 0x00000001,
984 0xFFFFFFFF,
985 },
986 []u32{
987 0xFFFFFFFF,
988 0x00000002,
989 0x7FFFFFFF,
990 },
991 []u32{
992 0xFFFFFFFF,
993 0x00000003,
994 0x55555555,
995 },
996 []u32{
997 0xFFFFFFFF,
998 0x00000010,
999 0x0FFFFFFF,
1000 },
1001 []u32{
1002 0xFFFFFFFF,
1003 0x078644FA,
1004 0x00000022,
1005 },
1006 []u32{
1007 0xFFFFFFFF,
1008 0x0747AE14,
1009 0x00000023,
1010 },
1011 []u32{
1012 0xFFFFFFFF,
1013 0x7FFFFFFF,
1014 0x00000002,
1015 },
1016 []u32{
1017 0xFFFFFFFF,
1018 0x80000000,
1019 0x00000001,
1020 },
1021 []u32{
1022 0xFFFFFFFF,
1023 0xFFFFFFFD,
1024 0x00000001,
1025 },
1026 []u32{
1027 0xFFFFFFFF,
1028 0xFFFFFFFE,
1029 0x00000001,
1030 },
1031 []u32{
1032 0xFFFFFFFF,
1033 0xFFFFFFFF,
1034 0x00000001,
1035 },
4631036 };
4641037
4651038 for (cases) |case| {
std/special/compiler_rt/muloti4.zig created+55
......@@ -0,0 +1,55 @@
1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
4
5pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {
6 @setRuntimeSafety(builtin.is_test);
7
8 const min = @bitCast(i128, u128(1 << (i128.bit_count - 1)));
9 const max = ~min;
10 overflow.* = 0;
11
12 const r = a *% b;
13 if (a == min) {
14 if (b != 0 and b != 1) {
15 overflow.* = 1;
16 }
17 return r;
18 }
19 if (b == min) {
20 if (a != 0 and a != 1) {
21 overflow.* = 1;
22 }
23 return r;
24 }
25
26 const sa = a >> (i128.bit_count - 1);
27 const abs_a = (a ^ sa) -% sa;
28 const sb = b >> (i128.bit_count - 1);
29 const abs_b = (b ^ sb) -% sb;
30
31 if (abs_a < 2 or abs_b < 2) {
32 return r;
33 }
34
35 if (sa == sb) {
36 if (abs_a > @divFloor(max, abs_b)) {
37 overflow.* = 1;
38 }
39 } else {
40 if (abs_a > @divFloor(min, -abs_b)) {
41 overflow.* = 1;
42 }
43 }
44
45 return r;
46}
47
48pub extern fn __muloti4_windows_x86_64(a: *const i128, b: *const i128, overflow: *c_int) void {
49 @setRuntimeSafety(builtin.is_test);
50 compiler_rt.setXmm0(i128, __muloti4(a.*, b.*, overflow));
51}
52
53test "import muloti4" {
54 _ = @import("muloti4_test.zig");
55}
std/special/compiler_rt/muloti4_test.zig created+76
......@@ -0,0 +1,76 @@
1const __muloti4 = @import("muloti4.zig").__muloti4;
2const assert = @import("std").debug.assert;
3
4fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) void {
5 var overflow: c_int = undefined;
6 const x = __muloti4(a, b, &overflow);
7 assert(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
8}
9
10test "muloti4" {
11 test__muloti4(0, 0, 0, 0);
12 test__muloti4(0, 1, 0, 0);
13 test__muloti4(1, 0, 0, 0);
14 test__muloti4(0, 10, 0, 0);
15 test__muloti4(10, 0, 0, 0);
16
17 test__muloti4(0, 81985529216486895, 0, 0);
18 test__muloti4(81985529216486895, 0, 0, 0);
19
20 test__muloti4(0, -1, 0, 0);
21 test__muloti4(-1, 0, 0, 0);
22 test__muloti4(0, -10, 0, 0);
23 test__muloti4(-10, 0, 0, 0);
24 test__muloti4(0, -81985529216486895, 0, 0);
25 test__muloti4(-81985529216486895, 0, 0, 0);
26
27 test__muloti4(3037000499, 3037000499, 9223372030926249001, 0);
28 test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0);
29 test__muloti4(3037000499, -3037000499, -9223372030926249001, 0);
30 test__muloti4(-3037000499, -3037000499, 9223372030926249001, 0);
31
32 test__muloti4(4398046511103, 2097152, 9223372036852678656, 0);
33 test__muloti4(-4398046511103, 2097152, -9223372036852678656, 0);
34 test__muloti4(4398046511103, -2097152, -9223372036852678656, 0);
35 test__muloti4(-4398046511103, -2097152, 9223372036852678656, 0);
36
37 test__muloti4(2097152, 4398046511103, 9223372036852678656, 0);
38 test__muloti4(-2097152, 4398046511103, -9223372036852678656, 0);
39 test__muloti4(2097152, -4398046511103, -9223372036852678656, 0);
40 test__muloti4(-2097152, -4398046511103, 9223372036852678656, 0);
41
42 test__muloti4(@bitCast(i128, u128(0x00000000000000B504F333F9DE5BE000)), @bitCast(i128, u128(0x000000000000000000B504F333F9DE5B)), @bitCast(i128, u128(0x7FFFFFFFFFFFF328DF915DA296E8A000)), 0);
43 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), -2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
44 test__muloti4(-2, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
45
46 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), -1, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
47 test__muloti4(-1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
48 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0, 0, 0);
49 test__muloti4(0, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0, 0);
50 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
51 test__muloti4(1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
52 test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
53 test__muloti4(2, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
54
55 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), -2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
56 test__muloti4(-2, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
57 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), -1, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
58 test__muloti4(-1, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
59 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 0, 0, 0);
60 test__muloti4(0, @bitCast(i128, u128(0x80000000000000000000000000000000)), 0, 0);
61 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 1, @bitCast(i128, u128(0x80000000000000000000000000000000)), 0);
62 test__muloti4(1, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 0);
63 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
64 test__muloti4(2, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
65
66 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), -2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
67 test__muloti4(-2, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
68 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), -1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
69 test__muloti4(-1, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
70 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 0, 0, 0);
71 test__muloti4(0, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0, 0);
72 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 1, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
73 test__muloti4(1, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
74 test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
75 test__muloti4(2, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
76}
std/special/compiler_rt/truncXfYf2.zig created+117
......@@ -0,0 +1,117 @@
1const std = @import("std");
2
3pub extern fn __truncsfhf2(a: f32) u16 {
4 return @bitCast(u16, truncXfYf2(f16, f32, a));
5}
6
7pub extern fn __trunctfsf2(a: f128) f32 {
8 return truncXfYf2(f32, f128, a);
9}
10
11pub extern fn __trunctfdf2(a: f128) f64 {
12 return truncXfYf2(f64, f128, a);
13}
14
15inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
16 const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
17 const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
18 const srcSigBits = std.math.floatMantissaBits(src_t);
19 const dstSigBits = std.math.floatMantissaBits(dst_t);
20 const SrcShift = std.math.Log2Int(src_rep_t);
21 const DstShift = std.math.Log2Int(dst_rep_t);
22
23 // Various constants whose values follow from the type parameters.
24 // Any reasonable optimizer will fold and propagate all of these.
25 const srcBits = src_t.bit_count;
26 const srcExpBits = srcBits - srcSigBits - 1;
27 const srcInfExp = (1 << srcExpBits) - 1;
28 const srcExpBias = srcInfExp >> 1;
29
30 const srcMinNormal = 1 << srcSigBits;
31 const srcSignificandMask = srcMinNormal - 1;
32 const srcInfinity = srcInfExp << srcSigBits;
33 const srcSignMask = 1 << (srcSigBits + srcExpBits);
34 const srcAbsMask = srcSignMask - 1;
35 const roundMask = (1 << (srcSigBits - dstSigBits)) - 1;
36 const halfway = 1 << (srcSigBits - dstSigBits - 1);
37 const srcQNaN = 1 << (srcSigBits - 1);
38 const srcNaNCode = srcQNaN - 1;
39
40 const dstBits = dst_t.bit_count;
41 const dstExpBits = dstBits - dstSigBits - 1;
42 const dstInfExp = (1 << dstExpBits) - 1;
43 const dstExpBias = dstInfExp >> 1;
44
45 const underflowExponent = srcExpBias + 1 - dstExpBias;
46 const overflowExponent = srcExpBias + dstInfExp - dstExpBias;
47 const underflow = underflowExponent << srcSigBits;
48 const overflow = overflowExponent << srcSigBits;
49
50 const dstQNaN = 1 << (dstSigBits - 1);
51 const dstNaNCode = dstQNaN - 1;
52
53 // Break a into a sign and representation of the absolute value
54 const aRep: src_rep_t = @bitCast(src_rep_t, a);
55 const aAbs: src_rep_t = aRep & srcAbsMask;
56 const sign: src_rep_t = aRep & srcSignMask;
57 var absResult: dst_rep_t = undefined;
58
59 if (aAbs -% underflow < aAbs -% overflow) {
60 // The exponent of a is within the range of normal numbers in the
61 // destination format. We can convert by simply right-shifting with
62 // rounding and adjusting the exponent.
63 absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits));
64 absResult -%= dst_rep_t(srcExpBias - dstExpBias) << dstSigBits;
65
66 const roundBits: src_rep_t = aAbs & roundMask;
67 if (roundBits > halfway) {
68 // Round to nearest
69 absResult += 1;
70 } else if (roundBits == halfway) {
71 // Ties to even
72 absResult += absResult & 1;
73 }
74 } else if (aAbs > srcInfinity) {
75 // a is NaN.
76 // Conjure the result by beginning with infinity, setting the qNaN
77 // bit and inserting the (truncated) trailing NaN field.
78 absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits;
79 absResult |= dstQNaN;
80 absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode);
81 } else if (aAbs >= overflow) {
82 // a overflows to infinity.
83 absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits;
84 } else {
85 // a underflows on conversion to the destination type or is an exact
86 // zero. The result may be a denormal or zero. Extract the exponent
87 // to get the shift amount for the denormalization.
88 const aExp = @intCast(u32, aAbs >> srcSigBits);
89 const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1);
90
91 const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal;
92
93 // Right shift by the denormalization amount with sticky.
94 if (shift > srcSigBits) {
95 absResult = 0;
96 } else {
97 const sticky: src_rep_t = significand << @intCast(SrcShift, srcBits - shift);
98 const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky;
99 absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits));
100 const roundBits: src_rep_t = denormalizedSignificand & roundMask;
101 if (roundBits > halfway) {
102 // Round to nearest
103 absResult += 1;
104 } else if (roundBits == halfway) {
105 // Ties to even
106 absResult += absResult & 1;
107 }
108 }
109 }
110
111 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits));
112 return @bitCast(dst_t, result);
113}
114
115test "import truncXfYf2" {
116 _ = @import("truncXfYf2_test.zig");
117}
std/special/compiler_rt/truncXfYf2_test.zig created+134
......@@ -0,0 +1,134 @@
1const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
2
3fn test__truncsfhf2(a: u32, expected: u16) void {
4 const actual = __truncsfhf2(@bitCast(f32, a));
5
6 if (actual == expected) {
7 return;
8 }
9
10 @panic("__truncsfhf2 test failure");
11}
12
13test "truncsfhf2" {
14 test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN
15 test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN
16
17 test__truncsfhf2(0, 0); // 0
18 test__truncsfhf2(0x80000000, 0x8000); // -0
19
20 test__truncsfhf2(0x7f800000, 0x7c00); // inf
21 test__truncsfhf2(0xff800000, 0xfc00); // -inf
22
23 test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf
24 test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf
25
26 test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf
27 test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf
28
29 test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14
30 test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14
31
32 test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504
33 test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504
34
35 test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504
36 test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504
37
38 test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504
39 test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504
40
41 test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10
42 test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10
43
44 test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3
45 test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3
46
47 test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535
48 test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535
49
50 test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12
51
52 test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1
53 test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14
54
55 test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24
56 test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24
57
58 test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24
59 test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24
60
61 test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20
62 test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24
63 test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero
64}
65
66const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2;
67
68fn test__trunctfsf2(a: f128, expected: u32) void {
69 const x = __trunctfsf2(a);
70
71 const rep = @bitCast(u32, x);
72 if (rep == expected) {
73 return;
74 }
75 // test other possible NaN representation(signal NaN)
76 else if (expected == 0x7fc00000) {
77 if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) {
78 return;
79 }
80 }
81
82 @panic("__trunctfsf2 test failure");
83}
84
85test "trunctfsf2" {
86 // qnan
87 test__trunctfsf2(@bitCast(f128, u128(0x7fff800000000000 << 64)), 0x7fc00000);
88 // nan
89 test__trunctfsf2(@bitCast(f128, u128((0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000);
90 // inf
91 test__trunctfsf2(@bitCast(f128, u128(0x7fff000000000000 << 64)), 0x7f800000);
92 // zero
93 test__trunctfsf2(0.0, 0x0);
94
95 test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156);
96 test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2);
97 test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000);
98 test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0);
99}
100
101const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2;
102
103fn test__trunctfdf2(a: f128, expected: u64) void {
104 const x = __trunctfdf2(a);
105
106 const rep = @bitCast(u64, x);
107 if (rep == expected) {
108 return;
109 }
110 // test other possible NaN representation(signal NaN)
111 else if (expected == 0x7ff8000000000000) {
112 if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) {
113 return;
114 }
115 }
116
117 @panic("__trunctfsf2 test failure");
118}
119
120test "trunctfdf2" {
121 // qnan
122 test__trunctfdf2(@bitCast(f128, u128(0x7fff800000000000 << 64)), 0x7ff8000000000000);
123 // nan
124 test__trunctfdf2(@bitCast(f128, u128((0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000);
125 // inf
126 test__trunctfdf2(@bitCast(f128, u128(0x7fff000000000000 << 64)), 0x7ff0000000000000);
127 // zero
128 test__trunctfdf2(0.0, 0x0);
129
130 test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb);
131 test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7);
132 test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000);
133 test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab);
134}
std/special/compiler_rt/udivmod.zig+42-39
......@@ -1,18 +1,21 @@
11const builtin = @import("builtin");
22const is_test = builtin.is_test;
33
4const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 };
4const low = switch (builtin.endian) {
5 builtin.Endian.Big => 1,
6 builtin.Endian.Little => 0,
7};
58const high = 1 - low;
69
7pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) DoubleInt {
10pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?*DoubleInt) DoubleInt {
811 @setRuntimeSafety(is_test);
912
1013 const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2));
1114 const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
12 const Log2SingleInt = @import("../../math/index.zig").Log2Int(SingleInt);
15 const Log2SingleInt = @import("std").math.Log2Int(SingleInt);
1316
14 const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #421
15 const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #421
17 const n = @ptrCast(*const [2]SingleInt, &a).*; // TODO issue #421
18 const d = @ptrCast(*const [2]SingleInt, &b).*; // TODO issue #421
1619 var q: [2]SingleInt = undefined;
1720 var r: [2]SingleInt = undefined;
1821 var sr: c_uint = undefined;
......@@ -23,7 +26,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
2326 // ---
2427 // 0 X
2528 if (maybe_rem) |rem| {
26 *rem = n[low] % d[low];
29 rem.* = n[low] % d[low];
2730 }
2831 return n[low] / d[low];
2932 }
......@@ -31,7 +34,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
3134 // ---
3235 // K X
3336 if (maybe_rem) |rem| {
34 *rem = n[low];
37 rem.* = n[low];
3538 }
3639 return 0;
3740 }
......@@ -42,7 +45,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
4245 // ---
4346 // 0 0
4447 if (maybe_rem) |rem| {
45 *rem = n[high] % d[low];
48 rem.* = n[high] % d[low];
4649 }
4750 return n[high] / d[low];
4851 }
......@@ -54,7 +57,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
5457 if (maybe_rem) |rem| {
5558 r[high] = n[high] % d[high];
5659 r[low] = 0;
57 *rem = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421
60 rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
5861 }
5962 return n[high] / d[high];
6063 }
......@@ -66,9 +69,9 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
6669 if (maybe_rem) |rem| {
6770 r[low] = n[low];
6871 r[high] = n[high] & (d[high] - 1);
69 *rem = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421
72 rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
7073 }
71 return n[high] >> Log2SingleInt(@ctz(d[high]));
74 return n[high] >> @intCast(Log2SingleInt, @ctz(d[high]));
7275 }
7376 // K K
7477 // ---
......@@ -77,7 +80,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
7780 // 0 <= sr <= SingleInt.bit_count - 2 or sr large
7881 if (sr > SingleInt.bit_count - 2) {
7982 if (maybe_rem) |rem| {
80 *rem = a;
83 rem.* = a;
8184 }
8285 return 0;
8386 }
......@@ -85,10 +88,10 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
8588 // 1 <= sr <= SingleInt.bit_count - 1
8689 // q.all = a << (DoubleInt.bit_count - sr);
8790 q[low] = 0;
88 q[high] = n[low] << Log2SingleInt(SingleInt.bit_count - sr);
91 q[high] = n[low] << @intCast(Log2SingleInt, SingleInt.bit_count - sr);
8992 // r.all = a >> sr;
90 r[high] = n[high] >> Log2SingleInt(sr);
91 r[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));
93 r[high] = n[high] >> @intCast(Log2SingleInt, sr);
94 r[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
9295 } else {
9396 // d[low] != 0
9497 if (d[high] == 0) {
......@@ -98,15 +101,15 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
98101 if ((d[low] & (d[low] - 1)) == 0) {
99102 // d is a power of 2
100103 if (maybe_rem) |rem| {
101 *rem = n[low] & (d[low] - 1);
104 rem.* = n[low] & (d[low] - 1);
102105 }
103106 if (d[low] == 1) {
104107 return a;
105108 }
106109 sr = @ctz(d[low]);
107 q[high] = n[high] >> Log2SingleInt(sr);
108 q[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));
109 return *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]); // TODO issue #421
110 q[high] = n[high] >> @intCast(Log2SingleInt, sr);
111 q[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
112 return @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421
110113 }
111114 // K X
112115 // ---
......@@ -123,15 +126,15 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
123126 } else if (sr < SingleInt.bit_count) {
124127 // 2 <= sr <= SingleInt.bit_count - 1
125128 q[low] = 0;
126 q[high] = n[low] << Log2SingleInt(SingleInt.bit_count - sr);
127 r[high] = n[high] >> Log2SingleInt(sr);
128 r[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));
129 q[high] = n[low] << @intCast(Log2SingleInt, SingleInt.bit_count - sr);
130 r[high] = n[high] >> @intCast(Log2SingleInt, sr);
131 r[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
129132 } else {
130133 // SingleInt.bit_count + 1 <= sr <= DoubleInt.bit_count - 1
131 q[low] = n[low] << Log2SingleInt(DoubleInt.bit_count - sr);
132 q[high] = (n[high] << Log2SingleInt(DoubleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr - SingleInt.bit_count));
134 q[low] = n[low] << @intCast(Log2SingleInt, DoubleInt.bit_count - sr);
135 q[high] = (n[high] << @intCast(Log2SingleInt, DoubleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr - SingleInt.bit_count));
133136 r[high] = 0;
134 r[low] = n[high] >> Log2SingleInt(sr - SingleInt.bit_count);
137 r[low] = n[high] >> @intCast(Log2SingleInt, sr - SingleInt.bit_count);
135138 }
136139 } else {
137140 // K X
......@@ -141,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
141144 // 0 <= sr <= SingleInt.bit_count - 1 or sr large
142145 if (sr > SingleInt.bit_count - 1) {
143146 if (maybe_rem) |rem| {
144 *rem = a;
147 rem.* = a;
145148 }
146149 return 0;
147150 }
......@@ -155,9 +158,9 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
155158 r[high] = 0;
156159 r[low] = n[high];
157160 } else {
158 r[high] = n[high] >> Log2SingleInt(sr);
159 r[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));
160 q[high] = n[low] << Log2SingleInt(SingleInt.bit_count - sr);
161 r[high] = n[high] >> @intCast(Log2SingleInt, sr);
162 r[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
163 q[high] = n[low] << @intCast(Log2SingleInt, SingleInt.bit_count - sr);
161164 }
162165 }
163166 }
......@@ -170,25 +173,25 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
170173 var r_all: DoubleInt = undefined;
171174 while (sr > 0) : (sr -= 1) {
172175 // r:q = ((r:q) << 1) | carry
173 r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1));
174 r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1));
175 q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1));
176 q[low] = (q[low] << 1) | carry;
176 r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1));
177 r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1));
178 q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1));
179 q[low] = (q[low] << 1) | carry;
177180 // carry = 0;
178181 // if (r.all >= b)
179182 // {
180183 // r.all -= b;
181184 // carry = 1;
182185 // }
183 r_all = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421
184 const s: SignedDoubleInt = SignedDoubleInt(b -% r_all -% 1) >> (DoubleInt.bit_count - 1);
185 carry = u32(s & 1);
186 r_all = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
187 const s: SignedDoubleInt = @intCast(SignedDoubleInt, b -% r_all -% 1) >> (DoubleInt.bit_count - 1);
188 carry = @intCast(u32, s & 1);
186189 r_all -= b & @bitCast(DoubleInt, s);
187 r = *@ptrCast(&[2]SingleInt, &r_all); // TODO issue #421
190 r = @ptrCast(*[2]SingleInt, &r_all).*; // TODO issue #421
188191 }
189 const q_all = ((*@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0])) << 1) | carry; // TODO issue #421
192 const q_all = ((@ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*) << 1) | carry; // TODO issue #421
190193 if (maybe_rem) |rem| {
191 *rem = r_all;
194 rem.* = r_all;
192195 }
193196 return q_all;
194197}
std/special/compiler_rt/udivmoddi4.zig+1-1
......@@ -1,7 +1,7 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const builtin = @import("builtin");
33
4pub extern fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) u64 {
4pub extern fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) u64 {
55 @setRuntimeSafety(builtin.is_test);
66 return udivmod(u64, a, b, maybe_rem);
77}
std/special/compiler_rt/udivmoddi4_test.zig+2
......@@ -1,3 +1,5 @@
1// Disable formatting to avoid unnecessary source repository bloat.
2// zig fmt: off
13const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
24const assert = @import("std").debug.assert;
35
std/special/compiler_rt/udivmodti4.zig+7-1
......@@ -1,11 +1,17 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
34
4pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) u128 {
5pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) u128 {
56 @setRuntimeSafety(builtin.is_test);
67 return udivmod(u128, a, b, maybe_rem);
78}
89
10pub extern fn __udivmodti4_windows_x86_64(a: *const u128, b: *const u128, maybe_rem: ?*u128) void {
11 @setRuntimeSafety(builtin.is_test);
12 compiler_rt.setXmm0(u128, udivmod(u128, a.*, b.*, maybe_rem));
13}
14
915test "import udivmodti4" {
1016 _ = @import("udivmodti4_test.zig");
1117}
std/special/compiler_rt/udivmodti4_test.zig+2
......@@ -1,3 +1,5 @@
1// Disable formatting to avoid unnecessary source repository bloat.
2// zig fmt: off
13const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
24const assert = @import("std").debug.assert;
35
std/special/compiler_rt/udivti3.zig+7-2
......@@ -1,7 +1,12 @@
1const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
1const udivmodti4 = @import("udivmodti4.zig");
22const builtin = @import("builtin");
33
44pub extern fn __udivti3(a: u128, b: u128) u128 {
55 @setRuntimeSafety(builtin.is_test);
6 return __udivmodti4(a, b, null);
6 return udivmodti4.__udivmodti4(a, b, null);
7}
8
9pub extern fn __udivti3_windows_x86_64(a: *const u128, b: *const u128) void {
10 @setRuntimeSafety(builtin.is_test);
11 udivmodti4.__udivmodti4_windows_x86_64(a, b, null);
712}
std/special/compiler_rt/umodti3.zig+8-2
......@@ -1,9 +1,15 @@
1const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
1const udivmodti4 = @import("udivmodti4.zig");
22const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
34
45pub extern fn __umodti3(a: u128, b: u128) u128 {
56 @setRuntimeSafety(builtin.is_test);
67 var r: u128 = undefined;
7 _ = __udivmodti4(a, b, &r);
8 _ = udivmodti4.__udivmodti4(a, b, &r);
89 return r;
910}
11
12pub extern fn __umodti3_windows_x86_64(a: *const u128, b: *const u128) void {
13 @setRuntimeSafety(builtin.is_test);
14 compiler_rt.setXmm0(u128, __umodti3(a.*, b.*));
15}
std/special/panic.zig+1-1
......@@ -6,7 +6,7 @@
66const builtin = @import("builtin");
77const std = @import("std");
88
9pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {
9pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
1010 @setCold(true);
1111 switch (builtin.os) {
1212 // TODO: fix panic in zen.
std/special/test_runner.zig+17-3
......@@ -5,11 +5,25 @@ const test_fn_list = builtin.__zig_test_fn_slice;
55const warn = std.debug.warn;
66
77pub fn main() !void {
8 var ok_count: usize = 0;
9 var skip_count: usize = 0;
810 for (test_fn_list) |test_fn, i| {
911 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1012
11 try test_fn.func();
12
13 warn("OK\n");
13 if (test_fn.func()) |_| {
14 ok_count += 1;
15 warn("OK\n");
16 } else |err| switch (err) {
17 error.SkipZigTest => {
18 skip_count += 1;
19 warn("SKIP\n");
20 },
21 else => return err,
22 }
23 }
24 if (ok_count == test_fn_list.len) {
25 warn("All tests passed.\n");
26 } else {
27 warn("{} passed; {} skipped.\n", ok_count, skip_count);
1428 }
1529}
std/unicode.zig+269-37
......@@ -1,5 +1,18 @@
11const std = @import("./index.zig");
2const builtin = @import("builtin");
23const debug = std.debug;
4const assert = std.debug.assert;
5const mem = std.mem;
6
7/// Returns how many bytes the UTF-8 representation would require
8/// for the given codepoint.
9pub fn utf8CodepointSequenceLength(c: u32) !u3 {
10 if (c < 0x80) return u3(1);
11 if (c < 0x800) return u3(2);
12 if (c < 0x10000) return u3(3);
13 if (c < 0x110000) return u3(4);
14 return error.CodepointTooLarge;
15}
316
417/// Given the first byte of a UTF-8 codepoint,
518/// returns a number 1-4 indicating the total length of the codepoint in bytes.
......@@ -12,11 +25,48 @@ pub fn utf8ByteSequenceLength(first_byte: u8) !u3 {
1225 return error.Utf8InvalidStartByte;
1326}
1427
28/// Encodes the given codepoint into a UTF-8 byte sequence.
29/// c: the codepoint.
30/// out: the out buffer to write to. Must have a len >= utf8CodepointSequenceLength(c).
31/// Errors: if c cannot be encoded in UTF-8.
32/// Returns: the number of bytes written to out.
33pub fn utf8Encode(c: u32, out: []u8) !u3 {
34 const length = try utf8CodepointSequenceLength(c);
35 debug.assert(out.len >= length);
36 switch (length) {
37 // The pattern for each is the same
38 // - Increasing the initial shift by 6 each time
39 // - Each time after the first shorten the shifted
40 // value to a max of 0b111111 (63)
41 1 => out[0] = @intCast(u8, c), // Can just do 0 + codepoint for initial range
42 2 => {
43 out[0] = @intCast(u8, 0b11000000 | (c >> 6));
44 out[1] = @intCast(u8, 0b10000000 | (c & 0b111111));
45 },
46 3 => {
47 if (0xd800 <= c and c <= 0xdfff) return error.Utf8CannotEncodeSurrogateHalf;
48 out[0] = @intCast(u8, 0b11100000 | (c >> 12));
49 out[1] = @intCast(u8, 0b10000000 | ((c >> 6) & 0b111111));
50 out[2] = @intCast(u8, 0b10000000 | (c & 0b111111));
51 },
52 4 => {
53 out[0] = @intCast(u8, 0b11110000 | (c >> 18));
54 out[1] = @intCast(u8, 0b10000000 | ((c >> 12) & 0b111111));
55 out[2] = @intCast(u8, 0b10000000 | ((c >> 6) & 0b111111));
56 out[3] = @intCast(u8, 0b10000000 | (c & 0b111111));
57 },
58 else => unreachable,
59 }
60 return length;
61}
62
63const Utf8DecodeError = Utf8Decode2Error || Utf8Decode3Error || Utf8Decode4Error;
64
1565/// Decodes the UTF-8 codepoint encoded in the given slice of bytes.
1666/// bytes.len must be equal to utf8ByteSequenceLength(bytes[0]) catch unreachable.
1767/// If you already know the length at comptime, you can call one of
1868/// utf8Decode2,utf8Decode3,utf8Decode4 directly instead of this function.
19pub fn utf8Decode(bytes: []const u8) !u32 {
69pub fn utf8Decode(bytes: []const u8) Utf8DecodeError!u32 {
2070 return switch (bytes.len) {
2171 1 => u32(bytes[0]),
2272 2 => utf8Decode2(bytes),
......@@ -25,7 +75,12 @@ pub fn utf8Decode(bytes: []const u8) !u32 {
2575 else => unreachable,
2676 };
2777}
28pub fn utf8Decode2(bytes: []const u8) !u32 {
78
79const Utf8Decode2Error = error{
80 Utf8ExpectedContinuation,
81 Utf8OverlongEncoding,
82};
83pub fn utf8Decode2(bytes: []const u8) Utf8Decode2Error!u32 {
2984 debug.assert(bytes.len == 2);
3085 debug.assert(bytes[0] & 0b11100000 == 0b11000000);
3186 var value: u32 = bytes[0] & 0b00011111;
......@@ -38,7 +93,13 @@ pub fn utf8Decode2(bytes: []const u8) !u32 {
3893
3994 return value;
4095}
41pub fn utf8Decode3(bytes: []const u8) !u32 {
96
97const Utf8Decode3Error = error{
98 Utf8ExpectedContinuation,
99 Utf8OverlongEncoding,
100 Utf8EncodesSurrogateHalf,
101};
102pub fn utf8Decode3(bytes: []const u8) Utf8Decode3Error!u32 {
42103 debug.assert(bytes.len == 3);
43104 debug.assert(bytes[0] & 0b11110000 == 0b11100000);
44105 var value: u32 = bytes[0] & 0b00001111;
......@@ -56,7 +117,13 @@ pub fn utf8Decode3(bytes: []const u8) !u32 {
56117
57118 return value;
58119}
59pub fn utf8Decode4(bytes: []const u8) !u32 {
120
121const Utf8Decode4Error = error{
122 Utf8ExpectedContinuation,
123 Utf8OverlongEncoding,
124 Utf8CodepointTooLarge,
125};
126pub fn utf8Decode4(bytes: []const u8) Utf8Decode4Error!u32 {
60127 debug.assert(bytes.len == 4);
61128 debug.assert(bytes[0] & 0b11111000 == 0b11110000);
62129 var value: u32 = bytes[0] & 0b00000111;
......@@ -87,7 +154,9 @@ pub fn utf8ValidateSlice(s: []const u8) bool {
87154 return false;
88155 }
89156
90 if (utf8Decode(s[i..i+cp_len])) |_| {} else |_| { return false; }
157 if (utf8Decode(s[i .. i + cp_len])) |_| {} else |_| {
158 return false;
159 }
91160 i += cp_len;
92161 } else |err| {
93162 return false;
......@@ -116,9 +185,7 @@ pub const Utf8View = struct {
116185 }
117186
118187 pub fn initUnchecked(s: []const u8) Utf8View {
119 return Utf8View {
120 .bytes = s,
121 };
188 return Utf8View{ .bytes = s };
122189 }
123190
124191 pub fn initComptime(comptime s: []const u8) Utf8View {
......@@ -128,12 +195,12 @@ pub const Utf8View = struct {
128195 error.InvalidUtf8 => {
129196 @compileError("invalid utf8");
130197 unreachable;
131 }
198 },
132199 }
133200 }
134201
135 pub fn iterator(s: &const Utf8View) Utf8Iterator {
136 return Utf8Iterator {
202 pub fn iterator(s: *const Utf8View) Utf8Iterator {
203 return Utf8Iterator{
137204 .bytes = s.bytes,
138205 .i = 0,
139206 };
......@@ -144,7 +211,7 @@ const Utf8Iterator = struct {
144211 bytes: []const u8,
145212 i: usize,
146213
147 pub fn nextCodepointSlice(it: &Utf8Iterator) ?[]const u8 {
214 pub fn nextCodepointSlice(it: *Utf8Iterator) ?[]const u8 {
148215 if (it.i >= it.bytes.len) {
149216 return null;
150217 }
......@@ -152,65 +219,128 @@ const Utf8Iterator = struct {
152219 const cp_len = utf8ByteSequenceLength(it.bytes[it.i]) catch unreachable;
153220
154221 it.i += cp_len;
155 return it.bytes[it.i-cp_len..it.i];
222 return it.bytes[it.i - cp_len .. it.i];
156223 }
157224
158 pub fn nextCodepoint(it: &Utf8Iterator) ?u32 {
159 const slice = it.nextCodepointSlice() ?? return null;
225 pub fn nextCodepoint(it: *Utf8Iterator) ?u32 {
226 const slice = it.nextCodepointSlice() orelse return null;
160227
161 const r = switch (slice.len) {
162 1 => u32(slice[0]),
163 2 => utf8Decode2(slice),
164 3 => utf8Decode3(slice),
165 4 => utf8Decode4(slice),
228 switch (slice.len) {
229 1 => return u32(slice[0]),
230 2 => return utf8Decode2(slice) catch unreachable,
231 3 => return utf8Decode3(slice) catch unreachable,
232 4 => return utf8Decode4(slice) catch unreachable,
166233 else => unreachable,
167 };
168
169 return r catch unreachable;
234 }
170235 }
171236};
172237
238test "utf8 encode" {
239 comptime testUtf8Encode() catch unreachable;
240 try testUtf8Encode();
241}
242fn testUtf8Encode() !void {
243 // A few taken from wikipedia a few taken elsewhere
244 var array: [4]u8 = undefined;
245 debug.assert((try utf8Encode(try utf8Decode("€"), array[0..])) == 3);
246 debug.assert(array[0] == 0b11100010);
247 debug.assert(array[1] == 0b10000010);
248 debug.assert(array[2] == 0b10101100);
249
250 debug.assert((try utf8Encode(try utf8Decode("$"), array[0..])) == 1);
251 debug.assert(array[0] == 0b00100100);
252
253 debug.assert((try utf8Encode(try utf8Decode("¢"), array[0..])) == 2);
254 debug.assert(array[0] == 0b11000010);
255 debug.assert(array[1] == 0b10100010);
256
257 debug.assert((try utf8Encode(try utf8Decode("𐍈"), array[0..])) == 4);
258 debug.assert(array[0] == 0b11110000);
259 debug.assert(array[1] == 0b10010000);
260 debug.assert(array[2] == 0b10001101);
261 debug.assert(array[3] == 0b10001000);
262}
263
264test "utf8 encode error" {
265 comptime testUtf8EncodeError();
266 testUtf8EncodeError();
267}
268fn testUtf8EncodeError() void {
269 var array: [4]u8 = undefined;
270 testErrorEncode(0xd800, array[0..], error.Utf8CannotEncodeSurrogateHalf);
271 testErrorEncode(0xdfff, array[0..], error.Utf8CannotEncodeSurrogateHalf);
272 testErrorEncode(0x110000, array[0..], error.CodepointTooLarge);
273 testErrorEncode(0xffffffff, array[0..], error.CodepointTooLarge);
274}
275
276fn testErrorEncode(codePoint: u32, array: []u8, expectedErr: error) void {
277 if (utf8Encode(codePoint, array)) |_| {
278 unreachable;
279 } else |err| {
280 debug.assert(err == expectedErr);
281 }
282}
283
173284test "utf8 iterator on ascii" {
285 comptime testUtf8IteratorOnAscii();
286 testUtf8IteratorOnAscii();
287}
288fn testUtf8IteratorOnAscii() void {
174289 const s = Utf8View.initComptime("abc");
175290
176291 var it1 = s.iterator();
177 debug.assert(std.mem.eql(u8, "a", ??it1.nextCodepointSlice()));
178 debug.assert(std.mem.eql(u8, "b", ??it1.nextCodepointSlice()));
179 debug.assert(std.mem.eql(u8, "c", ??it1.nextCodepointSlice()));
292 debug.assert(std.mem.eql(u8, "a", it1.nextCodepointSlice().?));
293 debug.assert(std.mem.eql(u8, "b", it1.nextCodepointSlice().?));
294 debug.assert(std.mem.eql(u8, "c", it1.nextCodepointSlice().?));
180295 debug.assert(it1.nextCodepointSlice() == null);
181296
182297 var it2 = s.iterator();
183 debug.assert(??it2.nextCodepoint() == 'a');
184 debug.assert(??it2.nextCodepoint() == 'b');
185 debug.assert(??it2.nextCodepoint() == 'c');
298 debug.assert(it2.nextCodepoint().? == 'a');
299 debug.assert(it2.nextCodepoint().? == 'b');
300 debug.assert(it2.nextCodepoint().? == 'c');
186301 debug.assert(it2.nextCodepoint() == null);
187302}
188303
189304test "utf8 view bad" {
305 comptime testUtf8ViewBad();
306 testUtf8ViewBad();
307}
308fn testUtf8ViewBad() void {
190309 // Compile-time error.
191310 // const s3 = Utf8View.initComptime("\xfe\xf2");
192
193311 const s = Utf8View.init("hel\xadlo");
194 if (s) |_| { unreachable; } else |err| { debug.assert(err == error.InvalidUtf8); }
312 if (s) |_| {
313 unreachable;
314 } else |err| {
315 debug.assert(err == error.InvalidUtf8);
316 }
195317}
196318
197319test "utf8 view ok" {
320 comptime testUtf8ViewOk();
321 testUtf8ViewOk();
322}
323fn testUtf8ViewOk() void {
198324 const s = Utf8View.initComptime("東京市");
199325
200326 var it1 = s.iterator();
201 debug.assert(std.mem.eql(u8, "東", ??it1.nextCodepointSlice()));
202 debug.assert(std.mem.eql(u8, "京", ??it1.nextCodepointSlice()));
203 debug.assert(std.mem.eql(u8, "市", ??it1.nextCodepointSlice()));
327 debug.assert(std.mem.eql(u8, "東", it1.nextCodepointSlice().?));
328 debug.assert(std.mem.eql(u8, "京", it1.nextCodepointSlice().?));
329 debug.assert(std.mem.eql(u8, "市", it1.nextCodepointSlice().?));
204330 debug.assert(it1.nextCodepointSlice() == null);
205331
206332 var it2 = s.iterator();
207 debug.assert(??it2.nextCodepoint() == 0x6771);
208 debug.assert(??it2.nextCodepoint() == 0x4eac);
209 debug.assert(??it2.nextCodepoint() == 0x5e02);
333 debug.assert(it2.nextCodepoint().? == 0x6771);
334 debug.assert(it2.nextCodepoint().? == 0x4eac);
335 debug.assert(it2.nextCodepoint().? == 0x5e02);
210336 debug.assert(it2.nextCodepoint() == null);
211337}
212338
213339test "bad utf8 slice" {
340 comptime testBadUtf8Slice();
341 testBadUtf8Slice();
342}
343fn testBadUtf8Slice() void {
214344 debug.assert(utf8ValidateSlice("abc"));
215345 debug.assert(!utf8ValidateSlice("abc\xc0"));
216346 debug.assert(!utf8ValidateSlice("abc\xc0abc"));
......@@ -218,6 +348,10 @@ test "bad utf8 slice" {
218348}
219349
220350test "valid utf8" {
351 comptime testValidUtf8();
352 testValidUtf8();
353}
354fn testValidUtf8() void {
221355 testValid("\x00", 0x0);
222356 testValid("\x20", 0x20);
223357 testValid("\x7f", 0x7f);
......@@ -233,6 +367,10 @@ test "valid utf8" {
233367}
234368
235369test "invalid utf8 continuation bytes" {
370 comptime testInvalidUtf8ContinuationBytes();
371 testInvalidUtf8ContinuationBytes();
372}
373fn testInvalidUtf8ContinuationBytes() void {
236374 // unexpected continuation
237375 testError("\x80", error.Utf8InvalidStartByte);
238376 testError("\xbf", error.Utf8InvalidStartByte);
......@@ -261,6 +399,10 @@ test "invalid utf8 continuation bytes" {
261399}
262400
263401test "overlong utf8 codepoint" {
402 comptime testOverlongUtf8Codepoint();
403 testOverlongUtf8Codepoint();
404}
405fn testOverlongUtf8Codepoint() void {
264406 testError("\xc0\x80", error.Utf8OverlongEncoding);
265407 testError("\xc1\xbf", error.Utf8OverlongEncoding);
266408 testError("\xe0\x80\x80", error.Utf8OverlongEncoding);
......@@ -270,6 +412,10 @@ test "overlong utf8 codepoint" {
270412}
271413
272414test "misc invalid utf8" {
415 comptime testMiscInvalidUtf8();
416 testMiscInvalidUtf8();
417}
418fn testMiscInvalidUtf8() void {
273419 // codepoint out of bounds
274420 testError("\xf4\x90\x80\x80", error.Utf8CodepointTooLarge);
275421 testError("\xf7\xbf\xbf\xbf", error.Utf8CodepointTooLarge);
......@@ -298,3 +444,89 @@ fn testDecode(bytes: []const u8) !u32 {
298444 debug.assert(bytes.len == length);
299445 return utf8Decode(bytes);
300446}
447
448// TODO: make this API on top of a non-allocating Utf16LeView
449pub fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
450 var result = std.ArrayList(u8).init(allocator);
451 // optimistically guess that it will all be ascii.
452 try result.ensureCapacity(utf16le.len);
453
454 const utf16le_as_bytes = @sliceToBytes(utf16le);
455 var i: usize = 0;
456 var out_index: usize = 0;
457 while (i < utf16le_as_bytes.len) : (i += 2) {
458 // decode
459 const c0: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
460 var codepoint: u32 = undefined;
461 if (c0 & ~u32(0x03ff) == 0xd800) {
462 // surrogate pair
463 i += 2;
464 if (i >= utf16le_as_bytes.len) return error.DanglingSurrogateHalf;
465 const c1: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
466 if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
467 codepoint = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
468 } else if (c0 & ~u32(0x03ff) == 0xdc00) {
469 return error.UnexpectedSecondSurrogateHalf;
470 } else {
471 codepoint = c0;
472 }
473
474 // encode
475 const utf8_len = utf8CodepointSequenceLength(codepoint) catch unreachable;
476 try result.resize(result.len + utf8_len);
477 _ = utf8Encode(codepoint, result.items[out_index..]) catch unreachable;
478 out_index += utf8_len;
479 }
480
481 return result.toOwnedSlice();
482}
483
484test "utf16leToUtf8" {
485 var utf16le: [2]u16 = undefined;
486 const utf16le_as_bytes = @sliceToBytes(utf16le[0..]);
487
488 {
489 mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little);
490 mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little);
491 const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
492 assert(mem.eql(u8, utf8, "Aa"));
493 }
494
495 {
496 mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little);
497 mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little);
498 const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
499 assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf"));
500 }
501
502 {
503 // the values just outside the surrogate half range
504 mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little);
505 mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little);
506 const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
507 assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80"));
508 }
509
510 {
511 // smallest surrogate pair
512 mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little);
513 mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
514 const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
515 assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80"));
516 }
517
518 {
519 // largest surrogate pair
520 mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
521 mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little);
522 const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
523 assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf"));
524 }
525
526 {
527 mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
528 mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
529 const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
530 assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
531 }
532}
std/zig/ast.zig+1750-1367
......@@ -1,12 +1,256 @@
11const std = @import("../index.zig");
22const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const Token = std.zig.Token;
3const SegmentedList = std.SegmentedList;
54const mem = std.mem;
5const Token = std.zig.Token;
6
7pub const TokenIndex = usize;
8
9pub const Tree = struct {
10 source: []const u8,
11 tokens: TokenList,
12 root_node: *Node.Root,
13 arena_allocator: std.heap.ArenaAllocator,
14 errors: ErrorList,
15
16 pub const TokenList = SegmentedList(Token, 64);
17 pub const ErrorList = SegmentedList(Error, 0);
18
19 pub fn deinit(self: *Tree) void {
20 self.arena_allocator.deinit();
21 }
22
23 pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void {
24 return parse_error.render(&self.tokens, stream);
25 }
26
27 pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {
28 return self.tokenSlicePtr(self.tokens.at(token_index));
29 }
30
31 pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 {
32 return self.source[token.start..token.end];
33 }
34
35 pub const Location = struct {
36 line: usize,
37 column: usize,
38 line_start: usize,
39 line_end: usize,
40 };
41
42 pub fn tokenLocationPtr(self: *Tree, start_index: usize, token: *const Token) Location {
43 var loc = Location{
44 .line = 0,
45 .column = 0,
46 .line_start = start_index,
47 .line_end = self.source.len,
48 };
49 const token_start = token.start;
50 for (self.source[start_index..]) |c, i| {
51 if (i + start_index == token_start) {
52 loc.line_end = i + start_index;
53 while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') : (loc.line_end += 1) {}
54 return loc;
55 }
56 if (c == '\n') {
57 loc.line += 1;
58 loc.column = 0;
59 loc.line_start = i + 1;
60 } else {
61 loc.column += 1;
62 }
63 }
64 return loc;
65 }
66
67 pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {
68 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));
69 }
70
71 pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool {
72 return self.tokensOnSameLinePtr(self.tokens.at(token1_index), self.tokens.at(token2_index));
73 }
74
75 pub fn tokensOnSameLinePtr(self: *Tree, token1: *const Token, token2: *const Token) bool {
76 return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null;
77 }
78
79 pub fn dump(self: *Tree) void {
80 self.root_node.base.dump(0);
81 }
82
83 /// Skips over comments
84 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {
85 var index = token_index - 1;
86 while (self.tokens.at(index).id == Token.Id.LineComment) {
87 index -= 1;
88 }
89 return index;
90 }
91
92 /// Skips over comments
93 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {
94 var index = token_index + 1;
95 while (self.tokens.at(index).id == Token.Id.LineComment) {
96 index += 1;
97 }
98 return index;
99 }
100};
101
102pub const Error = union(enum) {
103 InvalidToken: InvalidToken,
104 ExpectedVarDeclOrFn: ExpectedVarDeclOrFn,
105 ExpectedAggregateKw: ExpectedAggregateKw,
106 UnattachedDocComment: UnattachedDocComment,
107 ExpectedEqOrSemi: ExpectedEqOrSemi,
108 ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
109 ExpectedColonOrRParen: ExpectedColonOrRParen,
110 ExpectedLabelable: ExpectedLabelable,
111 ExpectedInlinable: ExpectedInlinable,
112 ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,
113 ExpectedCall: ExpectedCall,
114 ExpectedCallOrFnProto: ExpectedCallOrFnProto,
115 ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
116 ExtraAlignQualifier: ExtraAlignQualifier,
117 ExtraConstQualifier: ExtraConstQualifier,
118 ExtraVolatileQualifier: ExtraVolatileQualifier,
119 ExpectedPrimaryExpr: ExpectedPrimaryExpr,
120 ExpectedToken: ExpectedToken,
121 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
122
123 pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
124 switch (self.*) {
125 // TODO https://github.com/ziglang/zig/issues/683
126 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
127 @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
128 @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
129 @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
130 @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
131 @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
132 @TagType(Error).ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
133 @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
134 @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
135 @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
136 @TagType(Error).ExpectedCall => |*x| return x.render(tokens, stream),
137 @TagType(Error).ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
138 @TagType(Error).ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
139 @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
140 @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
141 @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
142 @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
143 @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
144 @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
145 }
146 }
147
148 pub fn loc(self: *const Error) TokenIndex {
149 switch (self.*) {
150 // TODO https://github.com/ziglang/zig/issues/683
151 @TagType(Error).InvalidToken => |x| return x.token,
152 @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
153 @TagType(Error).ExpectedAggregateKw => |x| return x.token,
154 @TagType(Error).UnattachedDocComment => |x| return x.token,
155 @TagType(Error).ExpectedEqOrSemi => |x| return x.token,
156 @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
157 @TagType(Error).ExpectedColonOrRParen => |x| return x.token,
158 @TagType(Error).ExpectedLabelable => |x| return x.token,
159 @TagType(Error).ExpectedInlinable => |x| return x.token,
160 @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
161 @TagType(Error).ExpectedCall => |x| return x.node.firstToken(),
162 @TagType(Error).ExpectedCallOrFnProto => |x| return x.node.firstToken(),
163 @TagType(Error).ExpectedSliceOrRBracket => |x| return x.token,
164 @TagType(Error).ExtraAlignQualifier => |x| return x.token,
165 @TagType(Error).ExtraConstQualifier => |x| return x.token,
166 @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
167 @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
168 @TagType(Error).ExpectedToken => |x| return x.token,
169 @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
170 }
171 }
172
173 pub const InvalidToken = SingleTokenError("Invalid token {}");
174 pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");
175 pub const ExpectedAggregateKw = SingleTokenError("Expected " ++ @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++ @tagName(Token.Id.Keyword_enum) ++ ", found {}");
176 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");
177 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");
178 pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found {}");
179 pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");
180 pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");
181 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++ @tagName(Token.Id.Identifier) ++ ", found {}");
182 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
183 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
184
185 pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
186 pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
187 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
188 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
189
190 pub const ExpectedCall = struct {
191 node: *Node,
192
193 pub fn render(self: *const ExpectedCall, tokens: *Tree.TokenList, stream: var) !void {
194 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", @tagName(self.node.id));
195 }
196 };
197
198 pub const ExpectedCallOrFnProto = struct {
199 node: *Node,
200
201 pub fn render(self: *const ExpectedCallOrFnProto, tokens: *Tree.TokenList, stream: var) !void {
202 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++ @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
203 }
204 };
205
206 pub const ExpectedToken = struct {
207 token: TokenIndex,
208 expected_id: @TagType(Token.Id),
209
210 pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
211 const token_name = @tagName(tokens.at(self.token).id);
212 return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
213 }
214 };
215
216 pub const ExpectedCommaOrEnd = struct {
217 token: TokenIndex,
218 end_id: @TagType(Token.Id),
219
220 pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void {
221 const token_name = @tagName(tokens.at(self.token).id);
222 return stream.print("expected ',' or {}, found {}", @tagName(self.end_id), token_name);
223 }
224 };
225
226 fn SingleTokenError(comptime msg: []const u8) type {
227 return struct {
228 const ThisError = this;
229
230 token: TokenIndex,
231
232 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
233 const token_name = @tagName(tokens.at(self.token).id);
234 return stream.print(msg, token_name);
235 }
236 };
237 }
238
239 fn SimpleError(comptime msg: []const u8) type {
240 return struct {
241 const ThisError = this;
242
243 token: TokenIndex,
244
245 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
246 return stream.write(msg);
247 }
248 };
249 }
250};
6251
7252pub const Node = struct {
8253 id: Id,
9 comment: ?&NodeLineComment,
10254
11255 pub const Id = enum {
12256 // Top level
......@@ -35,6 +279,7 @@ pub const Node = struct {
35279 VarType,
36280 ErrorType,
37281 FnProto,
282 PromiseType,
38283
39284 // Primary expressions
40285 IntegerLiteral,
......@@ -57,7 +302,7 @@ pub const Node = struct {
57302 Block,
58303
59304 // Misc
60 LineComment,
305 DocComment,
61306 SwitchCase,
62307 SwitchElse,
63308 Else,
......@@ -67,6 +312,7 @@ pub const Node = struct {
67312 StructField,
68313 UnionTag,
69314 EnumTag,
315 ErrorTag,
70316 AsmInput,
71317 AsmOutput,
72318 AsyncAttribute,
......@@ -74,1750 +320,1887 @@ pub const Node = struct {
74320 FieldInitializer,
75321 };
76322
77 const IdTypePair = struct {
78 id: Id,
79 Type: type,
80 };
81
82 // TODO: When @field exists, we could generate this by iterating over all members of `Id`,
83 // and making an array of `IdTypePair { .id = @field(Id, @memberName(Id, i)), .Type = @field(ast, "Node" ++ @memberName(Id, i)) }`
84 const idTypeTable = []IdTypePair {
85 IdTypePair { .id = Id.Root, .Type = NodeRoot },
86 IdTypePair { .id = Id.Use, .Type = NodeUse },
87 IdTypePair { .id = Id.TestDecl, .Type = NodeTestDecl },
88
89 IdTypePair { .id = Id.VarDecl, .Type = NodeVarDecl },
90 IdTypePair { .id = Id.Defer, .Type = NodeDefer },
91
92 IdTypePair { .id = Id.InfixOp, .Type = NodeInfixOp },
93 IdTypePair { .id = Id.PrefixOp, .Type = NodePrefixOp },
94 IdTypePair { .id = Id.SuffixOp, .Type = NodeSuffixOp },
95
96 IdTypePair { .id = Id.Switch, .Type = NodeSwitch },
97 IdTypePair { .id = Id.While, .Type = NodeWhile },
98 IdTypePair { .id = Id.For, .Type = NodeFor },
99 IdTypePair { .id = Id.If, .Type = NodeIf },
100 IdTypePair { .id = Id.ControlFlowExpression, .Type = NodeControlFlowExpression },
101 IdTypePair { .id = Id.Suspend, .Type = NodeSuspend },
102
103 IdTypePair { .id = Id.VarType, .Type = NodeVarType },
104 IdTypePair { .id = Id.ErrorType, .Type = NodeErrorType },
105 IdTypePair { .id = Id.FnProto, .Type = NodeFnProto },
106
107 IdTypePair { .id = Id.IntegerLiteral, .Type = NodeIntegerLiteral },
108 IdTypePair { .id = Id.FloatLiteral, .Type = NodeFloatLiteral },
109 IdTypePair { .id = Id.StringLiteral, .Type = NodeStringLiteral },
110 IdTypePair { .id = Id.MultilineStringLiteral, .Type = NodeMultilineStringLiteral },
111 IdTypePair { .id = Id.CharLiteral, .Type = NodeCharLiteral },
112 IdTypePair { .id = Id.BoolLiteral, .Type = NodeBoolLiteral },
113 IdTypePair { .id = Id.NullLiteral, .Type = NodeNullLiteral },
114 IdTypePair { .id = Id.UndefinedLiteral, .Type = NodeUndefinedLiteral },
115 IdTypePair { .id = Id.ThisLiteral, .Type = NodeThisLiteral },
116 IdTypePair { .id = Id.Unreachable, .Type = NodeUnreachable },
117 IdTypePair { .id = Id.Identifier, .Type = NodeIdentifier },
118 IdTypePair { .id = Id.GroupedExpression, .Type = NodeGroupedExpression },
119 IdTypePair { .id = Id.BuiltinCall, .Type = NodeBuiltinCall },
120 IdTypePair { .id = Id.ErrorSetDecl, .Type = NodeErrorSetDecl },
121 IdTypePair { .id = Id.ContainerDecl, .Type = NodeContainerDecl },
122 IdTypePair { .id = Id.Asm, .Type = NodeAsm },
123 IdTypePair { .id = Id.Comptime, .Type = NodeComptime },
124 IdTypePair { .id = Id.Block, .Type = NodeBlock },
125
126 IdTypePair { .id = Id.LineComment, .Type = NodeLineComment },
127 IdTypePair { .id = Id.SwitchCase, .Type = NodeSwitchCase },
128 IdTypePair { .id = Id.SwitchElse, .Type = NodeSwitchElse },
129 IdTypePair { .id = Id.Else, .Type = NodeElse },
130 IdTypePair { .id = Id.Payload, .Type = NodePayload },
131 IdTypePair { .id = Id.PointerPayload, .Type = NodePointerPayload },
132 IdTypePair { .id = Id.PointerIndexPayload, .Type = NodePointerIndexPayload },
133 IdTypePair { .id = Id.StructField, .Type = NodeStructField },
134 IdTypePair { .id = Id.UnionTag, .Type = NodeUnionTag },
135 IdTypePair { .id = Id.EnumTag, .Type = NodeEnumTag },
136 IdTypePair { .id = Id.AsmInput, .Type = NodeAsmInput },
137 IdTypePair { .id = Id.AsmOutput, .Type = NodeAsmOutput },
138 IdTypePair { .id = Id.AsyncAttribute, .Type = NodeAsyncAttribute },
139 IdTypePair { .id = Id.ParamDecl, .Type = NodeParamDecl },
140 IdTypePair { .id = Id.FieldInitializer, .Type = NodeFieldInitializer },
141 };
142
143 pub fn IdToType(comptime id: Id) type {
144 inline for (idTypeTable) |id_type_pair| {
145 if (id == id_type_pair.id)
146 return id_type_pair.Type;
323 pub fn cast(base: *Node, comptime T: type) ?*T {
324 if (base.id == comptime typeToId(T)) {
325 return @fieldParentPtr(T, "base", base);
147326 }
327 return null;
328 }
148329
330 pub fn iterate(base: *Node, index: usize) ?*Node {
331 comptime var i = 0;
332 inline while (i < @memberCount(Id)) : (i += 1) {
333 if (base.id == @field(Id, @memberName(Id, i))) {
334 const T = @field(Node, @memberName(Id, i));
335 return @fieldParentPtr(T, "base", base).iterate(index);
336 }
337 }
149338 unreachable;
150339 }
151340
152 pub fn typeToId(comptime T: type) Id {
153 inline for (idTypeTable) |id_type_pair| {
154 if (T == id_type_pair.Type)
155 return id_type_pair.id;
341 pub fn firstToken(base: *Node) TokenIndex {
342 comptime var i = 0;
343 inline while (i < @memberCount(Id)) : (i += 1) {
344 if (base.id == @field(Id, @memberName(Id, i))) {
345 const T = @field(Node, @memberName(Id, i));
346 return @fieldParentPtr(T, "base", base).firstToken();
347 }
156348 }
157
158349 unreachable;
159350 }
160351
161 pub fn iterate(base: &Node, index: usize) ?&Node {
162 inline for (idTypeTable) |id_type_pair| {
163 if (base.id == id_type_pair.id)
164 return @fieldParentPtr(id_type_pair.Type, "base", base).iterate(index);
352 pub fn lastToken(base: *Node) TokenIndex {
353 comptime var i = 0;
354 inline while (i < @memberCount(Id)) : (i += 1) {
355 if (base.id == @field(Id, @memberName(Id, i))) {
356 const T = @field(Node, @memberName(Id, i));
357 return @fieldParentPtr(T, "base", base).lastToken();
358 }
165359 }
166
167360 unreachable;
168361 }
169362
170 pub fn firstToken(base: &Node) Token {
171 inline for (idTypeTable) |id_type_pair| {
172 if (base.id == id_type_pair.id)
173 return @fieldParentPtr(id_type_pair.Type, "base", base).firstToken();
363 pub fn typeToId(comptime T: type) Id {
364 comptime var i = 0;
365 inline while (i < @memberCount(Id)) : (i += 1) {
366 if (T == @field(Node, @memberName(Id, i))) {
367 return @field(Id, @memberName(Id, i));
368 }
174369 }
175
176370 unreachable;
177371 }
178372
179 pub fn lastToken(base: &Node) Token {
180 inline for (idTypeTable) |id_type_pair| {
181 if (base.id == id_type_pair.id)
182 return @fieldParentPtr(id_type_pair.Type, "base", base).lastToken();
373 pub fn requireSemiColon(base: *const Node) bool {
374 var n = base;
375 while (true) {
376 switch (n.id) {
377 Id.Root,
378 Id.StructField,
379 Id.UnionTag,
380 Id.EnumTag,
381 Id.ParamDecl,
382 Id.Block,
383 Id.Payload,
384 Id.PointerPayload,
385 Id.PointerIndexPayload,
386 Id.Switch,
387 Id.SwitchCase,
388 Id.SwitchElse,
389 Id.FieldInitializer,
390 Id.DocComment,
391 Id.TestDecl,
392 => return false,
393 Id.While => {
394 const while_node = @fieldParentPtr(While, "base", n);
395 if (while_node.@"else") |@"else"| {
396 n = @"else".base;
397 continue;
398 }
399
400 return while_node.body.id != Id.Block;
401 },
402 Id.For => {
403 const for_node = @fieldParentPtr(For, "base", n);
404 if (for_node.@"else") |@"else"| {
405 n = @"else".base;
406 continue;
407 }
408
409 return for_node.body.id != Id.Block;
410 },
411 Id.If => {
412 const if_node = @fieldParentPtr(If, "base", n);
413 if (if_node.@"else") |@"else"| {
414 n = @"else".base;
415 continue;
416 }
417
418 return if_node.body.id != Id.Block;
419 },
420 Id.Else => {
421 const else_node = @fieldParentPtr(Else, "base", n);
422 n = else_node.body;
423 continue;
424 },
425 Id.Defer => {
426 const defer_node = @fieldParentPtr(Defer, "base", n);
427 return defer_node.expr.id != Id.Block;
428 },
429 Id.Comptime => {
430 const comptime_node = @fieldParentPtr(Comptime, "base", n);
431 return comptime_node.expr.id != Id.Block;
432 },
433 Id.Suspend => {
434 const suspend_node = @fieldParentPtr(Suspend, "base", n);
435 if (suspend_node.body) |body| {
436 return body.id != Id.Block;
437 }
438
439 return true;
440 },
441 else => return true,
442 }
183443 }
184
185 unreachable;
186444 }
187};
188445
189pub const NodeRoot = struct {
190 base: Node,
191 decls: ArrayList(&Node),
192 eof_token: Token,
446 pub fn dump(self: *Node, indent: usize) void {
447 {
448 var i: usize = 0;
449 while (i < indent) : (i += 1) {
450 std.debug.warn(" ");
451 }
452 }
453 std.debug.warn("{}\n", @tagName(self.id));
193454
194 pub fn iterate(self: &NodeRoot, index: usize) ?&Node {
195 if (index < self.decls.len) {
196 return self.decls.items[self.decls.len - index - 1];
455 var child_i: usize = 0;
456 while (self.iterate(child_i)) |child| : (child_i += 1) {
457 child.dump(indent + 2);
197458 }
198 return null;
199459 }
200460
201 pub fn firstToken(self: &NodeRoot) Token {
202 return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
203 }
461 pub const Root = struct {
462 base: Node,
463 doc_comments: ?*DocComment,
464 decls: DeclList,
465 eof_token: TokenIndex,
204466
205 pub fn lastToken(self: &NodeRoot) Token {
206 return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
207 }
208};
467 pub const DeclList = SegmentedList(*Node, 4);
209468
210pub const NodeVarDecl = struct {
211 base: Node,
212 visib_token: ?Token,
213 name_token: Token,
214 eq_token: Token,
215 mut_token: Token,
216 comptime_token: ?Token,
217 extern_export_token: ?Token,
218 lib_name: ?&Node,
219 type_node: ?&Node,
220 align_node: ?&Node,
221 init_node: ?&Node,
222 semicolon_token: Token,
223
224 pub fn iterate(self: &NodeVarDecl, index: usize) ?&Node {
225 var i = index;
226
227 if (self.type_node) |type_node| {
228 if (i < 1) return type_node;
229 i -= 1;
469 pub fn iterate(self: *Root, index: usize) ?*Node {
470 if (index < self.decls.len) {
471 return self.decls.at(index).*;
472 }
473 return null;
230474 }
231475
232 if (self.align_node) |align_node| {
233 if (i < 1) return align_node;
234 i -= 1;
476 pub fn firstToken(self: *Root) TokenIndex {
477 return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken();
235478 }
236479
237 if (self.init_node) |init_node| {
238 if (i < 1) return init_node;
239 i -= 1;
480 pub fn lastToken(self: *Root) TokenIndex {
481 return if (self.decls.len == 0) self.eof_token else (self.decls.at(self.decls.len - 1).*).lastToken();
240482 }
483 };
241484
242 return null;
243 }
244
245 pub fn firstToken(self: &NodeVarDecl) Token {
246 if (self.visib_token) |visib_token| return visib_token;
247 if (self.comptime_token) |comptime_token| return comptime_token;
248 if (self.extern_export_token) |extern_export_token| return extern_export_token;
249 assert(self.lib_name == null);
250 return self.mut_token;
251 }
252
253 pub fn lastToken(self: &NodeVarDecl) Token {
254 return self.semicolon_token;
255 }
256};
257
258pub const NodeUse = struct {
259 base: Node,
260 visib_token: ?Token,
261 expr: &Node,
262 semicolon_token: Token,
263
264 pub fn iterate(self: &NodeUse, index: usize) ?&Node {
265 var i = index;
485 pub const VarDecl = struct {
486 base: Node,
487 doc_comments: ?*DocComment,
488 visib_token: ?TokenIndex,
489 name_token: TokenIndex,
490 eq_token: TokenIndex,
491 mut_token: TokenIndex,
492 comptime_token: ?TokenIndex,
493 extern_export_token: ?TokenIndex,
494 lib_name: ?*Node,
495 type_node: ?*Node,
496 align_node: ?*Node,
497 init_node: ?*Node,
498 semicolon_token: TokenIndex,
499
500 pub fn iterate(self: *VarDecl, index: usize) ?*Node {
501 var i = index;
502
503 if (self.type_node) |type_node| {
504 if (i < 1) return type_node;
505 i -= 1;
506 }
266507
267 if (i < 1) return self.expr;
268 i -= 1;
508 if (self.align_node) |align_node| {
509 if (i < 1) return align_node;
510 i -= 1;
511 }
269512
270 return null;
271 }
513 if (self.init_node) |init_node| {
514 if (i < 1) return init_node;
515 i -= 1;
516 }
272517
273 pub fn firstToken(self: &NodeUse) Token {
274 if (self.visib_token) |visib_token| return visib_token;
275 return self.expr.firstToken();
276 }
518 return null;
519 }
277520
278 pub fn lastToken(self: &NodeUse) Token {
279 return self.semicolon_token;
280 }
281};
521 pub fn firstToken(self: *VarDecl) TokenIndex {
522 if (self.visib_token) |visib_token| return visib_token;
523 if (self.comptime_token) |comptime_token| return comptime_token;
524 if (self.extern_export_token) |extern_export_token| return extern_export_token;
525 assert(self.lib_name == null);
526 return self.mut_token;
527 }
282528
283pub const NodeErrorSetDecl = struct {
284 base: Node,
285 error_token: Token,
286 decls: ArrayList(&Node),
287 rbrace_token: Token,
529 pub fn lastToken(self: *VarDecl) TokenIndex {
530 return self.semicolon_token;
531 }
532 };
288533
289 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
290 var i = index;
534 pub const Use = struct {
535 base: Node,
536 doc_comments: ?*DocComment,
537 visib_token: ?TokenIndex,
538 use_token: TokenIndex,
539 expr: *Node,
540 semicolon_token: TokenIndex,
291541
292 if (i < self.decls.len) return self.decls.at(i);
293 i -= self.decls.len;
542 pub fn iterate(self: *Use, index: usize) ?*Node {
543 var i = index;
294544
295 return null;
296 }
545 if (i < 1) return self.expr;
546 i -= 1;
297547
298 pub fn firstToken(self: &NodeErrorSetDecl) Token {
299 return self.error_token;
300 }
548 return null;
549 }
301550
302 pub fn lastToken(self: &NodeErrorSetDecl) Token {
303 return self.rbrace_token;
304 }
305};
551 pub fn firstToken(self: *Use) TokenIndex {
552 if (self.visib_token) |visib_token| return visib_token;
553 return self.use_token;
554 }
306555
307pub const NodeContainerDecl = struct {
308 base: Node,
309 ltoken: Token,
310 layout: Layout,
311 kind: Kind,
312 init_arg_expr: InitArg,
313 fields_and_decls: ArrayList(&Node),
314 rbrace_token: Token,
315
316 const Layout = enum {
317 Auto,
318 Extern,
319 Packed,
556 pub fn lastToken(self: *Use) TokenIndex {
557 return self.semicolon_token;
558 }
320559 };
321560
322 const Kind = enum {
323 Struct,
324 Enum,
325 Union,
326 };
561 pub const ErrorSetDecl = struct {
562 base: Node,
563 error_token: TokenIndex,
564 decls: DeclList,
565 rbrace_token: TokenIndex,
327566
328 const InitArg = union(enum) {
329 None,
330 Enum,
331 Type: &Node,
332 };
567 pub const DeclList = SegmentedList(*Node, 2);
333568
334 pub fn iterate(self: &NodeContainerDecl, index: usize) ?&Node {
335 var i = index;
569 pub fn iterate(self: *ErrorSetDecl, index: usize) ?*Node {
570 var i = index;
336571
337 switch (self.init_arg_expr) {
338 InitArg.Type => |t| {
339 if (i < 1) return t;
340 i -= 1;
341 },
342 InitArg.None,
343 InitArg.Enum => { }
344 }
572 if (i < self.decls.len) return self.decls.at(i).*;
573 i -= self.decls.len;
345574
346 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
347 i -= self.fields_and_decls.len;
575 return null;
576 }
348577
349 return null;
350 }
578 pub fn firstToken(self: *ErrorSetDecl) TokenIndex {
579 return self.error_token;
580 }
351581
352 pub fn firstToken(self: &NodeContainerDecl) Token {
353 return self.ltoken;
354 }
582 pub fn lastToken(self: *ErrorSetDecl) TokenIndex {
583 return self.rbrace_token;
584 }
585 };
355586
356 pub fn lastToken(self: &NodeContainerDecl) Token {
357 return self.rbrace_token;
358 }
359};
587 pub const ContainerDecl = struct {
588 base: Node,
589 layout_token: ?TokenIndex,
590 kind_token: TokenIndex,
591 init_arg_expr: InitArg,
592 fields_and_decls: DeclList,
593 lbrace_token: TokenIndex,
594 rbrace_token: TokenIndex,
595
596 pub const DeclList = Root.DeclList;
597
598 const InitArg = union(enum) {
599 None,
600 Enum: ?*Node,
601 Type: *Node,
602 };
360603
361pub const NodeStructField = struct {
362 base: Node,
363 visib_token: ?Token,
364 name_token: Token,
365 type_expr: &Node,
604 pub fn iterate(self: *ContainerDecl, index: usize) ?*Node {
605 var i = index;
366606
367 pub fn iterate(self: &NodeStructField, index: usize) ?&Node {
368 var i = index;
607 switch (self.init_arg_expr) {
608 InitArg.Type => |t| {
609 if (i < 1) return t;
610 i -= 1;
611 },
612 InitArg.None, InitArg.Enum => {},
613 }
369614
370 if (i < 1) return self.type_expr;
371 i -= 1;
615 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;
616 i -= self.fields_and_decls.len;
372617
373 return null;
374 }
618 return null;
619 }
375620
376 pub fn firstToken(self: &NodeStructField) Token {
377 if (self.visib_token) |visib_token| return visib_token;
378 return self.name_token;
379 }
621 pub fn firstToken(self: *ContainerDecl) TokenIndex {
622 if (self.layout_token) |layout_token| {
623 return layout_token;
624 }
625 return self.kind_token;
626 }
380627
381 pub fn lastToken(self: &NodeStructField) Token {
382 return self.type_expr.lastToken();
383 }
384};
628 pub fn lastToken(self: *ContainerDecl) TokenIndex {
629 return self.rbrace_token;
630 }
631 };
385632
386pub const NodeUnionTag = struct {
387 base: Node,
388 name_token: Token,
389 type_expr: ?&Node,
633 pub const StructField = struct {
634 base: Node,
635 doc_comments: ?*DocComment,
636 visib_token: ?TokenIndex,
637 name_token: TokenIndex,
638 type_expr: *Node,
390639
391 pub fn iterate(self: &NodeUnionTag, index: usize) ?&Node {
392 var i = index;
640 pub fn iterate(self: *StructField, index: usize) ?*Node {
641 var i = index;
393642
394 if (self.type_expr) |type_expr| {
395 if (i < 1) return type_expr;
643 if (i < 1) return self.type_expr;
396644 i -= 1;
397 }
398645
399 return null;
400 }
646 return null;
647 }
401648
402 pub fn firstToken(self: &NodeUnionTag) Token {
403 return self.name_token;
404 }
649 pub fn firstToken(self: *StructField) TokenIndex {
650 if (self.visib_token) |visib_token| return visib_token;
651 return self.name_token;
652 }
405653
406 pub fn lastToken(self: &NodeUnionTag) Token {
407 if (self.type_expr) |type_expr| {
408 return type_expr.lastToken();
654 pub fn lastToken(self: *StructField) TokenIndex {
655 return self.type_expr.lastToken();
409656 }
657 };
410658
411 return self.name_token;
412 }
413};
659 pub const UnionTag = struct {
660 base: Node,
661 doc_comments: ?*DocComment,
662 name_token: TokenIndex,
663 type_expr: ?*Node,
664 value_expr: ?*Node,
414665
415pub const NodeEnumTag = struct {
416 base: Node,
417 name_token: Token,
418 value: ?&Node,
666 pub fn iterate(self: *UnionTag, index: usize) ?*Node {
667 var i = index;
419668
420 pub fn iterate(self: &NodeEnumTag, index: usize) ?&Node {
421 var i = index;
669 if (self.type_expr) |type_expr| {
670 if (i < 1) return type_expr;
671 i -= 1;
672 }
422673
423 if (self.value) |value| {
424 if (i < 1) return value;
425 i -= 1;
674 if (self.value_expr) |value_expr| {
675 if (i < 1) return value_expr;
676 i -= 1;
677 }
678
679 return null;
426680 }
427681
428 return null;
429 }
682 pub fn firstToken(self: *UnionTag) TokenIndex {
683 return self.name_token;
684 }
430685
431 pub fn firstToken(self: &NodeEnumTag) Token {
432 return self.name_token;
433 }
686 pub fn lastToken(self: *UnionTag) TokenIndex {
687 if (self.value_expr) |value_expr| {
688 return value_expr.lastToken();
689 }
690 if (self.type_expr) |type_expr| {
691 return type_expr.lastToken();
692 }
434693
435 pub fn lastToken(self: &NodeEnumTag) Token {
436 if (self.value) |value| {
437 return value.lastToken();
694 return self.name_token;
438695 }
696 };
439697
440 return self.name_token;
441 }
442};
443
444pub const NodeIdentifier = struct {
445 base: Node,
446 token: Token,
698 pub const EnumTag = struct {
699 base: Node,
700 doc_comments: ?*DocComment,
701 name_token: TokenIndex,
702 value: ?*Node,
447703
448 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
449 return null;
450 }
704 pub fn iterate(self: *EnumTag, index: usize) ?*Node {
705 var i = index;
451706
452 pub fn firstToken(self: &NodeIdentifier) Token {
453 return self.token;
454 }
707 if (self.value) |value| {
708 if (i < 1) return value;
709 i -= 1;
710 }
455711
456 pub fn lastToken(self: &NodeIdentifier) Token {
457 return self.token;
458 }
459};
712 return null;
713 }
460714
461pub const NodeAsyncAttribute = struct {
462 base: Node,
463 async_token: Token,
464 allocator_type: ?&Node,
465 rangle_bracket: ?Token,
715 pub fn firstToken(self: *EnumTag) TokenIndex {
716 return self.name_token;
717 }
466718
467 pub fn iterate(self: &NodeAsyncAttribute, index: usize) ?&Node {
468 var i = index;
719 pub fn lastToken(self: *EnumTag) TokenIndex {
720 if (self.value) |value| {
721 return value.lastToken();
722 }
469723
470 if (self.allocator_type) |allocator_type| {
471 if (i < 1) return allocator_type;
472 i -= 1;
724 return self.name_token;
473725 }
726 };
474727
475 return null;
476 }
728 pub const ErrorTag = struct {
729 base: Node,
730 doc_comments: ?*DocComment,
731 name_token: TokenIndex,
477732
478 pub fn firstToken(self: &NodeAsyncAttribute) Token {
479 return self.async_token;
480 }
733 pub fn iterate(self: *ErrorTag, index: usize) ?*Node {
734 var i = index;
481735
482 pub fn lastToken(self: &NodeAsyncAttribute) Token {
483 if (self.rangle_bracket) |rangle_bracket| {
484 return rangle_bracket;
736 if (self.doc_comments) |comments| {
737 if (i < 1) return &comments.base;
738 i -= 1;
739 }
740
741 return null;
485742 }
486743
487 return self.async_token;
488 }
489};
744 pub fn firstToken(self: *ErrorTag) TokenIndex {
745 return self.name_token;
746 }
490747
491pub const NodeFnProto = struct {
492 base: Node,
493 visib_token: ?Token,
494 fn_token: Token,
495 name_token: ?Token,
496 params: ArrayList(&Node),
497 return_type: ReturnType,
498 var_args_token: ?Token,
499 extern_export_inline_token: ?Token,
500 cc_token: ?Token,
501 async_attr: ?&NodeAsyncAttribute,
502 body_node: ?&Node,
503 lib_name: ?&Node, // populated if this is an extern declaration
504 align_expr: ?&Node, // populated if align(A) is present
505
506 pub const ReturnType = union(enum) {
507 Explicit: &Node,
508 InferErrorSet: &Node,
748 pub fn lastToken(self: *ErrorTag) TokenIndex {
749 return self.name_token;
750 }
509751 };
510752
511 pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {
512 var i = index;
753 pub const Identifier = struct {
754 base: Node,
755 token: TokenIndex,
513756
514 if (self.body_node) |body_node| {
515 if (i < 1) return body_node;
516 i -= 1;
757 pub fn iterate(self: *Identifier, index: usize) ?*Node {
758 return null;
517759 }
518760
519 switch (self.return_type) {
520 // TODO allow this and next prong to share bodies since the types are the same
521 ReturnType.Explicit => |node| {
522 if (i < 1) return node;
523 i -= 1;
524 },
525 ReturnType.InferErrorSet => |node| {
526 if (i < 1) return node;
527 i -= 1;
528 },
761 pub fn firstToken(self: *Identifier) TokenIndex {
762 return self.token;
529763 }
530764
531 if (self.align_expr) |align_expr| {
532 if (i < 1) return align_expr;
533 i -= 1;
765 pub fn lastToken(self: *Identifier) TokenIndex {
766 return self.token;
534767 }
768 };
535769
536 if (i < self.params.len) return self.params.items[self.params.len - i - 1];
537 i -= self.params.len;
770 pub const AsyncAttribute = struct {
771 base: Node,
772 async_token: TokenIndex,
773 allocator_type: ?*Node,
774 rangle_bracket: ?TokenIndex,
538775
539 if (self.lib_name) |lib_name| {
540 if (i < 1) return lib_name;
541 i -= 1;
542 }
776 pub fn iterate(self: *AsyncAttribute, index: usize) ?*Node {
777 var i = index;
543778
544 return null;
545 }
779 if (self.allocator_type) |allocator_type| {
780 if (i < 1) return allocator_type;
781 i -= 1;
782 }
546783
547 pub fn firstToken(self: &NodeFnProto) Token {
548 if (self.visib_token) |visib_token| return visib_token;
549 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
550 assert(self.lib_name == null);
551 if (self.cc_token) |cc_token| return cc_token;
552 return self.fn_token;
553 }
784 return null;
785 }
554786
555 pub fn lastToken(self: &NodeFnProto) Token {
556 if (self.body_node) |body_node| return body_node.lastToken();
557 switch (self.return_type) {
558 // TODO allow this and next prong to share bodies since the types are the same
559 ReturnType.Explicit => |node| return node.lastToken(),
560 ReturnType.InferErrorSet => |node| return node.lastToken(),
787 pub fn firstToken(self: *AsyncAttribute) TokenIndex {
788 return self.async_token;
561789 }
562 }
563};
564790
565pub const NodeParamDecl = struct {
566 base: Node,
567 comptime_token: ?Token,
568 noalias_token: ?Token,
569 name_token: ?Token,
570 type_node: &Node,
571 var_args_token: ?Token,
791 pub fn lastToken(self: *AsyncAttribute) TokenIndex {
792 if (self.rangle_bracket) |rangle_bracket| {
793 return rangle_bracket;
794 }
572795
573 pub fn iterate(self: &NodeParamDecl, index: usize) ?&Node {
574 var i = index;
796 return self.async_token;
797 }
798 };
575799
576 if (i < 1) return self.type_node;
577 i -= 1;
800 pub const FnProto = struct {
801 base: Node,
802 doc_comments: ?*DocComment,
803 visib_token: ?TokenIndex,
804 fn_token: TokenIndex,
805 name_token: ?TokenIndex,
806 params: ParamList,
807 return_type: ReturnType,
808 var_args_token: ?TokenIndex,
809 extern_export_inline_token: ?TokenIndex,
810 cc_token: ?TokenIndex,
811 async_attr: ?*AsyncAttribute,
812 body_node: ?*Node,
813 lib_name: ?*Node, // populated if this is an extern declaration
814 align_expr: ?*Node, // populated if align(A) is present
815
816 pub const ParamList = SegmentedList(*Node, 2);
817
818 pub const ReturnType = union(enum) {
819 Explicit: *Node,
820 InferErrorSet: *Node,
821 };
578822
579 return null;
580 }
823 pub fn iterate(self: *FnProto, index: usize) ?*Node {
824 var i = index;
581825
582 pub fn firstToken(self: &NodeParamDecl) Token {
583 if (self.comptime_token) |comptime_token| return comptime_token;
584 if (self.noalias_token) |noalias_token| return noalias_token;
585 if (self.name_token) |name_token| return name_token;
586 return self.type_node.firstToken();
587 }
826 if (self.lib_name) |lib_name| {
827 if (i < 1) return lib_name;
828 i -= 1;
829 }
588830
589 pub fn lastToken(self: &NodeParamDecl) Token {
590 if (self.var_args_token) |var_args_token| return var_args_token;
591 return self.type_node.lastToken();
592 }
593};
831 if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;
832 i -= self.params.len;
594833
595pub const NodeBlock = struct {
596 base: Node,
597 label: ?Token,
598 lbrace: Token,
599 statements: ArrayList(&Node),
600 rbrace: Token,
834 if (self.align_expr) |align_expr| {
835 if (i < 1) return align_expr;
836 i -= 1;
837 }
601838
602 pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
603 var i = index;
839 switch (self.return_type) {
840 // TODO allow this and next prong to share bodies since the types are the same
841 ReturnType.Explicit => |node| {
842 if (i < 1) return node;
843 i -= 1;
844 },
845 ReturnType.InferErrorSet => |node| {
846 if (i < 1) return node;
847 i -= 1;
848 },
849 }
604850
605 if (i < self.statements.len) return self.statements.items[i];
606 i -= self.statements.len;
851 if (self.body_node) |body_node| {
852 if (i < 1) return body_node;
853 i -= 1;
854 }
607855
608 return null;
609 }
856 return null;
857 }
610858
611 pub fn firstToken(self: &NodeBlock) Token {
612 if (self.label) |label| {
613 return label;
859 pub fn firstToken(self: *FnProto) TokenIndex {
860 if (self.visib_token) |visib_token| return visib_token;
861 if (self.async_attr) |async_attr| return async_attr.firstToken();
862 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
863 assert(self.lib_name == null);
864 if (self.cc_token) |cc_token| return cc_token;
865 return self.fn_token;
614866 }
615867
616 return self.lbrace;
617 }
868 pub fn lastToken(self: *FnProto) TokenIndex {
869 if (self.body_node) |body_node| return body_node.lastToken();
870 switch (self.return_type) {
871 // TODO allow this and next prong to share bodies since the types are the same
872 ReturnType.Explicit => |node| return node.lastToken(),
873 ReturnType.InferErrorSet => |node| return node.lastToken(),
874 }
875 }
876 };
618877
619 pub fn lastToken(self: &NodeBlock) Token {
620 return self.rbrace;
621 }
622};
878 pub const PromiseType = struct {
879 base: Node,
880 promise_token: TokenIndex,
881 result: ?Result,
623882
624pub const NodeDefer = struct {
625 base: Node,
626 defer_token: Token,
627 kind: Kind,
628 expr: &Node,
883 pub const Result = struct {
884 arrow_token: TokenIndex,
885 return_type: *Node,
886 };
629887
630 const Kind = enum {
631 Error,
632 Unconditional,
633 };
888 pub fn iterate(self: *PromiseType, index: usize) ?*Node {
889 var i = index;
634890
635 pub fn iterate(self: &NodeDefer, index: usize) ?&Node {
636 var i = index;
891 if (self.result) |result| {
892 if (i < 1) return result.return_type;
893 i -= 1;
894 }
637895
638 if (i < 1) return self.expr;
639 i -= 1;
896 return null;
897 }
640898
641 return null;
642 }
899 pub fn firstToken(self: *PromiseType) TokenIndex {
900 return self.promise_token;
901 }
643902
644 pub fn firstToken(self: &NodeDefer) Token {
645 return self.defer_token;
646 }
903 pub fn lastToken(self: *PromiseType) TokenIndex {
904 if (self.result) |result| return result.return_type.lastToken();
905 return self.promise_token;
906 }
907 };
647908
648 pub fn lastToken(self: &NodeDefer) Token {
649 return self.expr.lastToken();
650 }
651};
909 pub const ParamDecl = struct {
910 base: Node,
911 comptime_token: ?TokenIndex,
912 noalias_token: ?TokenIndex,
913 name_token: ?TokenIndex,
914 type_node: *Node,
915 var_args_token: ?TokenIndex,
652916
653pub const NodeComptime = struct {
654 base: Node,
655 comptime_token: Token,
656 expr: &Node,
917 pub fn iterate(self: *ParamDecl, index: usize) ?*Node {
918 var i = index;
657919
658 pub fn iterate(self: &NodeComptime, index: usize) ?&Node {
659 var i = index;
920 if (i < 1) return self.type_node;
921 i -= 1;
660922
661 if (i < 1) return self.expr;
662 i -= 1;
923 return null;
924 }
663925
664 return null;
665 }
926 pub fn firstToken(self: *ParamDecl) TokenIndex {
927 if (self.comptime_token) |comptime_token| return comptime_token;
928 if (self.noalias_token) |noalias_token| return noalias_token;
929 if (self.name_token) |name_token| return name_token;
930 return self.type_node.firstToken();
931 }
666932
667 pub fn firstToken(self: &NodeComptime) Token {
668 return self.comptime_token;
669 }
933 pub fn lastToken(self: *ParamDecl) TokenIndex {
934 if (self.var_args_token) |var_args_token| return var_args_token;
935 return self.type_node.lastToken();
936 }
937 };
670938
671 pub fn lastToken(self: &NodeComptime) Token {
672 return self.expr.lastToken();
673 }
674};
939 pub const Block = struct {
940 base: Node,
941 label: ?TokenIndex,
942 lbrace: TokenIndex,
943 statements: StatementList,
944 rbrace: TokenIndex,
675945
676pub const NodePayload = struct {
677 base: Node,
678 lpipe: Token,
679 error_symbol: &Node,
680 rpipe: Token,
946 pub const StatementList = Root.DeclList;
681947
682 pub fn iterate(self: &NodePayload, index: usize) ?&Node {
683 var i = index;
948 pub fn iterate(self: *Block, index: usize) ?*Node {
949 var i = index;
684950
685 if (i < 1) return self.error_symbol;
686 i -= 1;
951 if (i < self.statements.len) return self.statements.at(i).*;
952 i -= self.statements.len;
687953
688 return null;
689 }
954 return null;
955 }
690956
691 pub fn firstToken(self: &NodePayload) Token {
692 return self.lpipe;
693 }
957 pub fn firstToken(self: *Block) TokenIndex {
958 if (self.label) |label| {
959 return label;
960 }
694961
695 pub fn lastToken(self: &NodePayload) Token {
696 return self.rpipe;
697 }
698};
962 return self.lbrace;
963 }
699964
700pub const NodePointerPayload = struct {
701 base: Node,
702 lpipe: Token,
703 ptr_token: ?Token,
704 value_symbol: &Node,
705 rpipe: Token,
965 pub fn lastToken(self: *Block) TokenIndex {
966 return self.rbrace;
967 }
968 };
706969
707 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
708 var i = index;
970 pub const Defer = struct {
971 base: Node,
972 defer_token: TokenIndex,
973 expr: *Node,
709974
710 if (i < 1) return self.value_symbol;
711 i -= 1;
975 pub fn iterate(self: *Defer, index: usize) ?*Node {
976 var i = index;
712977
713 return null;
714 }
978 if (i < 1) return self.expr;
979 i -= 1;
715980
716 pub fn firstToken(self: &NodePointerPayload) Token {
717 return self.lpipe;
718 }
981 return null;
982 }
719983
720 pub fn lastToken(self: &NodePointerPayload) Token {
721 return self.rpipe;
722 }
723};
984 pub fn firstToken(self: *Defer) TokenIndex {
985 return self.defer_token;
986 }
724987
725pub const NodePointerIndexPayload = struct {
726 base: Node,
727 lpipe: Token,
728 ptr_token: ?Token,
729 value_symbol: &Node,
730 index_symbol: ?&Node,
731 rpipe: Token,
988 pub fn lastToken(self: *Defer) TokenIndex {
989 return self.expr.lastToken();
990 }
991 };
732992
733 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
734 var i = index;
993 pub const Comptime = struct {
994 base: Node,
995 doc_comments: ?*DocComment,
996 comptime_token: TokenIndex,
997 expr: *Node,
735998
736 if (i < 1) return self.value_symbol;
737 i -= 1;
999 pub fn iterate(self: *Comptime, index: usize) ?*Node {
1000 var i = index;
7381001
739 if (self.index_symbol) |index_symbol| {
740 if (i < 1) return index_symbol;
1002 if (i < 1) return self.expr;
7411003 i -= 1;
742 }
7431004
744 return null;
745 }
1005 return null;
1006 }
7461007
747 pub fn firstToken(self: &NodePointerIndexPayload) Token {
748 return self.lpipe;
749 }
1008 pub fn firstToken(self: *Comptime) TokenIndex {
1009 return self.comptime_token;
1010 }
7501011
751 pub fn lastToken(self: &NodePointerIndexPayload) Token {
752 return self.rpipe;
753 }
754};
1012 pub fn lastToken(self: *Comptime) TokenIndex {
1013 return self.expr.lastToken();
1014 }
1015 };
7551016
756pub const NodeElse = struct {
757 base: Node,
758 else_token: Token,
759 payload: ?&Node,
760 body: &Node,
1017 pub const Payload = struct {
1018 base: Node,
1019 lpipe: TokenIndex,
1020 error_symbol: *Node,
1021 rpipe: TokenIndex,
7611022
762 pub fn iterate(self: &NodeElse, index: usize) ?&Node {
763 var i = index;
1023 pub fn iterate(self: *Payload, index: usize) ?*Node {
1024 var i = index;
7641025
765 if (self.payload) |payload| {
766 if (i < 1) return payload;
1026 if (i < 1) return self.error_symbol;
7671027 i -= 1;
1028
1029 return null;
7681030 }
7691031
770 if (i < 1) return self.body;
771 i -= 1;
1032 pub fn firstToken(self: *Payload) TokenIndex {
1033 return self.lpipe;
1034 }
7721035
773 return null;
774 }
1036 pub fn lastToken(self: *Payload) TokenIndex {
1037 return self.rpipe;
1038 }
1039 };
7751040
776 pub fn firstToken(self: &NodeElse) Token {
777 return self.else_token;
778 }
1041 pub const PointerPayload = struct {
1042 base: Node,
1043 lpipe: TokenIndex,
1044 ptr_token: ?TokenIndex,
1045 value_symbol: *Node,
1046 rpipe: TokenIndex,
7791047
780 pub fn lastToken(self: &NodeElse) Token {
781 return self.body.lastToken();
782 }
783};
1048 pub fn iterate(self: *PointerPayload, index: usize) ?*Node {
1049 var i = index;
7841050
785pub const NodeSwitch = struct {
786 base: Node,
787 switch_token: Token,
788 expr: &Node,
789 cases: ArrayList(&NodeSwitchCase),
790 rbrace: Token,
1051 if (i < 1) return self.value_symbol;
1052 i -= 1;
7911053
792 pub fn iterate(self: &NodeSwitch, index: usize) ?&Node {
793 var i = index;
1054 return null;
1055 }
7941056
795 if (i < 1) return self.expr;
796 i -= 1;
1057 pub fn firstToken(self: *PointerPayload) TokenIndex {
1058 return self.lpipe;
1059 }
7971060
798 if (i < self.cases.len) return &self.cases.at(i).base;
799 i -= self.cases.len;
1061 pub fn lastToken(self: *PointerPayload) TokenIndex {
1062 return self.rpipe;
1063 }
1064 };
8001065
801 return null;
802 }
1066 pub const PointerIndexPayload = struct {
1067 base: Node,
1068 lpipe: TokenIndex,
1069 ptr_token: ?TokenIndex,
1070 value_symbol: *Node,
1071 index_symbol: ?*Node,
1072 rpipe: TokenIndex,
8031073
804 pub fn firstToken(self: &NodeSwitch) Token {
805 return self.switch_token;
806 }
1074 pub fn iterate(self: *PointerIndexPayload, index: usize) ?*Node {
1075 var i = index;
8071076
808 pub fn lastToken(self: &NodeSwitch) Token {
809 return self.rbrace;
810 }
811};
1077 if (i < 1) return self.value_symbol;
1078 i -= 1;
8121079
813pub const NodeSwitchCase = struct {
814 base: Node,
815 items: ArrayList(&Node),
816 payload: ?&Node,
817 expr: &Node,
1080 if (self.index_symbol) |index_symbol| {
1081 if (i < 1) return index_symbol;
1082 i -= 1;
1083 }
8181084
819 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
820 var i = index;
1085 return null;
1086 }
8211087
822 if (i < self.items.len) return self.items.at(i);
823 i -= self.items.len;
1088 pub fn firstToken(self: *PointerIndexPayload) TokenIndex {
1089 return self.lpipe;
1090 }
8241091
825 if (self.payload) |payload| {
826 if (i < 1) return payload;
827 i -= 1;
1092 pub fn lastToken(self: *PointerIndexPayload) TokenIndex {
1093 return self.rpipe;
8281094 }
1095 };
8291096
830 if (i < 1) return self.expr;
831 i -= 1;
1097 pub const Else = struct {
1098 base: Node,
1099 else_token: TokenIndex,
1100 payload: ?*Node,
1101 body: *Node,
8321102
833 return null;
834 }
1103 pub fn iterate(self: *Else, index: usize) ?*Node {
1104 var i = index;
8351105
836 pub fn firstToken(self: &NodeSwitchCase) Token {
837 return self.items.at(0).firstToken();
838 }
1106 if (self.payload) |payload| {
1107 if (i < 1) return payload;
1108 i -= 1;
1109 }
8391110
840 pub fn lastToken(self: &NodeSwitchCase) Token {
841 return self.expr.lastToken();
842 }
843};
1111 if (i < 1) return self.body;
1112 i -= 1;
8441113
845pub const NodeSwitchElse = struct {
846 base: Node,
847 token: Token,
1114 return null;
1115 }
8481116
849 pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node {
850 return null;
851 }
1117 pub fn firstToken(self: *Else) TokenIndex {
1118 return self.else_token;
1119 }
8521120
853 pub fn firstToken(self: &NodeSwitchElse) Token {
854 return self.token;
855 }
1121 pub fn lastToken(self: *Else) TokenIndex {
1122 return self.body.lastToken();
1123 }
1124 };
8561125
857 pub fn lastToken(self: &NodeSwitchElse) Token {
858 return self.token;
859 }
860};
1126 pub const Switch = struct {
1127 base: Node,
1128 switch_token: TokenIndex,
1129 expr: *Node,
8611130
862pub const NodeWhile = struct {
863 base: Node,
864 label: ?Token,
865 inline_token: ?Token,
866 while_token: Token,
867 condition: &Node,
868 payload: ?&Node,
869 continue_expr: ?&Node,
870 body: &Node,
871 @"else": ?&NodeElse,
872
873 pub fn iterate(self: &NodeWhile, index: usize) ?&Node {
874 var i = index;
875
876 if (i < 1) return self.condition;
877 i -= 1;
878
879 if (self.payload) |payload| {
880 if (i < 1) return payload;
881 i -= 1;
882 }
1131 /// these must be SwitchCase nodes
1132 cases: CaseList,
1133 rbrace: TokenIndex,
8831134
884 if (self.continue_expr) |continue_expr| {
885 if (i < 1) return continue_expr;
886 i -= 1;
887 }
1135 pub const CaseList = SegmentedList(*Node, 2);
8881136
889 if (i < 1) return self.body;
890 i -= 1;
1137 pub fn iterate(self: *Switch, index: usize) ?*Node {
1138 var i = index;
8911139
892 if (self.@"else") |@"else"| {
893 if (i < 1) return &@"else".base;
1140 if (i < 1) return self.expr;
8941141 i -= 1;
895 }
8961142
897 return null;
898 }
1143 if (i < self.cases.len) return self.cases.at(i).*;
1144 i -= self.cases.len;
8991145
900 pub fn firstToken(self: &NodeWhile) Token {
901 if (self.label) |label| {
902 return label;
1146 return null;
9031147 }
9041148
905 if (self.inline_token) |inline_token| {
906 return inline_token;
1149 pub fn firstToken(self: *Switch) TokenIndex {
1150 return self.switch_token;
9071151 }
9081152
909 return self.while_token;
910 }
911
912 pub fn lastToken(self: &NodeWhile) Token {
913 if (self.@"else") |@"else"| {
914 return @"else".body.lastToken();
1153 pub fn lastToken(self: *Switch) TokenIndex {
1154 return self.rbrace;
9151155 }
1156 };
9161157
917 return self.body.lastToken();
918 }
919};
1158 pub const SwitchCase = struct {
1159 base: Node,
1160 items: ItemList,
1161 arrow_token: TokenIndex,
1162 payload: ?*Node,
1163 expr: *Node,
9201164
921pub const NodeFor = struct {
922 base: Node,
923 label: ?Token,
924 inline_token: ?Token,
925 for_token: Token,
926 array_expr: &Node,
927 payload: ?&Node,
928 body: &Node,
929 @"else": ?&NodeElse,
1165 pub const ItemList = SegmentedList(*Node, 1);
9301166
931 pub fn iterate(self: &NodeFor, index: usize) ?&Node {
932 var i = index;
1167 pub fn iterate(self: *SwitchCase, index: usize) ?*Node {
1168 var i = index;
9331169
934 if (i < 1) return self.array_expr;
935 i -= 1;
1170 if (i < self.items.len) return self.items.at(i).*;
1171 i -= self.items.len;
9361172
937 if (self.payload) |payload| {
938 if (i < 1) return payload;
1173 if (self.payload) |payload| {
1174 if (i < 1) return payload;
1175 i -= 1;
1176 }
1177
1178 if (i < 1) return self.expr;
9391179 i -= 1;
1180
1181 return null;
9401182 }
9411183
942 if (i < 1) return self.body;
943 i -= 1;
1184 pub fn firstToken(self: *SwitchCase) TokenIndex {
1185 return (self.items.at(0).*).firstToken();
1186 }
9441187
945 if (self.@"else") |@"else"| {
946 if (i < 1) return &@"else".base;
947 i -= 1;
1188 pub fn lastToken(self: *SwitchCase) TokenIndex {
1189 return self.expr.lastToken();
9481190 }
1191 };
9491192
950 return null;
951 }
1193 pub const SwitchElse = struct {
1194 base: Node,
1195 token: TokenIndex,
9521196
953 pub fn firstToken(self: &NodeFor) Token {
954 if (self.label) |label| {
955 return label;
1197 pub fn iterate(self: *SwitchElse, index: usize) ?*Node {
1198 return null;
9561199 }
9571200
958 if (self.inline_token) |inline_token| {
959 return inline_token;
1201 pub fn firstToken(self: *SwitchElse) TokenIndex {
1202 return self.token;
9601203 }
9611204
962 return self.for_token;
963 }
964
965 pub fn lastToken(self: &NodeFor) Token {
966 if (self.@"else") |@"else"| {
967 return @"else".body.lastToken();
1205 pub fn lastToken(self: *SwitchElse) TokenIndex {
1206 return self.token;
9681207 }
1208 };
9691209
970 return self.body.lastToken();
971 }
972};
973
974pub const NodeIf = struct {
975 base: Node,
976 if_token: Token,
977 condition: &Node,
978 payload: ?&Node,
979 body: &Node,
980 @"else": ?&NodeElse,
1210 pub const While = struct {
1211 base: Node,
1212 label: ?TokenIndex,
1213 inline_token: ?TokenIndex,
1214 while_token: TokenIndex,
1215 condition: *Node,
1216 payload: ?*Node,
1217 continue_expr: ?*Node,
1218 body: *Node,
1219 @"else": ?*Else,
1220
1221 pub fn iterate(self: *While, index: usize) ?*Node {
1222 var i = index;
1223
1224 if (i < 1) return self.condition;
1225 i -= 1;
9811226
982 pub fn iterate(self: &NodeIf, index: usize) ?&Node {
983 var i = index;
1227 if (self.payload) |payload| {
1228 if (i < 1) return payload;
1229 i -= 1;
1230 }
9841231
985 if (i < 1) return self.condition;
986 i -= 1;
1232 if (self.continue_expr) |continue_expr| {
1233 if (i < 1) return continue_expr;
1234 i -= 1;
1235 }
9871236
988 if (self.payload) |payload| {
989 if (i < 1) return payload;
1237 if (i < 1) return self.body;
9901238 i -= 1;
991 }
9921239
993 if (i < 1) return self.body;
994 i -= 1;
1240 if (self.@"else") |@"else"| {
1241 if (i < 1) return &@"else".base;
1242 i -= 1;
1243 }
9951244
996 if (self.@"else") |@"else"| {
997 if (i < 1) return &@"else".base;
998 i -= 1;
1245 return null;
9991246 }
10001247
1001 return null;
1002 }
1248 pub fn firstToken(self: *While) TokenIndex {
1249 if (self.label) |label| {
1250 return label;
1251 }
10031252
1004 pub fn firstToken(self: &NodeIf) Token {
1005 return self.if_token;
1006 }
1253 if (self.inline_token) |inline_token| {
1254 return inline_token;
1255 }
10071256
1008 pub fn lastToken(self: &NodeIf) Token {
1009 if (self.@"else") |@"else"| {
1010 return @"else".body.lastToken();
1257 return self.while_token;
10111258 }
10121259
1013 return self.body.lastToken();
1014 }
1015};
1260 pub fn lastToken(self: *While) TokenIndex {
1261 if (self.@"else") |@"else"| {
1262 return @"else".body.lastToken();
1263 }
10161264
1017pub const NodeInfixOp = struct {
1018 base: Node,
1019 op_token: Token,
1020 lhs: &Node,
1021 op: InfixOp,
1022 rhs: &Node,
1023
1024 const InfixOp = union(enum) {
1025 Add,
1026 AddWrap,
1027 ArrayCat,
1028 ArrayMult,
1029 Assign,
1030 AssignBitAnd,
1031 AssignBitOr,
1032 AssignBitShiftLeft,
1033 AssignBitShiftRight,
1034 AssignBitXor,
1035 AssignDiv,
1036 AssignMinus,
1037 AssignMinusWrap,
1038 AssignMod,
1039 AssignPlus,
1040 AssignPlusWrap,
1041 AssignTimes,
1042 AssignTimesWarp,
1043 BangEqual,
1044 BitAnd,
1045 BitOr,
1046 BitShiftLeft,
1047 BitShiftRight,
1048 BitXor,
1049 BoolAnd,
1050 BoolOr,
1051 Catch: ?&Node,
1052 Div,
1053 EqualEqual,
1054 ErrorUnion,
1055 GreaterOrEqual,
1056 GreaterThan,
1057 LessOrEqual,
1058 LessThan,
1059 MergeErrorSets,
1060 Mod,
1061 Mult,
1062 MultWrap,
1063 Period,
1064 Range,
1065 Sub,
1066 SubWrap,
1067 UnwrapMaybe,
1265 return self.body.lastToken();
1266 }
10681267 };
10691268
1070 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
1071 var i = index;
1269 pub const For = struct {
1270 base: Node,
1271 label: ?TokenIndex,
1272 inline_token: ?TokenIndex,
1273 for_token: TokenIndex,
1274 array_expr: *Node,
1275 payload: ?*Node,
1276 body: *Node,
1277 @"else": ?*Else,
10721278
1073 if (i < 1) return self.lhs;
1074 i -= 1;
1279 pub fn iterate(self: *For, index: usize) ?*Node {
1280 var i = index;
10751281
1076 switch (self.op) {
1077 InfixOp.Catch => |maybe_payload| {
1078 if (maybe_payload) |payload| {
1079 if (i < 1) return payload;
1080 i -= 1;
1081 }
1082 },
1083
1084 InfixOp.Add,
1085 InfixOp.AddWrap,
1086 InfixOp.ArrayCat,
1087 InfixOp.ArrayMult,
1088 InfixOp.Assign,
1089 InfixOp.AssignBitAnd,
1090 InfixOp.AssignBitOr,
1091 InfixOp.AssignBitShiftLeft,
1092 InfixOp.AssignBitShiftRight,
1093 InfixOp.AssignBitXor,
1094 InfixOp.AssignDiv,
1095 InfixOp.AssignMinus,
1096 InfixOp.AssignMinusWrap,
1097 InfixOp.AssignMod,
1098 InfixOp.AssignPlus,
1099 InfixOp.AssignPlusWrap,
1100 InfixOp.AssignTimes,
1101 InfixOp.AssignTimesWarp,
1102 InfixOp.BangEqual,
1103 InfixOp.BitAnd,
1104 InfixOp.BitOr,
1105 InfixOp.BitShiftLeft,
1106 InfixOp.BitShiftRight,
1107 InfixOp.BitXor,
1108 InfixOp.BoolAnd,
1109 InfixOp.BoolOr,
1110 InfixOp.Div,
1111 InfixOp.EqualEqual,
1112 InfixOp.ErrorUnion,
1113 InfixOp.GreaterOrEqual,
1114 InfixOp.GreaterThan,
1115 InfixOp.LessOrEqual,
1116 InfixOp.LessThan,
1117 InfixOp.MergeErrorSets,
1118 InfixOp.Mod,
1119 InfixOp.Mult,
1120 InfixOp.MultWrap,
1121 InfixOp.Period,
1122 InfixOp.Range,
1123 InfixOp.Sub,
1124 InfixOp.SubWrap,
1125 InfixOp.UnwrapMaybe => {},
1126 }
1127
1128 if (i < 1) return self.rhs;
1129 i -= 1;
1282 if (i < 1) return self.array_expr;
1283 i -= 1;
11301284
1131 return null;
1132 }
1285 if (self.payload) |payload| {
1286 if (i < 1) return payload;
1287 i -= 1;
1288 }
11331289
1134 pub fn firstToken(self: &NodeInfixOp) Token {
1135 return self.lhs.firstToken();
1136 }
1290 if (i < 1) return self.body;
1291 i -= 1;
11371292
1138 pub fn lastToken(self: &NodeInfixOp) Token {
1139 return self.rhs.lastToken();
1140 }
1141};
1293 if (self.@"else") |@"else"| {
1294 if (i < 1) return &@"else".base;
1295 i -= 1;
1296 }
11421297
1143pub const NodePrefixOp = struct {
1144 base: Node,
1145 op_token: Token,
1146 op: PrefixOp,
1147 rhs: &Node,
1148
1149 const PrefixOp = union(enum) {
1150 AddrOf: AddrOfInfo,
1151 ArrayType: &Node,
1152 Await,
1153 BitNot,
1154 BoolNot,
1155 Cancel,
1156 Deref,
1157 MaybeType,
1158 Negation,
1159 NegationWrap,
1160 Resume,
1161 SliceType: AddrOfInfo,
1162 Try,
1163 UnwrapMaybe,
1164 };
1298 return null;
1299 }
1300
1301 pub fn firstToken(self: *For) TokenIndex {
1302 if (self.label) |label| {
1303 return label;
1304 }
11651305
1166 const AddrOfInfo = struct {
1167 align_expr: ?&Node,
1168 bit_offset_start_token: ?Token,
1169 bit_offset_end_token: ?Token,
1170 const_token: ?Token,
1171 volatile_token: ?Token,
1306 if (self.inline_token) |inline_token| {
1307 return inline_token;
1308 }
1309
1310 return self.for_token;
1311 }
1312
1313 pub fn lastToken(self: *For) TokenIndex {
1314 if (self.@"else") |@"else"| {
1315 return @"else".body.lastToken();
1316 }
1317
1318 return self.body.lastToken();
1319 }
11721320 };
11731321
1174 pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {
1175 var i = index;
1322 pub const If = struct {
1323 base: Node,
1324 if_token: TokenIndex,
1325 condition: *Node,
1326 payload: ?*Node,
1327 body: *Node,
1328 @"else": ?*Else,
11761329
1177 switch (self.op) {
1178 PrefixOp.SliceType => |addr_of_info| {
1179 if (addr_of_info.align_expr) |align_expr| {
1180 if (i < 1) return align_expr;
1181 i -= 1;
1182 }
1183 },
1184 PrefixOp.AddrOf => |addr_of_info| {
1185 if (addr_of_info.align_expr) |align_expr| {
1186 if (i < 1) return align_expr;
1187 i -= 1;
1188 }
1189 },
1190 PrefixOp.ArrayType => |size_expr| {
1191 if (i < 1) return size_expr;
1330 pub fn iterate(self: *If, index: usize) ?*Node {
1331 var i = index;
1332
1333 if (i < 1) return self.condition;
1334 i -= 1;
1335
1336 if (self.payload) |payload| {
1337 if (i < 1) return payload;
11921338 i -= 1;
1193 },
1194 PrefixOp.Await,
1195 PrefixOp.BitNot,
1196 PrefixOp.BoolNot,
1197 PrefixOp.Cancel,
1198 PrefixOp.Deref,
1199 PrefixOp.MaybeType,
1200 PrefixOp.Negation,
1201 PrefixOp.NegationWrap,
1202 PrefixOp.Try,
1203 PrefixOp.Resume,
1204 PrefixOp.UnwrapMaybe => {},
1205 }
1206
1207 if (i < 1) return self.rhs;
1208 i -= 1;
1339 }
12091340
1210 return null;
1211 }
1341 if (i < 1) return self.body;
1342 i -= 1;
12121343
1213 pub fn firstToken(self: &NodePrefixOp) Token {
1214 return self.op_token;
1215 }
1344 if (self.@"else") |@"else"| {
1345 if (i < 1) return &@"else".base;
1346 i -= 1;
1347 }
12161348
1217 pub fn lastToken(self: &NodePrefixOp) Token {
1218 return self.rhs.lastToken();
1219 }
1220};
1349 return null;
1350 }
12211351
1222pub const NodeFieldInitializer = struct {
1223 base: Node,
1224 period_token: Token,
1225 name_token: Token,
1226 expr: &Node,
1352 pub fn firstToken(self: *If) TokenIndex {
1353 return self.if_token;
1354 }
12271355
1228 pub fn iterate(self: &NodeFieldInitializer, index: usize) ?&Node {
1229 var i = index;
1356 pub fn lastToken(self: *If) TokenIndex {
1357 if (self.@"else") |@"else"| {
1358 return @"else".body.lastToken();
1359 }
12301360
1231 if (i < 1) return self.expr;
1232 i -= 1;
1361 return self.body.lastToken();
1362 }
1363 };
12331364
1234 return null;
1235 }
1365 pub const InfixOp = struct {
1366 base: Node,
1367 op_token: TokenIndex,
1368 lhs: *Node,
1369 op: Op,
1370 rhs: *Node,
1371
1372 pub const Op = union(enum) {
1373 Add,
1374 AddWrap,
1375 ArrayCat,
1376 ArrayMult,
1377 Assign,
1378 AssignBitAnd,
1379 AssignBitOr,
1380 AssignBitShiftLeft,
1381 AssignBitShiftRight,
1382 AssignBitXor,
1383 AssignDiv,
1384 AssignMinus,
1385 AssignMinusWrap,
1386 AssignMod,
1387 AssignPlus,
1388 AssignPlusWrap,
1389 AssignTimes,
1390 AssignTimesWarp,
1391 BangEqual,
1392 BitAnd,
1393 BitOr,
1394 BitShiftLeft,
1395 BitShiftRight,
1396 BitXor,
1397 BoolAnd,
1398 BoolOr,
1399 Catch: ?*Node,
1400 Div,
1401 EqualEqual,
1402 ErrorUnion,
1403 GreaterOrEqual,
1404 GreaterThan,
1405 LessOrEqual,
1406 LessThan,
1407 MergeErrorSets,
1408 Mod,
1409 Mult,
1410 MultWrap,
1411 Period,
1412 Range,
1413 Sub,
1414 SubWrap,
1415 UnwrapOptional,
1416 };
12361417
1237 pub fn firstToken(self: &NodeFieldInitializer) Token {
1238 return self.period_token;
1239 }
1418 pub fn iterate(self: *InfixOp, index: usize) ?*Node {
1419 var i = index;
12401420
1241 pub fn lastToken(self: &NodeFieldInitializer) Token {
1242 return self.expr.lastToken();
1243 }
1244};
1421 if (i < 1) return self.lhs;
1422 i -= 1;
12451423
1246pub const NodeSuffixOp = struct {
1247 base: Node,
1248 lhs: &Node,
1249 op: SuffixOp,
1250 rtoken: Token,
1251
1252 const SuffixOp = union(enum) {
1253 Call: CallInfo,
1254 ArrayAccess: &Node,
1255 Slice: SliceRange,
1256 ArrayInitializer: ArrayList(&Node),
1257 StructInitializer: ArrayList(&NodeFieldInitializer),
1258 };
1424 switch (self.op) {
1425 Op.Catch => |maybe_payload| {
1426 if (maybe_payload) |payload| {
1427 if (i < 1) return payload;
1428 i -= 1;
1429 }
1430 },
1431
1432 Op.Add,
1433 Op.AddWrap,
1434 Op.ArrayCat,
1435 Op.ArrayMult,
1436 Op.Assign,
1437 Op.AssignBitAnd,
1438 Op.AssignBitOr,
1439 Op.AssignBitShiftLeft,
1440 Op.AssignBitShiftRight,
1441 Op.AssignBitXor,
1442 Op.AssignDiv,
1443 Op.AssignMinus,
1444 Op.AssignMinusWrap,
1445 Op.AssignMod,
1446 Op.AssignPlus,
1447 Op.AssignPlusWrap,
1448 Op.AssignTimes,
1449 Op.AssignTimesWarp,
1450 Op.BangEqual,
1451 Op.BitAnd,
1452 Op.BitOr,
1453 Op.BitShiftLeft,
1454 Op.BitShiftRight,
1455 Op.BitXor,
1456 Op.BoolAnd,
1457 Op.BoolOr,
1458 Op.Div,
1459 Op.EqualEqual,
1460 Op.ErrorUnion,
1461 Op.GreaterOrEqual,
1462 Op.GreaterThan,
1463 Op.LessOrEqual,
1464 Op.LessThan,
1465 Op.MergeErrorSets,
1466 Op.Mod,
1467 Op.Mult,
1468 Op.MultWrap,
1469 Op.Period,
1470 Op.Range,
1471 Op.Sub,
1472 Op.SubWrap,
1473 Op.UnwrapOptional,
1474 => {},
1475 }
12591476
1260 const CallInfo = struct {
1261 params: ArrayList(&Node),
1262 async_attr: ?&NodeAsyncAttribute,
1263 };
1477 if (i < 1) return self.rhs;
1478 i -= 1;
12641479
1265 const SliceRange = struct {
1266 start: &Node,
1267 end: ?&Node,
1480 return null;
1481 }
1482
1483 pub fn firstToken(self: *InfixOp) TokenIndex {
1484 return self.lhs.firstToken();
1485 }
1486
1487 pub fn lastToken(self: *InfixOp) TokenIndex {
1488 return self.rhs.lastToken();
1489 }
12681490 };
12691491
1270 pub fn iterate(self: &NodeSuffixOp, index: usize) ?&Node {
1271 var i = index;
1492 pub const PrefixOp = struct {
1493 base: Node,
1494 op_token: TokenIndex,
1495 op: Op,
1496 rhs: *Node,
1497
1498 pub const Op = union(enum) {
1499 AddressOf,
1500 ArrayType: *Node,
1501 Await,
1502 BitNot,
1503 BoolNot,
1504 Cancel,
1505 OptionalType,
1506 Negation,
1507 NegationWrap,
1508 Resume,
1509 PtrType: PtrInfo,
1510 SliceType: PtrInfo,
1511 Try,
1512 };
12721513
1273 if (i < 1) return self.lhs;
1274 i -= 1;
1514 pub const PtrInfo = struct {
1515 align_info: ?Align,
1516 const_token: ?TokenIndex,
1517 volatile_token: ?TokenIndex,
12751518
1276 switch (self.op) {
1277 SuffixOp.Call => |call_info| {
1278 if (i < call_info.params.len) return call_info.params.at(i);
1279 i -= call_info.params.len;
1280 },
1281 SuffixOp.ArrayAccess => |index_expr| {
1282 if (i < 1) return index_expr;
1283 i -= 1;
1284 },
1285 SuffixOp.Slice => |range| {
1286 if (i < 1) return range.start;
1287 i -= 1;
1519 pub const Align = struct {
1520 node: *Node,
1521 bit_range: ?BitRange,
12881522
1289 if (range.end) |end| {
1290 if (i < 1) return end;
1291 i -= 1;
1292 }
1293 },
1294 SuffixOp.ArrayInitializer => |exprs| {
1295 if (i < exprs.len) return exprs.at(i);
1296 i -= exprs.len;
1297 },
1298 SuffixOp.StructInitializer => |fields| {
1299 if (i < fields.len) return &fields.at(i).base;
1300 i -= fields.len;
1301 },
1302 }
1523 pub const BitRange = struct {
1524 start: *Node,
1525 end: *Node,
1526 };
1527 };
1528 };
13031529
1304 return null;
1305 }
1530 pub fn iterate(self: *PrefixOp, index: usize) ?*Node {
1531 var i = index;
1532
1533 switch (self.op) {
1534 // TODO https://github.com/ziglang/zig/issues/1107
1535 Op.SliceType => |addr_of_info| {
1536 if (addr_of_info.align_info) |align_info| {
1537 if (i < 1) return align_info.node;
1538 i -= 1;
1539 }
1540 },
1541
1542 Op.PtrType => |addr_of_info| {
1543 if (addr_of_info.align_info) |align_info| {
1544 if (i < 1) return align_info.node;
1545 i -= 1;
1546 }
1547 },
1548
1549 Op.ArrayType => |size_expr| {
1550 if (i < 1) return size_expr;
1551 i -= 1;
1552 },
1553
1554 Op.AddressOf,
1555 Op.Await,
1556 Op.BitNot,
1557 Op.BoolNot,
1558 Op.Cancel,
1559 Op.OptionalType,
1560 Op.Negation,
1561 Op.NegationWrap,
1562 Op.Try,
1563 Op.Resume,
1564 => {},
1565 }
13061566
1307 pub fn firstToken(self: &NodeSuffixOp) Token {
1308 return self.lhs.firstToken();
1309 }
1567 if (i < 1) return self.rhs;
1568 i -= 1;
13101569
1311 pub fn lastToken(self: &NodeSuffixOp) Token {
1312 return self.rtoken;
1313 }
1314};
1570 return null;
1571 }
13151572
1316pub const NodeGroupedExpression = struct {
1317 base: Node,
1318 lparen: Token,
1319 expr: &Node,
1320 rparen: Token,
1573 pub fn firstToken(self: *PrefixOp) TokenIndex {
1574 return self.op_token;
1575 }
13211576
1322 pub fn iterate(self: &NodeGroupedExpression, index: usize) ?&Node {
1323 var i = index;
1577 pub fn lastToken(self: *PrefixOp) TokenIndex {
1578 return self.rhs.lastToken();
1579 }
1580 };
13241581
1325 if (i < 1) return self.expr;
1326 i -= 1;
1582 pub const FieldInitializer = struct {
1583 base: Node,
1584 period_token: TokenIndex,
1585 name_token: TokenIndex,
1586 expr: *Node,
13271587
1328 return null;
1329 }
1588 pub fn iterate(self: *FieldInitializer, index: usize) ?*Node {
1589 var i = index;
13301590
1331 pub fn firstToken(self: &NodeGroupedExpression) Token {
1332 return self.lparen;
1333 }
1591 if (i < 1) return self.expr;
1592 i -= 1;
13341593
1335 pub fn lastToken(self: &NodeGroupedExpression) Token {
1336 return self.rparen;
1337 }
1338};
1594 return null;
1595 }
13391596
1340pub const NodeControlFlowExpression = struct {
1341 base: Node,
1342 ltoken: Token,
1343 kind: Kind,
1344 rhs: ?&Node,
1597 pub fn firstToken(self: *FieldInitializer) TokenIndex {
1598 return self.period_token;
1599 }
13451600
1346 const Kind = union(enum) {
1347 Break: ?&Node,
1348 Continue: ?&Node,
1349 Return,
1601 pub fn lastToken(self: *FieldInitializer) TokenIndex {
1602 return self.expr.lastToken();
1603 }
13501604 };
13511605
1352 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
1353 var i = index;
1606 pub const SuffixOp = struct {
1607 base: Node,
1608 lhs: *Node,
1609 op: Op,
1610 rtoken: TokenIndex,
1611
1612 pub const Op = union(enum) {
1613 Call: Call,
1614 ArrayAccess: *Node,
1615 Slice: Slice,
1616 ArrayInitializer: InitList,
1617 StructInitializer: InitList,
1618 Deref,
1619 UnwrapOptional,
1620
1621 pub const InitList = SegmentedList(*Node, 2);
1622
1623 pub const Call = struct {
1624 params: ParamList,
1625 async_attr: ?*AsyncAttribute,
1626
1627 pub const ParamList = SegmentedList(*Node, 2);
1628 };
1629
1630 pub const Slice = struct {
1631 start: *Node,
1632 end: ?*Node,
1633 };
1634 };
1635
1636 pub fn iterate(self: *SuffixOp, index: usize) ?*Node {
1637 var i = index;
13541638
1355 switch (self.kind) {
1356 Kind.Break => |maybe_label| {
1357 if (maybe_label) |label| {
1358 if (i < 1) return label;
1639 if (i < 1) return self.lhs;
1640 i -= 1;
1641
1642 switch (self.op) {
1643 @TagType(Op).Call => |*call_info| {
1644 if (i < call_info.params.len) return call_info.params.at(i).*;
1645 i -= call_info.params.len;
1646 },
1647 Op.ArrayAccess => |index_expr| {
1648 if (i < 1) return index_expr;
13591649 i -= 1;
1360 }
1361 },
1362 Kind.Continue => |maybe_label| {
1363 if (maybe_label) |label| {
1364 if (i < 1) return label;
1650 },
1651 @TagType(Op).Slice => |range| {
1652 if (i < 1) return range.start;
13651653 i -= 1;
1366 }
1367 },
1368 Kind.Return => {},
1654
1655 if (range.end) |end| {
1656 if (i < 1) return end;
1657 i -= 1;
1658 }
1659 },
1660 Op.ArrayInitializer => |*exprs| {
1661 if (i < exprs.len) return exprs.at(i).*;
1662 i -= exprs.len;
1663 },
1664 Op.StructInitializer => |*fields| {
1665 if (i < fields.len) return fields.at(i).*;
1666 i -= fields.len;
1667 },
1668 Op.UnwrapOptional,
1669 Op.Deref,
1670 => {},
1671 }
1672
1673 return null;
13691674 }
13701675
1371 if (self.rhs) |rhs| {
1372 if (i < 1) return rhs;
1373 i -= 1;
1676 pub fn firstToken(self: *SuffixOp) TokenIndex {
1677 switch (self.op) {
1678 @TagType(Op).Call => |*call_info| if (call_info.async_attr) |async_attr| return async_attr.firstToken(),
1679 else => {},
1680 }
1681 return self.lhs.firstToken();
13741682 }
13751683
1376 return null;
1377 }
1684 pub fn lastToken(self: *SuffixOp) TokenIndex {
1685 return self.rtoken;
1686 }
1687 };
13781688
1379 pub fn firstToken(self: &NodeControlFlowExpression) Token {
1380 return self.ltoken;
1381 }
1689 pub const GroupedExpression = struct {
1690 base: Node,
1691 lparen: TokenIndex,
1692 expr: *Node,
1693 rparen: TokenIndex,
1694
1695 pub fn iterate(self: *GroupedExpression, index: usize) ?*Node {
1696 var i = index;
1697
1698 if (i < 1) return self.expr;
1699 i -= 1;
13821700
1383 pub fn lastToken(self: &NodeControlFlowExpression) Token {
1384 if (self.rhs) |rhs| {
1385 return rhs.lastToken();
1701 return null;
13861702 }
13871703
1388 switch (self.kind) {
1389 Kind.Break => |maybe_label| {
1390 if (maybe_label) |label| {
1391 return label.lastToken();
1392 }
1393 },
1394 Kind.Continue => |maybe_label| {
1395 if (maybe_label) |label| {
1396 return label.lastToken();
1397 }
1398 },
1399 Kind.Return => return self.ltoken,
1704 pub fn firstToken(self: *GroupedExpression) TokenIndex {
1705 return self.lparen;
14001706 }
14011707
1402 return self.ltoken;
1403 }
1404};
1708 pub fn lastToken(self: *GroupedExpression) TokenIndex {
1709 return self.rparen;
1710 }
1711 };
14051712
1406pub const NodeSuspend = struct {
1407 base: Node,
1408 suspend_token: Token,
1409 payload: ?&Node,
1410 body: ?&Node,
1713 pub const ControlFlowExpression = struct {
1714 base: Node,
1715 ltoken: TokenIndex,
1716 kind: Kind,
1717 rhs: ?*Node,
14111718
1412 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
1413 var i = index;
1719 const Kind = union(enum) {
1720 Break: ?*Node,
1721 Continue: ?*Node,
1722 Return,
1723 };
14141724
1415 if (self.payload) |payload| {
1416 if (i < 1) return payload;
1417 i -= 1;
1725 pub fn iterate(self: *ControlFlowExpression, index: usize) ?*Node {
1726 var i = index;
1727
1728 switch (self.kind) {
1729 Kind.Break => |maybe_label| {
1730 if (maybe_label) |label| {
1731 if (i < 1) return label;
1732 i -= 1;
1733 }
1734 },
1735 Kind.Continue => |maybe_label| {
1736 if (maybe_label) |label| {
1737 if (i < 1) return label;
1738 i -= 1;
1739 }
1740 },
1741 Kind.Return => {},
1742 }
1743
1744 if (self.rhs) |rhs| {
1745 if (i < 1) return rhs;
1746 i -= 1;
1747 }
1748
1749 return null;
14181750 }
14191751
1420 if (self.body) |body| {
1421 if (i < 1) return body;
1422 i -= 1;
1752 pub fn firstToken(self: *ControlFlowExpression) TokenIndex {
1753 return self.ltoken;
14231754 }
14241755
1425 return null;
1426 }
1756 pub fn lastToken(self: *ControlFlowExpression) TokenIndex {
1757 if (self.rhs) |rhs| {
1758 return rhs.lastToken();
1759 }
14271760
1428 pub fn firstToken(self: &NodeSuspend) Token {
1429 return self.suspend_token;
1430 }
1761 switch (self.kind) {
1762 Kind.Break => |maybe_label| {
1763 if (maybe_label) |label| {
1764 return label.lastToken();
1765 }
1766 },
1767 Kind.Continue => |maybe_label| {
1768 if (maybe_label) |label| {
1769 return label.lastToken();
1770 }
1771 },
1772 Kind.Return => return self.ltoken,
1773 }
14311774
1432 pub fn lastToken(self: &NodeSuspend) Token {
1433 if (self.body) |body| {
1434 return body.lastToken();
1775 return self.ltoken;
14351776 }
1777 };
1778
1779 pub const Suspend = struct {
1780 base: Node,
1781 suspend_token: TokenIndex,
1782 body: ?*Node,
1783
1784 pub fn iterate(self: *Suspend, index: usize) ?*Node {
1785 var i = index;
14361786
1437 if (self.payload) |payload| {
1438 return payload.lastToken();
1787 if (self.body) |body| {
1788 if (i < 1) return body;
1789 i -= 1;
1790 }
1791
1792 return null;
14391793 }
14401794
1441 return self.suspend_token;
1442 }
1443};
1795 pub fn firstToken(self: *Suspend) TokenIndex {
1796 return self.suspend_token;
1797 }
14441798
1445pub const NodeIntegerLiteral = struct {
1446 base: Node,
1447 token: Token,
1799 pub fn lastToken(self: *Suspend) TokenIndex {
1800 if (self.body) |body| {
1801 return body.lastToken();
1802 }
14481803
1449 pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node {
1450 return null;
1451 }
1804 return self.suspend_token;
1805 }
1806 };
14521807
1453 pub fn firstToken(self: &NodeIntegerLiteral) Token {
1454 return self.token;
1455 }
1808 pub const IntegerLiteral = struct {
1809 base: Node,
1810 token: TokenIndex,
14561811
1457 pub fn lastToken(self: &NodeIntegerLiteral) Token {
1458 return self.token;
1459 }
1460};
1812 pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node {
1813 return null;
1814 }
14611815
1462pub const NodeFloatLiteral = struct {
1463 base: Node,
1464 token: Token,
1816 pub fn firstToken(self: *IntegerLiteral) TokenIndex {
1817 return self.token;
1818 }
14651819
1466 pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node {
1467 return null;
1468 }
1820 pub fn lastToken(self: *IntegerLiteral) TokenIndex {
1821 return self.token;
1822 }
1823 };
14691824
1470 pub fn firstToken(self: &NodeFloatLiteral) Token {
1471 return self.token;
1472 }
1825 pub const FloatLiteral = struct {
1826 base: Node,
1827 token: TokenIndex,
14731828
1474 pub fn lastToken(self: &NodeFloatLiteral) Token {
1475 return self.token;
1476 }
1477};
1829 pub fn iterate(self: *FloatLiteral, index: usize) ?*Node {
1830 return null;
1831 }
14781832
1479pub const NodeBuiltinCall = struct {
1480 base: Node,
1481 builtin_token: Token,
1482 params: ArrayList(&Node),
1483 rparen_token: Token,
1833 pub fn firstToken(self: *FloatLiteral) TokenIndex {
1834 return self.token;
1835 }
14841836
1485 pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node {
1486 var i = index;
1837 pub fn lastToken(self: *FloatLiteral) TokenIndex {
1838 return self.token;
1839 }
1840 };
14871841
1488 if (i < self.params.len) return self.params.at(i);
1489 i -= self.params.len;
1842 pub const BuiltinCall = struct {
1843 base: Node,
1844 builtin_token: TokenIndex,
1845 params: ParamList,
1846 rparen_token: TokenIndex,
14901847
1491 return null;
1492 }
1848 pub const ParamList = SegmentedList(*Node, 2);
14931849
1494 pub fn firstToken(self: &NodeBuiltinCall) Token {
1495 return self.builtin_token;
1496 }
1850 pub fn iterate(self: *BuiltinCall, index: usize) ?*Node {
1851 var i = index;
14971852
1498 pub fn lastToken(self: &NodeBuiltinCall) Token {
1499 return self.rparen_token;
1500 }
1501};
1853 if (i < self.params.len) return self.params.at(i).*;
1854 i -= self.params.len;
15021855
1503pub const NodeStringLiteral = struct {
1504 base: Node,
1505 token: Token,
1856 return null;
1857 }
15061858
1507 pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
1508 return null;
1509 }
1859 pub fn firstToken(self: *BuiltinCall) TokenIndex {
1860 return self.builtin_token;
1861 }
15101862
1511 pub fn firstToken(self: &NodeStringLiteral) Token {
1512 return self.token;
1513 }
1863 pub fn lastToken(self: *BuiltinCall) TokenIndex {
1864 return self.rparen_token;
1865 }
1866 };
15141867
1515 pub fn lastToken(self: &NodeStringLiteral) Token {
1516 return self.token;
1517 }
1518};
1868 pub const StringLiteral = struct {
1869 base: Node,
1870 token: TokenIndex,
15191871
1520pub const NodeMultilineStringLiteral = struct {
1521 base: Node,
1522 tokens: ArrayList(Token),
1872 pub fn iterate(self: *StringLiteral, index: usize) ?*Node {
1873 return null;
1874 }
15231875
1524 pub fn iterate(self: &NodeMultilineStringLiteral, index: usize) ?&Node {
1525 return null;
1526 }
1876 pub fn firstToken(self: *StringLiteral) TokenIndex {
1877 return self.token;
1878 }
15271879
1528 pub fn firstToken(self: &NodeMultilineStringLiteral) Token {
1529 return self.tokens.at(0);
1530 }
1880 pub fn lastToken(self: *StringLiteral) TokenIndex {
1881 return self.token;
1882 }
1883 };
15311884
1532 pub fn lastToken(self: &NodeMultilineStringLiteral) Token {
1533 return self.tokens.at(self.tokens.len - 1);
1534 }
1535};
1885 pub const MultilineStringLiteral = struct {
1886 base: Node,
1887 lines: LineList,
15361888
1537pub const NodeCharLiteral = struct {
1538 base: Node,
1539 token: Token,
1889 pub const LineList = SegmentedList(TokenIndex, 4);
15401890
1541 pub fn iterate(self: &NodeCharLiteral, index: usize) ?&Node {
1542 return null;
1543 }
1891 pub fn iterate(self: *MultilineStringLiteral, index: usize) ?*Node {
1892 return null;
1893 }
15441894
1545 pub fn firstToken(self: &NodeCharLiteral) Token {
1546 return self.token;
1547 }
1895 pub fn firstToken(self: *MultilineStringLiteral) TokenIndex {
1896 return self.lines.at(0).*;
1897 }
15481898
1549 pub fn lastToken(self: &NodeCharLiteral) Token {
1550 return self.token;
1551 }
1552};
1899 pub fn lastToken(self: *MultilineStringLiteral) TokenIndex {
1900 return self.lines.at(self.lines.len - 1).*;
1901 }
1902 };
15531903
1554pub const NodeBoolLiteral = struct {
1555 base: Node,
1556 token: Token,
1904 pub const CharLiteral = struct {
1905 base: Node,
1906 token: TokenIndex,
15571907
1558 pub fn iterate(self: &NodeBoolLiteral, index: usize) ?&Node {
1559 return null;
1560 }
1908 pub fn iterate(self: *CharLiteral, index: usize) ?*Node {
1909 return null;
1910 }
15611911
1562 pub fn firstToken(self: &NodeBoolLiteral) Token {
1563 return self.token;
1564 }
1912 pub fn firstToken(self: *CharLiteral) TokenIndex {
1913 return self.token;
1914 }
15651915
1566 pub fn lastToken(self: &NodeBoolLiteral) Token {
1567 return self.token;
1568 }
1569};
1916 pub fn lastToken(self: *CharLiteral) TokenIndex {
1917 return self.token;
1918 }
1919 };
15701920
1571pub const NodeNullLiteral = struct {
1572 base: Node,
1573 token: Token,
1921 pub const BoolLiteral = struct {
1922 base: Node,
1923 token: TokenIndex,
15741924
1575 pub fn iterate(self: &NodeNullLiteral, index: usize) ?&Node {
1576 return null;
1577 }
1925 pub fn iterate(self: *BoolLiteral, index: usize) ?*Node {
1926 return null;
1927 }
15781928
1579 pub fn firstToken(self: &NodeNullLiteral) Token {
1580 return self.token;
1581 }
1929 pub fn firstToken(self: *BoolLiteral) TokenIndex {
1930 return self.token;
1931 }
15821932
1583 pub fn lastToken(self: &NodeNullLiteral) Token {
1584 return self.token;
1585 }
1586};
1933 pub fn lastToken(self: *BoolLiteral) TokenIndex {
1934 return self.token;
1935 }
1936 };
15871937
1588pub const NodeUndefinedLiteral = struct {
1589 base: Node,
1590 token: Token,
1938 pub const NullLiteral = struct {
1939 base: Node,
1940 token: TokenIndex,
15911941
1592 pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node {
1593 return null;
1594 }
1942 pub fn iterate(self: *NullLiteral, index: usize) ?*Node {
1943 return null;
1944 }
15951945
1596 pub fn firstToken(self: &NodeUndefinedLiteral) Token {
1597 return self.token;
1598 }
1946 pub fn firstToken(self: *NullLiteral) TokenIndex {
1947 return self.token;
1948 }
15991949
1600 pub fn lastToken(self: &NodeUndefinedLiteral) Token {
1601 return self.token;
1602 }
1603};
1950 pub fn lastToken(self: *NullLiteral) TokenIndex {
1951 return self.token;
1952 }
1953 };
16041954
1605pub const NodeThisLiteral = struct {
1606 base: Node,
1607 token: Token,
1955 pub const UndefinedLiteral = struct {
1956 base: Node,
1957 token: TokenIndex,
16081958
1609 pub fn iterate(self: &NodeThisLiteral, index: usize) ?&Node {
1610 return null;
1611 }
1959 pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node {
1960 return null;
1961 }
16121962
1613 pub fn firstToken(self: &NodeThisLiteral) Token {
1614 return self.token;
1615 }
1963 pub fn firstToken(self: *UndefinedLiteral) TokenIndex {
1964 return self.token;
1965 }
16161966
1617 pub fn lastToken(self: &NodeThisLiteral) Token {
1618 return self.token;
1619 }
1620};
1967 pub fn lastToken(self: *UndefinedLiteral) TokenIndex {
1968 return self.token;
1969 }
1970 };
1971
1972 pub const ThisLiteral = struct {
1973 base: Node,
1974 token: TokenIndex,
1975
1976 pub fn iterate(self: *ThisLiteral, index: usize) ?*Node {
1977 return null;
1978 }
16211979
1622pub const NodeAsmOutput = struct {
1623 base: Node,
1624 symbolic_name: &Node,
1625 constraint: &Node,
1626 kind: Kind,
1980 pub fn firstToken(self: *ThisLiteral) TokenIndex {
1981 return self.token;
1982 }
16271983
1628 const Kind = union(enum) {
1629 Variable: &NodeIdentifier,
1630 Return: &Node
1984 pub fn lastToken(self: *ThisLiteral) TokenIndex {
1985 return self.token;
1986 }
16311987 };
16321988
1633 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
1634 var i = index;
1989 pub const AsmOutput = struct {
1990 base: Node,
1991 lbracket: TokenIndex,
1992 symbolic_name: *Node,
1993 constraint: *Node,
1994 kind: Kind,
1995 rparen: TokenIndex,
1996
1997 const Kind = union(enum) {
1998 Variable: *Identifier,
1999 Return: *Node,
2000 };
16352001
1636 if (i < 1) return self.symbolic_name;
1637 i -= 1;
2002 pub fn iterate(self: *AsmOutput, index: usize) ?*Node {
2003 var i = index;
16382004
1639 if (i < 1) return self.constraint;
1640 i -= 1;
2005 if (i < 1) return self.symbolic_name;
2006 i -= 1;
16412007
1642 switch (self.kind) {
1643 Kind.Variable => |variable_name| {
1644 if (i < 1) return &variable_name.base;
1645 i -= 1;
1646 },
1647 Kind.Return => |return_type| {
1648 if (i < 1) return return_type;
1649 i -= 1;
2008 if (i < 1) return self.constraint;
2009 i -= 1;
2010
2011 switch (self.kind) {
2012 Kind.Variable => |variable_name| {
2013 if (i < 1) return &variable_name.base;
2014 i -= 1;
2015 },
2016 Kind.Return => |return_type| {
2017 if (i < 1) return return_type;
2018 i -= 1;
2019 },
16502020 }
2021
2022 return null;
16512023 }
16522024
1653 return null;
1654 }
2025 pub fn firstToken(self: *AsmOutput) TokenIndex {
2026 return self.lbracket;
2027 }
16552028
1656 pub fn firstToken(self: &NodeAsmOutput) Token {
1657 return self.symbolic_name.firstToken();
1658 }
2029 pub fn lastToken(self: *AsmOutput) TokenIndex {
2030 return self.rparen;
2031 }
2032 };
16592033
1660 pub fn lastToken(self: &NodeAsmOutput) Token {
1661 return switch (self.kind) {
1662 Kind.Variable => |variable_name| variable_name.lastToken(),
1663 Kind.Return => |return_type| return_type.lastToken(),
1664 };
1665 }
1666};
2034 pub const AsmInput = struct {
2035 base: Node,
2036 lbracket: TokenIndex,
2037 symbolic_name: *Node,
2038 constraint: *Node,
2039 expr: *Node,
2040 rparen: TokenIndex,
16672041
1668pub const NodeAsmInput = struct {
1669 base: Node,
1670 symbolic_name: &Node,
1671 constraint: &Node,
1672 expr: &Node,
2042 pub fn iterate(self: *AsmInput, index: usize) ?*Node {
2043 var i = index;
16732044
1674 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
1675 var i = index;
2045 if (i < 1) return self.symbolic_name;
2046 i -= 1;
16762047
1677 if (i < 1) return self.symbolic_name;
1678 i -= 1;
2048 if (i < 1) return self.constraint;
2049 i -= 1;
16792050
1680 if (i < 1) return self.constraint;
1681 i -= 1;
2051 if (i < 1) return self.expr;
2052 i -= 1;
16822053
1683 if (i < 1) return self.expr;
1684 i -= 1;
2054 return null;
2055 }
16852056
1686 return null;
1687 }
2057 pub fn firstToken(self: *AsmInput) TokenIndex {
2058 return self.lbracket;
2059 }
16882060
1689 pub fn firstToken(self: &NodeAsmInput) Token {
1690 return self.symbolic_name.firstToken();
1691 }
2061 pub fn lastToken(self: *AsmInput) TokenIndex {
2062 return self.rparen;
2063 }
2064 };
16922065
1693 pub fn lastToken(self: &NodeAsmInput) Token {
1694 return self.expr.lastToken();
1695 }
1696};
2066 pub const Asm = struct {
2067 base: Node,
2068 asm_token: TokenIndex,
2069 volatile_token: ?TokenIndex,
2070 template: *Node,
2071 outputs: OutputList,
2072 inputs: InputList,
2073 clobbers: ClobberList,
2074 rparen: TokenIndex,
16972075
1698pub const NodeAsm = struct {
1699 base: Node,
1700 asm_token: Token,
1701 volatile_token: ?Token,
1702 template: &Node,
1703 //tokens: ArrayList(AsmToken),
1704 outputs: ArrayList(&NodeAsmOutput),
1705 inputs: ArrayList(&NodeAsmInput),
1706 cloppers: ArrayList(&Node),
1707 rparen: Token,
2076 const OutputList = SegmentedList(*AsmOutput, 2);
2077 const InputList = SegmentedList(*AsmInput, 2);
2078 const ClobberList = SegmentedList(TokenIndex, 2);
17082079
1709 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
1710 var i = index;
2080 pub fn iterate(self: *Asm, index: usize) ?*Node {
2081 var i = index;
17112082
1712 if (i < self.outputs.len) return &self.outputs.at(index).base;
1713 i -= self.outputs.len;
2083 if (i < self.outputs.len) return &self.outputs.at(index).*.base;
2084 i -= self.outputs.len;
17142085
1715 if (i < self.inputs.len) return &self.inputs.at(index).base;
1716 i -= self.inputs.len;
2086 if (i < self.inputs.len) return &self.inputs.at(index).*.base;
2087 i -= self.inputs.len;
17172088
1718 if (i < self.cloppers.len) return self.cloppers.at(index);
1719 i -= self.cloppers.len;
2089 return null;
2090 }
17202091
1721 return null;
1722 }
2092 pub fn firstToken(self: *Asm) TokenIndex {
2093 return self.asm_token;
2094 }
17232095
1724 pub fn firstToken(self: &NodeAsm) Token {
1725 return self.asm_token;
1726 }
2096 pub fn lastToken(self: *Asm) TokenIndex {
2097 return self.rparen;
2098 }
2099 };
17272100
1728 pub fn lastToken(self: &NodeAsm) Token {
1729 return self.rparen;
1730 }
1731};
2101 pub const Unreachable = struct {
2102 base: Node,
2103 token: TokenIndex,
17322104
1733pub const NodeUnreachable = struct {
1734 base: Node,
1735 token: Token,
2105 pub fn iterate(self: *Unreachable, index: usize) ?*Node {
2106 return null;
2107 }
17362108
1737 pub fn iterate(self: &NodeUnreachable, index: usize) ?&Node {
1738 return null;
1739 }
2109 pub fn firstToken(self: *Unreachable) TokenIndex {
2110 return self.token;
2111 }
17402112
1741 pub fn firstToken(self: &NodeUnreachable) Token {
1742 return self.token;
1743 }
2113 pub fn lastToken(self: *Unreachable) TokenIndex {
2114 return self.token;
2115 }
2116 };
17442117
1745 pub fn lastToken(self: &NodeUnreachable) Token {
1746 return self.token;
1747 }
1748};
2118 pub const ErrorType = struct {
2119 base: Node,
2120 token: TokenIndex,
17492121
1750pub const NodeErrorType = struct {
1751 base: Node,
1752 token: Token,
2122 pub fn iterate(self: *ErrorType, index: usize) ?*Node {
2123 return null;
2124 }
17532125
1754 pub fn iterate(self: &NodeErrorType, index: usize) ?&Node {
1755 return null;
1756 }
2126 pub fn firstToken(self: *ErrorType) TokenIndex {
2127 return self.token;
2128 }
17572129
1758 pub fn firstToken(self: &NodeErrorType) Token {
1759 return self.token;
1760 }
2130 pub fn lastToken(self: *ErrorType) TokenIndex {
2131 return self.token;
2132 }
2133 };
17612134
1762 pub fn lastToken(self: &NodeErrorType) Token {
1763 return self.token;
1764 }
1765};
2135 pub const VarType = struct {
2136 base: Node,
2137 token: TokenIndex,
17662138
1767pub const NodeVarType = struct {
1768 base: Node,
1769 token: Token,
2139 pub fn iterate(self: *VarType, index: usize) ?*Node {
2140 return null;
2141 }
17702142
1771 pub fn iterate(self: &NodeVarType, index: usize) ?&Node {
1772 return null;
1773 }
2143 pub fn firstToken(self: *VarType) TokenIndex {
2144 return self.token;
2145 }
17742146
1775 pub fn firstToken(self: &NodeVarType) Token {
1776 return self.token;
1777 }
2147 pub fn lastToken(self: *VarType) TokenIndex {
2148 return self.token;
2149 }
2150 };
17782151
1779 pub fn lastToken(self: &NodeVarType) Token {
1780 return self.token;
1781 }
1782};
2152 pub const DocComment = struct {
2153 base: Node,
2154 lines: LineList,
17832155
1784pub const NodeLineComment = struct {
1785 base: Node,
1786 lines: ArrayList(Token),
2156 pub const LineList = SegmentedList(TokenIndex, 4);
17872157
1788 pub fn iterate(self: &NodeLineComment, index: usize) ?&Node {
1789 return null;
1790 }
2158 pub fn iterate(self: *DocComment, index: usize) ?*Node {
2159 return null;
2160 }
17912161
1792 pub fn firstToken(self: &NodeLineComment) Token {
1793 return self.lines.at(0);
1794 }
2162 pub fn firstToken(self: *DocComment) TokenIndex {
2163 return self.lines.at(0).*;
2164 }
17952165
1796 pub fn lastToken(self: &NodeLineComment) Token {
1797 return self.lines.at(self.lines.len - 1);
1798 }
1799};
2166 pub fn lastToken(self: *DocComment) TokenIndex {
2167 return self.lines.at(self.lines.len - 1).*;
2168 }
2169 };
18002170
1801pub const NodeTestDecl = struct {
1802 base: Node,
1803 test_token: Token,
1804 name: &Node,
1805 body_node: &Node,
2171 pub const TestDecl = struct {
2172 base: Node,
2173 doc_comments: ?*DocComment,
2174 test_token: TokenIndex,
2175 name: *Node,
2176 body_node: *Node,
18062177
1807 pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
1808 var i = index;
2178 pub fn iterate(self: *TestDecl, index: usize) ?*Node {
2179 var i = index;
18092180
1810 if (i < 1) return self.body_node;
1811 i -= 1;
2181 if (i < 1) return self.body_node;
2182 i -= 1;
18122183
1813 return null;
1814 }
2184 return null;
2185 }
18152186
1816 pub fn firstToken(self: &NodeTestDecl) Token {
1817 return self.test_token;
1818 }
2187 pub fn firstToken(self: *TestDecl) TokenIndex {
2188 return self.test_token;
2189 }
18192190
1820 pub fn lastToken(self: &NodeTestDecl) Token {
1821 return self.body_node.lastToken();
1822 }
2191 pub fn lastToken(self: *TestDecl) TokenIndex {
2192 return self.body_node.lastToken();
2193 }
2194 };
18232195};
2196
2197test "iterate" {
2198 var root = Node.Root{
2199 .base = Node{ .id = Node.Id.Root },
2200 .doc_comments = null,
2201 .decls = Node.Root.DeclList.init(std.debug.global_allocator),
2202 .eof_token = 0,
2203 };
2204 var base = &root.base;
2205 assert(base.iterate(0) == null);
2206}
std/zig/bench.zig created+36
......@@ -0,0 +1,36 @@
1const std = @import("std");
2const mem = std.mem;
3const warn = std.debug.warn;
4const Tokenizer = std.zig.Tokenizer;
5const Parser = std.zig.Parser;
6const io = std.io;
7
8const source = @embedFile("../os/index.zig");
9var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
10
11pub fn main() !void {
12 var i: usize = 0;
13 var timer = try std.os.time.Timer.start();
14 const start = timer.lap();
15 const iterations = 100;
16 var memory_used: usize = 0;
17 while (i < iterations) : (i += 1) {
18 memory_used += testOnce();
19 }
20 const end = timer.read();
21 memory_used /= iterations;
22 const elapsed_s = @intToFloat(f64, end - start) / std.os.time.ns_per_s;
23 const bytes_per_sec = @intToFloat(f64, source.len * iterations) / elapsed_s;
24 const mb_per_sec = bytes_per_sec / (1024 * 1024);
25
26 var stdout_file = try std.io.getStdOut();
27 const stdout = &std.io.FileOutStream.init(&stdout_file).stream;
28 try stdout.print("{.3} MiB/s, {} KiB used \n", mb_per_sec, memory_used / 1024);
29}
30
31fn testOnce() usize {
32 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
33 var allocator = &fixed_buf_alloc.allocator;
34 _ = std.zig.parse(allocator, source) catch @panic("parse failure");
35 return fixed_buf_alloc.end_index;
36}
std/zig/index.zig+8-3
......@@ -1,11 +1,16 @@
11const tokenizer = @import("tokenizer.zig");
22pub const Token = tokenizer.Token;
33pub const Tokenizer = tokenizer.Tokenizer;
4pub const Parser = @import("parser.zig").Parser;
4pub const parse = @import("parse.zig").parse;
5pub const parseStringLiteral = @import("parse_string_literal.zig").parseStringLiteral;
6pub const render = @import("render.zig").render;
57pub const ast = @import("ast.zig");
68
79test "std.zig tests" {
8 _ = @import("tokenizer.zig");
9 _ = @import("parser.zig");
1010 _ = @import("ast.zig");
11 _ = @import("parse.zig");
12 _ = @import("render.zig");
13 _ = @import("tokenizer.zig");
14 _ = @import("parse_string_literal.zig");
1115}
16
std/zig/parse.zig created+3358
......@@ -0,0 +1,3358 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Tokenizer = std.zig.Tokenizer;
6const Token = std.zig.Token;
7const TokenIndex = ast.TokenIndex;
8const Error = ast.Error;
9
10/// Result should be freed with tree.deinit() when there are
11/// no more references to any of the tokens or nodes.
12pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
13 var tree_arena = std.heap.ArenaAllocator.init(allocator);
14 errdefer tree_arena.deinit();
15
16 var stack = std.ArrayList(State).init(allocator);
17 defer stack.deinit();
18
19 const arena = &tree_arena.allocator;
20 const root_node = try arena.create(ast.Node.Root{
21 .base = ast.Node{ .id = ast.Node.Id.Root },
22 .decls = ast.Node.Root.DeclList.init(arena),
23 .doc_comments = null,
24 // initialized when we get the eof token
25 .eof_token = undefined,
26 });
27
28 var tree = ast.Tree{
29 .source = source,
30 .root_node = root_node,
31 .arena_allocator = tree_arena,
32 .tokens = ast.Tree.TokenList.init(arena),
33 .errors = ast.Tree.ErrorList.init(arena),
34 };
35
36 var tokenizer = Tokenizer.init(tree.source);
37 while (true) {
38 const token_ptr = try tree.tokens.addOne();
39 token_ptr.* = tokenizer.next();
40 if (token_ptr.id == Token.Id.Eof) break;
41 }
42 var tok_it = tree.tokens.iterator(0);
43
44 // skip over line comments at the top of the file
45 while (true) {
46 const next_tok = tok_it.peek() orelse break;
47 if (next_tok.id != Token.Id.LineComment) break;
48 _ = tok_it.next();
49 }
50
51 try stack.append(State.TopLevel);
52
53 while (true) {
54 // This gives us 1 free push that can't fail
55 const state = stack.pop();
56
57 switch (state) {
58 State.TopLevel => {
59 const comments = try eatDocComments(arena, &tok_it, &tree);
60
61 const token = nextToken(&tok_it, &tree);
62 const token_index = token.index;
63 const token_ptr = token.ptr;
64 switch (token_ptr.id) {
65 Token.Id.Keyword_test => {
66 stack.append(State.TopLevel) catch unreachable;
67
68 const block = try arena.create(ast.Node.Block{
69 .base = ast.Node{ .id = ast.Node.Id.Block },
70 .label = null,
71 .lbrace = undefined,
72 .statements = ast.Node.Block.StatementList.init(arena),
73 .rbrace = undefined,
74 });
75 const test_node = try arena.create(ast.Node.TestDecl{
76 .base = ast.Node{ .id = ast.Node.Id.TestDecl },
77 .doc_comments = comments,
78 .test_token = token_index,
79 .name = undefined,
80 .body_node = &block.base,
81 });
82 try root_node.decls.push(&test_node.base);
83 try stack.append(State{ .Block = block });
84 try stack.append(State{
85 .ExpectTokenSave = ExpectTokenSave{
86 .id = Token.Id.LBrace,
87 .ptr = &block.lbrace,
88 },
89 });
90 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &test_node.name } });
91 continue;
92 },
93 Token.Id.Eof => {
94 root_node.eof_token = token_index;
95 root_node.doc_comments = comments;
96 return tree;
97 },
98 Token.Id.Keyword_pub => {
99 stack.append(State.TopLevel) catch unreachable;
100 try stack.append(State{
101 .TopLevelExtern = TopLevelDeclCtx{
102 .decls = &root_node.decls,
103 .visib_token = token_index,
104 .extern_export_inline_token = null,
105 .lib_name = null,
106 .comments = comments,
107 },
108 });
109 continue;
110 },
111 Token.Id.Keyword_comptime => {
112 const block = try arena.create(ast.Node.Block{
113 .base = ast.Node{ .id = ast.Node.Id.Block },
114 .label = null,
115 .lbrace = undefined,
116 .statements = ast.Node.Block.StatementList.init(arena),
117 .rbrace = undefined,
118 });
119 const node = try arena.create(ast.Node.Comptime{
120 .base = ast.Node{ .id = ast.Node.Id.Comptime },
121 .comptime_token = token_index,
122 .expr = &block.base,
123 .doc_comments = comments,
124 });
125 try root_node.decls.push(&node.base);
126
127 stack.append(State.TopLevel) catch unreachable;
128 try stack.append(State{ .Block = block });
129 try stack.append(State{
130 .ExpectTokenSave = ExpectTokenSave{
131 .id = Token.Id.LBrace,
132 .ptr = &block.lbrace,
133 },
134 });
135 continue;
136 },
137 else => {
138 prevToken(&tok_it, &tree);
139 stack.append(State.TopLevel) catch unreachable;
140 try stack.append(State{
141 .TopLevelExtern = TopLevelDeclCtx{
142 .decls = &root_node.decls,
143 .visib_token = null,
144 .extern_export_inline_token = null,
145 .lib_name = null,
146 .comments = comments,
147 },
148 });
149 continue;
150 },
151 }
152 },
153 State.TopLevelExtern => |ctx| {
154 const token = nextToken(&tok_it, &tree);
155 const token_index = token.index;
156 const token_ptr = token.ptr;
157 switch (token_ptr.id) {
158 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
159 stack.append(State{
160 .TopLevelDecl = TopLevelDeclCtx{
161 .decls = ctx.decls,
162 .visib_token = ctx.visib_token,
163 .extern_export_inline_token = AnnotatedToken{
164 .index = token_index,
165 .ptr = token_ptr,
166 },
167 .lib_name = null,
168 .comments = ctx.comments,
169 },
170 }) catch unreachable;
171 continue;
172 },
173 Token.Id.Keyword_extern => {
174 stack.append(State{
175 .TopLevelLibname = TopLevelDeclCtx{
176 .decls = ctx.decls,
177 .visib_token = ctx.visib_token,
178 .extern_export_inline_token = AnnotatedToken{
179 .index = token_index,
180 .ptr = token_ptr,
181 },
182 .lib_name = null,
183 .comments = ctx.comments,
184 },
185 }) catch unreachable;
186 continue;
187 },
188 else => {
189 prevToken(&tok_it, &tree);
190 stack.append(State{ .TopLevelDecl = ctx }) catch unreachable;
191 continue;
192 },
193 }
194 },
195 State.TopLevelLibname => |ctx| {
196 const lib_name = blk: {
197 const lib_name_token = nextToken(&tok_it, &tree);
198 const lib_name_token_index = lib_name_token.index;
199 const lib_name_token_ptr = lib_name_token.ptr;
200 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) orelse {
201 prevToken(&tok_it, &tree);
202 break :blk null;
203 };
204 };
205
206 stack.append(State{
207 .TopLevelDecl = TopLevelDeclCtx{
208 .decls = ctx.decls,
209 .visib_token = ctx.visib_token,
210 .extern_export_inline_token = ctx.extern_export_inline_token,
211 .lib_name = lib_name,
212 .comments = ctx.comments,
213 },
214 }) catch unreachable;
215 continue;
216 },
217 State.TopLevelDecl => |ctx| {
218 const token = nextToken(&tok_it, &tree);
219 const token_index = token.index;
220 const token_ptr = token.ptr;
221 switch (token_ptr.id) {
222 Token.Id.Keyword_use => {
223 if (ctx.extern_export_inline_token) |annotated_token| {
224 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
225 return tree;
226 }
227
228 const node = try arena.create(ast.Node.Use{
229 .base = ast.Node{ .id = ast.Node.Id.Use },
230 .use_token = token_index,
231 .visib_token = ctx.visib_token,
232 .expr = undefined,
233 .semicolon_token = undefined,
234 .doc_comments = ctx.comments,
235 });
236 try ctx.decls.push(&node.base);
237
238 stack.append(State{
239 .ExpectTokenSave = ExpectTokenSave{
240 .id = Token.Id.Semicolon,
241 .ptr = &node.semicolon_token,
242 },
243 }) catch unreachable;
244 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
245 continue;
246 },
247 Token.Id.Keyword_var, Token.Id.Keyword_const => {
248 if (ctx.extern_export_inline_token) |annotated_token| {
249 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
250 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
251 return tree;
252 }
253 }
254
255 try stack.append(State{
256 .VarDecl = VarDeclCtx{
257 .comments = ctx.comments,
258 .visib_token = ctx.visib_token,
259 .lib_name = ctx.lib_name,
260 .comptime_token = null,
261 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
262 .mut_token = token_index,
263 .list = ctx.decls,
264 },
265 });
266 continue;
267 },
268 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
269 const fn_proto = try arena.create(ast.Node.FnProto{
270 .base = ast.Node{ .id = ast.Node.Id.FnProto },
271 .doc_comments = ctx.comments,
272 .visib_token = ctx.visib_token,
273 .name_token = null,
274 .fn_token = undefined,
275 .params = ast.Node.FnProto.ParamList.init(arena),
276 .return_type = undefined,
277 .var_args_token = null,
278 .extern_export_inline_token = if (ctx.extern_export_inline_token) |at| at.index else null,
279 .cc_token = null,
280 .async_attr = null,
281 .body_node = null,
282 .lib_name = ctx.lib_name,
283 .align_expr = null,
284 });
285 try ctx.decls.push(&fn_proto.base);
286 stack.append(State{ .FnDef = fn_proto }) catch unreachable;
287 try stack.append(State{ .FnProto = fn_proto });
288
289 switch (token_ptr.id) {
290 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
291 fn_proto.cc_token = token_index;
292 try stack.append(State{
293 .ExpectTokenSave = ExpectTokenSave{
294 .id = Token.Id.Keyword_fn,
295 .ptr = &fn_proto.fn_token,
296 },
297 });
298 continue;
299 },
300 Token.Id.Keyword_async => {
301 const async_node = try arena.create(ast.Node.AsyncAttribute{
302 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
303 .async_token = token_index,
304 .allocator_type = null,
305 .rangle_bracket = null,
306 });
307 fn_proto.async_attr = async_node;
308
309 try stack.append(State{
310 .ExpectTokenSave = ExpectTokenSave{
311 .id = Token.Id.Keyword_fn,
312 .ptr = &fn_proto.fn_token,
313 },
314 });
315 try stack.append(State{ .AsyncAllocator = async_node });
316 continue;
317 },
318 Token.Id.Keyword_fn => {
319 fn_proto.fn_token = token_index;
320 continue;
321 },
322 else => unreachable,
323 }
324 },
325 else => {
326 ((try tree.errors.addOne())).* = Error{ .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn{ .token = token_index } };
327 return tree;
328 },
329 }
330 },
331 State.TopLevelExternOrField => |ctx| {
332 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
333 const node = try arena.create(ast.Node.StructField{
334 .base = ast.Node{ .id = ast.Node.Id.StructField },
335 .doc_comments = ctx.comments,
336 .visib_token = ctx.visib_token,
337 .name_token = identifier,
338 .type_expr = undefined,
339 });
340 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
341 node_ptr.* = &node.base;
342
343 stack.append(State{ .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
344 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.type_expr } });
345 try stack.append(State{ .ExpectToken = Token.Id.Colon });
346 continue;
347 }
348
349 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
350 try stack.append(State{
351 .TopLevelExtern = TopLevelDeclCtx{
352 .decls = &ctx.container_decl.fields_and_decls,
353 .visib_token = ctx.visib_token,
354 .extern_export_inline_token = null,
355 .lib_name = null,
356 .comments = ctx.comments,
357 },
358 });
359 continue;
360 },
361
362 State.FieldInitValue => |ctx| {
363 const eq_tok = nextToken(&tok_it, &tree);
364 const eq_tok_index = eq_tok.index;
365 const eq_tok_ptr = eq_tok.ptr;
366 if (eq_tok_ptr.id != Token.Id.Equal) {
367 prevToken(&tok_it, &tree);
368 continue;
369 }
370 stack.append(State{ .Expression = ctx }) catch unreachable;
371 continue;
372 },
373
374 State.ContainerKind => |ctx| {
375 const token = nextToken(&tok_it, &tree);
376 const token_index = token.index;
377 const token_ptr = token.ptr;
378 const node = try arena.create(ast.Node.ContainerDecl{
379 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
380 .layout_token = ctx.layout_token,
381 .kind_token = switch (token_ptr.id) {
382 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => token_index,
383 else => {
384 ((try tree.errors.addOne())).* = Error{ .ExpectedAggregateKw = Error.ExpectedAggregateKw{ .token = token_index } };
385 return tree;
386 },
387 },
388 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
389 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
390 .lbrace_token = undefined,
391 .rbrace_token = undefined,
392 });
393 ctx.opt_ctx.store(&node.base);
394
395 stack.append(State{ .ContainerDecl = node }) catch unreachable;
396 try stack.append(State{
397 .ExpectTokenSave = ExpectTokenSave{
398 .id = Token.Id.LBrace,
399 .ptr = &node.lbrace_token,
400 },
401 });
402 try stack.append(State{ .ContainerInitArgStart = node });
403 continue;
404 },
405
406 State.ContainerInitArgStart => |container_decl| {
407 if (eatToken(&tok_it, &tree, Token.Id.LParen) == null) {
408 continue;
409 }
410
411 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
412 try stack.append(State{ .ContainerInitArg = container_decl });
413 continue;
414 },
415
416 State.ContainerInitArg => |container_decl| {
417 const init_arg_token = nextToken(&tok_it, &tree);
418 const init_arg_token_index = init_arg_token.index;
419 const init_arg_token_ptr = init_arg_token.ptr;
420 switch (init_arg_token_ptr.id) {
421 Token.Id.Keyword_enum => {
422 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Enum = null };
423 const lparen_tok = nextToken(&tok_it, &tree);
424 const lparen_tok_index = lparen_tok.index;
425 const lparen_tok_ptr = lparen_tok.ptr;
426 if (lparen_tok_ptr.id == Token.Id.LParen) {
427 try stack.append(State{ .ExpectToken = Token.Id.RParen });
428 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } });
429 } else {
430 prevToken(&tok_it, &tree);
431 }
432 },
433 else => {
434 prevToken(&tok_it, &tree);
435 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined };
436 stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
437 },
438 }
439 continue;
440 },
441
442 State.ContainerDecl => |container_decl| {
443 const comments = try eatDocComments(arena, &tok_it, &tree);
444 const token = nextToken(&tok_it, &tree);
445 const token_index = token.index;
446 const token_ptr = token.ptr;
447 switch (token_ptr.id) {
448 Token.Id.Identifier => {
449 switch (tree.tokens.at(container_decl.kind_token).id) {
450 Token.Id.Keyword_struct => {
451 const node = try arena.create(ast.Node.StructField{
452 .base = ast.Node{ .id = ast.Node.Id.StructField },
453 .doc_comments = comments,
454 .visib_token = null,
455 .name_token = token_index,
456 .type_expr = undefined,
457 });
458 const node_ptr = try container_decl.fields_and_decls.addOne();
459 node_ptr.* = &node.base;
460
461 try stack.append(State{ .FieldListCommaOrEnd = container_decl });
462 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.type_expr } });
463 try stack.append(State{ .ExpectToken = Token.Id.Colon });
464 continue;
465 },
466 Token.Id.Keyword_union => {
467 const node = try arena.create(ast.Node.UnionTag{
468 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
469 .name_token = token_index,
470 .type_expr = null,
471 .value_expr = null,
472 .doc_comments = comments,
473 });
474 try container_decl.fields_and_decls.push(&node.base);
475
476 stack.append(State{ .FieldListCommaOrEnd = container_decl }) catch unreachable;
477 try stack.append(State{ .FieldInitValue = OptionalCtx{ .RequiredNull = &node.value_expr } });
478 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &node.type_expr } });
479 try stack.append(State{ .IfToken = Token.Id.Colon });
480 continue;
481 },
482 Token.Id.Keyword_enum => {
483 const node = try arena.create(ast.Node.EnumTag{
484 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
485 .name_token = token_index,
486 .value = null,
487 .doc_comments = comments,
488 });
489 try container_decl.fields_and_decls.push(&node.base);
490
491 stack.append(State{ .FieldListCommaOrEnd = container_decl }) catch unreachable;
492 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &node.value } });
493 try stack.append(State{ .IfToken = Token.Id.Equal });
494 continue;
495 },
496 else => unreachable,
497 }
498 },
499 Token.Id.Keyword_pub => {
500 switch (tree.tokens.at(container_decl.kind_token).id) {
501 Token.Id.Keyword_struct => {
502 try stack.append(State{
503 .TopLevelExternOrField = TopLevelExternOrFieldCtx{
504 .visib_token = token_index,
505 .container_decl = container_decl,
506 .comments = comments,
507 },
508 });
509 continue;
510 },
511 else => {
512 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
513 try stack.append(State{
514 .TopLevelExtern = TopLevelDeclCtx{
515 .decls = &container_decl.fields_and_decls,
516 .visib_token = token_index,
517 .extern_export_inline_token = null,
518 .lib_name = null,
519 .comments = comments,
520 },
521 });
522 continue;
523 },
524 }
525 },
526 Token.Id.Keyword_export => {
527 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
528 try stack.append(State{
529 .TopLevelExtern = TopLevelDeclCtx{
530 .decls = &container_decl.fields_and_decls,
531 .visib_token = token_index,
532 .extern_export_inline_token = null,
533 .lib_name = null,
534 .comments = comments,
535 },
536 });
537 continue;
538 },
539 Token.Id.RBrace => {
540 if (comments != null) {
541 ((try tree.errors.addOne())).* = Error{ .UnattachedDocComment = Error.UnattachedDocComment{ .token = token_index } };
542 return tree;
543 }
544 container_decl.rbrace_token = token_index;
545 continue;
546 },
547 else => {
548 prevToken(&tok_it, &tree);
549 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
550 try stack.append(State{
551 .TopLevelExtern = TopLevelDeclCtx{
552 .decls = &container_decl.fields_and_decls,
553 .visib_token = null,
554 .extern_export_inline_token = null,
555 .lib_name = null,
556 .comments = comments,
557 },
558 });
559 continue;
560 },
561 }
562 },
563
564 State.VarDecl => |ctx| {
565 const var_decl = try arena.create(ast.Node.VarDecl{
566 .base = ast.Node{ .id = ast.Node.Id.VarDecl },
567 .doc_comments = ctx.comments,
568 .visib_token = ctx.visib_token,
569 .mut_token = ctx.mut_token,
570 .comptime_token = ctx.comptime_token,
571 .extern_export_token = ctx.extern_export_token,
572 .type_node = null,
573 .align_node = null,
574 .init_node = null,
575 .lib_name = ctx.lib_name,
576 // initialized later
577 .name_token = undefined,
578 .eq_token = undefined,
579 .semicolon_token = undefined,
580 });
581 try ctx.list.push(&var_decl.base);
582
583 try stack.append(State{ .VarDeclAlign = var_decl });
584 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &var_decl.type_node } });
585 try stack.append(State{ .IfToken = Token.Id.Colon });
586 try stack.append(State{
587 .ExpectTokenSave = ExpectTokenSave{
588 .id = Token.Id.Identifier,
589 .ptr = &var_decl.name_token,
590 },
591 });
592 continue;
593 },
594 State.VarDeclAlign => |var_decl| {
595 try stack.append(State{ .VarDeclEq = var_decl });
596
597 const next_token = nextToken(&tok_it, &tree);
598 const next_token_index = next_token.index;
599 const next_token_ptr = next_token.ptr;
600 if (next_token_ptr.id == Token.Id.Keyword_align) {
601 try stack.append(State{ .ExpectToken = Token.Id.RParen });
602 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.align_node } });
603 try stack.append(State{ .ExpectToken = Token.Id.LParen });
604 continue;
605 }
606
607 prevToken(&tok_it, &tree);
608 continue;
609 },
610 State.VarDeclEq => |var_decl| {
611 const token = nextToken(&tok_it, &tree);
612 const token_index = token.index;
613 const token_ptr = token.ptr;
614 switch (token_ptr.id) {
615 Token.Id.Equal => {
616 var_decl.eq_token = token_index;
617 stack.append(State{ .VarDeclSemiColon = var_decl }) catch unreachable;
618 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.init_node } });
619 continue;
620 },
621 Token.Id.Semicolon => {
622 var_decl.semicolon_token = token_index;
623 continue;
624 },
625 else => {
626 ((try tree.errors.addOne())).* = Error{ .ExpectedEqOrSemi = Error.ExpectedEqOrSemi{ .token = token_index } };
627 return tree;
628 },
629 }
630 },
631
632 State.VarDeclSemiColon => |var_decl| {
633 const semicolon_token = nextToken(&tok_it, &tree);
634
635 if (semicolon_token.ptr.id != Token.Id.Semicolon) {
636 ((try tree.errors.addOne())).* = Error{
637 .ExpectedToken = Error.ExpectedToken{
638 .token = semicolon_token.index,
639 .expected_id = Token.Id.Semicolon,
640 },
641 };
642 return tree;
643 }
644
645 var_decl.semicolon_token = semicolon_token.index;
646
647 if (eatToken(&tok_it, &tree, Token.Id.DocComment)) |doc_comment_token| {
648 const loc = tree.tokenLocation(semicolon_token.ptr.end, doc_comment_token);
649 if (loc.line == 0) {
650 try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments);
651 } else {
652 prevToken(&tok_it, &tree);
653 }
654 }
655 },
656
657 State.FnDef => |fn_proto| {
658 const token = nextToken(&tok_it, &tree);
659 const token_index = token.index;
660 const token_ptr = token.ptr;
661 switch (token_ptr.id) {
662 Token.Id.LBrace => {
663 const block = try arena.create(ast.Node.Block{
664 .base = ast.Node{ .id = ast.Node.Id.Block },
665 .label = null,
666 .lbrace = token_index,
667 .statements = ast.Node.Block.StatementList.init(arena),
668 .rbrace = undefined,
669 });
670 fn_proto.body_node = &block.base;
671 stack.append(State{ .Block = block }) catch unreachable;
672 continue;
673 },
674 Token.Id.Semicolon => continue,
675 else => {
676 ((try tree.errors.addOne())).* = Error{ .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace{ .token = token_index } };
677 return tree;
678 },
679 }
680 },
681 State.FnProto => |fn_proto| {
682 stack.append(State{ .FnProtoAlign = fn_proto }) catch unreachable;
683 try stack.append(State{ .ParamDecl = fn_proto });
684 try stack.append(State{ .ExpectToken = Token.Id.LParen });
685
686 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| {
687 fn_proto.name_token = name_token;
688 }
689 continue;
690 },
691 State.FnProtoAlign => |fn_proto| {
692 stack.append(State{ .FnProtoReturnType = fn_proto }) catch unreachable;
693
694 if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| {
695 try stack.append(State{ .ExpectToken = Token.Id.RParen });
696 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &fn_proto.align_expr } });
697 try stack.append(State{ .ExpectToken = Token.Id.LParen });
698 }
699 continue;
700 },
701 State.FnProtoReturnType => |fn_proto| {
702 const token = nextToken(&tok_it, &tree);
703 const token_index = token.index;
704 const token_ptr = token.ptr;
705 switch (token_ptr.id) {
706 Token.Id.Bang => {
707 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .InferErrorSet = undefined };
708 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.InferErrorSet } }) catch unreachable;
709 continue;
710 },
711 else => {
712 // TODO: this is a special case. Remove this when #760 is fixed
713 if (token_ptr.id == Token.Id.Keyword_error) {
714 if (tok_it.peek().?.id == Token.Id.LBrace) {
715 const error_type_node = try arena.create(ast.Node.ErrorType{
716 .base = ast.Node{ .id = ast.Node.Id.ErrorType },
717 .token = token_index,
718 });
719 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base };
720 continue;
721 }
722 }
723
724 prevToken(&tok_it, &tree);
725 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined };
726 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable;
727 continue;
728 },
729 }
730 },
731
732 State.ParamDecl => |fn_proto| {
733 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
734 continue;
735 }
736 const param_decl = try arena.create(ast.Node.ParamDecl{
737 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },
738 .comptime_token = null,
739 .noalias_token = null,
740 .name_token = null,
741 .type_node = undefined,
742 .var_args_token = null,
743 });
744 try fn_proto.params.push(&param_decl.base);
745
746 stack.append(State{
747 .ParamDeclEnd = ParamDeclEndCtx{
748 .param_decl = param_decl,
749 .fn_proto = fn_proto,
750 },
751 }) catch unreachable;
752 try stack.append(State{ .ParamDeclName = param_decl });
753 try stack.append(State{ .ParamDeclAliasOrComptime = param_decl });
754 continue;
755 },
756 State.ParamDeclAliasOrComptime => |param_decl| {
757 if (eatToken(&tok_it, &tree, Token.Id.Keyword_comptime)) |comptime_token| {
758 param_decl.comptime_token = comptime_token;
759 } else if (eatToken(&tok_it, &tree, Token.Id.Keyword_noalias)) |noalias_token| {
760 param_decl.noalias_token = noalias_token;
761 }
762 continue;
763 },
764 State.ParamDeclName => |param_decl| {
765 // TODO: Here, we eat two tokens in one state. This means that we can't have
766 // comments between these two tokens.
767 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
768 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
769 param_decl.name_token = ident_token;
770 } else {
771 prevToken(&tok_it, &tree);
772 }
773 }
774 continue;
775 },
776 State.ParamDeclEnd => |ctx| {
777 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
778 ctx.param_decl.var_args_token = ellipsis3;
779 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
780 continue;
781 }
782
783 try stack.append(State{ .ParamDeclComma = ctx.fn_proto });
784 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &ctx.param_decl.type_node } });
785 continue;
786 },
787 State.ParamDeclComma => |fn_proto| {
788 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
789 ExpectCommaOrEndResult.end_token => |t| {
790 if (t == null) {
791 stack.append(State{ .ParamDecl = fn_proto }) catch unreachable;
792 }
793 continue;
794 },
795 ExpectCommaOrEndResult.parse_error => |e| {
796 try tree.errors.push(e);
797 return tree;
798 },
799 }
800 },
801
802 State.MaybeLabeledExpression => |ctx| {
803 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
804 stack.append(State{
805 .LabeledExpression = LabelCtx{
806 .label = ctx.label,
807 .opt_ctx = ctx.opt_ctx,
808 },
809 }) catch unreachable;
810 continue;
811 }
812
813 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
814 continue;
815 },
816 State.LabeledExpression => |ctx| {
817 const token = nextToken(&tok_it, &tree);
818 const token_index = token.index;
819 const token_ptr = token.ptr;
820 switch (token_ptr.id) {
821 Token.Id.LBrace => {
822 const block = try arena.create(ast.Node.Block{
823 .base = ast.Node{ .id = ast.Node.Id.Block },
824 .label = ctx.label,
825 .lbrace = token_index,
826 .statements = ast.Node.Block.StatementList.init(arena),
827 .rbrace = undefined,
828 });
829 ctx.opt_ctx.store(&block.base);
830 stack.append(State{ .Block = block }) catch unreachable;
831 continue;
832 },
833 Token.Id.Keyword_while => {
834 stack.append(State{
835 .While = LoopCtx{
836 .label = ctx.label,
837 .inline_token = null,
838 .loop_token = token_index,
839 .opt_ctx = ctx.opt_ctx.toRequired(),
840 },
841 }) catch unreachable;
842 continue;
843 },
844 Token.Id.Keyword_for => {
845 stack.append(State{
846 .For = LoopCtx{
847 .label = ctx.label,
848 .inline_token = null,
849 .loop_token = token_index,
850 .opt_ctx = ctx.opt_ctx.toRequired(),
851 },
852 }) catch unreachable;
853 continue;
854 },
855 Token.Id.Keyword_inline => {
856 stack.append(State{
857 .Inline = InlineCtx{
858 .label = ctx.label,
859 .inline_token = token_index,
860 .opt_ctx = ctx.opt_ctx.toRequired(),
861 },
862 }) catch unreachable;
863 continue;
864 },
865 else => {
866 if (ctx.opt_ctx != OptionalCtx.Optional) {
867 ((try tree.errors.addOne())).* = Error{ .ExpectedLabelable = Error.ExpectedLabelable{ .token = token_index } };
868 return tree;
869 }
870
871 prevToken(&tok_it, &tree);
872 continue;
873 },
874 }
875 },
876 State.Inline => |ctx| {
877 const token = nextToken(&tok_it, &tree);
878 const token_index = token.index;
879 const token_ptr = token.ptr;
880 switch (token_ptr.id) {
881 Token.Id.Keyword_while => {
882 stack.append(State{
883 .While = LoopCtx{
884 .inline_token = ctx.inline_token,
885 .label = ctx.label,
886 .loop_token = token_index,
887 .opt_ctx = ctx.opt_ctx.toRequired(),
888 },
889 }) catch unreachable;
890 continue;
891 },
892 Token.Id.Keyword_for => {
893 stack.append(State{
894 .For = LoopCtx{
895 .inline_token = ctx.inline_token,
896 .label = ctx.label,
897 .loop_token = token_index,
898 .opt_ctx = ctx.opt_ctx.toRequired(),
899 },
900 }) catch unreachable;
901 continue;
902 },
903 else => {
904 if (ctx.opt_ctx != OptionalCtx.Optional) {
905 ((try tree.errors.addOne())).* = Error{ .ExpectedInlinable = Error.ExpectedInlinable{ .token = token_index } };
906 return tree;
907 }
908
909 prevToken(&tok_it, &tree);
910 continue;
911 },
912 }
913 },
914 State.While => |ctx| {
915 const node = try arena.create(ast.Node.While{
916 .base = ast.Node{ .id = ast.Node.Id.While },
917 .label = ctx.label,
918 .inline_token = ctx.inline_token,
919 .while_token = ctx.loop_token,
920 .condition = undefined,
921 .payload = null,
922 .continue_expr = null,
923 .body = undefined,
924 .@"else" = null,
925 });
926 ctx.opt_ctx.store(&node.base);
927 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
928 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
929 try stack.append(State{ .WhileContinueExpr = &node.continue_expr });
930 try stack.append(State{ .IfToken = Token.Id.Colon });
931 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
932 try stack.append(State{ .ExpectToken = Token.Id.RParen });
933 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.condition } });
934 try stack.append(State{ .ExpectToken = Token.Id.LParen });
935 continue;
936 },
937 State.WhileContinueExpr => |dest| {
938 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
939 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = dest } });
940 try stack.append(State{ .ExpectToken = Token.Id.LParen });
941 continue;
942 },
943 State.For => |ctx| {
944 const node = try arena.create(ast.Node.For{
945 .base = ast.Node{ .id = ast.Node.Id.For },
946 .label = ctx.label,
947 .inline_token = ctx.inline_token,
948 .for_token = ctx.loop_token,
949 .array_expr = undefined,
950 .payload = null,
951 .body = undefined,
952 .@"else" = null,
953 });
954 ctx.opt_ctx.store(&node.base);
955 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
956 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
957 try stack.append(State{ .PointerIndexPayload = OptionalCtx{ .Optional = &node.payload } });
958 try stack.append(State{ .ExpectToken = Token.Id.RParen });
959 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.array_expr } });
960 try stack.append(State{ .ExpectToken = Token.Id.LParen });
961 continue;
962 },
963 State.Else => |dest| {
964 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
965 const node = try arena.create(ast.Node.Else{
966 .base = ast.Node{ .id = ast.Node.Id.Else },
967 .else_token = else_token,
968 .payload = null,
969 .body = undefined,
970 });
971 dest.* = node;
972
973 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }) catch unreachable;
974 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
975 continue;
976 } else {
977 continue;
978 }
979 },
980
981 State.Block => |block| {
982 const token = nextToken(&tok_it, &tree);
983 const token_index = token.index;
984 const token_ptr = token.ptr;
985 switch (token_ptr.id) {
986 Token.Id.RBrace => {
987 block.rbrace = token_index;
988 continue;
989 },
990 else => {
991 prevToken(&tok_it, &tree);
992 stack.append(State{ .Block = block }) catch unreachable;
993
994 try stack.append(State{ .Statement = block });
995 continue;
996 },
997 }
998 },
999 State.Statement => |block| {
1000 const token = nextToken(&tok_it, &tree);
1001 const token_index = token.index;
1002 const token_ptr = token.ptr;
1003 switch (token_ptr.id) {
1004 Token.Id.Keyword_comptime => {
1005 stack.append(State{
1006 .ComptimeStatement = ComptimeStatementCtx{
1007 .comptime_token = token_index,
1008 .block = block,
1009 },
1010 }) catch unreachable;
1011 continue;
1012 },
1013 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1014 stack.append(State{
1015 .VarDecl = VarDeclCtx{
1016 .comments = null,
1017 .visib_token = null,
1018 .comptime_token = null,
1019 .extern_export_token = null,
1020 .lib_name = null,
1021 .mut_token = token_index,
1022 .list = &block.statements,
1023 },
1024 }) catch unreachable;
1025 continue;
1026 },
1027 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1028 const node = try arena.create(ast.Node.Defer{
1029 .base = ast.Node{ .id = ast.Node.Id.Defer },
1030 .defer_token = token_index,
1031 .expr = undefined,
1032 });
1033 const node_ptr = try block.statements.addOne();
1034 node_ptr.* = &node.base;
1035
1036 stack.append(State{ .Semicolon = node_ptr }) catch unreachable;
1037 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1038 continue;
1039 },
1040 Token.Id.LBrace => {
1041 const inner_block = try arena.create(ast.Node.Block{
1042 .base = ast.Node{ .id = ast.Node.Id.Block },
1043 .label = null,
1044 .lbrace = token_index,
1045 .statements = ast.Node.Block.StatementList.init(arena),
1046 .rbrace = undefined,
1047 });
1048 try block.statements.push(&inner_block.base);
1049
1050 stack.append(State{ .Block = inner_block }) catch unreachable;
1051 continue;
1052 },
1053 else => {
1054 prevToken(&tok_it, &tree);
1055 const statement = try block.statements.addOne();
1056 try stack.append(State{ .Semicolon = statement });
1057 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1058 continue;
1059 },
1060 }
1061 },
1062 State.ComptimeStatement => |ctx| {
1063 const token = nextToken(&tok_it, &tree);
1064 const token_index = token.index;
1065 const token_ptr = token.ptr;
1066 switch (token_ptr.id) {
1067 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1068 stack.append(State{
1069 .VarDecl = VarDeclCtx{
1070 .comments = null,
1071 .visib_token = null,
1072 .comptime_token = ctx.comptime_token,
1073 .extern_export_token = null,
1074 .lib_name = null,
1075 .mut_token = token_index,
1076 .list = &ctx.block.statements,
1077 },
1078 }) catch unreachable;
1079 continue;
1080 },
1081 else => {
1082 prevToken(&tok_it, &tree);
1083 prevToken(&tok_it, &tree);
1084 const statement = try ctx.block.statements.addOne();
1085 try stack.append(State{ .Semicolon = statement });
1086 try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } });
1087 continue;
1088 },
1089 }
1090 },
1091 State.Semicolon => |node_ptr| {
1092 const node = node_ptr.*;
1093 if (node.requireSemiColon()) {
1094 stack.append(State{ .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1095 continue;
1096 }
1097 continue;
1098 },
1099
1100 State.AsmOutputItems => |items| {
1101 const lbracket = nextToken(&tok_it, &tree);
1102 const lbracket_index = lbracket.index;
1103 const lbracket_ptr = lbracket.ptr;
1104 if (lbracket_ptr.id != Token.Id.LBracket) {
1105 prevToken(&tok_it, &tree);
1106 continue;
1107 }
1108
1109 const node = try arena.create(ast.Node.AsmOutput{
1110 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
1111 .lbracket = lbracket_index,
1112 .symbolic_name = undefined,
1113 .constraint = undefined,
1114 .kind = undefined,
1115 .rparen = undefined,
1116 });
1117 try items.push(node);
1118
1119 stack.append(State{ .AsmOutputItems = items }) catch unreachable;
1120 try stack.append(State{ .IfToken = Token.Id.Comma });
1121 try stack.append(State{
1122 .ExpectTokenSave = ExpectTokenSave{
1123 .id = Token.Id.RParen,
1124 .ptr = &node.rparen,
1125 },
1126 });
1127 try stack.append(State{ .AsmOutputReturnOrType = node });
1128 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1129 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
1130 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1131 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.symbolic_name } });
1132 continue;
1133 },
1134 State.AsmOutputReturnOrType => |node| {
1135 const token = nextToken(&tok_it, &tree);
1136 const token_index = token.index;
1137 const token_ptr = token.ptr;
1138 switch (token_ptr.id) {
1139 Token.Id.Identifier => {
1140 node.kind = ast.Node.AsmOutput.Kind{ .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1141 continue;
1142 },
1143 Token.Id.Arrow => {
1144 node.kind = ast.Node.AsmOutput.Kind{ .Return = undefined };
1145 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.kind.Return } });
1146 continue;
1147 },
1148 else => {
1149 ((try tree.errors.addOne())).* = Error{ .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType{ .token = token_index } };
1150 return tree;
1151 },
1152 }
1153 },
1154 State.AsmInputItems => |items| {
1155 const lbracket = nextToken(&tok_it, &tree);
1156 const lbracket_index = lbracket.index;
1157 const lbracket_ptr = lbracket.ptr;
1158 if (lbracket_ptr.id != Token.Id.LBracket) {
1159 prevToken(&tok_it, &tree);
1160 continue;
1161 }
1162
1163 const node = try arena.create(ast.Node.AsmInput{
1164 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
1165 .lbracket = lbracket_index,
1166 .symbolic_name = undefined,
1167 .constraint = undefined,
1168 .expr = undefined,
1169 .rparen = undefined,
1170 });
1171 try items.push(node);
1172
1173 stack.append(State{ .AsmInputItems = items }) catch unreachable;
1174 try stack.append(State{ .IfToken = Token.Id.Comma });
1175 try stack.append(State{
1176 .ExpectTokenSave = ExpectTokenSave{
1177 .id = Token.Id.RParen,
1178 .ptr = &node.rparen,
1179 },
1180 });
1181 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1182 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1183 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
1184 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1185 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.symbolic_name } });
1186 continue;
1187 },
1188 State.AsmClobberItems => |items| {
1189 while (eatToken(&tok_it, &tree, Token.Id.StringLiteral)) |strlit| {
1190 try items.push(strlit);
1191 if (eatToken(&tok_it, &tree, Token.Id.Comma) == null)
1192 break;
1193 }
1194 continue;
1195 },
1196
1197 State.ExprListItemOrEnd => |list_state| {
1198 if (eatToken(&tok_it, &tree, list_state.end)) |token_index| {
1199 (list_state.ptr).* = token_index;
1200 continue;
1201 }
1202
1203 stack.append(State{ .ExprListCommaOrEnd = list_state }) catch unreachable;
1204 try stack.append(State{ .Expression = OptionalCtx{ .Required = try list_state.list.addOne() } });
1205 continue;
1206 },
1207 State.ExprListCommaOrEnd => |list_state| {
1208 switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) {
1209 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1210 (list_state.ptr).* = end;
1211 continue;
1212 } else {
1213 stack.append(State{ .ExprListItemOrEnd = list_state }) catch unreachable;
1214 continue;
1215 },
1216 ExpectCommaOrEndResult.parse_error => |e| {
1217 try tree.errors.push(e);
1218 return tree;
1219 },
1220 }
1221 },
1222 State.FieldInitListItemOrEnd => |list_state| {
1223 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1224 (list_state.ptr).* = rbrace;
1225 continue;
1226 }
1227
1228 const node = try arena.create(ast.Node.FieldInitializer{
1229 .base = ast.Node{ .id = ast.Node.Id.FieldInitializer },
1230 .period_token = undefined,
1231 .name_token = undefined,
1232 .expr = undefined,
1233 });
1234 try list_state.list.push(&node.base);
1235
1236 stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1237 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1238 try stack.append(State{ .ExpectToken = Token.Id.Equal });
1239 try stack.append(State{
1240 .ExpectTokenSave = ExpectTokenSave{
1241 .id = Token.Id.Identifier,
1242 .ptr = &node.name_token,
1243 },
1244 });
1245 try stack.append(State{
1246 .ExpectTokenSave = ExpectTokenSave{
1247 .id = Token.Id.Period,
1248 .ptr = &node.period_token,
1249 },
1250 });
1251 continue;
1252 },
1253 State.FieldInitListCommaOrEnd => |list_state| {
1254 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1255 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1256 (list_state.ptr).* = end;
1257 continue;
1258 } else {
1259 stack.append(State{ .FieldInitListItemOrEnd = list_state }) catch unreachable;
1260 continue;
1261 },
1262 ExpectCommaOrEndResult.parse_error => |e| {
1263 try tree.errors.push(e);
1264 return tree;
1265 },
1266 }
1267 },
1268 State.FieldListCommaOrEnd => |container_decl| {
1269 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1270 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1271 container_decl.rbrace_token = end;
1272 continue;
1273 } else {
1274 try stack.append(State{ .ContainerDecl = container_decl });
1275 continue;
1276 },
1277 ExpectCommaOrEndResult.parse_error => |e| {
1278 try tree.errors.push(e);
1279 return tree;
1280 },
1281 }
1282 },
1283 State.ErrorTagListItemOrEnd => |list_state| {
1284 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1285 (list_state.ptr).* = rbrace;
1286 continue;
1287 }
1288
1289 const node_ptr = try list_state.list.addOne();
1290
1291 try stack.append(State{ .ErrorTagListCommaOrEnd = list_state });
1292 try stack.append(State{ .ErrorTag = node_ptr });
1293 continue;
1294 },
1295 State.ErrorTagListCommaOrEnd => |list_state| {
1296 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1297 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1298 (list_state.ptr).* = end;
1299 continue;
1300 } else {
1301 stack.append(State{ .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1302 continue;
1303 },
1304 ExpectCommaOrEndResult.parse_error => |e| {
1305 try tree.errors.push(e);
1306 return tree;
1307 },
1308 }
1309 },
1310 State.SwitchCaseOrEnd => |list_state| {
1311 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1312 (list_state.ptr).* = rbrace;
1313 continue;
1314 }
1315
1316 const comments = try eatDocComments(arena, &tok_it, &tree);
1317 const node = try arena.create(ast.Node.SwitchCase{
1318 .base = ast.Node{ .id = ast.Node.Id.SwitchCase },
1319 .items = ast.Node.SwitchCase.ItemList.init(arena),
1320 .payload = null,
1321 .expr = undefined,
1322 .arrow_token = undefined,
1323 });
1324 try list_state.list.push(&node.base);
1325 try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });
1326 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1327 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
1328 try stack.append(State{ .SwitchCaseFirstItem = node });
1329
1330 continue;
1331 },
1332
1333 State.SwitchCaseCommaOrEnd => |list_state| {
1334 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1335 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1336 (list_state.ptr).* = end;
1337 continue;
1338 } else {
1339 try stack.append(State{ .SwitchCaseOrEnd = list_state });
1340 continue;
1341 },
1342 ExpectCommaOrEndResult.parse_error => |e| {
1343 try tree.errors.push(e);
1344 return tree;
1345 },
1346 }
1347 },
1348
1349 State.SwitchCaseFirstItem => |switch_case| {
1350 const token = nextToken(&tok_it, &tree);
1351 const token_index = token.index;
1352 const token_ptr = token.ptr;
1353 if (token_ptr.id == Token.Id.Keyword_else) {
1354 const else_node = try arena.create(ast.Node.SwitchElse{
1355 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
1356 .token = token_index,
1357 });
1358 try switch_case.items.push(&else_node.base);
1359
1360 try stack.append(State{
1361 .ExpectTokenSave = ExpectTokenSave{
1362 .id = Token.Id.EqualAngleBracketRight,
1363 .ptr = &switch_case.arrow_token,
1364 },
1365 });
1366 continue;
1367 } else {
1368 prevToken(&tok_it, &tree);
1369 stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable;
1370 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } });
1371 continue;
1372 }
1373 },
1374 State.SwitchCaseItemOrEnd => |switch_case| {
1375 const token = nextToken(&tok_it, &tree);
1376 if (token.ptr.id == Token.Id.EqualAngleBracketRight) {
1377 switch_case.arrow_token = token.index;
1378 continue;
1379 } else {
1380 prevToken(&tok_it, &tree);
1381 stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable;
1382 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } });
1383 continue;
1384 }
1385 },
1386 State.SwitchCaseItemCommaOrEnd => |switch_case| {
1387 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1388 ExpectCommaOrEndResult.end_token => |end_token| {
1389 if (end_token) |t| {
1390 switch_case.arrow_token = t;
1391 } else {
1392 stack.append(State{ .SwitchCaseItemOrEnd = switch_case }) catch unreachable;
1393 }
1394 continue;
1395 },
1396 ExpectCommaOrEndResult.parse_error => |e| {
1397 try tree.errors.push(e);
1398 return tree;
1399 },
1400 }
1401 continue;
1402 },
1403
1404 State.SuspendBody => |suspend_node| {
1405 const token = nextToken(&tok_it, &tree);
1406 switch (token.ptr.id) {
1407 Token.Id.Semicolon => {
1408 prevToken(&tok_it, &tree);
1409 continue;
1410 },
1411 Token.Id.LBrace => {
1412 prevToken(&tok_it, &tree);
1413 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
1414 continue;
1415 },
1416 else => {
1417 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = token.index } };
1418 },
1419 }
1420 },
1421 State.AsyncAllocator => |async_node| {
1422 if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
1423 continue;
1424 }
1425
1426 async_node.rangle_bracket = TokenIndex(0);
1427 try stack.append(State{
1428 .ExpectTokenSave = ExpectTokenSave{
1429 .id = Token.Id.AngleBracketRight,
1430 .ptr = &async_node.rangle_bracket.?,
1431 },
1432 });
1433 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } });
1434 continue;
1435 },
1436 State.AsyncEnd => |ctx| {
1437 const node = ctx.ctx.get() orelse continue;
1438
1439 switch (node.id) {
1440 ast.Node.Id.FnProto => {
1441 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1442 fn_proto.async_attr = ctx.attribute;
1443 continue;
1444 },
1445 ast.Node.Id.SuffixOp => {
1446 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1447 if (suffix_op.op == @TagType(ast.Node.SuffixOp.Op).Call) {
1448 suffix_op.op.Call.async_attr = ctx.attribute;
1449 continue;
1450 }
1451
1452 ((try tree.errors.addOne())).* = Error{ .ExpectedCall = Error.ExpectedCall{ .node = node } };
1453 return tree;
1454 },
1455 else => {
1456 ((try tree.errors.addOne())).* = Error{ .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto{ .node = node } };
1457 return tree;
1458 },
1459 }
1460 },
1461
1462 State.ExternType => |ctx| {
1463 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
1464 const fn_proto = try arena.create(ast.Node.FnProto{
1465 .base = ast.Node{ .id = ast.Node.Id.FnProto },
1466 .doc_comments = ctx.comments,
1467 .visib_token = null,
1468 .name_token = null,
1469 .fn_token = fn_token,
1470 .params = ast.Node.FnProto.ParamList.init(arena),
1471 .return_type = undefined,
1472 .var_args_token = null,
1473 .extern_export_inline_token = ctx.extern_token,
1474 .cc_token = null,
1475 .async_attr = null,
1476 .body_node = null,
1477 .lib_name = null,
1478 .align_expr = null,
1479 });
1480 ctx.opt_ctx.store(&fn_proto.base);
1481 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
1482 continue;
1483 }
1484
1485 stack.append(State{
1486 .ContainerKind = ContainerKindCtx{
1487 .opt_ctx = ctx.opt_ctx,
1488 .layout_token = ctx.extern_token,
1489 },
1490 }) catch unreachable;
1491 continue;
1492 },
1493 State.SliceOrArrayAccess => |node| {
1494 const token = nextToken(&tok_it, &tree);
1495 const token_index = token.index;
1496 const token_ptr = token.ptr;
1497 switch (token_ptr.id) {
1498 Token.Id.Ellipsis2 => {
1499 const start = node.op.ArrayAccess;
1500 node.op = ast.Node.SuffixOp.Op{
1501 .Slice = ast.Node.SuffixOp.Op.Slice{
1502 .start = start,
1503 .end = null,
1504 },
1505 };
1506
1507 stack.append(State{
1508 .ExpectTokenSave = ExpectTokenSave{
1509 .id = Token.Id.RBracket,
1510 .ptr = &node.rtoken,
1511 },
1512 }) catch unreachable;
1513 try stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.op.Slice.end } });
1514 continue;
1515 },
1516 Token.Id.RBracket => {
1517 node.rtoken = token_index;
1518 continue;
1519 },
1520 else => {
1521 ((try tree.errors.addOne())).* = Error{ .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket{ .token = token_index } };
1522 return tree;
1523 },
1524 }
1525 },
1526 State.SliceOrArrayType => |node| {
1527 if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| {
1528 node.op = ast.Node.PrefixOp.Op{
1529 .SliceType = ast.Node.PrefixOp.PtrInfo{
1530 .align_info = null,
1531 .const_token = null,
1532 .volatile_token = null,
1533 },
1534 };
1535 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1536 try stack.append(State{ .PtrTypeModifiers = &node.op.SliceType });
1537 continue;
1538 }
1539
1540 node.op = ast.Node.PrefixOp.Op{ .ArrayType = undefined };
1541 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1542 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1543 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.op.ArrayType } });
1544 continue;
1545 },
1546
1547 State.PtrTypeModifiers => |addr_of_info| {
1548 const token = nextToken(&tok_it, &tree);
1549 const token_index = token.index;
1550 const token_ptr = token.ptr;
1551 switch (token_ptr.id) {
1552 Token.Id.Keyword_align => {
1553 stack.append(state) catch unreachable;
1554 if (addr_of_info.align_info != null) {
1555 ((try tree.errors.addOne())).* = Error{ .ExtraAlignQualifier = Error.ExtraAlignQualifier{ .token = token_index } };
1556 return tree;
1557 }
1558 addr_of_info.align_info = ast.Node.PrefixOp.PtrInfo.Align{
1559 .node = undefined,
1560 .bit_range = null,
1561 };
1562 // TODO https://github.com/ziglang/zig/issues/1022
1563 const align_info = &addr_of_info.align_info.?;
1564
1565 try stack.append(State{ .AlignBitRange = align_info });
1566 try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } });
1567 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1568 continue;
1569 },
1570 Token.Id.Keyword_const => {
1571 stack.append(state) catch unreachable;
1572 if (addr_of_info.const_token != null) {
1573 ((try tree.errors.addOne())).* = Error{ .ExtraConstQualifier = Error.ExtraConstQualifier{ .token = token_index } };
1574 return tree;
1575 }
1576 addr_of_info.const_token = token_index;
1577 continue;
1578 },
1579 Token.Id.Keyword_volatile => {
1580 stack.append(state) catch unreachable;
1581 if (addr_of_info.volatile_token != null) {
1582 ((try tree.errors.addOne())).* = Error{ .ExtraVolatileQualifier = Error.ExtraVolatileQualifier{ .token = token_index } };
1583 return tree;
1584 }
1585 addr_of_info.volatile_token = token_index;
1586 continue;
1587 },
1588 else => {
1589 prevToken(&tok_it, &tree);
1590 continue;
1591 },
1592 }
1593 },
1594
1595 State.AlignBitRange => |align_info| {
1596 const token = nextToken(&tok_it, &tree);
1597 switch (token.ptr.id) {
1598 Token.Id.Colon => {
1599 align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined);
1600 const bit_range = &align_info.bit_range.?;
1601
1602 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1603 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } });
1604 try stack.append(State{ .ExpectToken = Token.Id.Colon });
1605 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.start } });
1606 continue;
1607 },
1608 Token.Id.RParen => continue,
1609 else => {
1610 (try tree.errors.addOne()).* = Error{
1611 .ExpectedColonOrRParen = Error.ExpectedColonOrRParen{ .token = token.index },
1612 };
1613 return tree;
1614 },
1615 }
1616 },
1617
1618 State.Payload => |opt_ctx| {
1619 const token = nextToken(&tok_it, &tree);
1620 const token_index = token.index;
1621 const token_ptr = token.ptr;
1622 if (token_ptr.id != Token.Id.Pipe) {
1623 if (opt_ctx != OptionalCtx.Optional) {
1624 ((try tree.errors.addOne())).* = Error{
1625 .ExpectedToken = Error.ExpectedToken{
1626 .token = token_index,
1627 .expected_id = Token.Id.Pipe,
1628 },
1629 };
1630 return tree;
1631 }
1632
1633 prevToken(&tok_it, &tree);
1634 continue;
1635 }
1636
1637 const node = try arena.create(ast.Node.Payload{
1638 .base = ast.Node{ .id = ast.Node.Id.Payload },
1639 .lpipe = token_index,
1640 .error_symbol = undefined,
1641 .rpipe = undefined,
1642 });
1643 opt_ctx.store(&node.base);
1644
1645 stack.append(State{
1646 .ExpectTokenSave = ExpectTokenSave{
1647 .id = Token.Id.Pipe,
1648 .ptr = &node.rpipe,
1649 },
1650 }) catch unreachable;
1651 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.error_symbol } });
1652 continue;
1653 },
1654 State.PointerPayload => |opt_ctx| {
1655 const token = nextToken(&tok_it, &tree);
1656 const token_index = token.index;
1657 const token_ptr = token.ptr;
1658 if (token_ptr.id != Token.Id.Pipe) {
1659 if (opt_ctx != OptionalCtx.Optional) {
1660 ((try tree.errors.addOne())).* = Error{
1661 .ExpectedToken = Error.ExpectedToken{
1662 .token = token_index,
1663 .expected_id = Token.Id.Pipe,
1664 },
1665 };
1666 return tree;
1667 }
1668
1669 prevToken(&tok_it, &tree);
1670 continue;
1671 }
1672
1673 const node = try arena.create(ast.Node.PointerPayload{
1674 .base = ast.Node{ .id = ast.Node.Id.PointerPayload },
1675 .lpipe = token_index,
1676 .ptr_token = null,
1677 .value_symbol = undefined,
1678 .rpipe = undefined,
1679 });
1680 opt_ctx.store(&node.base);
1681
1682 try stack.append(State{
1683 .ExpectTokenSave = ExpectTokenSave{
1684 .id = Token.Id.Pipe,
1685 .ptr = &node.rpipe,
1686 },
1687 });
1688 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.value_symbol } });
1689 try stack.append(State{
1690 .OptionalTokenSave = OptionalTokenSave{
1691 .id = Token.Id.Asterisk,
1692 .ptr = &node.ptr_token,
1693 },
1694 });
1695 continue;
1696 },
1697 State.PointerIndexPayload => |opt_ctx| {
1698 const token = nextToken(&tok_it, &tree);
1699 const token_index = token.index;
1700 const token_ptr = token.ptr;
1701 if (token_ptr.id != Token.Id.Pipe) {
1702 if (opt_ctx != OptionalCtx.Optional) {
1703 ((try tree.errors.addOne())).* = Error{
1704 .ExpectedToken = Error.ExpectedToken{
1705 .token = token_index,
1706 .expected_id = Token.Id.Pipe,
1707 },
1708 };
1709 return tree;
1710 }
1711
1712 prevToken(&tok_it, &tree);
1713 continue;
1714 }
1715
1716 const node = try arena.create(ast.Node.PointerIndexPayload{
1717 .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },
1718 .lpipe = token_index,
1719 .ptr_token = null,
1720 .value_symbol = undefined,
1721 .index_symbol = null,
1722 .rpipe = undefined,
1723 });
1724 opt_ctx.store(&node.base);
1725
1726 stack.append(State{
1727 .ExpectTokenSave = ExpectTokenSave{
1728 .id = Token.Id.Pipe,
1729 .ptr = &node.rpipe,
1730 },
1731 }) catch unreachable;
1732 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.index_symbol } });
1733 try stack.append(State{ .IfToken = Token.Id.Comma });
1734 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.value_symbol } });
1735 try stack.append(State{
1736 .OptionalTokenSave = OptionalTokenSave{
1737 .id = Token.Id.Asterisk,
1738 .ptr = &node.ptr_token,
1739 },
1740 });
1741 continue;
1742 },
1743
1744 State.Expression => |opt_ctx| {
1745 const token = nextToken(&tok_it, &tree);
1746 const token_index = token.index;
1747 const token_ptr = token.ptr;
1748 switch (token_ptr.id) {
1749 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1750 const node = try arena.create(ast.Node.ControlFlowExpression{
1751 .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },
1752 .ltoken = token_index,
1753 .kind = undefined,
1754 .rhs = null,
1755 });
1756 opt_ctx.store(&node.base);
1757
1758 stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.rhs } }) catch unreachable;
1759
1760 switch (token_ptr.id) {
1761 Token.Id.Keyword_break => {
1762 node.kind = ast.Node.ControlFlowExpression.Kind{ .Break = null };
1763 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.kind.Break } });
1764 try stack.append(State{ .IfToken = Token.Id.Colon });
1765 },
1766 Token.Id.Keyword_continue => {
1767 node.kind = ast.Node.ControlFlowExpression.Kind{ .Continue = null };
1768 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.kind.Continue } });
1769 try stack.append(State{ .IfToken = Token.Id.Colon });
1770 },
1771 Token.Id.Keyword_return => {
1772 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1773 },
1774 else => unreachable,
1775 }
1776 continue;
1777 },
1778 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1779 const node = try arena.create(ast.Node.PrefixOp{
1780 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
1781 .op_token = token_index,
1782 .op = switch (token_ptr.id) {
1783 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
1784 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op{ .Cancel = void{} },
1785 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op{ .Resume = void{} },
1786 else => unreachable,
1787 },
1788 .rhs = undefined,
1789 });
1790 opt_ctx.store(&node.base);
1791
1792 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1793 continue;
1794 },
1795 else => {
1796 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1797 prevToken(&tok_it, &tree);
1798 stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1799 }
1800 continue;
1801 },
1802 }
1803 },
1804 State.RangeExpressionBegin => |opt_ctx| {
1805 stack.append(State{ .RangeExpressionEnd = opt_ctx }) catch unreachable;
1806 try stack.append(State{ .Expression = opt_ctx });
1807 continue;
1808 },
1809 State.RangeExpressionEnd => |opt_ctx| {
1810 const lhs = opt_ctx.get() orelse continue;
1811
1812 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
1813 const node = try arena.create(ast.Node.InfixOp{
1814 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1815 .lhs = lhs,
1816 .op_token = ellipsis3,
1817 .op = ast.Node.InfixOp.Op.Range,
1818 .rhs = undefined,
1819 });
1820 opt_ctx.store(&node.base);
1821 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1822 continue;
1823 }
1824 },
1825 State.AssignmentExpressionBegin => |opt_ctx| {
1826 stack.append(State{ .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1827 try stack.append(State{ .Expression = opt_ctx });
1828 continue;
1829 },
1830
1831 State.AssignmentExpressionEnd => |opt_ctx| {
1832 const lhs = opt_ctx.get() orelse continue;
1833
1834 const token = nextToken(&tok_it, &tree);
1835 const token_index = token.index;
1836 const token_ptr = token.ptr;
1837 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1838 const node = try arena.create(ast.Node.InfixOp{
1839 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1840 .lhs = lhs,
1841 .op_token = token_index,
1842 .op = ass_id,
1843 .rhs = undefined,
1844 });
1845 opt_ctx.store(&node.base);
1846 stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1847 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
1848 continue;
1849 } else {
1850 prevToken(&tok_it, &tree);
1851 continue;
1852 }
1853 },
1854
1855 State.UnwrapExpressionBegin => |opt_ctx| {
1856 stack.append(State{ .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1857 try stack.append(State{ .BoolOrExpressionBegin = opt_ctx });
1858 continue;
1859 },
1860
1861 State.UnwrapExpressionEnd => |opt_ctx| {
1862 const lhs = opt_ctx.get() orelse continue;
1863
1864 const token = nextToken(&tok_it, &tree);
1865 const token_index = token.index;
1866 const token_ptr = token.ptr;
1867 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1868 const node = try arena.create(ast.Node.InfixOp{
1869 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1870 .lhs = lhs,
1871 .op_token = token_index,
1872 .op = unwrap_id,
1873 .rhs = undefined,
1874 });
1875 opt_ctx.store(&node.base);
1876
1877 stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1878 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
1879
1880 if (node.op == ast.Node.InfixOp.Op.Catch) {
1881 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.op.Catch } });
1882 }
1883 continue;
1884 } else {
1885 prevToken(&tok_it, &tree);
1886 continue;
1887 }
1888 },
1889
1890 State.BoolOrExpressionBegin => |opt_ctx| {
1891 stack.append(State{ .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1892 try stack.append(State{ .BoolAndExpressionBegin = opt_ctx });
1893 continue;
1894 },
1895
1896 State.BoolOrExpressionEnd => |opt_ctx| {
1897 const lhs = opt_ctx.get() orelse continue;
1898
1899 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
1900 const node = try arena.create(ast.Node.InfixOp{
1901 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1902 .lhs = lhs,
1903 .op_token = or_token,
1904 .op = ast.Node.InfixOp.Op.BoolOr,
1905 .rhs = undefined,
1906 });
1907 opt_ctx.store(&node.base);
1908 stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1909 try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1910 continue;
1911 }
1912 },
1913
1914 State.BoolAndExpressionBegin => |opt_ctx| {
1915 stack.append(State{ .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1916 try stack.append(State{ .ComparisonExpressionBegin = opt_ctx });
1917 continue;
1918 },
1919
1920 State.BoolAndExpressionEnd => |opt_ctx| {
1921 const lhs = opt_ctx.get() orelse continue;
1922
1923 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
1924 const node = try arena.create(ast.Node.InfixOp{
1925 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1926 .lhs = lhs,
1927 .op_token = and_token,
1928 .op = ast.Node.InfixOp.Op.BoolAnd,
1929 .rhs = undefined,
1930 });
1931 opt_ctx.store(&node.base);
1932 stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1933 try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1934 continue;
1935 }
1936 },
1937
1938 State.ComparisonExpressionBegin => |opt_ctx| {
1939 stack.append(State{ .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1940 try stack.append(State{ .BinaryOrExpressionBegin = opt_ctx });
1941 continue;
1942 },
1943
1944 State.ComparisonExpressionEnd => |opt_ctx| {
1945 const lhs = opt_ctx.get() orelse continue;
1946
1947 const token = nextToken(&tok_it, &tree);
1948 const token_index = token.index;
1949 const token_ptr = token.ptr;
1950 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1951 const node = try arena.create(ast.Node.InfixOp{
1952 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1953 .lhs = lhs,
1954 .op_token = token_index,
1955 .op = comp_id,
1956 .rhs = undefined,
1957 });
1958 opt_ctx.store(&node.base);
1959 stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1960 try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1961 continue;
1962 } else {
1963 prevToken(&tok_it, &tree);
1964 continue;
1965 }
1966 },
1967
1968 State.BinaryOrExpressionBegin => |opt_ctx| {
1969 stack.append(State{ .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
1970 try stack.append(State{ .BinaryXorExpressionBegin = opt_ctx });
1971 continue;
1972 },
1973
1974 State.BinaryOrExpressionEnd => |opt_ctx| {
1975 const lhs = opt_ctx.get() orelse continue;
1976
1977 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
1978 const node = try arena.create(ast.Node.InfixOp{
1979 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1980 .lhs = lhs,
1981 .op_token = pipe,
1982 .op = ast.Node.InfixOp.Op.BitOr,
1983 .rhs = undefined,
1984 });
1985 opt_ctx.store(&node.base);
1986 stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1987 try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1988 continue;
1989 }
1990 },
1991
1992 State.BinaryXorExpressionBegin => |opt_ctx| {
1993 stack.append(State{ .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
1994 try stack.append(State{ .BinaryAndExpressionBegin = opt_ctx });
1995 continue;
1996 },
1997
1998 State.BinaryXorExpressionEnd => |opt_ctx| {
1999 const lhs = opt_ctx.get() orelse continue;
2000
2001 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
2002 const node = try arena.create(ast.Node.InfixOp{
2003 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2004 .lhs = lhs,
2005 .op_token = caret,
2006 .op = ast.Node.InfixOp.Op.BitXor,
2007 .rhs = undefined,
2008 });
2009 opt_ctx.store(&node.base);
2010 stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2011 try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2012 continue;
2013 }
2014 },
2015
2016 State.BinaryAndExpressionBegin => |opt_ctx| {
2017 stack.append(State{ .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2018 try stack.append(State{ .BitShiftExpressionBegin = opt_ctx });
2019 continue;
2020 },
2021
2022 State.BinaryAndExpressionEnd => |opt_ctx| {
2023 const lhs = opt_ctx.get() orelse continue;
2024
2025 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
2026 const node = try arena.create(ast.Node.InfixOp{
2027 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2028 .lhs = lhs,
2029 .op_token = ampersand,
2030 .op = ast.Node.InfixOp.Op.BitAnd,
2031 .rhs = undefined,
2032 });
2033 opt_ctx.store(&node.base);
2034 stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2035 try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2036 continue;
2037 }
2038 },
2039
2040 State.BitShiftExpressionBegin => |opt_ctx| {
2041 stack.append(State{ .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2042 try stack.append(State{ .AdditionExpressionBegin = opt_ctx });
2043 continue;
2044 },
2045
2046 State.BitShiftExpressionEnd => |opt_ctx| {
2047 const lhs = opt_ctx.get() orelse continue;
2048
2049 const token = nextToken(&tok_it, &tree);
2050 const token_index = token.index;
2051 const token_ptr = token.ptr;
2052 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2053 const node = try arena.create(ast.Node.InfixOp{
2054 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2055 .lhs = lhs,
2056 .op_token = token_index,
2057 .op = bitshift_id,
2058 .rhs = undefined,
2059 });
2060 opt_ctx.store(&node.base);
2061 stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2062 try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2063 continue;
2064 } else {
2065 prevToken(&tok_it, &tree);
2066 continue;
2067 }
2068 },
2069
2070 State.AdditionExpressionBegin => |opt_ctx| {
2071 stack.append(State{ .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2072 try stack.append(State{ .MultiplyExpressionBegin = opt_ctx });
2073 continue;
2074 },
2075
2076 State.AdditionExpressionEnd => |opt_ctx| {
2077 const lhs = opt_ctx.get() orelse continue;
2078
2079 const token = nextToken(&tok_it, &tree);
2080 const token_index = token.index;
2081 const token_ptr = token.ptr;
2082 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2083 const node = try arena.create(ast.Node.InfixOp{
2084 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2085 .lhs = lhs,
2086 .op_token = token_index,
2087 .op = add_id,
2088 .rhs = undefined,
2089 });
2090 opt_ctx.store(&node.base);
2091 stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2092 try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2093 continue;
2094 } else {
2095 prevToken(&tok_it, &tree);
2096 continue;
2097 }
2098 },
2099
2100 State.MultiplyExpressionBegin => |opt_ctx| {
2101 stack.append(State{ .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2102 try stack.append(State{ .CurlySuffixExpressionBegin = opt_ctx });
2103 continue;
2104 },
2105
2106 State.MultiplyExpressionEnd => |opt_ctx| {
2107 const lhs = opt_ctx.get() orelse continue;
2108
2109 const token = nextToken(&tok_it, &tree);
2110 const token_index = token.index;
2111 const token_ptr = token.ptr;
2112 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2113 const node = try arena.create(ast.Node.InfixOp{
2114 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2115 .lhs = lhs,
2116 .op_token = token_index,
2117 .op = mult_id,
2118 .rhs = undefined,
2119 });
2120 opt_ctx.store(&node.base);
2121 stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2122 try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2123 continue;
2124 } else {
2125 prevToken(&tok_it, &tree);
2126 continue;
2127 }
2128 },
2129
2130 State.CurlySuffixExpressionBegin => |opt_ctx| {
2131 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2132 try stack.append(State{ .IfToken = Token.Id.LBrace });
2133 try stack.append(State{ .TypeExprBegin = opt_ctx });
2134 continue;
2135 },
2136
2137 State.CurlySuffixExpressionEnd => |opt_ctx| {
2138 const lhs = opt_ctx.get() orelse continue;
2139
2140 if (tok_it.peek().?.id == Token.Id.Period) {
2141 const node = try arena.create(ast.Node.SuffixOp{
2142 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2143 .lhs = lhs,
2144 .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
2145 .rtoken = undefined,
2146 });
2147 opt_ctx.store(&node.base);
2148
2149 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2150 try stack.append(State{ .IfToken = Token.Id.LBrace });
2151 try stack.append(State{
2152 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)){
2153 .list = &node.op.StructInitializer,
2154 .ptr = &node.rtoken,
2155 },
2156 });
2157 continue;
2158 }
2159
2160 const node = try arena.create(ast.Node.SuffixOp{
2161 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2162 .lhs = lhs,
2163 .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
2164 .rtoken = undefined,
2165 });
2166 opt_ctx.store(&node.base);
2167 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2168 try stack.append(State{ .IfToken = Token.Id.LBrace });
2169 try stack.append(State{
2170 .ExprListItemOrEnd = ExprListCtx{
2171 .list = &node.op.ArrayInitializer,
2172 .end = Token.Id.RBrace,
2173 .ptr = &node.rtoken,
2174 },
2175 });
2176 continue;
2177 },
2178
2179 State.TypeExprBegin => |opt_ctx| {
2180 stack.append(State{ .TypeExprEnd = opt_ctx }) catch unreachable;
2181 try stack.append(State{ .PrefixOpExpression = opt_ctx });
2182 continue;
2183 },
2184
2185 State.TypeExprEnd => |opt_ctx| {
2186 const lhs = opt_ctx.get() orelse continue;
2187
2188 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
2189 const node = try arena.create(ast.Node.InfixOp{
2190 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2191 .lhs = lhs,
2192 .op_token = bang,
2193 .op = ast.Node.InfixOp.Op.ErrorUnion,
2194 .rhs = undefined,
2195 });
2196 opt_ctx.store(&node.base);
2197 stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2198 try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } });
2199 continue;
2200 }
2201 },
2202
2203 State.PrefixOpExpression => |opt_ctx| {
2204 const token = nextToken(&tok_it, &tree);
2205 const token_index = token.index;
2206 const token_ptr = token.ptr;
2207 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2208 var node = try arena.create(ast.Node.PrefixOp{
2209 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2210 .op_token = token_index,
2211 .op = prefix_id,
2212 .rhs = undefined,
2213 });
2214 opt_ctx.store(&node.base);
2215
2216 // Treat '**' token as two pointer types
2217 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2218 const child = try arena.create(ast.Node.PrefixOp{
2219 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2220 .op_token = token_index,
2221 .op = prefix_id,
2222 .rhs = undefined,
2223 });
2224 node.rhs = &child.base;
2225 node = child;
2226 }
2227
2228 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
2229 if (node.op == ast.Node.PrefixOp.Op.PtrType) {
2230 try stack.append(State{ .PtrTypeModifiers = &node.op.PtrType });
2231 }
2232 continue;
2233 } else {
2234 prevToken(&tok_it, &tree);
2235 stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2236 continue;
2237 }
2238 },
2239
2240 State.SuffixOpExpressionBegin => |opt_ctx| {
2241 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
2242 const async_node = try arena.create(ast.Node.AsyncAttribute{
2243 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
2244 .async_token = async_token,
2245 .allocator_type = null,
2246 .rangle_bracket = null,
2247 });
2248 stack.append(State{
2249 .AsyncEnd = AsyncEndCtx{
2250 .ctx = opt_ctx,
2251 .attribute = async_node,
2252 },
2253 }) catch unreachable;
2254 try stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2255 try stack.append(State{ .PrimaryExpression = opt_ctx.toRequired() });
2256 try stack.append(State{ .AsyncAllocator = async_node });
2257 continue;
2258 }
2259
2260 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2261 try stack.append(State{ .PrimaryExpression = opt_ctx });
2262 continue;
2263 },
2264
2265 State.SuffixOpExpressionEnd => |opt_ctx| {
2266 const lhs = opt_ctx.get() orelse continue;
2267
2268 const token = nextToken(&tok_it, &tree);
2269 const token_index = token.index;
2270 const token_ptr = token.ptr;
2271 switch (token_ptr.id) {
2272 Token.Id.LParen => {
2273 const node = try arena.create(ast.Node.SuffixOp{
2274 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2275 .lhs = lhs,
2276 .op = ast.Node.SuffixOp.Op{
2277 .Call = ast.Node.SuffixOp.Op.Call{
2278 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2279 .async_attr = null,
2280 },
2281 },
2282 .rtoken = undefined,
2283 });
2284 opt_ctx.store(&node.base);
2285
2286 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2287 try stack.append(State{
2288 .ExprListItemOrEnd = ExprListCtx{
2289 .list = &node.op.Call.params,
2290 .end = Token.Id.RParen,
2291 .ptr = &node.rtoken,
2292 },
2293 });
2294 continue;
2295 },
2296 Token.Id.LBracket => {
2297 const node = try arena.create(ast.Node.SuffixOp{
2298 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2299 .lhs = lhs,
2300 .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },
2301 .rtoken = undefined,
2302 });
2303 opt_ctx.store(&node.base);
2304
2305 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2306 try stack.append(State{ .SliceOrArrayAccess = node });
2307 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.op.ArrayAccess } });
2308 continue;
2309 },
2310 Token.Id.Period => {
2311 if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| {
2312 const node = try arena.create(ast.Node.SuffixOp{
2313 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2314 .lhs = lhs,
2315 .op = ast.Node.SuffixOp.Op.Deref,
2316 .rtoken = asterisk_token,
2317 });
2318 opt_ctx.store(&node.base);
2319 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2320 continue;
2321 }
2322 if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| {
2323 const node = try arena.create(ast.Node.SuffixOp{
2324 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2325 .lhs = lhs,
2326 .op = ast.Node.SuffixOp.Op.UnwrapOptional,
2327 .rtoken = question_token,
2328 });
2329 opt_ctx.store(&node.base);
2330 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2331 continue;
2332 }
2333 const node = try arena.create(ast.Node.InfixOp{
2334 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2335 .lhs = lhs,
2336 .op_token = token_index,
2337 .op = ast.Node.InfixOp.Op.Period,
2338 .rhs = undefined,
2339 });
2340 opt_ctx.store(&node.base);
2341
2342 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2343 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } });
2344 continue;
2345 },
2346 else => {
2347 prevToken(&tok_it, &tree);
2348 continue;
2349 },
2350 }
2351 },
2352
2353 State.PrimaryExpression => |opt_ctx| {
2354 const token = nextToken(&tok_it, &tree);
2355 switch (token.ptr.id) {
2356 Token.Id.IntegerLiteral => {
2357 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.IntegerLiteral, token.index);
2358 continue;
2359 },
2360 Token.Id.FloatLiteral => {
2361 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token.index);
2362 continue;
2363 },
2364 Token.Id.CharLiteral => {
2365 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token.index);
2366 continue;
2367 },
2368 Token.Id.Keyword_undefined => {
2369 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);
2370 continue;
2371 },
2372 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2373 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);
2374 continue;
2375 },
2376 Token.Id.Keyword_null => {
2377 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token.index);
2378 continue;
2379 },
2380 Token.Id.Keyword_this => {
2381 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token.index);
2382 continue;
2383 },
2384 Token.Id.Keyword_var => {
2385 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token.index);
2386 continue;
2387 },
2388 Token.Id.Keyword_unreachable => {
2389 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token.index);
2390 continue;
2391 },
2392 Token.Id.Keyword_promise => {
2393 const node = try arena.create(ast.Node.PromiseType{
2394 .base = ast.Node{ .id = ast.Node.Id.PromiseType },
2395 .promise_token = token.index,
2396 .result = null,
2397 });
2398 opt_ctx.store(&node.base);
2399 const next_token = nextToken(&tok_it, &tree);
2400 const next_token_index = next_token.index;
2401 const next_token_ptr = next_token.ptr;
2402 if (next_token_ptr.id != Token.Id.Arrow) {
2403 prevToken(&tok_it, &tree);
2404 continue;
2405 }
2406 node.result = ast.Node.PromiseType.Result{
2407 .arrow_token = next_token_index,
2408 .return_type = undefined,
2409 };
2410 const return_type_ptr = &node.result.?.return_type;
2411 try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } });
2412 continue;
2413 },
2414 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2415 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) orelse unreachable);
2416 continue;
2417 },
2418 Token.Id.LParen => {
2419 const node = try arena.create(ast.Node.GroupedExpression{
2420 .base = ast.Node{ .id = ast.Node.Id.GroupedExpression },
2421 .lparen = token.index,
2422 .expr = undefined,
2423 .rparen = undefined,
2424 });
2425 opt_ctx.store(&node.base);
2426
2427 stack.append(State{
2428 .ExpectTokenSave = ExpectTokenSave{
2429 .id = Token.Id.RParen,
2430 .ptr = &node.rparen,
2431 },
2432 }) catch unreachable;
2433 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
2434 continue;
2435 },
2436 Token.Id.Builtin => {
2437 const node = try arena.create(ast.Node.BuiltinCall{
2438 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
2439 .builtin_token = token.index,
2440 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2441 .rparen_token = undefined,
2442 });
2443 opt_ctx.store(&node.base);
2444
2445 stack.append(State{
2446 .ExprListItemOrEnd = ExprListCtx{
2447 .list = &node.params,
2448 .end = Token.Id.RParen,
2449 .ptr = &node.rparen_token,
2450 },
2451 }) catch unreachable;
2452 try stack.append(State{ .ExpectToken = Token.Id.LParen });
2453 continue;
2454 },
2455 Token.Id.LBracket => {
2456 const node = try arena.create(ast.Node.PrefixOp{
2457 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2458 .op_token = token.index,
2459 .op = undefined,
2460 .rhs = undefined,
2461 });
2462 opt_ctx.store(&node.base);
2463
2464 stack.append(State{ .SliceOrArrayType = node }) catch unreachable;
2465 continue;
2466 },
2467 Token.Id.Keyword_error => {
2468 stack.append(State{
2469 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx{
2470 .error_token = token.index,
2471 .opt_ctx = opt_ctx,
2472 },
2473 }) catch unreachable;
2474 continue;
2475 },
2476 Token.Id.Keyword_packed => {
2477 stack.append(State{
2478 .ContainerKind = ContainerKindCtx{
2479 .opt_ctx = opt_ctx,
2480 .layout_token = token.index,
2481 },
2482 }) catch unreachable;
2483 continue;
2484 },
2485 Token.Id.Keyword_extern => {
2486 stack.append(State{
2487 .ExternType = ExternTypeCtx{
2488 .opt_ctx = opt_ctx,
2489 .extern_token = token.index,
2490 .comments = null,
2491 },
2492 }) catch unreachable;
2493 continue;
2494 },
2495 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2496 prevToken(&tok_it, &tree);
2497 stack.append(State{
2498 .ContainerKind = ContainerKindCtx{
2499 .opt_ctx = opt_ctx,
2500 .layout_token = null,
2501 },
2502 }) catch unreachable;
2503 continue;
2504 },
2505 Token.Id.Identifier => {
2506 stack.append(State{
2507 .MaybeLabeledExpression = MaybeLabeledExpressionCtx{
2508 .label = token.index,
2509 .opt_ctx = opt_ctx,
2510 },
2511 }) catch unreachable;
2512 continue;
2513 },
2514 Token.Id.Keyword_fn => {
2515 const fn_proto = try arena.create(ast.Node.FnProto{
2516 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2517 .doc_comments = null,
2518 .visib_token = null,
2519 .name_token = null,
2520 .fn_token = token.index,
2521 .params = ast.Node.FnProto.ParamList.init(arena),
2522 .return_type = undefined,
2523 .var_args_token = null,
2524 .extern_export_inline_token = null,
2525 .cc_token = null,
2526 .async_attr = null,
2527 .body_node = null,
2528 .lib_name = null,
2529 .align_expr = null,
2530 });
2531 opt_ctx.store(&fn_proto.base);
2532 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
2533 continue;
2534 },
2535 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2536 const fn_proto = try arena.create(ast.Node.FnProto{
2537 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2538 .doc_comments = null,
2539 .visib_token = null,
2540 .name_token = null,
2541 .fn_token = undefined,
2542 .params = ast.Node.FnProto.ParamList.init(arena),
2543 .return_type = undefined,
2544 .var_args_token = null,
2545 .extern_export_inline_token = null,
2546 .cc_token = token.index,
2547 .async_attr = null,
2548 .body_node = null,
2549 .lib_name = null,
2550 .align_expr = null,
2551 });
2552 opt_ctx.store(&fn_proto.base);
2553 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
2554 try stack.append(State{
2555 .ExpectTokenSave = ExpectTokenSave{
2556 .id = Token.Id.Keyword_fn,
2557 .ptr = &fn_proto.fn_token,
2558 },
2559 });
2560 continue;
2561 },
2562 Token.Id.Keyword_asm => {
2563 const node = try arena.create(ast.Node.Asm{
2564 .base = ast.Node{ .id = ast.Node.Id.Asm },
2565 .asm_token = token.index,
2566 .volatile_token = null,
2567 .template = undefined,
2568 .outputs = ast.Node.Asm.OutputList.init(arena),
2569 .inputs = ast.Node.Asm.InputList.init(arena),
2570 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2571 .rparen = undefined,
2572 });
2573 opt_ctx.store(&node.base);
2574
2575 stack.append(State{
2576 .ExpectTokenSave = ExpectTokenSave{
2577 .id = Token.Id.RParen,
2578 .ptr = &node.rparen,
2579 },
2580 }) catch unreachable;
2581 try stack.append(State{ .AsmClobberItems = &node.clobbers });
2582 try stack.append(State{ .IfToken = Token.Id.Colon });
2583 try stack.append(State{ .AsmInputItems = &node.inputs });
2584 try stack.append(State{ .IfToken = Token.Id.Colon });
2585 try stack.append(State{ .AsmOutputItems = &node.outputs });
2586 try stack.append(State{ .IfToken = Token.Id.Colon });
2587 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.template } });
2588 try stack.append(State{ .ExpectToken = Token.Id.LParen });
2589 try stack.append(State{
2590 .OptionalTokenSave = OptionalTokenSave{
2591 .id = Token.Id.Keyword_volatile,
2592 .ptr = &node.volatile_token,
2593 },
2594 });
2595 },
2596 Token.Id.Keyword_inline => {
2597 stack.append(State{
2598 .Inline = InlineCtx{
2599 .label = null,
2600 .inline_token = token.index,
2601 .opt_ctx = opt_ctx,
2602 },
2603 }) catch unreachable;
2604 continue;
2605 },
2606 else => {
2607 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2608 prevToken(&tok_it, &tree);
2609 if (opt_ctx != OptionalCtx.Optional) {
2610 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } };
2611 return tree;
2612 }
2613 }
2614 continue;
2615 },
2616 }
2617 },
2618
2619 State.ErrorTypeOrSetDecl => |ctx| {
2620 if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {
2621 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2622 continue;
2623 }
2624
2625 const node = try arena.create(ast.Node.ErrorSetDecl{
2626 .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },
2627 .error_token = ctx.error_token,
2628 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2629 .rbrace_token = undefined,
2630 });
2631 ctx.opt_ctx.store(&node.base);
2632
2633 stack.append(State{
2634 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)){
2635 .list = &node.decls,
2636 .ptr = &node.rbrace_token,
2637 },
2638 }) catch unreachable;
2639 continue;
2640 },
2641 State.StringLiteral => |opt_ctx| {
2642 const token = nextToken(&tok_it, &tree);
2643 const token_index = token.index;
2644 const token_ptr = token.ptr;
2645 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) orelse {
2646 prevToken(&tok_it, &tree);
2647 if (opt_ctx != OptionalCtx.Optional) {
2648 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
2649 return tree;
2650 }
2651
2652 continue;
2653 });
2654 },
2655
2656 State.Identifier => |opt_ctx| {
2657 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |ident_token| {
2658 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2659 continue;
2660 }
2661
2662 if (opt_ctx != OptionalCtx.Optional) {
2663 const token = nextToken(&tok_it, &tree);
2664 const token_index = token.index;
2665 const token_ptr = token.ptr;
2666 ((try tree.errors.addOne())).* = Error{
2667 .ExpectedToken = Error.ExpectedToken{
2668 .token = token_index,
2669 .expected_id = Token.Id.Identifier,
2670 },
2671 };
2672 return tree;
2673 }
2674 },
2675
2676 State.ErrorTag => |node_ptr| {
2677 const comments = try eatDocComments(arena, &tok_it, &tree);
2678 const ident_token = nextToken(&tok_it, &tree);
2679 const ident_token_index = ident_token.index;
2680 const ident_token_ptr = ident_token.ptr;
2681 if (ident_token_ptr.id != Token.Id.Identifier) {
2682 ((try tree.errors.addOne())).* = Error{
2683 .ExpectedToken = Error.ExpectedToken{
2684 .token = ident_token_index,
2685 .expected_id = Token.Id.Identifier,
2686 },
2687 };
2688 return tree;
2689 }
2690
2691 const node = try arena.create(ast.Node.ErrorTag{
2692 .base = ast.Node{ .id = ast.Node.Id.ErrorTag },
2693 .doc_comments = comments,
2694 .name_token = ident_token_index,
2695 });
2696 node_ptr.* = &node.base;
2697 continue;
2698 },
2699
2700 State.ExpectToken => |token_id| {
2701 const token = nextToken(&tok_it, &tree);
2702 const token_index = token.index;
2703 const token_ptr = token.ptr;
2704 if (token_ptr.id != token_id) {
2705 ((try tree.errors.addOne())).* = Error{
2706 .ExpectedToken = Error.ExpectedToken{
2707 .token = token_index,
2708 .expected_id = token_id,
2709 },
2710 };
2711 return tree;
2712 }
2713 continue;
2714 },
2715 State.ExpectTokenSave => |expect_token_save| {
2716 const token = nextToken(&tok_it, &tree);
2717 const token_index = token.index;
2718 const token_ptr = token.ptr;
2719 if (token_ptr.id != expect_token_save.id) {
2720 ((try tree.errors.addOne())).* = Error{
2721 .ExpectedToken = Error.ExpectedToken{
2722 .token = token_index,
2723 .expected_id = expect_token_save.id,
2724 },
2725 };
2726 return tree;
2727 }
2728 expect_token_save.ptr.* = token_index;
2729 continue;
2730 },
2731 State.IfToken => |token_id| {
2732 if (eatToken(&tok_it, &tree, token_id)) |_| {
2733 continue;
2734 }
2735
2736 _ = stack.pop();
2737 continue;
2738 },
2739 State.IfTokenSave => |if_token_save| {
2740 if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| {
2741 (if_token_save.ptr).* = token_index;
2742 continue;
2743 }
2744
2745 _ = stack.pop();
2746 continue;
2747 },
2748 State.OptionalTokenSave => |optional_token_save| {
2749 if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| {
2750 (optional_token_save.ptr).* = token_index;
2751 continue;
2752 }
2753
2754 continue;
2755 },
2756 }
2757 }
2758}
2759
2760const AnnotatedToken = struct {
2761 ptr: *Token,
2762 index: TokenIndex,
2763};
2764
2765const TopLevelDeclCtx = struct {
2766 decls: *ast.Node.Root.DeclList,
2767 visib_token: ?TokenIndex,
2768 extern_export_inline_token: ?AnnotatedToken,
2769 lib_name: ?*ast.Node,
2770 comments: ?*ast.Node.DocComment,
2771};
2772
2773const VarDeclCtx = struct {
2774 mut_token: TokenIndex,
2775 visib_token: ?TokenIndex,
2776 comptime_token: ?TokenIndex,
2777 extern_export_token: ?TokenIndex,
2778 lib_name: ?*ast.Node,
2779 list: *ast.Node.Root.DeclList,
2780 comments: ?*ast.Node.DocComment,
2781};
2782
2783const TopLevelExternOrFieldCtx = struct {
2784 visib_token: TokenIndex,
2785 container_decl: *ast.Node.ContainerDecl,
2786 comments: ?*ast.Node.DocComment,
2787};
2788
2789const ExternTypeCtx = struct {
2790 opt_ctx: OptionalCtx,
2791 extern_token: TokenIndex,
2792 comments: ?*ast.Node.DocComment,
2793};
2794
2795const ContainerKindCtx = struct {
2796 opt_ctx: OptionalCtx,
2797 layout_token: ?TokenIndex,
2798};
2799
2800const ExpectTokenSave = struct {
2801 id: @TagType(Token.Id),
2802 ptr: *TokenIndex,
2803};
2804
2805const OptionalTokenSave = struct {
2806 id: @TagType(Token.Id),
2807 ptr: *?TokenIndex,
2808};
2809
2810const ExprListCtx = struct {
2811 list: *ast.Node.SuffixOp.Op.InitList,
2812 end: Token.Id,
2813 ptr: *TokenIndex,
2814};
2815
2816fn ListSave(comptime List: type) type {
2817 return struct {
2818 list: *List,
2819 ptr: *TokenIndex,
2820 };
2821}
2822
2823const MaybeLabeledExpressionCtx = struct {
2824 label: TokenIndex,
2825 opt_ctx: OptionalCtx,
2826};
2827
2828const LabelCtx = struct {
2829 label: ?TokenIndex,
2830 opt_ctx: OptionalCtx,
2831};
2832
2833const InlineCtx = struct {
2834 label: ?TokenIndex,
2835 inline_token: ?TokenIndex,
2836 opt_ctx: OptionalCtx,
2837};
2838
2839const LoopCtx = struct {
2840 label: ?TokenIndex,
2841 inline_token: ?TokenIndex,
2842 loop_token: TokenIndex,
2843 opt_ctx: OptionalCtx,
2844};
2845
2846const AsyncEndCtx = struct {
2847 ctx: OptionalCtx,
2848 attribute: *ast.Node.AsyncAttribute,
2849};
2850
2851const ErrorTypeOrSetDeclCtx = struct {
2852 opt_ctx: OptionalCtx,
2853 error_token: TokenIndex,
2854};
2855
2856const ParamDeclEndCtx = struct {
2857 fn_proto: *ast.Node.FnProto,
2858 param_decl: *ast.Node.ParamDecl,
2859};
2860
2861const ComptimeStatementCtx = struct {
2862 comptime_token: TokenIndex,
2863 block: *ast.Node.Block,
2864};
2865
2866const OptionalCtx = union(enum) {
2867 Optional: *?*ast.Node,
2868 RequiredNull: *?*ast.Node,
2869 Required: **ast.Node,
2870
2871 pub fn store(self: *const OptionalCtx, value: *ast.Node) void {
2872 switch (self.*) {
2873 OptionalCtx.Optional => |ptr| ptr.* = value,
2874 OptionalCtx.RequiredNull => |ptr| ptr.* = value,
2875 OptionalCtx.Required => |ptr| ptr.* = value,
2876 }
2877 }
2878
2879 pub fn get(self: *const OptionalCtx) ?*ast.Node {
2880 switch (self.*) {
2881 OptionalCtx.Optional => |ptr| return ptr.*,
2882 OptionalCtx.RequiredNull => |ptr| return ptr.*.?,
2883 OptionalCtx.Required => |ptr| return ptr.*,
2884 }
2885 }
2886
2887 pub fn toRequired(self: *const OptionalCtx) OptionalCtx {
2888 switch (self.*) {
2889 OptionalCtx.Optional => |ptr| {
2890 return OptionalCtx{ .RequiredNull = ptr };
2891 },
2892 OptionalCtx.RequiredNull => |ptr| return self.*,
2893 OptionalCtx.Required => |ptr| return self.*,
2894 }
2895 }
2896};
2897
2898const AddCommentsCtx = struct {
2899 node_ptr: **ast.Node,
2900 comments: ?*ast.Node.DocComment,
2901};
2902
2903const State = union(enum) {
2904 TopLevel,
2905 TopLevelExtern: TopLevelDeclCtx,
2906 TopLevelLibname: TopLevelDeclCtx,
2907 TopLevelDecl: TopLevelDeclCtx,
2908 TopLevelExternOrField: TopLevelExternOrFieldCtx,
2909
2910 ContainerKind: ContainerKindCtx,
2911 ContainerInitArgStart: *ast.Node.ContainerDecl,
2912 ContainerInitArg: *ast.Node.ContainerDecl,
2913 ContainerDecl: *ast.Node.ContainerDecl,
2914
2915 VarDecl: VarDeclCtx,
2916 VarDeclAlign: *ast.Node.VarDecl,
2917 VarDeclEq: *ast.Node.VarDecl,
2918 VarDeclSemiColon: *ast.Node.VarDecl,
2919
2920 FnDef: *ast.Node.FnProto,
2921 FnProto: *ast.Node.FnProto,
2922 FnProtoAlign: *ast.Node.FnProto,
2923 FnProtoReturnType: *ast.Node.FnProto,
2924
2925 ParamDecl: *ast.Node.FnProto,
2926 ParamDeclAliasOrComptime: *ast.Node.ParamDecl,
2927 ParamDeclName: *ast.Node.ParamDecl,
2928 ParamDeclEnd: ParamDeclEndCtx,
2929 ParamDeclComma: *ast.Node.FnProto,
2930
2931 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
2932 LabeledExpression: LabelCtx,
2933 Inline: InlineCtx,
2934 While: LoopCtx,
2935 WhileContinueExpr: *?*ast.Node,
2936 For: LoopCtx,
2937 Else: *?*ast.Node.Else,
2938
2939 Block: *ast.Node.Block,
2940 Statement: *ast.Node.Block,
2941 ComptimeStatement: ComptimeStatementCtx,
2942 Semicolon: **ast.Node,
2943
2944 AsmOutputItems: *ast.Node.Asm.OutputList,
2945 AsmOutputReturnOrType: *ast.Node.AsmOutput,
2946 AsmInputItems: *ast.Node.Asm.InputList,
2947 AsmClobberItems: *ast.Node.Asm.ClobberList,
2948
2949 ExprListItemOrEnd: ExprListCtx,
2950 ExprListCommaOrEnd: ExprListCtx,
2951 FieldInitListItemOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2952 FieldInitListCommaOrEnd: ListSave(ast.Node.SuffixOp.Op.InitList),
2953 FieldListCommaOrEnd: *ast.Node.ContainerDecl,
2954 FieldInitValue: OptionalCtx,
2955 ErrorTagListItemOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2956 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2957 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
2958 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
2959 SwitchCaseFirstItem: *ast.Node.SwitchCase,
2960 SwitchCaseItemCommaOrEnd: *ast.Node.SwitchCase,
2961 SwitchCaseItemOrEnd: *ast.Node.SwitchCase,
2962
2963 SuspendBody: *ast.Node.Suspend,
2964 AsyncAllocator: *ast.Node.AsyncAttribute,
2965 AsyncEnd: AsyncEndCtx,
2966
2967 ExternType: ExternTypeCtx,
2968 SliceOrArrayAccess: *ast.Node.SuffixOp,
2969 SliceOrArrayType: *ast.Node.PrefixOp,
2970 PtrTypeModifiers: *ast.Node.PrefixOp.PtrInfo,
2971 AlignBitRange: *ast.Node.PrefixOp.PtrInfo.Align,
2972
2973 Payload: OptionalCtx,
2974 PointerPayload: OptionalCtx,
2975 PointerIndexPayload: OptionalCtx,
2976
2977 Expression: OptionalCtx,
2978 RangeExpressionBegin: OptionalCtx,
2979 RangeExpressionEnd: OptionalCtx,
2980 AssignmentExpressionBegin: OptionalCtx,
2981 AssignmentExpressionEnd: OptionalCtx,
2982 UnwrapExpressionBegin: OptionalCtx,
2983 UnwrapExpressionEnd: OptionalCtx,
2984 BoolOrExpressionBegin: OptionalCtx,
2985 BoolOrExpressionEnd: OptionalCtx,
2986 BoolAndExpressionBegin: OptionalCtx,
2987 BoolAndExpressionEnd: OptionalCtx,
2988 ComparisonExpressionBegin: OptionalCtx,
2989 ComparisonExpressionEnd: OptionalCtx,
2990 BinaryOrExpressionBegin: OptionalCtx,
2991 BinaryOrExpressionEnd: OptionalCtx,
2992 BinaryXorExpressionBegin: OptionalCtx,
2993 BinaryXorExpressionEnd: OptionalCtx,
2994 BinaryAndExpressionBegin: OptionalCtx,
2995 BinaryAndExpressionEnd: OptionalCtx,
2996 BitShiftExpressionBegin: OptionalCtx,
2997 BitShiftExpressionEnd: OptionalCtx,
2998 AdditionExpressionBegin: OptionalCtx,
2999 AdditionExpressionEnd: OptionalCtx,
3000 MultiplyExpressionBegin: OptionalCtx,
3001 MultiplyExpressionEnd: OptionalCtx,
3002 CurlySuffixExpressionBegin: OptionalCtx,
3003 CurlySuffixExpressionEnd: OptionalCtx,
3004 TypeExprBegin: OptionalCtx,
3005 TypeExprEnd: OptionalCtx,
3006 PrefixOpExpression: OptionalCtx,
3007 SuffixOpExpressionBegin: OptionalCtx,
3008 SuffixOpExpressionEnd: OptionalCtx,
3009 PrimaryExpression: OptionalCtx,
3010
3011 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
3012 StringLiteral: OptionalCtx,
3013 Identifier: OptionalCtx,
3014 ErrorTag: **ast.Node,
3015
3016 IfToken: @TagType(Token.Id),
3017 IfTokenSave: ExpectTokenSave,
3018 ExpectToken: @TagType(Token.Id),
3019 ExpectTokenSave: ExpectTokenSave,
3020 OptionalTokenSave: OptionalTokenSave,
3021};
3022
3023fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*ast.Node.DocComment) !void {
3024 const node = blk: {
3025 if (result.*) |comment_node| {
3026 break :blk comment_node;
3027 } else {
3028 const comment_node = try arena.create(ast.Node.DocComment{
3029 .base = ast.Node{ .id = ast.Node.Id.DocComment },
3030 .lines = ast.Node.DocComment.LineList.init(arena),
3031 });
3032 result.* = comment_node;
3033 break :blk comment_node;
3034 }
3035 };
3036 try node.lines.push(line_comment);
3037}
3038
3039fn eatDocComments(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) !?*ast.Node.DocComment {
3040 var result: ?*ast.Node.DocComment = null;
3041 while (true) {
3042 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {
3043 try pushDocComment(arena, line_comment, &result);
3044 continue;
3045 }
3046 break;
3047 }
3048 return result;
3049}
3050
3051fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterator, token_ptr: *const Token, token_index: TokenIndex, tree: *ast.Tree) !?*ast.Node {
3052 switch (token_ptr.id) {
3053 Token.Id.StringLiteral => {
3054 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3055 },
3056 Token.Id.MultilineStringLiteralLine => {
3057 const node = try arena.create(ast.Node.MultilineStringLiteral{
3058 .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },
3059 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3060 });
3061 try node.lines.push(token_index);
3062 while (true) {
3063 const multiline_str = nextToken(tok_it, tree);
3064 const multiline_str_index = multiline_str.index;
3065 const multiline_str_ptr = multiline_str.ptr;
3066 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3067 prevToken(tok_it, tree);
3068 break;
3069 }
3070
3071 try node.lines.push(multiline_str_index);
3072 }
3073
3074 return &node.base;
3075 },
3076 // TODO: We shouldn't need a cast, but:
3077 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
3078 else => return (?*ast.Node)(null),
3079 }
3080}
3081
3082fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *const OptionalCtx, token_ptr: *const Token, token_index: TokenIndex) !bool {
3083 switch (token_ptr.id) {
3084 Token.Id.Keyword_suspend => {
3085 const node = try arena.create(ast.Node.Suspend{
3086 .base = ast.Node{ .id = ast.Node.Id.Suspend },
3087 .suspend_token = token_index,
3088 .body = null,
3089 });
3090 ctx.store(&node.base);
3091
3092 stack.append(State{ .SuspendBody = node }) catch unreachable;
3093 return true;
3094 },
3095 Token.Id.Keyword_if => {
3096 const node = try arena.create(ast.Node.If{
3097 .base = ast.Node{ .id = ast.Node.Id.If },
3098 .if_token = token_index,
3099 .condition = undefined,
3100 .payload = null,
3101 .body = undefined,
3102 .@"else" = null,
3103 });
3104 ctx.store(&node.base);
3105
3106 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
3107 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
3108 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
3109 try stack.append(State{ .ExpectToken = Token.Id.RParen });
3110 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.condition } });
3111 try stack.append(State{ .ExpectToken = Token.Id.LParen });
3112 return true;
3113 },
3114 Token.Id.Keyword_while => {
3115 stack.append(State{
3116 .While = LoopCtx{
3117 .label = null,
3118 .inline_token = null,
3119 .loop_token = token_index,
3120 .opt_ctx = ctx.*,
3121 },
3122 }) catch unreachable;
3123 return true;
3124 },
3125 Token.Id.Keyword_for => {
3126 stack.append(State{
3127 .For = LoopCtx{
3128 .label = null,
3129 .inline_token = null,
3130 .loop_token = token_index,
3131 .opt_ctx = ctx.*,
3132 },
3133 }) catch unreachable;
3134 return true;
3135 },
3136 Token.Id.Keyword_switch => {
3137 const node = try arena.create(ast.Node.Switch{
3138 .base = ast.Node{ .id = ast.Node.Id.Switch },
3139 .switch_token = token_index,
3140 .expr = undefined,
3141 .cases = ast.Node.Switch.CaseList.init(arena),
3142 .rbrace = undefined,
3143 });
3144 ctx.store(&node.base);
3145
3146 stack.append(State{
3147 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)){
3148 .list = &node.cases,
3149 .ptr = &node.rbrace,
3150 },
3151 }) catch unreachable;
3152 try stack.append(State{ .ExpectToken = Token.Id.LBrace });
3153 try stack.append(State{ .ExpectToken = Token.Id.RParen });
3154 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
3155 try stack.append(State{ .ExpectToken = Token.Id.LParen });
3156 return true;
3157 },
3158 Token.Id.Keyword_comptime => {
3159 const node = try arena.create(ast.Node.Comptime{
3160 .base = ast.Node{ .id = ast.Node.Id.Comptime },
3161 .comptime_token = token_index,
3162 .expr = undefined,
3163 .doc_comments = null,
3164 });
3165 ctx.store(&node.base);
3166
3167 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
3168 return true;
3169 },
3170 Token.Id.LBrace => {
3171 const block = try arena.create(ast.Node.Block{
3172 .base = ast.Node{ .id = ast.Node.Id.Block },
3173 .label = null,
3174 .lbrace = token_index,
3175 .statements = ast.Node.Block.StatementList.init(arena),
3176 .rbrace = undefined,
3177 });
3178 ctx.store(&block.base);
3179 stack.append(State{ .Block = block }) catch unreachable;
3180 return true;
3181 },
3182 else => {
3183 return false;
3184 },
3185 }
3186}
3187
3188const ExpectCommaOrEndResult = union(enum) {
3189 end_token: ?TokenIndex,
3190 parse_error: Error,
3191};
3192
3193fn expectCommaOrEnd(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, end: @TagType(Token.Id)) ExpectCommaOrEndResult {
3194 const token = nextToken(tok_it, tree);
3195 const token_index = token.index;
3196 const token_ptr = token.ptr;
3197 switch (token_ptr.id) {
3198 Token.Id.Comma => return ExpectCommaOrEndResult{ .end_token = null },
3199 else => {
3200 if (end == token_ptr.id) {
3201 return ExpectCommaOrEndResult{ .end_token = token_index };
3202 }
3203
3204 return ExpectCommaOrEndResult{
3205 .parse_error = Error{
3206 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd{
3207 .token = token_index,
3208 .end_id = end,
3209 },
3210 },
3211 };
3212 },
3213 }
3214}
3215
3216fn tokenIdToAssignment(id: *const Token.Id) ?ast.Node.InfixOp.Op {
3217 // TODO: We have to cast all cases because of this:
3218 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3219 return switch (id.*) {
3220 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op{ .AssignBitAnd = {} },
3221 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op{ .AssignBitShiftLeft = {} },
3222 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op{ .AssignBitShiftRight = {} },
3223 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op{ .AssignTimes = {} },
3224 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op{ .AssignTimesWarp = {} },
3225 Token.Id.CaretEqual => ast.Node.InfixOp.Op{ .AssignBitXor = {} },
3226 Token.Id.Equal => ast.Node.InfixOp.Op{ .Assign = {} },
3227 Token.Id.MinusEqual => ast.Node.InfixOp.Op{ .AssignMinus = {} },
3228 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op{ .AssignMinusWrap = {} },
3229 Token.Id.PercentEqual => ast.Node.InfixOp.Op{ .AssignMod = {} },
3230 Token.Id.PipeEqual => ast.Node.InfixOp.Op{ .AssignBitOr = {} },
3231 Token.Id.PlusEqual => ast.Node.InfixOp.Op{ .AssignPlus = {} },
3232 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op{ .AssignPlusWrap = {} },
3233 Token.Id.SlashEqual => ast.Node.InfixOp.Op{ .AssignDiv = {} },
3234 else => null,
3235 };
3236}
3237
3238fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3239 return switch (id) {
3240 Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null },
3241 Token.Id.Keyword_orelse => ast.Node.InfixOp.Op{ .UnwrapOptional = void{} },
3242 else => null,
3243 };
3244}
3245
3246fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3247 return switch (id) {
3248 Token.Id.BangEqual => ast.Node.InfixOp.Op{ .BangEqual = void{} },
3249 Token.Id.EqualEqual => ast.Node.InfixOp.Op{ .EqualEqual = void{} },
3250 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op{ .LessThan = void{} },
3251 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op{ .LessOrEqual = void{} },
3252 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op{ .GreaterThan = void{} },
3253 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op{ .GreaterOrEqual = void{} },
3254 else => null,
3255 };
3256}
3257
3258fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3259 return switch (id) {
3260 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op{ .BitShiftLeft = void{} },
3261 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op{ .BitShiftRight = void{} },
3262 else => null,
3263 };
3264}
3265
3266fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3267 return switch (id) {
3268 Token.Id.Minus => ast.Node.InfixOp.Op{ .Sub = void{} },
3269 Token.Id.MinusPercent => ast.Node.InfixOp.Op{ .SubWrap = void{} },
3270 Token.Id.Plus => ast.Node.InfixOp.Op{ .Add = void{} },
3271 Token.Id.PlusPercent => ast.Node.InfixOp.Op{ .AddWrap = void{} },
3272 Token.Id.PlusPlus => ast.Node.InfixOp.Op{ .ArrayCat = void{} },
3273 else => null,
3274 };
3275}
3276
3277fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3278 return switch (id) {
3279 Token.Id.Slash => ast.Node.InfixOp.Op{ .Div = void{} },
3280 Token.Id.Asterisk => ast.Node.InfixOp.Op{ .Mult = void{} },
3281 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op{ .ArrayMult = void{} },
3282 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op{ .MultWrap = void{} },
3283 Token.Id.Percent => ast.Node.InfixOp.Op{ .Mod = void{} },
3284 Token.Id.PipePipe => ast.Node.InfixOp.Op{ .MergeErrorSets = void{} },
3285 else => null,
3286 };
3287}
3288
3289fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3290 return switch (id) {
3291 Token.Id.Bang => ast.Node.PrefixOp.Op{ .BoolNot = void{} },
3292 Token.Id.Tilde => ast.Node.PrefixOp.Op{ .BitNot = void{} },
3293 Token.Id.Minus => ast.Node.PrefixOp.Op{ .Negation = void{} },
3294 Token.Id.MinusPercent => ast.Node.PrefixOp.Op{ .NegationWrap = void{} },
3295 Token.Id.Ampersand => ast.Node.PrefixOp.Op{ .AddressOf = void{} },
3296 Token.Id.Asterisk, Token.Id.AsteriskAsterisk, Token.Id.BracketStarBracket => ast.Node.PrefixOp.Op{
3297 .PtrType = ast.Node.PrefixOp.PtrInfo{
3298 .align_info = null,
3299 .const_token = null,
3300 .volatile_token = null,
3301 },
3302 },
3303 Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} },
3304 Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} },
3305 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
3306 else => null,
3307 };
3308}
3309
3310fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T {
3311 return arena.create(T{
3312 .base = ast.Node{ .id = ast.Node.typeToId(T) },
3313 .token = token_index,
3314 });
3315}
3316
3317fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: *const OptionalCtx, comptime T: type, token_index: TokenIndex) !*T {
3318 const node = try createLiteral(arena, T, token_index);
3319 opt_ctx.store(&node.base);
3320
3321 return node;
3322}
3323
3324fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3325 const token = tok_it.peek().?;
3326
3327 if (token.id == id) {
3328 return nextToken(tok_it, tree).index;
3329 }
3330
3331 return null;
3332}
3333
3334fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedToken {
3335 const result = AnnotatedToken{
3336 .index = tok_it.index,
3337 .ptr = tok_it.next().?,
3338 };
3339 assert(result.ptr.id != Token.Id.LineComment);
3340
3341 while (true) {
3342 const next_tok = tok_it.peek() orelse return result;
3343 if (next_tok.id != Token.Id.LineComment) return result;
3344 _ = tok_it.next();
3345 }
3346}
3347
3348fn prevToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) void {
3349 while (true) {
3350 const prev_tok = tok_it.prev() orelse return;
3351 if (prev_tok.id == Token.Id.LineComment) continue;
3352 return;
3353 }
3354}
3355
3356test "std.zig.parser" {
3357 _ = @import("parser_test.zig");
3358}
std/zig/parse_string_literal.zig created+76
......@@ -0,0 +1,76 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3
4const State = enum {
5 Start,
6 Backslash,
7};
8
9pub const ParseStringLiteralError = error{
10 OutOfMemory,
11
12 /// When this is returned, index will be the position of the character.
13 InvalidCharacter,
14};
15
16/// caller owns returned memory
17pub fn parseStringLiteral(
18 allocator: *std.mem.Allocator,
19 bytes: []const u8,
20 bad_index: *usize, // populated if error.InvalidCharacter is returned
21) ParseStringLiteralError![]u8 {
22 const first_index = if (bytes[0] == 'c') usize(2) else usize(1);
23 assert(bytes[bytes.len - 1] == '"');
24
25 var list = std.ArrayList(u8).init(allocator);
26 errdefer list.deinit();
27
28 const slice = bytes[first_index..];
29 try list.ensureCapacity(slice.len - 1);
30
31 var state = State.Start;
32 for (slice) |b, index| {
33 switch (state) {
34 State.Start => switch (b) {
35 '\\' => state = State.Backslash,
36 '\n' => {
37 bad_index.* = index;
38 return error.InvalidCharacter;
39 },
40 '"' => return list.toOwnedSlice(),
41 else => try list.append(b),
42 },
43 State.Backslash => switch (b) {
44 'x' => @panic("TODO"),
45 'u' => @panic("TODO"),
46 'U' => @panic("TODO"),
47 'n' => {
48 try list.append('\n');
49 state = State.Start;
50 },
51 'r' => {
52 try list.append('\r');
53 state = State.Start;
54 },
55 '\\' => {
56 try list.append('\\');
57 state = State.Start;
58 },
59 't' => {
60 try list.append('\t');
61 state = State.Start;
62 },
63 '"' => {
64 try list.append('"');
65 state = State.Start;
66 },
67 else => {
68 bad_index.* = index;
69 return error.InvalidCharacter;
70 },
71 },
72 else => unreachable,
73 }
74 }
75 unreachable;
76}
std/zig/parser.zig deleted-5265
......@@ -1,5265 +0,0 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const ArrayList = std.ArrayList;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Tokenizer = std.zig.Tokenizer;
7const Token = std.zig.Token;
8const builtin = @import("builtin");
9const io = std.io;
10
11// TODO when we make parse errors into error types instead of printing directly,
12// get rid of this
13const warn = std.debug.warn;
14
15pub const Parser = struct {
16 util_allocator: &mem.Allocator,
17 tokenizer: &Tokenizer,
18 put_back_tokens: [2]Token,
19 put_back_count: usize,
20 source_file_name: []const u8,
21 pending_line_comment_node: ?&ast.NodeLineComment,
22
23 pub const Tree = struct {
24 root_node: &ast.NodeRoot,
25 arena_allocator: std.heap.ArenaAllocator,
26
27 pub fn deinit(self: &Tree) void {
28 self.arena_allocator.deinit();
29 }
30 };
31
32 // This memory contents are used only during a function call. It's used to repurpose memory;
33 // we reuse the same bytes for the stack data structure used by parsing, tree rendering, and
34 // source rendering.
35 const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } );
36 utility_bytes: []align(utility_bytes_align) u8,
37
38 /// allocator must outlive the returned Parser and all the parse trees you create with it.
39 pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) Parser {
40 return Parser {
41 .util_allocator = allocator,
42 .tokenizer = tokenizer,
43 .put_back_tokens = undefined,
44 .put_back_count = 0,
45 .source_file_name = source_file_name,
46 .utility_bytes = []align(utility_bytes_align) u8{},
47 .pending_line_comment_node = null,
48 };
49 }
50
51 pub fn deinit(self: &Parser) void {
52 self.util_allocator.free(self.utility_bytes);
53 }
54
55 const TopLevelDeclCtx = struct {
56 decls: &ArrayList(&ast.Node),
57 visib_token: ?Token,
58 extern_export_inline_token: ?Token,
59 lib_name: ?&ast.Node,
60 };
61
62 const VarDeclCtx = struct {
63 mut_token: Token,
64 visib_token: ?Token,
65 comptime_token: ?Token,
66 extern_export_token: ?Token,
67 lib_name: ?&ast.Node,
68 list: &ArrayList(&ast.Node),
69 };
70
71 const TopLevelExternOrFieldCtx = struct {
72 visib_token: Token,
73 container_decl: &ast.NodeContainerDecl,
74 };
75
76 const ExternTypeCtx = struct {
77 opt_ctx: OptionalCtx,
78 extern_token: Token,
79 };
80
81 const ContainerKindCtx = struct {
82 opt_ctx: OptionalCtx,
83 ltoken: Token,
84 layout: ast.NodeContainerDecl.Layout,
85 };
86
87 const ExpectTokenSave = struct {
88 id: Token.Id,
89 ptr: &Token,
90 };
91
92 const OptionalTokenSave = struct {
93 id: Token.Id,
94 ptr: &?Token,
95 };
96
97 const ExprListCtx = struct {
98 list: &ArrayList(&ast.Node),
99 end: Token.Id,
100 ptr: &Token,
101 };
102
103 fn ListSave(comptime T: type) type {
104 return struct {
105 list: &ArrayList(T),
106 ptr: &Token,
107 };
108 }
109
110 const MaybeLabeledExpressionCtx = struct {
111 label: Token,
112 opt_ctx: OptionalCtx,
113 };
114
115 const LabelCtx = struct {
116 label: ?Token,
117 opt_ctx: OptionalCtx,
118 };
119
120 const InlineCtx = struct {
121 label: ?Token,
122 inline_token: ?Token,
123 opt_ctx: OptionalCtx,
124 };
125
126 const LoopCtx = struct {
127 label: ?Token,
128 inline_token: ?Token,
129 loop_token: Token,
130 opt_ctx: OptionalCtx,
131 };
132
133 const AsyncEndCtx = struct {
134 ctx: OptionalCtx,
135 attribute: &ast.NodeAsyncAttribute,
136 };
137
138 const ErrorTypeOrSetDeclCtx = struct {
139 opt_ctx: OptionalCtx,
140 error_token: Token,
141 };
142
143 const ParamDeclEndCtx = struct {
144 fn_proto: &ast.NodeFnProto,
145 param_decl: &ast.NodeParamDecl,
146 };
147
148 const ComptimeStatementCtx = struct {
149 comptime_token: Token,
150 block: &ast.NodeBlock,
151 };
152
153 const OptionalCtx = union(enum) {
154 Optional: &?&ast.Node,
155 RequiredNull: &?&ast.Node,
156 Required: &&ast.Node,
157
158 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
159 switch (*self) {
160 OptionalCtx.Optional => |ptr| *ptr = value,
161 OptionalCtx.RequiredNull => |ptr| *ptr = value,
162 OptionalCtx.Required => |ptr| *ptr = value,
163 }
164 }
165
166 pub fn get(self: &const OptionalCtx) ?&ast.Node {
167 switch (*self) {
168 OptionalCtx.Optional => |ptr| return *ptr,
169 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
170 OptionalCtx.Required => |ptr| return *ptr,
171 }
172 }
173
174 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
175 switch (*self) {
176 OptionalCtx.Optional => |ptr| {
177 return OptionalCtx { .RequiredNull = ptr };
178 },
179 OptionalCtx.RequiredNull => |ptr| return *self,
180 OptionalCtx.Required => |ptr| return *self,
181 }
182 }
183 };
184
185 const State = union(enum) {
186 TopLevel,
187 TopLevelExtern: TopLevelDeclCtx,
188 TopLevelLibname: TopLevelDeclCtx,
189 TopLevelDecl: TopLevelDeclCtx,
190 TopLevelExternOrField: TopLevelExternOrFieldCtx,
191
192 ContainerKind: ContainerKindCtx,
193 ContainerInitArgStart: &ast.NodeContainerDecl,
194 ContainerInitArg: &ast.NodeContainerDecl,
195 ContainerDecl: &ast.NodeContainerDecl,
196
197 VarDecl: VarDeclCtx,
198 VarDeclAlign: &ast.NodeVarDecl,
199 VarDeclEq: &ast.NodeVarDecl,
200
201 FnDef: &ast.NodeFnProto,
202 FnProto: &ast.NodeFnProto,
203 FnProtoAlign: &ast.NodeFnProto,
204 FnProtoReturnType: &ast.NodeFnProto,
205
206 ParamDecl: &ast.NodeFnProto,
207 ParamDeclAliasOrComptime: &ast.NodeParamDecl,
208 ParamDeclName: &ast.NodeParamDecl,
209 ParamDeclEnd: ParamDeclEndCtx,
210 ParamDeclComma: &ast.NodeFnProto,
211
212 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
213 LabeledExpression: LabelCtx,
214 Inline: InlineCtx,
215 While: LoopCtx,
216 WhileContinueExpr: &?&ast.Node,
217 For: LoopCtx,
218 Else: &?&ast.NodeElse,
219
220 Block: &ast.NodeBlock,
221 Statement: &ast.NodeBlock,
222 ComptimeStatement: ComptimeStatementCtx,
223 Semicolon: &&ast.Node,
224
225 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
226 AsmOutputReturnOrType: &ast.NodeAsmOutput,
227 AsmInputItems: &ArrayList(&ast.NodeAsmInput),
228 AsmClopperItems: &ArrayList(&ast.Node),
229
230 ExprListItemOrEnd: ExprListCtx,
231 ExprListCommaOrEnd: ExprListCtx,
232 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
233 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
234 FieldListCommaOrEnd: &ast.NodeContainerDecl,
235 IdentifierListItemOrEnd: ListSave(&ast.Node),
236 IdentifierListCommaOrEnd: ListSave(&ast.Node),
237 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
238 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
239 SwitchCaseFirstItem: &ArrayList(&ast.Node),
240 SwitchCaseItem: &ArrayList(&ast.Node),
241 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
242
243 SuspendBody: &ast.NodeSuspend,
244 AsyncAllocator: &ast.NodeAsyncAttribute,
245 AsyncEnd: AsyncEndCtx,
246
247 ExternType: ExternTypeCtx,
248 SliceOrArrayAccess: &ast.NodeSuffixOp,
249 SliceOrArrayType: &ast.NodePrefixOp,
250 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
251
252 Payload: OptionalCtx,
253 PointerPayload: OptionalCtx,
254 PointerIndexPayload: OptionalCtx,
255
256 Expression: OptionalCtx,
257 RangeExpressionBegin: OptionalCtx,
258 RangeExpressionEnd: OptionalCtx,
259 AssignmentExpressionBegin: OptionalCtx,
260 AssignmentExpressionEnd: OptionalCtx,
261 UnwrapExpressionBegin: OptionalCtx,
262 UnwrapExpressionEnd: OptionalCtx,
263 BoolOrExpressionBegin: OptionalCtx,
264 BoolOrExpressionEnd: OptionalCtx,
265 BoolAndExpressionBegin: OptionalCtx,
266 BoolAndExpressionEnd: OptionalCtx,
267 ComparisonExpressionBegin: OptionalCtx,
268 ComparisonExpressionEnd: OptionalCtx,
269 BinaryOrExpressionBegin: OptionalCtx,
270 BinaryOrExpressionEnd: OptionalCtx,
271 BinaryXorExpressionBegin: OptionalCtx,
272 BinaryXorExpressionEnd: OptionalCtx,
273 BinaryAndExpressionBegin: OptionalCtx,
274 BinaryAndExpressionEnd: OptionalCtx,
275 BitShiftExpressionBegin: OptionalCtx,
276 BitShiftExpressionEnd: OptionalCtx,
277 AdditionExpressionBegin: OptionalCtx,
278 AdditionExpressionEnd: OptionalCtx,
279 MultiplyExpressionBegin: OptionalCtx,
280 MultiplyExpressionEnd: OptionalCtx,
281 CurlySuffixExpressionBegin: OptionalCtx,
282 CurlySuffixExpressionEnd: OptionalCtx,
283 TypeExprBegin: OptionalCtx,
284 TypeExprEnd: OptionalCtx,
285 PrefixOpExpression: OptionalCtx,
286 SuffixOpExpressionBegin: OptionalCtx,
287 SuffixOpExpressionEnd: OptionalCtx,
288 PrimaryExpression: OptionalCtx,
289
290 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
291 StringLiteral: OptionalCtx,
292 Identifier: OptionalCtx,
293
294
295 IfToken: @TagType(Token.Id),
296 IfTokenSave: ExpectTokenSave,
297 ExpectToken: @TagType(Token.Id),
298 ExpectTokenSave: ExpectTokenSave,
299 OptionalTokenSave: OptionalTokenSave,
300 };
301
302 /// Returns an AST tree, allocated with the parser's allocator.
303 /// Result should be freed with tree.deinit() when there are
304 /// no more references to any AST nodes of the tree.
305 pub fn parse(self: &Parser) !Tree {
306 var stack = self.initUtilityArrayList(State);
307 defer self.deinitUtilityArrayList(stack);
308
309 var arena_allocator = std.heap.ArenaAllocator.init(self.util_allocator);
310 errdefer arena_allocator.deinit();
311
312 const arena = &arena_allocator.allocator;
313 const root_node = try self.createNode(arena, ast.NodeRoot,
314 ast.NodeRoot {
315 .base = undefined,
316 .decls = ArrayList(&ast.Node).init(arena),
317 // initialized when we get the eof token
318 .eof_token = undefined,
319 }
320 );
321
322 try stack.append(State.TopLevel);
323
324 while (true) {
325 //{
326 // const token = self.getNextToken();
327 // warn("{} ", @tagName(token.id));
328 // self.putBackToken(token);
329 // var i: usize = stack.len;
330 // while (i != 0) {
331 // i -= 1;
332 // warn("{} ", @tagName(stack.items[i]));
333 // }
334 // warn("\n");
335 //}
336
337 // look for line comments
338 while (true) {
339 if (self.eatToken(Token.Id.LineComment)) |line_comment| {
340 const node = blk: {
341 if (self.pending_line_comment_node) |comment_node| {
342 break :blk comment_node;
343 } else {
344 const comment_node = try arena.create(ast.NodeLineComment);
345 *comment_node = ast.NodeLineComment {
346 .base = ast.Node {
347 .id = ast.Node.Id.LineComment,
348 .comment = null,
349 },
350 .lines = ArrayList(Token).init(arena),
351 };
352 self.pending_line_comment_node = comment_node;
353 break :blk comment_node;
354 }
355 };
356 try node.lines.append(line_comment);
357 continue;
358 }
359 break;
360 }
361
362 // This gives us 1 free append that can't fail
363 const state = stack.pop();
364
365 switch (state) {
366 State.TopLevel => {
367 const token = self.getNextToken();
368 switch (token.id) {
369 Token.Id.Keyword_test => {
370 stack.append(State.TopLevel) catch unreachable;
371
372 const block = try self.createNode(arena, ast.NodeBlock,
373 ast.NodeBlock {
374 .base = undefined,
375 .label = null,
376 .lbrace = undefined,
377 .statements = ArrayList(&ast.Node).init(arena),
378 .rbrace = undefined,
379 }
380 );
381 const test_node = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
382 ast.NodeTestDecl {
383 .base = undefined,
384 .test_token = token,
385 .name = undefined,
386 .body_node = &block.base,
387 }
388 );
389 stack.append(State { .Block = block }) catch unreachable;
390 try stack.append(State {
391 .ExpectTokenSave = ExpectTokenSave {
392 .id = Token.Id.LBrace,
393 .ptr = &block.rbrace,
394 }
395 });
396 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
397 continue;
398 },
399 Token.Id.Eof => {
400 root_node.eof_token = token;
401 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
402 },
403 Token.Id.Keyword_pub => {
404 stack.append(State.TopLevel) catch unreachable;
405 try stack.append(State {
406 .TopLevelExtern = TopLevelDeclCtx {
407 .decls = &root_node.decls,
408 .visib_token = token,
409 .extern_export_inline_token = null,
410 .lib_name = null,
411 }
412 });
413 continue;
414 },
415 Token.Id.Keyword_comptime => {
416 const block = try self.createNode(arena, ast.NodeBlock,
417 ast.NodeBlock {
418 .base = undefined,
419 .label = null,
420 .lbrace = undefined,
421 .statements = ArrayList(&ast.Node).init(arena),
422 .rbrace = undefined,
423 }
424 );
425 const node = try self.createAttachNode(arena, &root_node.decls, ast.NodeComptime,
426 ast.NodeComptime {
427 .base = undefined,
428 .comptime_token = token,
429 .expr = &block.base,
430 }
431 );
432 stack.append(State.TopLevel) catch unreachable;
433 try stack.append(State { .Block = block });
434 try stack.append(State {
435 .ExpectTokenSave = ExpectTokenSave {
436 .id = Token.Id.LBrace,
437 .ptr = &block.rbrace,
438 }
439 });
440 continue;
441 },
442 else => {
443 self.putBackToken(token);
444 stack.append(State.TopLevel) catch unreachable;
445 try stack.append(State {
446 .TopLevelExtern = TopLevelDeclCtx {
447 .decls = &root_node.decls,
448 .visib_token = null,
449 .extern_export_inline_token = null,
450 .lib_name = null,
451 }
452 });
453 continue;
454 },
455 }
456 },
457 State.TopLevelExtern => |ctx| {
458 const token = self.getNextToken();
459 switch (token.id) {
460 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
461 stack.append(State {
462 .TopLevelDecl = TopLevelDeclCtx {
463 .decls = ctx.decls,
464 .visib_token = ctx.visib_token,
465 .extern_export_inline_token = token,
466 .lib_name = null,
467 },
468 }) catch unreachable;
469 continue;
470 },
471 Token.Id.Keyword_extern => {
472 stack.append(State {
473 .TopLevelLibname = TopLevelDeclCtx {
474 .decls = ctx.decls,
475 .visib_token = ctx.visib_token,
476 .extern_export_inline_token = token,
477 .lib_name = null,
478 },
479 }) catch unreachable;
480 continue;
481 },
482 else => {
483 self.putBackToken(token);
484 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
485 continue;
486 }
487 }
488 },
489 State.TopLevelLibname => |ctx| {
490 const lib_name = blk: {
491 const lib_name_token = self.getNextToken();
492 break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? {
493 self.putBackToken(lib_name_token);
494 break :blk null;
495 };
496 };
497
498 stack.append(State {
499 .TopLevelDecl = TopLevelDeclCtx {
500 .decls = ctx.decls,
501 .visib_token = ctx.visib_token,
502 .extern_export_inline_token = ctx.extern_export_inline_token,
503 .lib_name = lib_name,
504 },
505 }) catch unreachable;
506 continue;
507 },
508 State.TopLevelDecl => |ctx| {
509 const token = self.getNextToken();
510 switch (token.id) {
511 Token.Id.Keyword_use => {
512 if (ctx.extern_export_inline_token != null) {
513 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
514 }
515
516 const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
517 ast.NodeUse {
518 .base = undefined,
519 .visib_token = ctx.visib_token,
520 .expr = undefined,
521 .semicolon_token = undefined,
522 }
523 );
524 stack.append(State {
525 .ExpectTokenSave = ExpectTokenSave {
526 .id = Token.Id.Semicolon,
527 .ptr = &node.semicolon_token,
528 }
529 }) catch unreachable;
530 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
531 continue;
532 },
533 Token.Id.Keyword_var, Token.Id.Keyword_const => {
534 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
535 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
536 return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
537 }
538 }
539
540 stack.append(State {
541 .VarDecl = VarDeclCtx {
542 .visib_token = ctx.visib_token,
543 .lib_name = ctx.lib_name,
544 .comptime_token = null,
545 .extern_export_token = ctx.extern_export_inline_token,
546 .mut_token = token,
547 .list = ctx.decls
548 }
549 }) catch unreachable;
550 continue;
551 },
552 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
553 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
554 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
555 ast.NodeFnProto {
556 .base = undefined,
557 .visib_token = ctx.visib_token,
558 .name_token = null,
559 .fn_token = undefined,
560 .params = ArrayList(&ast.Node).init(arena),
561 .return_type = undefined,
562 .var_args_token = null,
563 .extern_export_inline_token = ctx.extern_export_inline_token,
564 .cc_token = null,
565 .async_attr = null,
566 .body_node = null,
567 .lib_name = ctx.lib_name,
568 .align_expr = null,
569 }
570 );
571 stack.append(State { .FnDef = fn_proto }) catch unreachable;
572 try stack.append(State { .FnProto = fn_proto });
573
574 switch (token.id) {
575 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
576 fn_proto.cc_token = token;
577 try stack.append(State {
578 .ExpectTokenSave = ExpectTokenSave {
579 .id = Token.Id.Keyword_fn,
580 .ptr = &fn_proto.fn_token,
581 }
582 });
583 continue;
584 },
585 Token.Id.Keyword_async => {
586 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
587 ast.NodeAsyncAttribute {
588 .base = undefined,
589 .async_token = token,
590 .allocator_type = null,
591 .rangle_bracket = null,
592 }
593 );
594 fn_proto.async_attr = async_node;
595
596 try stack.append(State {
597 .ExpectTokenSave = ExpectTokenSave {
598 .id = Token.Id.Keyword_fn,
599 .ptr = &fn_proto.fn_token,
600 }
601 });
602 try stack.append(State { .AsyncAllocator = async_node });
603 continue;
604 },
605 Token.Id.Keyword_fn => {
606 fn_proto.fn_token = token;
607 continue;
608 },
609 else => unreachable,
610 }
611 },
612 else => {
613 return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
614 },
615 }
616 },
617 State.TopLevelExternOrField => |ctx| {
618 if (self.eatToken(Token.Id.Identifier)) |identifier| {
619 std.debug.assert(ctx.container_decl.kind == ast.NodeContainerDecl.Kind.Struct);
620 const node = try self.createAttachNode(arena, &ctx.container_decl.fields_and_decls, ast.NodeStructField,
621 ast.NodeStructField {
622 .base = undefined,
623 .visib_token = ctx.visib_token,
624 .name_token = identifier,
625 .type_expr = undefined,
626 }
627 );
628
629 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
630 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
631 try stack.append(State { .ExpectToken = Token.Id.Colon });
632 continue;
633 }
634
635 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
636 try stack.append(State {
637 .TopLevelExtern = TopLevelDeclCtx {
638 .decls = &ctx.container_decl.fields_and_decls,
639 .visib_token = ctx.visib_token,
640 .extern_export_inline_token = null,
641 .lib_name = null,
642 }
643 });
644 continue;
645 },
646
647
648 State.ContainerKind => |ctx| {
649 const token = self.getNextToken();
650 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeContainerDecl,
651 ast.NodeContainerDecl {
652 .base = undefined,
653 .ltoken = ctx.ltoken,
654 .layout = ctx.layout,
655 .kind = switch (token.id) {
656 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
657 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
658 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
659 else => {
660 return self.parseError(token, "expected {}, {} or {}, found {}",
661 @tagName(Token.Id.Keyword_struct),
662 @tagName(Token.Id.Keyword_union),
663 @tagName(Token.Id.Keyword_enum),
664 @tagName(token.id));
665 },
666 },
667 .init_arg_expr = ast.NodeContainerDecl.InitArg.None,
668 .fields_and_decls = ArrayList(&ast.Node).init(arena),
669 .rbrace_token = undefined,
670 }
671 );
672
673 stack.append(State { .ContainerDecl = node }) catch unreachable;
674 try stack.append(State { .ExpectToken = Token.Id.LBrace });
675 try stack.append(State { .ContainerInitArgStart = node });
676 continue;
677 },
678
679 State.ContainerInitArgStart => |container_decl| {
680 if (self.eatToken(Token.Id.LParen) == null) {
681 continue;
682 }
683
684 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
685 try stack.append(State { .ContainerInitArg = container_decl });
686 continue;
687 },
688
689 State.ContainerInitArg => |container_decl| {
690 const init_arg_token = self.getNextToken();
691 switch (init_arg_token.id) {
692 Token.Id.Keyword_enum => {
693 container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
694 },
695 else => {
696 self.putBackToken(init_arg_token);
697 container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
698 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
699 },
700 }
701 continue;
702 },
703 State.ContainerDecl => |container_decl| {
704 const token = self.getNextToken();
705 switch (token.id) {
706 Token.Id.Identifier => {
707 switch (container_decl.kind) {
708 ast.NodeContainerDecl.Kind.Struct => {
709 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
710 ast.NodeStructField {
711 .base = undefined,
712 .visib_token = null,
713 .name_token = token,
714 .type_expr = undefined,
715 }
716 );
717
718 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
719 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
720 try stack.append(State { .ExpectToken = Token.Id.Colon });
721 continue;
722 },
723 ast.NodeContainerDecl.Kind.Union => {
724 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeUnionTag,
725 ast.NodeUnionTag {
726 .base = undefined,
727 .name_token = token,
728 .type_expr = null,
729 }
730 );
731
732 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
733 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
734 try stack.append(State { .IfToken = Token.Id.Colon });
735 continue;
736 },
737 ast.NodeContainerDecl.Kind.Enum => {
738 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeEnumTag,
739 ast.NodeEnumTag {
740 .base = undefined,
741 .name_token = token,
742 .value = null,
743 }
744 );
745
746 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
747 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
748 try stack.append(State { .IfToken = Token.Id.Equal });
749 continue;
750 },
751 }
752 },
753 Token.Id.Keyword_pub => {
754 switch (container_decl.kind) {
755 ast.NodeContainerDecl.Kind.Struct => {
756 try stack.append(State {
757 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
758 .visib_token = token,
759 .container_decl = container_decl,
760 }
761 });
762 continue;
763 },
764 else => {
765 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
766 try stack.append(State {
767 .TopLevelExtern = TopLevelDeclCtx {
768 .decls = &container_decl.fields_and_decls,
769 .visib_token = token,
770 .extern_export_inline_token = null,
771 .lib_name = null,
772 }
773 });
774 continue;
775 }
776 }
777 },
778 Token.Id.Keyword_export => {
779 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
780 try stack.append(State {
781 .TopLevelExtern = TopLevelDeclCtx {
782 .decls = &container_decl.fields_and_decls,
783 .visib_token = token,
784 .extern_export_inline_token = null,
785 .lib_name = null,
786 }
787 });
788 continue;
789 },
790 Token.Id.RBrace => {
791 container_decl.rbrace_token = token;
792 continue;
793 },
794 else => {
795 self.putBackToken(token);
796 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
797 try stack.append(State {
798 .TopLevelExtern = TopLevelDeclCtx {
799 .decls = &container_decl.fields_and_decls,
800 .visib_token = null,
801 .extern_export_inline_token = null,
802 .lib_name = null,
803 }
804 });
805 continue;
806 }
807 }
808 },
809
810
811 State.VarDecl => |ctx| {
812 const var_decl = try self.createAttachNode(arena, ctx.list, ast.NodeVarDecl,
813 ast.NodeVarDecl {
814 .base = undefined,
815 .visib_token = ctx.visib_token,
816 .mut_token = ctx.mut_token,
817 .comptime_token = ctx.comptime_token,
818 .extern_export_token = ctx.extern_export_token,
819 .type_node = null,
820 .align_node = null,
821 .init_node = null,
822 .lib_name = ctx.lib_name,
823 // initialized later
824 .name_token = undefined,
825 .eq_token = undefined,
826 .semicolon_token = undefined,
827 }
828 );
829
830 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
831 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
832 try stack.append(State { .IfToken = Token.Id.Colon });
833 try stack.append(State {
834 .ExpectTokenSave = ExpectTokenSave {
835 .id = Token.Id.Identifier,
836 .ptr = &var_decl.name_token,
837 }
838 });
839 continue;
840 },
841 State.VarDeclAlign => |var_decl| {
842 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
843
844 const next_token = self.getNextToken();
845 if (next_token.id == Token.Id.Keyword_align) {
846 try stack.append(State { .ExpectToken = Token.Id.RParen });
847 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
848 try stack.append(State { .ExpectToken = Token.Id.LParen });
849 continue;
850 }
851
852 self.putBackToken(next_token);
853 continue;
854 },
855 State.VarDeclEq => |var_decl| {
856 const token = self.getNextToken();
857 switch (token.id) {
858 Token.Id.Equal => {
859 var_decl.eq_token = token;
860 stack.append(State {
861 .ExpectTokenSave = ExpectTokenSave {
862 .id = Token.Id.Semicolon,
863 .ptr = &var_decl.semicolon_token,
864 },
865 }) catch unreachable;
866 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
867 continue;
868 },
869 Token.Id.Semicolon => {
870 var_decl.semicolon_token = token;
871 continue;
872 },
873 else => {
874 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
875 }
876 }
877 },
878
879
880 State.FnDef => |fn_proto| {
881 const token = self.getNextToken();
882 switch(token.id) {
883 Token.Id.LBrace => {
884 const block = try self.createNode(arena, ast.NodeBlock,
885 ast.NodeBlock {
886 .base = undefined,
887 .label = null,
888 .lbrace = token,
889 .statements = ArrayList(&ast.Node).init(arena),
890 .rbrace = undefined,
891 }
892 );
893 fn_proto.body_node = &block.base;
894 stack.append(State { .Block = block }) catch unreachable;
895 continue;
896 },
897 Token.Id.Semicolon => continue,
898 else => {
899 return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id));
900 },
901 }
902 },
903 State.FnProto => |fn_proto| {
904 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
905 try stack.append(State { .ParamDecl = fn_proto });
906 try stack.append(State { .ExpectToken = Token.Id.LParen });
907
908 if (self.eatToken(Token.Id.Identifier)) |name_token| {
909 fn_proto.name_token = name_token;
910 }
911 continue;
912 },
913 State.FnProtoAlign => |fn_proto| {
914 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
915
916 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
917 try stack.append(State { .ExpectToken = Token.Id.RParen });
918 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
919 try stack.append(State { .ExpectToken = Token.Id.LParen });
920 }
921 continue;
922 },
923 State.FnProtoReturnType => |fn_proto| {
924 const token = self.getNextToken();
925 switch (token.id) {
926 Token.Id.Bang => {
927 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
928 stack.append(State {
929 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
930 }) catch unreachable;
931 continue;
932 },
933 else => {
934 // TODO: this is a special case. Remove this when #760 is fixed
935 if (token.id == Token.Id.Keyword_error) {
936 if (self.isPeekToken(Token.Id.LBrace)) {
937 fn_proto.return_type = ast.NodeFnProto.ReturnType {
938 .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base
939 };
940 continue;
941 }
942 }
943
944 self.putBackToken(token);
945 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
946 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
947 continue;
948 },
949 }
950 },
951
952
953 State.ParamDecl => |fn_proto| {
954 if (self.eatToken(Token.Id.RParen)) |_| {
955 continue;
956 }
957 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
958 ast.NodeParamDecl {
959 .base = undefined,
960 .comptime_token = null,
961 .noalias_token = null,
962 .name_token = null,
963 .type_node = undefined,
964 .var_args_token = null,
965 },
966 );
967
968 stack.append(State {
969 .ParamDeclEnd = ParamDeclEndCtx {
970 .param_decl = param_decl,
971 .fn_proto = fn_proto,
972 }
973 }) catch unreachable;
974 try stack.append(State { .ParamDeclName = param_decl });
975 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
976 continue;
977 },
978 State.ParamDeclAliasOrComptime => |param_decl| {
979 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
980 param_decl.comptime_token = comptime_token;
981 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
982 param_decl.noalias_token = noalias_token;
983 }
984 continue;
985 },
986 State.ParamDeclName => |param_decl| {
987 // TODO: Here, we eat two tokens in one state. This means that we can't have
988 // comments between these two tokens.
989 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
990 if (self.eatToken(Token.Id.Colon)) |_| {
991 param_decl.name_token = ident_token;
992 } else {
993 self.putBackToken(ident_token);
994 }
995 }
996 continue;
997 },
998 State.ParamDeclEnd => |ctx| {
999 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1000 ctx.param_decl.var_args_token = ellipsis3;
1001 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1002 continue;
1003 }
1004
1005 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
1006 try stack.append(State {
1007 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
1008 });
1009 continue;
1010 },
1011 State.ParamDeclComma => |fn_proto| {
1012 if ((try self.expectCommaOrEnd(Token.Id.RParen)) == null) {
1013 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
1014 }
1015 continue;
1016 },
1017
1018 State.MaybeLabeledExpression => |ctx| {
1019 if (self.eatToken(Token.Id.Colon)) |_| {
1020 stack.append(State {
1021 .LabeledExpression = LabelCtx {
1022 .label = ctx.label,
1023 .opt_ctx = ctx.opt_ctx,
1024 }
1025 }) catch unreachable;
1026 continue;
1027 }
1028
1029 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeIdentifier, ctx.label);
1030 continue;
1031 },
1032 State.LabeledExpression => |ctx| {
1033 const token = self.getNextToken();
1034 switch (token.id) {
1035 Token.Id.LBrace => {
1036 const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeBlock,
1037 ast.NodeBlock {
1038 .base = undefined,
1039 .label = ctx.label,
1040 .lbrace = token,
1041 .statements = ArrayList(&ast.Node).init(arena),
1042 .rbrace = undefined,
1043 }
1044 );
1045 stack.append(State { .Block = block }) catch unreachable;
1046 continue;
1047 },
1048 Token.Id.Keyword_while => {
1049 stack.append(State {
1050 .While = LoopCtx {
1051 .label = ctx.label,
1052 .inline_token = null,
1053 .loop_token = token,
1054 .opt_ctx = ctx.opt_ctx.toRequired(),
1055 }
1056 }) catch unreachable;
1057 continue;
1058 },
1059 Token.Id.Keyword_for => {
1060 stack.append(State {
1061 .For = LoopCtx {
1062 .label = ctx.label,
1063 .inline_token = null,
1064 .loop_token = token,
1065 .opt_ctx = ctx.opt_ctx.toRequired(),
1066 }
1067 }) catch unreachable;
1068 continue;
1069 },
1070 Token.Id.Keyword_inline => {
1071 stack.append(State {
1072 .Inline = InlineCtx {
1073 .label = ctx.label,
1074 .inline_token = token,
1075 .opt_ctx = ctx.opt_ctx.toRequired(),
1076 }
1077 }) catch unreachable;
1078 continue;
1079 },
1080 else => {
1081 if (ctx.opt_ctx != OptionalCtx.Optional) {
1082 return self.parseError(token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
1083 }
1084
1085 self.putBackToken(token);
1086 continue;
1087 },
1088 }
1089 },
1090 State.Inline => |ctx| {
1091 const token = self.getNextToken();
1092 switch (token.id) {
1093 Token.Id.Keyword_while => {
1094 stack.append(State {
1095 .While = LoopCtx {
1096 .inline_token = ctx.inline_token,
1097 .label = ctx.label,
1098 .loop_token = token,
1099 .opt_ctx = ctx.opt_ctx.toRequired(),
1100 }
1101 }) catch unreachable;
1102 continue;
1103 },
1104 Token.Id.Keyword_for => {
1105 stack.append(State {
1106 .For = LoopCtx {
1107 .inline_token = ctx.inline_token,
1108 .label = ctx.label,
1109 .loop_token = token,
1110 .opt_ctx = ctx.opt_ctx.toRequired(),
1111 }
1112 }) catch unreachable;
1113 continue;
1114 },
1115 else => {
1116 if (ctx.opt_ctx != OptionalCtx.Optional) {
1117 return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
1118 }
1119
1120 self.putBackToken(token);
1121 continue;
1122 },
1123 }
1124 },
1125 State.While => |ctx| {
1126 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeWhile,
1127 ast.NodeWhile {
1128 .base = undefined,
1129 .label = ctx.label,
1130 .inline_token = ctx.inline_token,
1131 .while_token = ctx.loop_token,
1132 .condition = undefined,
1133 .payload = null,
1134 .continue_expr = null,
1135 .body = undefined,
1136 .@"else" = null,
1137 }
1138 );
1139 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1140 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1141 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
1142 try stack.append(State { .IfToken = Token.Id.Colon });
1143 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1144 try stack.append(State { .ExpectToken = Token.Id.RParen });
1145 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
1146 try stack.append(State { .ExpectToken = Token.Id.LParen });
1147 continue;
1148 },
1149 State.WhileContinueExpr => |dest| {
1150 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1151 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
1152 try stack.append(State { .ExpectToken = Token.Id.LParen });
1153 continue;
1154 },
1155 State.For => |ctx| {
1156 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFor,
1157 ast.NodeFor {
1158 .base = undefined,
1159 .label = ctx.label,
1160 .inline_token = ctx.inline_token,
1161 .for_token = ctx.loop_token,
1162 .array_expr = undefined,
1163 .payload = null,
1164 .body = undefined,
1165 .@"else" = null,
1166 }
1167 );
1168 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1169 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1170 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1171 try stack.append(State { .ExpectToken = Token.Id.RParen });
1172 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1173 try stack.append(State { .ExpectToken = Token.Id.LParen });
1174 continue;
1175 },
1176 State.Else => |dest| {
1177 if (self.eatToken(Token.Id.Keyword_else)) |else_token| {
1178 const node = try self.createNode(arena, ast.NodeElse,
1179 ast.NodeElse {
1180 .base = undefined,
1181 .else_token = else_token,
1182 .payload = null,
1183 .body = undefined,
1184 }
1185 );
1186 *dest = node;
1187
1188 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1189 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1190 continue;
1191 } else {
1192 continue;
1193 }
1194 },
1195
1196
1197 State.Block => |block| {
1198 const token = self.getNextToken();
1199 switch (token.id) {
1200 Token.Id.RBrace => {
1201 block.rbrace = token;
1202 continue;
1203 },
1204 else => {
1205 self.putBackToken(token);
1206 stack.append(State { .Block = block }) catch unreachable;
1207 try stack.append(State { .Statement = block });
1208 continue;
1209 },
1210 }
1211 },
1212 State.Statement => |block| {
1213 const token = self.getNextToken();
1214 switch (token.id) {
1215 Token.Id.Keyword_comptime => {
1216 stack.append(State {
1217 .ComptimeStatement = ComptimeStatementCtx {
1218 .comptime_token = token,
1219 .block = block,
1220 }
1221 }) catch unreachable;
1222 continue;
1223 },
1224 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1225 stack.append(State {
1226 .VarDecl = VarDeclCtx {
1227 .visib_token = null,
1228 .comptime_token = null,
1229 .extern_export_token = null,
1230 .lib_name = null,
1231 .mut_token = token,
1232 .list = &block.statements,
1233 }
1234 }) catch unreachable;
1235 continue;
1236 },
1237 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1238 const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
1239 ast.NodeDefer {
1240 .base = undefined,
1241 .defer_token = token,
1242 .kind = switch (token.id) {
1243 Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
1244 Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
1245 else => unreachable,
1246 },
1247 .expr = undefined,
1248 }
1249 );
1250 stack.append(State { .Semicolon = &&node.base }) catch unreachable;
1251 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1252 continue;
1253 },
1254 Token.Id.LBrace => {
1255 const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
1256 ast.NodeBlock {
1257 .base = undefined,
1258 .label = null,
1259 .lbrace = token,
1260 .statements = ArrayList(&ast.Node).init(arena),
1261 .rbrace = undefined,
1262 }
1263 );
1264 stack.append(State { .Block = inner_block }) catch unreachable;
1265 continue;
1266 },
1267 else => {
1268 self.putBackToken(token);
1269 const statememt = try block.statements.addOne();
1270 stack.append(State { .Semicolon = statememt }) catch unreachable;
1271 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statememt } });
1272 continue;
1273 }
1274 }
1275 },
1276 State.ComptimeStatement => |ctx| {
1277 const token = self.getNextToken();
1278 switch (token.id) {
1279 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1280 stack.append(State {
1281 .VarDecl = VarDeclCtx {
1282 .visib_token = null,
1283 .comptime_token = ctx.comptime_token,
1284 .extern_export_token = null,
1285 .lib_name = null,
1286 .mut_token = token,
1287 .list = &ctx.block.statements,
1288 }
1289 }) catch unreachable;
1290 continue;
1291 },
1292 else => {
1293 self.putBackToken(token);
1294 self.putBackToken(ctx.comptime_token);
1295 const statememt = try ctx.block.statements.addOne();
1296 stack.append(State { .Semicolon = statememt }) catch unreachable;
1297 try stack.append(State { .Expression = OptionalCtx { .Required = statememt } });
1298 continue;
1299 }
1300 }
1301 },
1302 State.Semicolon => |node_ptr| {
1303 const node = *node_ptr;
1304 if (requireSemiColon(node)) {
1305 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1306 continue;
1307 }
1308 continue;
1309 },
1310
1311
1312 State.AsmOutputItems => |items| {
1313 const lbracket = self.getNextToken();
1314 if (lbracket.id != Token.Id.LBracket) {
1315 self.putBackToken(lbracket);
1316 continue;
1317 }
1318
1319 const node = try self.createNode(arena, ast.NodeAsmOutput,
1320 ast.NodeAsmOutput {
1321 .base = undefined,
1322 .symbolic_name = undefined,
1323 .constraint = undefined,
1324 .kind = undefined,
1325 }
1326 );
1327 try items.append(node);
1328
1329 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1330 try stack.append(State { .IfToken = Token.Id.Comma });
1331 try stack.append(State { .ExpectToken = Token.Id.RParen });
1332 try stack.append(State { .AsmOutputReturnOrType = node });
1333 try stack.append(State { .ExpectToken = Token.Id.LParen });
1334 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1335 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1336 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1337 continue;
1338 },
1339 State.AsmOutputReturnOrType => |node| {
1340 const token = self.getNextToken();
1341 switch (token.id) {
1342 Token.Id.Identifier => {
1343 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, token) };
1344 continue;
1345 },
1346 Token.Id.Arrow => {
1347 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1348 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1349 continue;
1350 },
1351 else => {
1352 return self.parseError(token, "expected '->' or {}, found {}",
1353 @tagName(Token.Id.Identifier),
1354 @tagName(token.id));
1355 },
1356 }
1357 },
1358 State.AsmInputItems => |items| {
1359 const lbracket = self.getNextToken();
1360 if (lbracket.id != Token.Id.LBracket) {
1361 self.putBackToken(lbracket);
1362 continue;
1363 }
1364
1365 const node = try self.createNode(arena, ast.NodeAsmInput,
1366 ast.NodeAsmInput {
1367 .base = undefined,
1368 .symbolic_name = undefined,
1369 .constraint = undefined,
1370 .expr = undefined,
1371 }
1372 );
1373 try items.append(node);
1374
1375 stack.append(State { .AsmInputItems = items }) catch unreachable;
1376 try stack.append(State { .IfToken = Token.Id.Comma });
1377 try stack.append(State { .ExpectToken = Token.Id.RParen });
1378 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1379 try stack.append(State { .ExpectToken = Token.Id.LParen });
1380 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1381 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1382 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1383 continue;
1384 },
1385 State.AsmClopperItems => |items| {
1386 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1387 try stack.append(State { .IfToken = Token.Id.Comma });
1388 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1389 continue;
1390 },
1391
1392
1393 State.ExprListItemOrEnd => |list_state| {
1394 if (self.eatToken(list_state.end)) |token| {
1395 *list_state.ptr = token;
1396 continue;
1397 }
1398
1399 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1400 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1401 continue;
1402 },
1403 State.ExprListCommaOrEnd => |list_state| {
1404 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1405 *list_state.ptr = end;
1406 continue;
1407 } else {
1408 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1409 continue;
1410 }
1411 },
1412 State.FieldInitListItemOrEnd => |list_state| {
1413 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1414 *list_state.ptr = rbrace;
1415 continue;
1416 }
1417
1418 const node = try self.createNode(arena, ast.NodeFieldInitializer,
1419 ast.NodeFieldInitializer {
1420 .base = undefined,
1421 .period_token = undefined,
1422 .name_token = undefined,
1423 .expr = undefined,
1424 }
1425 );
1426 try list_state.list.append(node);
1427
1428 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1429 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1430 try stack.append(State { .ExpectToken = Token.Id.Equal });
1431 try stack.append(State {
1432 .ExpectTokenSave = ExpectTokenSave {
1433 .id = Token.Id.Identifier,
1434 .ptr = &node.name_token,
1435 }
1436 });
1437 try stack.append(State {
1438 .ExpectTokenSave = ExpectTokenSave {
1439 .id = Token.Id.Period,
1440 .ptr = &node.period_token,
1441 }
1442 });
1443 continue;
1444 },
1445 State.FieldInitListCommaOrEnd => |list_state| {
1446 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1447 *list_state.ptr = end;
1448 continue;
1449 } else {
1450 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1451 continue;
1452 }
1453 },
1454 State.FieldListCommaOrEnd => |container_decl| {
1455 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1456 container_decl.rbrace_token = end;
1457 continue;
1458 } else {
1459 stack.append(State { .ContainerDecl = container_decl }) catch unreachable;
1460 continue;
1461 }
1462 },
1463 State.IdentifierListItemOrEnd => |list_state| {
1464 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1465 *list_state.ptr = rbrace;
1466 continue;
1467 }
1468
1469 stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
1470 try stack.append(State { .Identifier = OptionalCtx { .Required = try list_state.list.addOne() } });
1471 continue;
1472 },
1473 State.IdentifierListCommaOrEnd => |list_state| {
1474 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1475 *list_state.ptr = end;
1476 continue;
1477 } else {
1478 stack.append(State { .IdentifierListItemOrEnd = list_state }) catch unreachable;
1479 continue;
1480 }
1481 },
1482 State.SwitchCaseOrEnd => |list_state| {
1483 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1484 *list_state.ptr = rbrace;
1485 continue;
1486 }
1487
1488 const node = try self.createNode(arena, ast.NodeSwitchCase,
1489 ast.NodeSwitchCase {
1490 .base = undefined,
1491 .items = ArrayList(&ast.Node).init(arena),
1492 .payload = null,
1493 .expr = undefined,
1494 }
1495 );
1496 try list_state.list.append(node);
1497 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
1498 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1499 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1500 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1501 continue;
1502 },
1503 State.SwitchCaseCommaOrEnd => |list_state| {
1504 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1505 *list_state.ptr = end;
1506 continue;
1507 } else {
1508 stack.append(State { .SwitchCaseOrEnd = list_state }) catch unreachable;
1509 continue;
1510 }
1511 },
1512 State.SwitchCaseFirstItem => |case_items| {
1513 const token = self.getNextToken();
1514 if (token.id == Token.Id.Keyword_else) {
1515 const else_node = try self.createAttachNode(arena, case_items, ast.NodeSwitchElse,
1516 ast.NodeSwitchElse {
1517 .base = undefined,
1518 .token = token,
1519 }
1520 );
1521 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1522 continue;
1523 } else {
1524 self.putBackToken(token);
1525 try stack.append(State { .SwitchCaseItem = case_items });
1526 continue;
1527 }
1528 },
1529 State.SwitchCaseItem => |case_items| {
1530 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1531 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1532 },
1533 State.SwitchCaseItemCommaOrEnd => |case_items| {
1534 if ((try self.expectCommaOrEnd(Token.Id.EqualAngleBracketRight)) == null) {
1535 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1536 }
1537 continue;
1538 },
1539
1540
1541 State.SuspendBody => |suspend_node| {
1542 if (suspend_node.payload != null) {
1543 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1544 }
1545 continue;
1546 },
1547 State.AsyncAllocator => |async_node| {
1548 if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
1549 continue;
1550 }
1551
1552 async_node.rangle_bracket = Token(undefined);
1553 try stack.append(State {
1554 .ExpectTokenSave = ExpectTokenSave {
1555 .id = Token.Id.AngleBracketRight,
1556 .ptr = &??async_node.rangle_bracket,
1557 }
1558 });
1559 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1560 continue;
1561 },
1562 State.AsyncEnd => |ctx| {
1563 const node = ctx.ctx.get() ?? continue;
1564
1565 switch (node.id) {
1566 ast.Node.Id.FnProto => {
1567 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
1568 fn_proto.async_attr = ctx.attribute;
1569 continue;
1570 },
1571 ast.Node.Id.SuffixOp => {
1572 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
1573 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
1574 suffix_op.op.Call.async_attr = ctx.attribute;
1575 continue;
1576 }
1577
1578 return self.parseError(node.firstToken(), "expected {}, found {}.",
1579 @tagName(ast.NodeSuffixOp.SuffixOp.Call),
1580 @tagName(suffix_op.op));
1581 },
1582 else => {
1583 return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
1584 @tagName(ast.NodeSuffixOp.SuffixOp.Call),
1585 @tagName(ast.Node.Id.FnProto),
1586 @tagName(node.id));
1587 }
1588 }
1589 },
1590
1591
1592 State.ExternType => |ctx| {
1593 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1594 const fn_proto = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFnProto,
1595 ast.NodeFnProto {
1596 .base = undefined,
1597 .visib_token = null,
1598 .name_token = null,
1599 .fn_token = fn_token,
1600 .params = ArrayList(&ast.Node).init(arena),
1601 .return_type = undefined,
1602 .var_args_token = null,
1603 .extern_export_inline_token = ctx.extern_token,
1604 .cc_token = null,
1605 .async_attr = null,
1606 .body_node = null,
1607 .lib_name = null,
1608 .align_expr = null,
1609 }
1610 );
1611 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1612 continue;
1613 }
1614
1615 stack.append(State {
1616 .ContainerKind = ContainerKindCtx {
1617 .opt_ctx = ctx.opt_ctx,
1618 .ltoken = ctx.extern_token,
1619 .layout = ast.NodeContainerDecl.Layout.Extern,
1620 },
1621 }) catch unreachable;
1622 continue;
1623 },
1624 State.SliceOrArrayAccess => |node| {
1625 var token = self.getNextToken();
1626 switch (token.id) {
1627 Token.Id.Ellipsis2 => {
1628 const start = node.op.ArrayAccess;
1629 node.op = ast.NodeSuffixOp.SuffixOp {
1630 .Slice = ast.NodeSuffixOp.SliceRange {
1631 .start = start,
1632 .end = null,
1633 }
1634 };
1635
1636 stack.append(State {
1637 .ExpectTokenSave = ExpectTokenSave {
1638 .id = Token.Id.RBracket,
1639 .ptr = &node.rtoken,
1640 }
1641 }) catch unreachable;
1642 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1643 continue;
1644 },
1645 Token.Id.RBracket => {
1646 node.rtoken = token;
1647 continue;
1648 },
1649 else => {
1650 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
1651 }
1652 }
1653 },
1654 State.SliceOrArrayType => |node| {
1655 if (self.eatToken(Token.Id.RBracket)) |_| {
1656 node.op = ast.NodePrefixOp.PrefixOp {
1657 .SliceType = ast.NodePrefixOp.AddrOfInfo {
1658 .align_expr = null,
1659 .bit_offset_start_token = null,
1660 .bit_offset_end_token = null,
1661 .const_token = null,
1662 .volatile_token = null,
1663 }
1664 };
1665 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1666 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1667 continue;
1668 }
1669
1670 node.op = ast.NodePrefixOp.PrefixOp { .ArrayType = undefined };
1671 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1672 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1673 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1674 continue;
1675 },
1676 State.AddrOfModifiers => |addr_of_info| {
1677 var token = self.getNextToken();
1678 switch (token.id) {
1679 Token.Id.Keyword_align => {
1680 stack.append(state) catch unreachable;
1681 if (addr_of_info.align_expr != null) {
1682 return self.parseError(token, "multiple align qualifiers");
1683 }
1684 try stack.append(State { .ExpectToken = Token.Id.RParen });
1685 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1686 try stack.append(State { .ExpectToken = Token.Id.LParen });
1687 continue;
1688 },
1689 Token.Id.Keyword_const => {
1690 stack.append(state) catch unreachable;
1691 if (addr_of_info.const_token != null) {
1692 return self.parseError(token, "duplicate qualifier: const");
1693 }
1694 addr_of_info.const_token = token;
1695 continue;
1696 },
1697 Token.Id.Keyword_volatile => {
1698 stack.append(state) catch unreachable;
1699 if (addr_of_info.volatile_token != null) {
1700 return self.parseError(token, "duplicate qualifier: volatile");
1701 }
1702 addr_of_info.volatile_token = token;
1703 continue;
1704 },
1705 else => {
1706 self.putBackToken(token);
1707 continue;
1708 },
1709 }
1710 },
1711
1712
1713 State.Payload => |opt_ctx| {
1714 const token = self.getNextToken();
1715 if (token.id != Token.Id.Pipe) {
1716 if (opt_ctx != OptionalCtx.Optional) {
1717 return self.parseError(token, "expected {}, found {}.",
1718 @tagName(Token.Id.Pipe),
1719 @tagName(token.id));
1720 }
1721
1722 self.putBackToken(token);
1723 continue;
1724 }
1725
1726 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePayload,
1727 ast.NodePayload {
1728 .base = undefined,
1729 .lpipe = token,
1730 .error_symbol = undefined,
1731 .rpipe = undefined
1732 }
1733 );
1734
1735 stack.append(State {
1736 .ExpectTokenSave = ExpectTokenSave {
1737 .id = Token.Id.Pipe,
1738 .ptr = &node.rpipe,
1739 }
1740 }) catch unreachable;
1741 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1742 continue;
1743 },
1744 State.PointerPayload => |opt_ctx| {
1745 const token = self.getNextToken();
1746 if (token.id != Token.Id.Pipe) {
1747 if (opt_ctx != OptionalCtx.Optional) {
1748 return self.parseError(token, "expected {}, found {}.",
1749 @tagName(Token.Id.Pipe),
1750 @tagName(token.id));
1751 }
1752
1753 self.putBackToken(token);
1754 continue;
1755 }
1756
1757 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerPayload,
1758 ast.NodePointerPayload {
1759 .base = undefined,
1760 .lpipe = token,
1761 .ptr_token = null,
1762 .value_symbol = undefined,
1763 .rpipe = undefined
1764 }
1765 );
1766
1767 stack.append(State {
1768 .ExpectTokenSave = ExpectTokenSave {
1769 .id = Token.Id.Pipe,
1770 .ptr = &node.rpipe,
1771 }
1772 }) catch unreachable;
1773 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1774 try stack.append(State {
1775 .OptionalTokenSave = OptionalTokenSave {
1776 .id = Token.Id.Asterisk,
1777 .ptr = &node.ptr_token,
1778 }
1779 });
1780 continue;
1781 },
1782 State.PointerIndexPayload => |opt_ctx| {
1783 const token = self.getNextToken();
1784 if (token.id != Token.Id.Pipe) {
1785 if (opt_ctx != OptionalCtx.Optional) {
1786 return self.parseError(token, "expected {}, found {}.",
1787 @tagName(Token.Id.Pipe),
1788 @tagName(token.id));
1789 }
1790
1791 self.putBackToken(token);
1792 continue;
1793 }
1794
1795 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerIndexPayload,
1796 ast.NodePointerIndexPayload {
1797 .base = undefined,
1798 .lpipe = token,
1799 .ptr_token = null,
1800 .value_symbol = undefined,
1801 .index_symbol = null,
1802 .rpipe = undefined
1803 }
1804 );
1805
1806 stack.append(State {
1807 .ExpectTokenSave = ExpectTokenSave {
1808 .id = Token.Id.Pipe,
1809 .ptr = &node.rpipe,
1810 }
1811 }) catch unreachable;
1812 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1813 try stack.append(State { .IfToken = Token.Id.Comma });
1814 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1815 try stack.append(State {
1816 .OptionalTokenSave = OptionalTokenSave {
1817 .id = Token.Id.Asterisk,
1818 .ptr = &node.ptr_token,
1819 }
1820 });
1821 continue;
1822 },
1823
1824
1825 State.Expression => |opt_ctx| {
1826 const token = self.getNextToken();
1827 switch (token.id) {
1828 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1829 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeControlFlowExpression,
1830 ast.NodeControlFlowExpression {
1831 .base = undefined,
1832 .ltoken = token,
1833 .kind = undefined,
1834 .rhs = null,
1835 }
1836 );
1837
1838 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1839
1840 switch (token.id) {
1841 Token.Id.Keyword_break => {
1842 node.kind = ast.NodeControlFlowExpression.Kind { .Break = null };
1843 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1844 try stack.append(State { .IfToken = Token.Id.Colon });
1845 },
1846 Token.Id.Keyword_continue => {
1847 node.kind = ast.NodeControlFlowExpression.Kind { .Continue = null };
1848 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1849 try stack.append(State { .IfToken = Token.Id.Colon });
1850 },
1851 Token.Id.Keyword_return => {
1852 node.kind = ast.NodeControlFlowExpression.Kind.Return;
1853 },
1854 else => unreachable,
1855 }
1856 continue;
1857 },
1858 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1859 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
1860 ast.NodePrefixOp {
1861 .base = undefined,
1862 .op_token = token,
1863 .op = switch (token.id) {
1864 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{} },
1865 Token.Id.Keyword_cancel => ast.NodePrefixOp.PrefixOp { .Cancel = void{} },
1866 Token.Id.Keyword_resume => ast.NodePrefixOp.PrefixOp { .Resume = void{} },
1867 else => unreachable,
1868 },
1869 .rhs = undefined,
1870 }
1871 );
1872
1873 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1874 continue;
1875 },
1876 else => {
1877 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
1878 self.putBackToken(token);
1879 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1880 }
1881 continue;
1882 }
1883 }
1884 },
1885 State.RangeExpressionBegin => |opt_ctx| {
1886 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1887 try stack.append(State { .Expression = opt_ctx });
1888 continue;
1889 },
1890 State.RangeExpressionEnd => |opt_ctx| {
1891 const lhs = opt_ctx.get() ?? continue;
1892
1893 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1894 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1895 ast.NodeInfixOp {
1896 .base = undefined,
1897 .lhs = lhs,
1898 .op_token = ellipsis3,
1899 .op = ast.NodeInfixOp.InfixOp.Range,
1900 .rhs = undefined,
1901 }
1902 );
1903 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1904 continue;
1905 }
1906 },
1907 State.AssignmentExpressionBegin => |opt_ctx| {
1908 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1909 try stack.append(State { .Expression = opt_ctx });
1910 continue;
1911 },
1912
1913 State.AssignmentExpressionEnd => |opt_ctx| {
1914 const lhs = opt_ctx.get() ?? continue;
1915
1916 const token = self.getNextToken();
1917 if (tokenIdToAssignment(token.id)) |ass_id| {
1918 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1919 ast.NodeInfixOp {
1920 .base = undefined,
1921 .lhs = lhs,
1922 .op_token = token,
1923 .op = ass_id,
1924 .rhs = undefined,
1925 }
1926 );
1927 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1928 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1929 continue;
1930 } else {
1931 self.putBackToken(token);
1932 continue;
1933 }
1934 },
1935
1936 State.UnwrapExpressionBegin => |opt_ctx| {
1937 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1938 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
1939 continue;
1940 },
1941
1942 State.UnwrapExpressionEnd => |opt_ctx| {
1943 const lhs = opt_ctx.get() ?? continue;
1944
1945 const token = self.getNextToken();
1946 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
1947 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1948 ast.NodeInfixOp {
1949 .base = undefined,
1950 .lhs = lhs,
1951 .op_token = token,
1952 .op = unwrap_id,
1953 .rhs = undefined,
1954 }
1955 );
1956
1957 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1958 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1959
1960 if (node.op == ast.NodeInfixOp.InfixOp.Catch) {
1961 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1962 }
1963 continue;
1964 } else {
1965 self.putBackToken(token);
1966 continue;
1967 }
1968 },
1969
1970 State.BoolOrExpressionBegin => |opt_ctx| {
1971 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1972 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
1973 continue;
1974 },
1975
1976 State.BoolOrExpressionEnd => |opt_ctx| {
1977 const lhs = opt_ctx.get() ?? continue;
1978
1979 if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
1980 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1981 ast.NodeInfixOp {
1982 .base = undefined,
1983 .lhs = lhs,
1984 .op_token = or_token,
1985 .op = ast.NodeInfixOp.InfixOp.BoolOr,
1986 .rhs = undefined,
1987 }
1988 );
1989 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1990 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1991 continue;
1992 }
1993 },
1994
1995 State.BoolAndExpressionBegin => |opt_ctx| {
1996 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1997 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
1998 continue;
1999 },
2000
2001 State.BoolAndExpressionEnd => |opt_ctx| {
2002 const lhs = opt_ctx.get() ?? continue;
2003
2004 if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
2005 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2006 ast.NodeInfixOp {
2007 .base = undefined,
2008 .lhs = lhs,
2009 .op_token = and_token,
2010 .op = ast.NodeInfixOp.InfixOp.BoolAnd,
2011 .rhs = undefined,
2012 }
2013 );
2014 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2015 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2016 continue;
2017 }
2018 },
2019
2020 State.ComparisonExpressionBegin => |opt_ctx| {
2021 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2022 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
2023 continue;
2024 },
2025
2026 State.ComparisonExpressionEnd => |opt_ctx| {
2027 const lhs = opt_ctx.get() ?? continue;
2028
2029 const token = self.getNextToken();
2030 if (tokenIdToComparison(token.id)) |comp_id| {
2031 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2032 ast.NodeInfixOp {
2033 .base = undefined,
2034 .lhs = lhs,
2035 .op_token = token,
2036 .op = comp_id,
2037 .rhs = undefined,
2038 }
2039 );
2040 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2041 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2042 continue;
2043 } else {
2044 self.putBackToken(token);
2045 continue;
2046 }
2047 },
2048
2049 State.BinaryOrExpressionBegin => |opt_ctx| {
2050 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2051 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2052 continue;
2053 },
2054
2055 State.BinaryOrExpressionEnd => |opt_ctx| {
2056 const lhs = opt_ctx.get() ?? continue;
2057
2058 if (self.eatToken(Token.Id.Pipe)) |pipe| {
2059 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2060 ast.NodeInfixOp {
2061 .base = undefined,
2062 .lhs = lhs,
2063 .op_token = pipe,
2064 .op = ast.NodeInfixOp.InfixOp.BitOr,
2065 .rhs = undefined,
2066 }
2067 );
2068 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2069 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2070 continue;
2071 }
2072 },
2073
2074 State.BinaryXorExpressionBegin => |opt_ctx| {
2075 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2076 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2077 continue;
2078 },
2079
2080 State.BinaryXorExpressionEnd => |opt_ctx| {
2081 const lhs = opt_ctx.get() ?? continue;
2082
2083 if (self.eatToken(Token.Id.Caret)) |caret| {
2084 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2085 ast.NodeInfixOp {
2086 .base = undefined,
2087 .lhs = lhs,
2088 .op_token = caret,
2089 .op = ast.NodeInfixOp.InfixOp.BitXor,
2090 .rhs = undefined,
2091 }
2092 );
2093 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2094 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2095 continue;
2096 }
2097 },
2098
2099 State.BinaryAndExpressionBegin => |opt_ctx| {
2100 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2101 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2102 continue;
2103 },
2104
2105 State.BinaryAndExpressionEnd => |opt_ctx| {
2106 const lhs = opt_ctx.get() ?? continue;
2107
2108 if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
2109 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2110 ast.NodeInfixOp {
2111 .base = undefined,
2112 .lhs = lhs,
2113 .op_token = ampersand,
2114 .op = ast.NodeInfixOp.InfixOp.BitAnd,
2115 .rhs = undefined,
2116 }
2117 );
2118 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2119 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2120 continue;
2121 }
2122 },
2123
2124 State.BitShiftExpressionBegin => |opt_ctx| {
2125 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2126 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2127 continue;
2128 },
2129
2130 State.BitShiftExpressionEnd => |opt_ctx| {
2131 const lhs = opt_ctx.get() ?? continue;
2132
2133 const token = self.getNextToken();
2134 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2135 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2136 ast.NodeInfixOp {
2137 .base = undefined,
2138 .lhs = lhs,
2139 .op_token = token,
2140 .op = bitshift_id,
2141 .rhs = undefined,
2142 }
2143 );
2144 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2145 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2146 continue;
2147 } else {
2148 self.putBackToken(token);
2149 continue;
2150 }
2151 },
2152
2153 State.AdditionExpressionBegin => |opt_ctx| {
2154 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2155 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2156 continue;
2157 },
2158
2159 State.AdditionExpressionEnd => |opt_ctx| {
2160 const lhs = opt_ctx.get() ?? continue;
2161
2162 const token = self.getNextToken();
2163 if (tokenIdToAddition(token.id)) |add_id| {
2164 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2165 ast.NodeInfixOp {
2166 .base = undefined,
2167 .lhs = lhs,
2168 .op_token = token,
2169 .op = add_id,
2170 .rhs = undefined,
2171 }
2172 );
2173 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2174 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2175 continue;
2176 } else {
2177 self.putBackToken(token);
2178 continue;
2179 }
2180 },
2181
2182 State.MultiplyExpressionBegin => |opt_ctx| {
2183 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2184 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2185 continue;
2186 },
2187
2188 State.MultiplyExpressionEnd => |opt_ctx| {
2189 const lhs = opt_ctx.get() ?? continue;
2190
2191 const token = self.getNextToken();
2192 if (tokenIdToMultiply(token.id)) |mult_id| {
2193 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2194 ast.NodeInfixOp {
2195 .base = undefined,
2196 .lhs = lhs,
2197 .op_token = token,
2198 .op = mult_id,
2199 .rhs = undefined,
2200 }
2201 );
2202 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2203 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2204 continue;
2205 } else {
2206 self.putBackToken(token);
2207 continue;
2208 }
2209 },
2210
2211 State.CurlySuffixExpressionBegin => |opt_ctx| {
2212 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2213 try stack.append(State { .IfToken = Token.Id.LBrace });
2214 try stack.append(State { .TypeExprBegin = opt_ctx });
2215 continue;
2216 },
2217
2218 State.CurlySuffixExpressionEnd => |opt_ctx| {
2219 const lhs = opt_ctx.get() ?? continue;
2220
2221 if (self.isPeekToken(Token.Id.Period)) {
2222 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2223 ast.NodeSuffixOp {
2224 .base = undefined,
2225 .lhs = lhs,
2226 .op = ast.NodeSuffixOp.SuffixOp {
2227 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
2228 },
2229 .rtoken = undefined,
2230 }
2231 );
2232 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2233 try stack.append(State { .IfToken = Token.Id.LBrace });
2234 try stack.append(State {
2235 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
2236 .list = &node.op.StructInitializer,
2237 .ptr = &node.rtoken,
2238 }
2239 });
2240 continue;
2241 }
2242
2243 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2244 ast.NodeSuffixOp {
2245 .base = undefined,
2246 .lhs = lhs,
2247 .op = ast.NodeSuffixOp.SuffixOp {
2248 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
2249 },
2250 .rtoken = undefined,
2251 }
2252 );
2253 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2254 try stack.append(State { .IfToken = Token.Id.LBrace });
2255 try stack.append(State {
2256 .ExprListItemOrEnd = ExprListCtx {
2257 .list = &node.op.ArrayInitializer,
2258 .end = Token.Id.RBrace,
2259 .ptr = &node.rtoken,
2260 }
2261 });
2262 continue;
2263 },
2264
2265 State.TypeExprBegin => |opt_ctx| {
2266 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2267 try stack.append(State { .PrefixOpExpression = opt_ctx });
2268 continue;
2269 },
2270
2271 State.TypeExprEnd => |opt_ctx| {
2272 const lhs = opt_ctx.get() ?? continue;
2273
2274 if (self.eatToken(Token.Id.Bang)) |bang| {
2275 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2276 ast.NodeInfixOp {
2277 .base = undefined,
2278 .lhs = lhs,
2279 .op_token = bang,
2280 .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
2281 .rhs = undefined,
2282 }
2283 );
2284 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2285 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2286 continue;
2287 }
2288 },
2289
2290 State.PrefixOpExpression => |opt_ctx| {
2291 const token = self.getNextToken();
2292 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2293 var node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
2294 ast.NodePrefixOp {
2295 .base = undefined,
2296 .op_token = token,
2297 .op = prefix_id,
2298 .rhs = undefined,
2299 }
2300 );
2301
2302 // Treat '**' token as two derefs
2303 if (token.id == Token.Id.AsteriskAsterisk) {
2304 const child = try self.createNode(arena, ast.NodePrefixOp,
2305 ast.NodePrefixOp {
2306 .base = undefined,
2307 .op_token = token,
2308 .op = prefix_id,
2309 .rhs = undefined,
2310 }
2311 );
2312 node.rhs = &child.base;
2313 node = child;
2314 }
2315
2316 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2317 if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
2318 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
2319 }
2320 continue;
2321 } else {
2322 self.putBackToken(token);
2323 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2324 continue;
2325 }
2326 },
2327
2328 State.SuffixOpExpressionBegin => |opt_ctx| {
2329 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2330 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
2331 ast.NodeAsyncAttribute {
2332 .base = undefined,
2333 .async_token = async_token,
2334 .allocator_type = null,
2335 .rangle_bracket = null,
2336 }
2337 );
2338 stack.append(State {
2339 .AsyncEnd = AsyncEndCtx {
2340 .ctx = opt_ctx,
2341 .attribute = async_node,
2342 }
2343 }) catch unreachable;
2344 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2345 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2346 try stack.append(State { .AsyncAllocator = async_node });
2347 continue;
2348 }
2349
2350 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2351 try stack.append(State { .PrimaryExpression = opt_ctx });
2352 continue;
2353 },
2354
2355 State.SuffixOpExpressionEnd => |opt_ctx| {
2356 const lhs = opt_ctx.get() ?? continue;
2357
2358 const token = self.getNextToken();
2359 switch (token.id) {
2360 Token.Id.LParen => {
2361 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2362 ast.NodeSuffixOp {
2363 .base = undefined,
2364 .lhs = lhs,
2365 .op = ast.NodeSuffixOp.SuffixOp {
2366 .Call = ast.NodeSuffixOp.CallInfo {
2367 .params = ArrayList(&ast.Node).init(arena),
2368 .async_attr = null,
2369 }
2370 },
2371 .rtoken = undefined,
2372 }
2373 );
2374 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2375 try stack.append(State {
2376 .ExprListItemOrEnd = ExprListCtx {
2377 .list = &node.op.Call.params,
2378 .end = Token.Id.RParen,
2379 .ptr = &node.rtoken,
2380 }
2381 });
2382 continue;
2383 },
2384 Token.Id.LBracket => {
2385 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2386 ast.NodeSuffixOp {
2387 .base = undefined,
2388 .lhs = lhs,
2389 .op = ast.NodeSuffixOp.SuffixOp {
2390 .ArrayAccess = undefined,
2391 },
2392 .rtoken = undefined
2393 }
2394 );
2395 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2396 try stack.append(State { .SliceOrArrayAccess = node });
2397 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2398 continue;
2399 },
2400 Token.Id.Period => {
2401 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2402 ast.NodeInfixOp {
2403 .base = undefined,
2404 .lhs = lhs,
2405 .op_token = token,
2406 .op = ast.NodeInfixOp.InfixOp.Period,
2407 .rhs = undefined,
2408 }
2409 );
2410 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2411 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2412 continue;
2413 },
2414 else => {
2415 self.putBackToken(token);
2416 continue;
2417 },
2418 }
2419 },
2420
2421 State.PrimaryExpression => |opt_ctx| {
2422 const token = self.getNextToken();
2423 switch (token.id) {
2424 Token.Id.IntegerLiteral => {
2425 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeStringLiteral, token);
2426 continue;
2427 },
2428 Token.Id.FloatLiteral => {
2429 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeFloatLiteral, token);
2430 continue;
2431 },
2432 Token.Id.CharLiteral => {
2433 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeCharLiteral, token);
2434 continue;
2435 },
2436 Token.Id.Keyword_undefined => {
2437 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeUndefinedLiteral, token);
2438 continue;
2439 },
2440 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2441 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeBoolLiteral, token);
2442 continue;
2443 },
2444 Token.Id.Keyword_null => {
2445 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeNullLiteral, token);
2446 continue;
2447 },
2448 Token.Id.Keyword_this => {
2449 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeThisLiteral, token);
2450 continue;
2451 },
2452 Token.Id.Keyword_var => {
2453 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeVarType, token);
2454 continue;
2455 },
2456 Token.Id.Keyword_unreachable => {
2457 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeUnreachable, token);
2458 continue;
2459 },
2460 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2461 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2462 continue;
2463 },
2464 Token.Id.LParen => {
2465 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeGroupedExpression,
2466 ast.NodeGroupedExpression {
2467 .base = undefined,
2468 .lparen = token,
2469 .expr = undefined,
2470 .rparen = undefined,
2471 }
2472 );
2473 stack.append(State {
2474 .ExpectTokenSave = ExpectTokenSave {
2475 .id = Token.Id.RParen,
2476 .ptr = &node.rparen,
2477 }
2478 }) catch unreachable;
2479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2480 continue;
2481 },
2482 Token.Id.Builtin => {
2483 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeBuiltinCall,
2484 ast.NodeBuiltinCall {
2485 .base = undefined,
2486 .builtin_token = token,
2487 .params = ArrayList(&ast.Node).init(arena),
2488 .rparen_token = undefined,
2489 }
2490 );
2491 stack.append(State {
2492 .ExprListItemOrEnd = ExprListCtx {
2493 .list = &node.params,
2494 .end = Token.Id.RParen,
2495 .ptr = &node.rparen_token,
2496 }
2497 }) catch unreachable;
2498 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2499 continue;
2500 },
2501 Token.Id.LBracket => {
2502 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
2503 ast.NodePrefixOp {
2504 .base = undefined,
2505 .op_token = token,
2506 .op = undefined,
2507 .rhs = undefined,
2508 }
2509 );
2510 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2511 continue;
2512 },
2513 Token.Id.Keyword_error => {
2514 stack.append(State {
2515 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2516 .error_token = token,
2517 .opt_ctx = opt_ctx
2518 }
2519 }) catch unreachable;
2520 continue;
2521 },
2522 Token.Id.Keyword_packed => {
2523 stack.append(State {
2524 .ContainerKind = ContainerKindCtx {
2525 .opt_ctx = opt_ctx,
2526 .ltoken = token,
2527 .layout = ast.NodeContainerDecl.Layout.Packed,
2528 },
2529 }) catch unreachable;
2530 continue;
2531 },
2532 Token.Id.Keyword_extern => {
2533 stack.append(State {
2534 .ExternType = ExternTypeCtx {
2535 .opt_ctx = opt_ctx,
2536 .extern_token = token,
2537 },
2538 }) catch unreachable;
2539 continue;
2540 },
2541 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2542 self.putBackToken(token);
2543 stack.append(State {
2544 .ContainerKind = ContainerKindCtx {
2545 .opt_ctx = opt_ctx,
2546 .ltoken = token,
2547 .layout = ast.NodeContainerDecl.Layout.Auto,
2548 },
2549 }) catch unreachable;
2550 continue;
2551 },
2552 Token.Id.Identifier => {
2553 stack.append(State {
2554 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2555 .label = token,
2556 .opt_ctx = opt_ctx
2557 }
2558 }) catch unreachable;
2559 continue;
2560 },
2561 Token.Id.Keyword_fn => {
2562 const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
2563 ast.NodeFnProto {
2564 .base = undefined,
2565 .visib_token = null,
2566 .name_token = null,
2567 .fn_token = token,
2568 .params = ArrayList(&ast.Node).init(arena),
2569 .return_type = undefined,
2570 .var_args_token = null,
2571 .extern_export_inline_token = null,
2572 .cc_token = null,
2573 .async_attr = null,
2574 .body_node = null,
2575 .lib_name = null,
2576 .align_expr = null,
2577 }
2578 );
2579 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2580 continue;
2581 },
2582 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2583 const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
2584 ast.NodeFnProto {
2585 .base = undefined,
2586 .visib_token = null,
2587 .name_token = null,
2588 .fn_token = undefined,
2589 .params = ArrayList(&ast.Node).init(arena),
2590 .return_type = undefined,
2591 .var_args_token = null,
2592 .extern_export_inline_token = null,
2593 .cc_token = token,
2594 .async_attr = null,
2595 .body_node = null,
2596 .lib_name = null,
2597 .align_expr = null,
2598 }
2599 );
2600 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2601 try stack.append(State {
2602 .ExpectTokenSave = ExpectTokenSave {
2603 .id = Token.Id.Keyword_fn,
2604 .ptr = &fn_proto.fn_token
2605 }
2606 });
2607 continue;
2608 },
2609 Token.Id.Keyword_asm => {
2610 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeAsm,
2611 ast.NodeAsm {
2612 .base = undefined,
2613 .asm_token = token,
2614 .volatile_token = null,
2615 .template = undefined,
2616 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
2617 .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
2618 .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
2619 .cloppers = ArrayList(&ast.Node).init(arena),
2620 .rparen = undefined,
2621 }
2622 );
2623 stack.append(State {
2624 .ExpectTokenSave = ExpectTokenSave {
2625 .id = Token.Id.RParen,
2626 .ptr = &node.rparen,
2627 }
2628 }) catch unreachable;
2629 try stack.append(State { .AsmClopperItems = &node.cloppers });
2630 try stack.append(State { .IfToken = Token.Id.Colon });
2631 try stack.append(State { .AsmInputItems = &node.inputs });
2632 try stack.append(State { .IfToken = Token.Id.Colon });
2633 try stack.append(State { .AsmOutputItems = &node.outputs });
2634 try stack.append(State { .IfToken = Token.Id.Colon });
2635 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2636 try stack.append(State { .ExpectToken = Token.Id.LParen });
2637 try stack.append(State {
2638 .OptionalTokenSave = OptionalTokenSave {
2639 .id = Token.Id.Keyword_volatile,
2640 .ptr = &node.volatile_token,
2641 }
2642 });
2643 },
2644 Token.Id.Keyword_inline => {
2645 stack.append(State {
2646 .Inline = InlineCtx {
2647 .label = null,
2648 .inline_token = token,
2649 .opt_ctx = opt_ctx,
2650 }
2651 }) catch unreachable;
2652 continue;
2653 },
2654 else => {
2655 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2656 self.putBackToken(token);
2657 if (opt_ctx != OptionalCtx.Optional) {
2658 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2659 }
2660 }
2661 continue;
2662 }
2663 }
2664 },
2665
2666
2667 State.ErrorTypeOrSetDecl => |ctx| {
2668 if (self.eatToken(Token.Id.LBrace) == null) {
2669 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeErrorType, ctx.error_token);
2670 continue;
2671 }
2672
2673 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeErrorSetDecl,
2674 ast.NodeErrorSetDecl {
2675 .base = undefined,
2676 .error_token = ctx.error_token,
2677 .decls = ArrayList(&ast.Node).init(arena),
2678 .rbrace_token = undefined,
2679 }
2680 );
2681
2682 stack.append(State {
2683 .IdentifierListItemOrEnd = ListSave(&ast.Node) {
2684 .list = &node.decls,
2685 .ptr = &node.rbrace_token,
2686 }
2687 }) catch unreachable;
2688 continue;
2689 },
2690 State.StringLiteral => |opt_ctx| {
2691 const token = self.getNextToken();
2692 opt_ctx.store(
2693 (try self.parseStringLiteral(arena, token)) ?? {
2694 self.putBackToken(token);
2695 if (opt_ctx != OptionalCtx.Optional) {
2696 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2697 }
2698
2699 continue;
2700 }
2701 );
2702 },
2703 State.Identifier => |opt_ctx| {
2704 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2705 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeIdentifier, ident_token);
2706 continue;
2707 }
2708
2709 if (opt_ctx != OptionalCtx.Optional) {
2710 const token = self.getNextToken();
2711 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
2712 }
2713 },
2714
2715
2716 State.ExpectToken => |token_id| {
2717 _ = try self.expectToken(token_id);
2718 continue;
2719 },
2720 State.ExpectTokenSave => |expect_token_save| {
2721 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2722 continue;
2723 },
2724 State.IfToken => |token_id| {
2725 if (self.eatToken(token_id)) |_| {
2726 continue;
2727 }
2728
2729 _ = stack.pop();
2730 continue;
2731 },
2732 State.IfTokenSave => |if_token_save| {
2733 if (self.eatToken(if_token_save.id)) |token| {
2734 *if_token_save.ptr = token;
2735 continue;
2736 }
2737
2738 _ = stack.pop();
2739 continue;
2740 },
2741 State.OptionalTokenSave => |optional_token_save| {
2742 if (self.eatToken(optional_token_save.id)) |token| {
2743 *optional_token_save.ptr = token;
2744 continue;
2745 }
2746
2747 continue;
2748 },
2749 }
2750 }
2751 }
2752
2753 fn requireSemiColon(node: &const ast.Node) bool {
2754 var n = node;
2755 while (true) {
2756 switch (n.id) {
2757 ast.Node.Id.Root,
2758 ast.Node.Id.StructField,
2759 ast.Node.Id.UnionTag,
2760 ast.Node.Id.EnumTag,
2761 ast.Node.Id.ParamDecl,
2762 ast.Node.Id.Block,
2763 ast.Node.Id.Payload,
2764 ast.Node.Id.PointerPayload,
2765 ast.Node.Id.PointerIndexPayload,
2766 ast.Node.Id.Switch,
2767 ast.Node.Id.SwitchCase,
2768 ast.Node.Id.SwitchElse,
2769 ast.Node.Id.FieldInitializer,
2770 ast.Node.Id.LineComment,
2771 ast.Node.Id.TestDecl => return false,
2772 ast.Node.Id.While => {
2773 const while_node = @fieldParentPtr(ast.NodeWhile, "base", n);
2774 if (while_node.@"else") |@"else"| {
2775 n = @"else".base;
2776 continue;
2777 }
2778
2779 return while_node.body.id != ast.Node.Id.Block;
2780 },
2781 ast.Node.Id.For => {
2782 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
2783 if (for_node.@"else") |@"else"| {
2784 n = @"else".base;
2785 continue;
2786 }
2787
2788 return for_node.body.id != ast.Node.Id.Block;
2789 },
2790 ast.Node.Id.If => {
2791 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
2792 if (if_node.@"else") |@"else"| {
2793 n = @"else".base;
2794 continue;
2795 }
2796
2797 return if_node.body.id != ast.Node.Id.Block;
2798 },
2799 ast.Node.Id.Else => {
2800 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
2801 n = else_node.body;
2802 continue;
2803 },
2804 ast.Node.Id.Defer => {
2805 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
2806 return defer_node.expr.id != ast.Node.Id.Block;
2807 },
2808 ast.Node.Id.Comptime => {
2809 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
2810 return comptime_node.expr.id != ast.Node.Id.Block;
2811 },
2812 ast.Node.Id.Suspend => {
2813 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
2814 if (suspend_node.body) |body| {
2815 return body.id != ast.Node.Id.Block;
2816 }
2817
2818 return true;
2819 },
2820 else => return true,
2821 }
2822 }
2823 }
2824
2825 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
2826 switch (token.id) {
2827 Token.Id.StringLiteral => {
2828 return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base;
2829 },
2830 Token.Id.MultilineStringLiteralLine => {
2831 const node = try self.createNode(arena, ast.NodeMultilineStringLiteral,
2832 ast.NodeMultilineStringLiteral {
2833 .base = undefined,
2834 .tokens = ArrayList(Token).init(arena),
2835 }
2836 );
2837 try node.tokens.append(token);
2838 while (true) {
2839 const multiline_str = self.getNextToken();
2840 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
2841 self.putBackToken(multiline_str);
2842 break;
2843 }
2844
2845 try node.tokens.append(multiline_str);
2846 }
2847
2848 return &node.base;
2849 },
2850 // TODO: We shouldn't need a cast, but:
2851 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
2852 else => return (?&ast.Node)(null),
2853 }
2854 }
2855
2856 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
2857 switch (token.id) {
2858 Token.Id.Keyword_suspend => {
2859 const node = try self.createToCtxNode(arena, ctx, ast.NodeSuspend,
2860 ast.NodeSuspend {
2861 .base = undefined,
2862 .suspend_token = *token,
2863 .payload = null,
2864 .body = null,
2865 }
2866 );
2867
2868 stack.append(State { .SuspendBody = node }) catch unreachable;
2869 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
2870 return true;
2871 },
2872 Token.Id.Keyword_if => {
2873 const node = try self.createToCtxNode(arena, ctx, ast.NodeIf,
2874 ast.NodeIf {
2875 .base = undefined,
2876 .if_token = *token,
2877 .condition = undefined,
2878 .payload = null,
2879 .body = undefined,
2880 .@"else" = null,
2881 }
2882 );
2883
2884 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2885 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
2886 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
2887 try stack.append(State { .ExpectToken = Token.Id.RParen });
2888 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
2889 try stack.append(State { .ExpectToken = Token.Id.LParen });
2890 return true;
2891 },
2892 Token.Id.Keyword_while => {
2893 stack.append(State {
2894 .While = LoopCtx {
2895 .label = null,
2896 .inline_token = null,
2897 .loop_token = *token,
2898 .opt_ctx = *ctx,
2899 }
2900 }) catch unreachable;
2901 return true;
2902 },
2903 Token.Id.Keyword_for => {
2904 stack.append(State {
2905 .For = LoopCtx {
2906 .label = null,
2907 .inline_token = null,
2908 .loop_token = *token,
2909 .opt_ctx = *ctx,
2910 }
2911 }) catch unreachable;
2912 return true;
2913 },
2914 Token.Id.Keyword_switch => {
2915 const node = try self.createToCtxNode(arena, ctx, ast.NodeSwitch,
2916 ast.NodeSwitch {
2917 .base = undefined,
2918 .switch_token = *token,
2919 .expr = undefined,
2920 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
2921 .rbrace = undefined,
2922 }
2923 );
2924
2925 stack.append(State {
2926 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
2927 .list = &node.cases,
2928 .ptr = &node.rbrace,
2929 },
2930 }) catch unreachable;
2931 try stack.append(State { .ExpectToken = Token.Id.LBrace });
2932 try stack.append(State { .ExpectToken = Token.Id.RParen });
2933 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2934 try stack.append(State { .ExpectToken = Token.Id.LParen });
2935 return true;
2936 },
2937 Token.Id.Keyword_comptime => {
2938 const node = try self.createToCtxNode(arena, ctx, ast.NodeComptime,
2939 ast.NodeComptime {
2940 .base = undefined,
2941 .comptime_token = *token,
2942 .expr = undefined,
2943 }
2944 );
2945 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2946 return true;
2947 },
2948 Token.Id.LBrace => {
2949 const block = try self.createToCtxNode(arena, ctx, ast.NodeBlock,
2950 ast.NodeBlock {
2951 .base = undefined,
2952 .label = null,
2953 .lbrace = *token,
2954 .statements = ArrayList(&ast.Node).init(arena),
2955 .rbrace = undefined,
2956 }
2957 );
2958 stack.append(State { .Block = block }) catch unreachable;
2959 return true;
2960 },
2961 else => {
2962 return false;
2963 }
2964 }
2965 }
2966
2967 fn expectCommaOrEnd(self: &Parser, end: @TagType(Token.Id)) !?Token {
2968 var token = self.getNextToken();
2969 switch (token.id) {
2970 Token.Id.Comma => return null,
2971 else => {
2972 if (end == token.id) {
2973 return token;
2974 }
2975
2976 return self.parseError(token, "expected ',' or {}, found {}", @tagName(end), @tagName(token.id));
2977 },
2978 }
2979 }
2980
2981 fn tokenIdToAssignment(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2982 // TODO: We have to cast all cases because of this:
2983 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2984 return switch (*id) {
2985 Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp { .AssignBitAnd = void{} },
2986 Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftLeft = void{} },
2987 Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftRight = void{} },
2988 Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp { .AssignTimes = void{} },
2989 Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp { .AssignTimesWarp = void{} },
2990 Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp { .AssignBitXor = void{} },
2991 Token.Id.Equal => ast.NodeInfixOp.InfixOp { .Assign = void{} },
2992 Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp { .AssignMinus = void{} },
2993 Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignMinusWrap = void{} },
2994 Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp { .AssignMod = void{} },
2995 Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp { .AssignBitOr = void{} },
2996 Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp { .AssignPlus = void{} },
2997 Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignPlusWrap = void{} },
2998 Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp { .AssignDiv = void{} },
2999 else => null,
3000 };
3001 }
3002
3003 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3004 return switch (id) {
3005 Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
3006 Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
3007 else => null,
3008 };
3009 }
3010
3011 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3012 return switch (id) {
3013 Token.Id.BangEqual => ast.NodeInfixOp.InfixOp { .BangEqual = void{} },
3014 Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp { .EqualEqual = void{} },
3015 Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp { .LessThan = void{} },
3016 Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .LessOrEqual = void{} },
3017 Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp { .GreaterThan = void{} },
3018 Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .GreaterOrEqual = void{} },
3019 else => null,
3020 };
3021 }
3022
3023 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3024 return switch (id) {
3025 Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp { .BitShiftLeft = void{} },
3026 Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp { .BitShiftRight = void{} },
3027 else => null,
3028 };
3029 }
3030
3031 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3032 return switch (id) {
3033 Token.Id.Minus => ast.NodeInfixOp.InfixOp { .Sub = void{} },
3034 Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp { .SubWrap = void{} },
3035 Token.Id.Plus => ast.NodeInfixOp.InfixOp { .Add = void{} },
3036 Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp { .AddWrap = void{} },
3037 Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp { .ArrayCat = void{} },
3038 else => null,
3039 };
3040 }
3041
3042 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3043 return switch (id) {
3044 Token.Id.Slash => ast.NodeInfixOp.InfixOp { .Div = void{} },
3045 Token.Id.Asterisk => ast.NodeInfixOp.InfixOp { .Mult = void{} },
3046 Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp { .ArrayMult = void{} },
3047 Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp { .MultWrap = void{} },
3048 Token.Id.Percent => ast.NodeInfixOp.InfixOp { .Mod = void{} },
3049 Token.Id.PipePipe => ast.NodeInfixOp.InfixOp { .MergeErrorSets = void{} },
3050 else => null,
3051 };
3052 }
3053
3054 fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.NodePrefixOp.PrefixOp {
3055 return switch (id) {
3056 Token.Id.Bang => ast.NodePrefixOp.PrefixOp { .BoolNot = void{} },
3057 Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} },
3058 Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} },
3059 Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} },
3060 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
3061 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
3062 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
3063 .align_expr = null,
3064 .bit_offset_start_token = null,
3065 .bit_offset_end_token = null,
3066 .const_token = null,
3067 .volatile_token = null,
3068 },
3069 },
3070 Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} },
3071 Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} },
3072 Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} },
3073 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } },
3074 else => null,
3075 };
3076 }
3077
3078 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3079 const node = try arena.create(T);
3080 *node = *init_to;
3081 node.base = blk: {
3082 const id = ast.Node.typeToId(T);
3083 if (self.pending_line_comment_node) |comment_node| {
3084 self.pending_line_comment_node = null;
3085 break :blk ast.Node {.id = id, .comment = comment_node};
3086 }
3087 break :blk ast.Node {.id = id, .comment = null };
3088 };
3089
3090 return node;
3091 }
3092
3093 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
3094 const node = try self.createNode(arena, T, init_to);
3095 try list.append(&node.base);
3096
3097 return node;
3098 }
3099
3100 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3101 const node = try self.createNode(arena, T, init_to);
3102 opt_ctx.store(&node.base);
3103
3104 return node;
3105 }
3106
3107 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
3108 return self.createNode(arena, T,
3109 T {
3110 .base = undefined,
3111 .token = *token,
3112 }
3113 );
3114 }
3115
3116 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
3117 const node = try self.createLiteral(arena, T, token);
3118 opt_ctx.store(&node.base);
3119
3120 return node;
3121 }
3122
3123 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
3124 const loc = self.tokenizer.getTokenLocation(0, token);
3125 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3126 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3127 {
3128 var i: usize = 0;
3129 while (i < loc.column) : (i += 1) {
3130 warn(" ");
3131 }
3132 }
3133 {
3134 const caret_count = token.end - token.start;
3135 var i: usize = 0;
3136 while (i < caret_count) : (i += 1) {
3137 warn("~");
3138 }
3139 }
3140 warn("\n");
3141 return error.ParseError;
3142 }
3143
3144 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
3145 const token = self.getNextToken();
3146 if (token.id != id) {
3147 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
3148 }
3149 return token;
3150 }
3151
3152 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
3153 if (self.isPeekToken(id)) {
3154 return self.getNextToken();
3155 }
3156 return null;
3157 }
3158
3159 fn putBackToken(self: &Parser, token: &const Token) void {
3160 self.put_back_tokens[self.put_back_count] = *token;
3161 self.put_back_count += 1;
3162 }
3163
3164 fn getNextToken(self: &Parser) Token {
3165 if (self.put_back_count != 0) {
3166 const put_back_index = self.put_back_count - 1;
3167 const put_back_token = self.put_back_tokens[put_back_index];
3168 self.put_back_count = put_back_index;
3169 return put_back_token;
3170 } else {
3171 return self.tokenizer.next();
3172 }
3173 }
3174
3175 fn isPeekToken(self: &Parser, id: @TagType(Token.Id)) bool {
3176 const token = self.getNextToken();
3177 defer self.putBackToken(token);
3178 return id == token.id;
3179 }
3180
3181 const RenderAstFrame = struct {
3182 node: &ast.Node,
3183 indent: usize,
3184 };
3185
3186 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
3187 var stack = self.initUtilityArrayList(RenderAstFrame);
3188 defer self.deinitUtilityArrayList(stack);
3189
3190 try stack.append(RenderAstFrame {
3191 .node = &root_node.base,
3192 .indent = 0,
3193 });
3194
3195 while (stack.popOrNull()) |frame| {
3196 {
3197 var i: usize = 0;
3198 while (i < frame.indent) : (i += 1) {
3199 try stream.print(" ");
3200 }
3201 }
3202 try stream.print("{}\n", @tagName(frame.node.id));
3203 var child_i: usize = 0;
3204 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3205 try stack.append(RenderAstFrame {
3206 .node = child,
3207 .indent = frame.indent + 2,
3208 });
3209 }
3210 }
3211 }
3212
3213 const RenderState = union(enum) {
3214 TopLevelDecl: &ast.Node,
3215 ParamDecl: &ast.Node,
3216 Text: []const u8,
3217 Expression: &ast.Node,
3218 VarDecl: &ast.NodeVarDecl,
3219 Statement: &ast.Node,
3220 FieldInitializer: &ast.NodeFieldInitializer,
3221 PrintIndent,
3222 Indent: usize,
3223 };
3224
3225 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
3226 var stack = self.initUtilityArrayList(RenderState);
3227 defer self.deinitUtilityArrayList(stack);
3228
3229 {
3230 try stack.append(RenderState { .Text = "\n"});
3231
3232 var i = root_node.decls.len;
3233 while (i != 0) {
3234 i -= 1;
3235 const decl = root_node.decls.items[i];
3236 try stack.append(RenderState {.TopLevelDecl = decl});
3237 if (i != 0) {
3238 try stack.append(RenderState {
3239 .Text = blk: {
3240 const prev_node = root_node.decls.at(i - 1);
3241 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken());
3242 if (loc.line >= 2) {
3243 break :blk "\n\n";
3244 }
3245 break :blk "\n";
3246 },
3247 });
3248 }
3249 }
3250 }
3251
3252 const indent_delta = 4;
3253 var indent: usize = 0;
3254 while (stack.popOrNull()) |state| {
3255 switch (state) {
3256 RenderState.TopLevelDecl => |decl| {
3257 switch (decl.id) {
3258 ast.Node.Id.FnProto => {
3259 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);
3260
3261 if (fn_proto.body_node) |body_node| {
3262 stack.append(RenderState { .Expression = body_node}) catch unreachable;
3263 try stack.append(RenderState { .Text = " "});
3264 } else {
3265 stack.append(RenderState { .Text = ";" }) catch unreachable;
3266 }
3267
3268 try stack.append(RenderState { .Expression = decl });
3269 },
3270 ast.Node.Id.Use => {
3271 const use_decl = @fieldParentPtr(ast.NodeUse, "base", decl);
3272 if (use_decl.visib_token) |visib_token| {
3273 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3274 }
3275 try stream.print("use ");
3276 try stack.append(RenderState { .Text = ";" });
3277 try stack.append(RenderState { .Expression = use_decl.expr });
3278 },
3279 ast.Node.Id.VarDecl => {
3280 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
3281 try stack.append(RenderState { .VarDecl = var_decl});
3282 },
3283 ast.Node.Id.TestDecl => {
3284 const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
3285 try stream.print("test ");
3286 try stack.append(RenderState { .Expression = test_decl.body_node });
3287 try stack.append(RenderState { .Text = " " });
3288 try stack.append(RenderState { .Expression = test_decl.name });
3289 },
3290 ast.Node.Id.StructField => {
3291 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
3292 if (field.visib_token) |visib_token| {
3293 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3294 }
3295 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3296 try stack.append(RenderState { .Expression = field.type_expr});
3297 },
3298 ast.Node.Id.UnionTag => {
3299 const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl);
3300 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3301
3302 if (tag.type_expr) |type_expr| {
3303 try stream.print(": ");
3304 try stack.append(RenderState { .Expression = type_expr});
3305 }
3306 },
3307 ast.Node.Id.EnumTag => {
3308 const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl);
3309 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3310
3311 if (tag.value) |value| {
3312 try stream.print(" = ");
3313 try stack.append(RenderState { .Expression = value});
3314 }
3315 },
3316 ast.Node.Id.Comptime => {
3317 if (requireSemiColon(decl)) {
3318 try stack.append(RenderState { .Text = ";" });
3319 }
3320 try stack.append(RenderState { .Expression = decl });
3321 },
3322 else => unreachable,
3323 }
3324 },
3325
3326 RenderState.FieldInitializer => |field_init| {
3327 try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token));
3328 try stream.print(" = ");
3329 try stack.append(RenderState { .Expression = field_init.expr });
3330 },
3331
3332 RenderState.VarDecl => |var_decl| {
3333 try stack.append(RenderState { .Text = ";" });
3334 if (var_decl.init_node) |init_node| {
3335 try stack.append(RenderState { .Expression = init_node });
3336 try stack.append(RenderState { .Text = " = " });
3337 }
3338 if (var_decl.align_node) |align_node| {
3339 try stack.append(RenderState { .Text = ")" });
3340 try stack.append(RenderState { .Expression = align_node });
3341 try stack.append(RenderState { .Text = " align(" });
3342 }
3343 if (var_decl.type_node) |type_node| {
3344 try stack.append(RenderState { .Expression = type_node });
3345 try stack.append(RenderState { .Text = ": " });
3346 }
3347 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) });
3348 try stack.append(RenderState { .Text = " " });
3349 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) });
3350
3351 if (var_decl.comptime_token) |comptime_token| {
3352 try stack.append(RenderState { .Text = " " });
3353 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3354 }
3355
3356 if (var_decl.extern_export_token) |extern_export_token| {
3357 if (var_decl.lib_name != null) {
3358 try stack.append(RenderState { .Text = " " });
3359 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3360 }
3361 try stack.append(RenderState { .Text = " " });
3362 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) });
3363 }
3364
3365 if (var_decl.visib_token) |visib_token| {
3366 try stack.append(RenderState { .Text = " " });
3367 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3368 }
3369 },
3370
3371 RenderState.ParamDecl => |base| {
3372 const param_decl = @fieldParentPtr(ast.NodeParamDecl, "base", base);
3373 if (param_decl.comptime_token) |comptime_token| {
3374 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
3375 }
3376 if (param_decl.noalias_token) |noalias_token| {
3377 try stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token));
3378 }
3379 if (param_decl.name_token) |name_token| {
3380 try stream.print("{}: ", self.tokenizer.getTokenSlice(name_token));
3381 }
3382 if (param_decl.var_args_token) |var_args_token| {
3383 try stream.print("{}", self.tokenizer.getTokenSlice(var_args_token));
3384 } else {
3385 try stack.append(RenderState { .Expression = param_decl.type_node});
3386 }
3387 },
3388 RenderState.Text => |bytes| {
3389 try stream.write(bytes);
3390 },
3391 RenderState.Expression => |base| switch (base.id) {
3392 ast.Node.Id.Identifier => {
3393 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);
3394 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
3395 },
3396 ast.Node.Id.Block => {
3397 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
3398 if (block.label) |label| {
3399 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3400 }
3401
3402 if (block.statements.len == 0) {
3403 try stream.write("{}");
3404 } else {
3405 try stream.write("{");
3406 try stack.append(RenderState { .Text = "}"});
3407 try stack.append(RenderState.PrintIndent);
3408 try stack.append(RenderState { .Indent = indent});
3409 try stack.append(RenderState { .Text = "\n"});
3410 var i = block.statements.len;
3411 while (i != 0) {
3412 i -= 1;
3413 const statement_node = block.statements.items[i];
3414 try stack.append(RenderState { .Statement = statement_node});
3415 try stack.append(RenderState.PrintIndent);
3416 try stack.append(RenderState { .Indent = indent + indent_delta});
3417 try stack.append(RenderState {
3418 .Text = blk: {
3419 if (i != 0) {
3420 const prev_node = block.statements.items[i - 1];
3421 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken());
3422 if (loc.line >= 2) {
3423 break :blk "\n\n";
3424 }
3425 }
3426 break :blk "\n";
3427 },
3428 });
3429 }
3430 }
3431 },
3432 ast.Node.Id.Defer => {
3433 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", base);
3434 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
3435 try stack.append(RenderState { .Expression = defer_node.expr });
3436 },
3437 ast.Node.Id.Comptime => {
3438 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", base);
3439 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
3440 try stack.append(RenderState { .Expression = comptime_node.expr });
3441 },
3442 ast.Node.Id.AsyncAttribute => {
3443 const async_attr = @fieldParentPtr(ast.NodeAsyncAttribute, "base", base);
3444 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
3445
3446 if (async_attr.allocator_type) |allocator_type| {
3447 try stack.append(RenderState { .Text = ">" });
3448 try stack.append(RenderState { .Expression = allocator_type });
3449 try stack.append(RenderState { .Text = "<" });
3450 }
3451 },
3452 ast.Node.Id.Suspend => {
3453 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", base);
3454 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
3455
3456 if (suspend_node.body) |body| {
3457 try stack.append(RenderState { .Expression = body });
3458 try stack.append(RenderState { .Text = " " });
3459 }
3460
3461 if (suspend_node.payload) |payload| {
3462 try stack.append(RenderState { .Expression = payload });
3463 try stack.append(RenderState { .Text = " " });
3464 }
3465 },
3466 ast.Node.Id.InfixOp => {
3467 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
3468 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3469
3470 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
3471 if (prefix_op_node.op.Catch) |payload| {
3472 try stack.append(RenderState { .Text = " " });
3473 try stack.append(RenderState { .Expression = payload });
3474 }
3475 try stack.append(RenderState { .Text = " catch " });
3476 } else {
3477 const text = switch (prefix_op_node.op) {
3478 ast.NodeInfixOp.InfixOp.Add => " + ",
3479 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
3480 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
3481 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
3482 ast.NodeInfixOp.InfixOp.Assign => " = ",
3483 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
3484 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
3485 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
3486 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
3487 ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
3488 ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
3489 ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
3490 ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
3491 ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
3492 ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
3493 ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
3494 ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
3495 ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
3496 ast.NodeInfixOp.InfixOp.BangEqual => " != ",
3497 ast.NodeInfixOp.InfixOp.BitAnd => " & ",
3498 ast.NodeInfixOp.InfixOp.BitOr => " | ",
3499 ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
3500 ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
3501 ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
3502 ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
3503 ast.NodeInfixOp.InfixOp.BoolOr => " or ",
3504 ast.NodeInfixOp.InfixOp.Div => " / ",
3505 ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
3506 ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
3507 ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
3508 ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
3509 ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
3510 ast.NodeInfixOp.InfixOp.LessThan => " < ",
3511 ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
3512 ast.NodeInfixOp.InfixOp.Mod => " % ",
3513 ast.NodeInfixOp.InfixOp.Mult => " * ",
3514 ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
3515 ast.NodeInfixOp.InfixOp.Period => ".",
3516 ast.NodeInfixOp.InfixOp.Sub => " - ",
3517 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
3518 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
3519 ast.NodeInfixOp.InfixOp.Range => " ... ",
3520 ast.NodeInfixOp.InfixOp.Catch => unreachable,
3521 };
3522
3523 try stack.append(RenderState { .Text = text });
3524 }
3525 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
3526 },
3527 ast.Node.Id.PrefixOp => {
3528 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
3529 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
3530 switch (prefix_op_node.op) {
3531 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
3532 try stream.write("&");
3533 if (addr_of_info.volatile_token != null) {
3534 try stack.append(RenderState { .Text = "volatile "});
3535 }
3536 if (addr_of_info.const_token != null) {
3537 try stack.append(RenderState { .Text = "const "});
3538 }
3539 if (addr_of_info.align_expr) |align_expr| {
3540 try stream.print("align(");
3541 try stack.append(RenderState { .Text = ") "});
3542 try stack.append(RenderState { .Expression = align_expr});
3543 }
3544 },
3545 ast.NodePrefixOp.PrefixOp.SliceType => |addr_of_info| {
3546 try stream.write("[]");
3547 if (addr_of_info.volatile_token != null) {
3548 try stack.append(RenderState { .Text = "volatile "});
3549 }
3550 if (addr_of_info.const_token != null) {
3551 try stack.append(RenderState { .Text = "const "});
3552 }
3553 if (addr_of_info.align_expr) |align_expr| {
3554 try stream.print("align(");
3555 try stack.append(RenderState { .Text = ") "});
3556 try stack.append(RenderState { .Expression = align_expr});
3557 }
3558 },
3559 ast.NodePrefixOp.PrefixOp.ArrayType => |array_index| {
3560 try stack.append(RenderState { .Text = "]"});
3561 try stack.append(RenderState { .Expression = array_index});
3562 try stack.append(RenderState { .Text = "["});
3563 },
3564 ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"),
3565 ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"),
3566 ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"),
3567 ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"),
3568 ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"),
3569 ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "),
3570 ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"),
3571 ast.NodePrefixOp.PrefixOp.MaybeType => try stream.write("?"),
3572 ast.NodePrefixOp.PrefixOp.Await => try stream.write("await "),
3573 ast.NodePrefixOp.PrefixOp.Cancel => try stream.write("cancel "),
3574 ast.NodePrefixOp.PrefixOp.Resume => try stream.write("resume "),
3575 }
3576 },
3577 ast.Node.Id.SuffixOp => {
3578 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", base);
3579
3580 switch (suffix_op.op) {
3581 ast.NodeSuffixOp.SuffixOp.Call => |call_info| {
3582 try stack.append(RenderState { .Text = ")"});
3583 var i = call_info.params.len;
3584 while (i != 0) {
3585 i -= 1;
3586 const param_node = call_info.params.at(i);
3587 try stack.append(RenderState { .Expression = param_node});
3588 if (i != 0) {
3589 try stack.append(RenderState { .Text = ", " });
3590 }
3591 }
3592 try stack.append(RenderState { .Text = "("});
3593 try stack.append(RenderState { .Expression = suffix_op.lhs });
3594
3595 if (call_info.async_attr) |async_attr| {
3596 try stack.append(RenderState { .Text = " "});
3597 try stack.append(RenderState { .Expression = &async_attr.base });
3598 }
3599 },
3600 ast.NodeSuffixOp.SuffixOp.ArrayAccess => |index_expr| {
3601 try stack.append(RenderState { .Text = "]"});
3602 try stack.append(RenderState { .Expression = index_expr});
3603 try stack.append(RenderState { .Text = "["});
3604 try stack.append(RenderState { .Expression = suffix_op.lhs });
3605 },
3606 ast.NodeSuffixOp.SuffixOp.Slice => |range| {
3607 try stack.append(RenderState { .Text = "]"});
3608 if (range.end) |end| {
3609 try stack.append(RenderState { .Expression = end});
3610 }
3611 try stack.append(RenderState { .Text = ".."});
3612 try stack.append(RenderState { .Expression = range.start});
3613 try stack.append(RenderState { .Text = "["});
3614 try stack.append(RenderState { .Expression = suffix_op.lhs });
3615 },
3616 ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {
3617 if (field_inits.len == 0) {
3618 try stack.append(RenderState { .Text = "{}" });
3619 try stack.append(RenderState { .Expression = suffix_op.lhs });
3620 continue;
3621 }
3622 try stack.append(RenderState { .Text = "}"});
3623 try stack.append(RenderState.PrintIndent);
3624 try stack.append(RenderState { .Indent = indent });
3625 var i = field_inits.len;
3626 while (i != 0) {
3627 i -= 1;
3628 const field_init = field_inits.at(i);
3629 try stack.append(RenderState { .Text = ",\n" });
3630 try stack.append(RenderState { .FieldInitializer = field_init });
3631 try stack.append(RenderState.PrintIndent);
3632 }
3633 try stack.append(RenderState { .Indent = indent + indent_delta });
3634 try stack.append(RenderState { .Text = " {\n"});
3635 try stack.append(RenderState { .Expression = suffix_op.lhs });
3636 },
3637 ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {
3638 if (exprs.len == 0) {
3639 try stack.append(RenderState { .Text = "{}" });
3640 try stack.append(RenderState { .Expression = suffix_op.lhs });
3641 continue;
3642 }
3643 try stack.append(RenderState { .Text = "}"});
3644 try stack.append(RenderState.PrintIndent);
3645 try stack.append(RenderState { .Indent = indent });
3646 var i = exprs.len;
3647 while (i != 0) {
3648 i -= 1;
3649 const expr = exprs.at(i);
3650 try stack.append(RenderState { .Text = ",\n" });
3651 try stack.append(RenderState { .Expression = expr });
3652 try stack.append(RenderState.PrintIndent);
3653 }
3654 try stack.append(RenderState { .Indent = indent + indent_delta });
3655 try stack.append(RenderState { .Text = " {\n"});
3656 try stack.append(RenderState { .Expression = suffix_op.lhs });
3657 },
3658 }
3659 },
3660 ast.Node.Id.ControlFlowExpression => {
3661 const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
3662
3663 if (flow_expr.rhs) |rhs| {
3664 try stack.append(RenderState { .Expression = rhs });
3665 try stack.append(RenderState { .Text = " " });
3666 }
3667
3668 switch (flow_expr.kind) {
3669 ast.NodeControlFlowExpression.Kind.Break => |maybe_label| {
3670 try stream.print("break");
3671 if (maybe_label) |label| {
3672 try stream.print(" :");
3673 try stack.append(RenderState { .Expression = label });
3674 }
3675 },
3676 ast.NodeControlFlowExpression.Kind.Continue => |maybe_label| {
3677 try stream.print("continue");
3678 if (maybe_label) |label| {
3679 try stream.print(" :");
3680 try stack.append(RenderState { .Expression = label });
3681 }
3682 },
3683 ast.NodeControlFlowExpression.Kind.Return => {
3684 try stream.print("return");
3685 },
3686
3687 }
3688 },
3689 ast.Node.Id.Payload => {
3690 const payload = @fieldParentPtr(ast.NodePayload, "base", base);
3691 try stack.append(RenderState { .Text = "|"});
3692 try stack.append(RenderState { .Expression = payload.error_symbol });
3693 try stack.append(RenderState { .Text = "|"});
3694 },
3695 ast.Node.Id.PointerPayload => {
3696 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
3697 try stack.append(RenderState { .Text = "|"});
3698 try stack.append(RenderState { .Expression = payload.value_symbol });
3699
3700 if (payload.ptr_token) |ptr_token| {
3701 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
3702 }
3703
3704 try stack.append(RenderState { .Text = "|"});
3705 },
3706 ast.Node.Id.PointerIndexPayload => {
3707 const payload = @fieldParentPtr(ast.NodePointerIndexPayload, "base", base);
3708 try stack.append(RenderState { .Text = "|"});
3709
3710 if (payload.index_symbol) |index_symbol| {
3711 try stack.append(RenderState { .Expression = index_symbol });
3712 try stack.append(RenderState { .Text = ", "});
3713 }
3714
3715 try stack.append(RenderState { .Expression = payload.value_symbol });
3716
3717 if (payload.ptr_token) |ptr_token| {
3718 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
3719 }
3720
3721 try stack.append(RenderState { .Text = "|"});
3722 },
3723 ast.Node.Id.GroupedExpression => {
3724 const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base);
3725 try stack.append(RenderState { .Text = ")"});
3726 try stack.append(RenderState { .Expression = grouped_expr.expr });
3727 try stack.append(RenderState { .Text = "("});
3728 },
3729 ast.Node.Id.FieldInitializer => {
3730 const field_init = @fieldParentPtr(ast.NodeFieldInitializer, "base", base);
3731 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
3732 try stack.append(RenderState { .Expression = field_init.expr });
3733 },
3734 ast.Node.Id.IntegerLiteral => {
3735 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);
3736 try stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token));
3737 },
3738 ast.Node.Id.FloatLiteral => {
3739 const float_literal = @fieldParentPtr(ast.NodeFloatLiteral, "base", base);
3740 try stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token));
3741 },
3742 ast.Node.Id.StringLiteral => {
3743 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
3744 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
3745 },
3746 ast.Node.Id.CharLiteral => {
3747 const char_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3748 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
3749 },
3750 ast.Node.Id.BoolLiteral => {
3751 const bool_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3752 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
3753 },
3754 ast.Node.Id.NullLiteral => {
3755 const null_literal = @fieldParentPtr(ast.NodeNullLiteral, "base", base);
3756 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
3757 },
3758 ast.Node.Id.ThisLiteral => {
3759 const this_literal = @fieldParentPtr(ast.NodeThisLiteral, "base", base);
3760 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
3761 },
3762 ast.Node.Id.Unreachable => {
3763 const unreachable_node = @fieldParentPtr(ast.NodeUnreachable, "base", base);
3764 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
3765 },
3766 ast.Node.Id.ErrorType => {
3767 const error_type = @fieldParentPtr(ast.NodeErrorType, "base", base);
3768 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
3769 },
3770 ast.Node.Id.VarType => {
3771 const var_type = @fieldParentPtr(ast.NodeVarType, "base", base);
3772 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
3773 },
3774 ast.Node.Id.ContainerDecl => {
3775 const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base);
3776
3777 switch (container_decl.layout) {
3778 ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "),
3779 ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "),
3780 ast.NodeContainerDecl.Layout.Auto => { },
3781 }
3782
3783 switch (container_decl.kind) {
3784 ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"),
3785 ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"),
3786 ast.NodeContainerDecl.Kind.Union => try stream.print("union"),
3787 }
3788
3789 try stack.append(RenderState { .Text = "}"});
3790 try stack.append(RenderState.PrintIndent);
3791 try stack.append(RenderState { .Indent = indent });
3792 try stack.append(RenderState { .Text = "\n"});
3793
3794 const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
3795 var i = fields_and_decls.len;
3796 while (i != 0) {
3797 i -= 1;
3798 const node = fields_and_decls[i];
3799 switch (node.id) {
3800 ast.Node.Id.StructField,
3801 ast.Node.Id.UnionTag,
3802 ast.Node.Id.EnumTag => {
3803 try stack.append(RenderState { .Text = "," });
3804 },
3805 else => { }
3806 }
3807 try stack.append(RenderState { .TopLevelDecl = node});
3808 try stack.append(RenderState.PrintIndent);
3809 try stack.append(RenderState {
3810 .Text = blk: {
3811 if (i != 0) {
3812 const prev_node = fields_and_decls[i - 1];
3813 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3814 if (loc.line >= 2) {
3815 break :blk "\n\n";
3816 }
3817 }
3818 break :blk "\n";
3819 },
3820 });
3821 }
3822 try stack.append(RenderState { .Indent = indent + indent_delta});
3823 try stack.append(RenderState { .Text = "{"});
3824
3825 switch (container_decl.init_arg_expr) {
3826 ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
3827 ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
3828 ast.NodeContainerDecl.InitArg.Type => |type_expr| {
3829 try stack.append(RenderState { .Text = ") "});
3830 try stack.append(RenderState { .Expression = type_expr});
3831 try stack.append(RenderState { .Text = "("});
3832 },
3833 }
3834 },
3835 ast.Node.Id.ErrorSetDecl => {
3836 const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base);
3837 try stream.print("error ");
3838
3839 try stack.append(RenderState { .Text = "}"});
3840 try stack.append(RenderState.PrintIndent);
3841 try stack.append(RenderState { .Indent = indent });
3842 try stack.append(RenderState { .Text = "\n"});
3843
3844 const decls = err_set_decl.decls.toSliceConst();
3845 var i = decls.len;
3846 while (i != 0) {
3847 i -= 1;
3848 const node = decls[i];
3849 try stack.append(RenderState { .Text = "," });
3850 try stack.append(RenderState { .Expression = node });
3851 try stack.append(RenderState.PrintIndent);
3852 try stack.append(RenderState {
3853 .Text = blk: {
3854 if (i != 0) {
3855 const prev_node = decls[i - 1];
3856 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3857 if (loc.line >= 2) {
3858 break :blk "\n\n";
3859 }
3860 }
3861 break :blk "\n";
3862 },
3863 });
3864 }
3865 try stack.append(RenderState { .Indent = indent + indent_delta});
3866 try stack.append(RenderState { .Text = "{"});
3867 },
3868 ast.Node.Id.MultilineStringLiteral => {
3869 const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
3870 try stream.print("\n");
3871
3872 var i : usize = 0;
3873 while (i < multiline_str_literal.tokens.len) : (i += 1) {
3874 const t = multiline_str_literal.tokens.at(i);
3875 try stream.writeByteNTimes(' ', indent + indent_delta);
3876 try stream.print("{}", self.tokenizer.getTokenSlice(t));
3877 }
3878 try stream.writeByteNTimes(' ', indent + indent_delta);
3879 },
3880 ast.Node.Id.UndefinedLiteral => {
3881 const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);
3882 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
3883 },
3884 ast.Node.Id.BuiltinCall => {
3885 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);
3886 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
3887 try stack.append(RenderState { .Text = ")"});
3888 var i = builtin_call.params.len;
3889 while (i != 0) {
3890 i -= 1;
3891 const param_node = builtin_call.params.at(i);
3892 try stack.append(RenderState { .Expression = param_node});
3893 if (i != 0) {
3894 try stack.append(RenderState { .Text = ", " });
3895 }
3896 }
3897 },
3898 ast.Node.Id.FnProto => {
3899 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", base);
3900
3901 switch (fn_proto.return_type) {
3902 ast.NodeFnProto.ReturnType.Explicit => |node| {
3903 try stack.append(RenderState { .Expression = node});
3904 },
3905 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
3906 try stack.append(RenderState { .Expression = node});
3907 try stack.append(RenderState { .Text = "!"});
3908 },
3909 }
3910
3911 if (fn_proto.align_expr) |align_expr| {
3912 try stack.append(RenderState { .Text = ") " });
3913 try stack.append(RenderState { .Expression = align_expr});
3914 try stack.append(RenderState { .Text = "align(" });
3915 }
3916
3917 try stack.append(RenderState { .Text = ") " });
3918 var i = fn_proto.params.len;
3919 while (i != 0) {
3920 i -= 1;
3921 const param_decl_node = fn_proto.params.items[i];
3922 try stack.append(RenderState { .ParamDecl = param_decl_node});
3923 if (i != 0) {
3924 try stack.append(RenderState { .Text = ", " });
3925 }
3926 }
3927
3928 try stack.append(RenderState { .Text = "(" });
3929 if (fn_proto.name_token) |name_token| {
3930 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) });
3931 try stack.append(RenderState { .Text = " " });
3932 }
3933
3934 try stack.append(RenderState { .Text = "fn" });
3935
3936 if (fn_proto.async_attr) |async_attr| {
3937 try stack.append(RenderState { .Text = " " });
3938 try stack.append(RenderState { .Expression = &async_attr.base });
3939 }
3940
3941 if (fn_proto.cc_token) |cc_token| {
3942 try stack.append(RenderState { .Text = " " });
3943 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) });
3944 }
3945
3946 if (fn_proto.lib_name) |lib_name| {
3947 try stack.append(RenderState { .Text = " " });
3948 try stack.append(RenderState { .Expression = lib_name });
3949 }
3950 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
3951 try stack.append(RenderState { .Text = " " });
3952 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) });
3953 }
3954
3955 if (fn_proto.visib_token) |visib_token| {
3956 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
3957 try stack.append(RenderState { .Text = " " });
3958 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3959 }
3960 },
3961 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
3962 ast.Node.Id.Switch => {
3963 const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base);
3964 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
3965
3966 try stack.append(RenderState { .Text = "}"});
3967 try stack.append(RenderState.PrintIndent);
3968 try stack.append(RenderState { .Indent = indent });
3969 try stack.append(RenderState { .Text = "\n"});
3970
3971 const cases = switch_node.cases.toSliceConst();
3972 var i = cases.len;
3973 while (i != 0) {
3974 i -= 1;
3975 const node = cases[i];
3976 try stack.append(RenderState { .Text = ","});
3977 try stack.append(RenderState { .Expression = &node.base});
3978 try stack.append(RenderState.PrintIndent);
3979 try stack.append(RenderState {
3980 .Text = blk: {
3981 if (i != 0) {
3982 const prev_node = cases[i - 1];
3983 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3984 if (loc.line >= 2) {
3985 break :blk "\n\n";
3986 }
3987 }
3988 break :blk "\n";
3989 },
3990 });
3991 }
3992 try stack.append(RenderState { .Indent = indent + indent_delta});
3993 try stack.append(RenderState { .Text = ") {"});
3994 try stack.append(RenderState { .Expression = switch_node.expr });
3995 },
3996 ast.Node.Id.SwitchCase => {
3997 const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
3998
3999 try stack.append(RenderState { .Expression = switch_case.expr });
4000 if (switch_case.payload) |payload| {
4001 try stack.append(RenderState { .Text = " " });
4002 try stack.append(RenderState { .Expression = payload });
4003 }
4004 try stack.append(RenderState { .Text = " => "});
4005
4006 const items = switch_case.items.toSliceConst();
4007 var i = items.len;
4008 while (i != 0) {
4009 i -= 1;
4010 try stack.append(RenderState { .Expression = items[i] });
4011
4012 if (i != 0) {
4013 try stack.append(RenderState.PrintIndent);
4014 try stack.append(RenderState { .Text = ",\n" });
4015 }
4016 }
4017 },
4018 ast.Node.Id.SwitchElse => {
4019 const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
4020 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
4021 },
4022 ast.Node.Id.Else => {
4023 const else_node = @fieldParentPtr(ast.NodeElse, "base", base);
4024 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
4025
4026 switch (else_node.body.id) {
4027 ast.Node.Id.Block, ast.Node.Id.If,
4028 ast.Node.Id.For, ast.Node.Id.While,
4029 ast.Node.Id.Switch => {
4030 try stream.print(" ");
4031 try stack.append(RenderState { .Expression = else_node.body });
4032 },
4033 else => {
4034 try stack.append(RenderState { .Indent = indent });
4035 try stack.append(RenderState { .Expression = else_node.body });
4036 try stack.append(RenderState.PrintIndent);
4037 try stack.append(RenderState { .Indent = indent + indent_delta });
4038 try stack.append(RenderState { .Text = "\n" });
4039 }
4040 }
4041
4042 if (else_node.payload) |payload| {
4043 try stack.append(RenderState { .Text = " " });
4044 try stack.append(RenderState { .Expression = payload });
4045 }
4046 },
4047 ast.Node.Id.While => {
4048 const while_node = @fieldParentPtr(ast.NodeWhile, "base", base);
4049 if (while_node.label) |label| {
4050 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4051 }
4052
4053 if (while_node.inline_token) |inline_token| {
4054 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4055 }
4056
4057 try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token));
4058
4059 if (while_node.@"else") |@"else"| {
4060 try stack.append(RenderState { .Expression = &@"else".base });
4061
4062 if (while_node.body.id == ast.Node.Id.Block) {
4063 try stack.append(RenderState { .Text = " " });
4064 } else {
4065 try stack.append(RenderState.PrintIndent);
4066 try stack.append(RenderState { .Text = "\n" });
4067 }
4068 }
4069
4070 if (while_node.body.id == ast.Node.Id.Block) {
4071 try stack.append(RenderState { .Expression = while_node.body });
4072 try stack.append(RenderState { .Text = " " });
4073 } else {
4074 try stack.append(RenderState { .Indent = indent });
4075 try stack.append(RenderState { .Expression = while_node.body });
4076 try stack.append(RenderState.PrintIndent);
4077 try stack.append(RenderState { .Indent = indent + indent_delta });
4078 try stack.append(RenderState { .Text = "\n" });
4079 }
4080
4081 if (while_node.continue_expr) |continue_expr| {
4082 try stack.append(RenderState { .Text = ")" });
4083 try stack.append(RenderState { .Expression = continue_expr });
4084 try stack.append(RenderState { .Text = ": (" });
4085 try stack.append(RenderState { .Text = " " });
4086 }
4087
4088 if (while_node.payload) |payload| {
4089 try stack.append(RenderState { .Expression = payload });
4090 try stack.append(RenderState { .Text = " " });
4091 }
4092
4093 try stack.append(RenderState { .Text = ")" });
4094 try stack.append(RenderState { .Expression = while_node.condition });
4095 try stack.append(RenderState { .Text = "(" });
4096 },
4097 ast.Node.Id.For => {
4098 const for_node = @fieldParentPtr(ast.NodeFor, "base", base);
4099 if (for_node.label) |label| {
4100 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4101 }
4102
4103 if (for_node.inline_token) |inline_token| {
4104 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4105 }
4106
4107 try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
4108
4109 if (for_node.@"else") |@"else"| {
4110 try stack.append(RenderState { .Expression = &@"else".base });
4111
4112 if (for_node.body.id == ast.Node.Id.Block) {
4113 try stack.append(RenderState { .Text = " " });
4114 } else {
4115 try stack.append(RenderState.PrintIndent);
4116 try stack.append(RenderState { .Text = "\n" });
4117 }
4118 }
4119
4120 if (for_node.body.id == ast.Node.Id.Block) {
4121 try stack.append(RenderState { .Expression = for_node.body });
4122 try stack.append(RenderState { .Text = " " });
4123 } else {
4124 try stack.append(RenderState { .Indent = indent });
4125 try stack.append(RenderState { .Expression = for_node.body });
4126 try stack.append(RenderState.PrintIndent);
4127 try stack.append(RenderState { .Indent = indent + indent_delta });
4128 try stack.append(RenderState { .Text = "\n" });
4129 }
4130
4131 if (for_node.payload) |payload| {
4132 try stack.append(RenderState { .Expression = payload });
4133 try stack.append(RenderState { .Text = " " });
4134 }
4135
4136 try stack.append(RenderState { .Text = ")" });
4137 try stack.append(RenderState { .Expression = for_node.array_expr });
4138 try stack.append(RenderState { .Text = "(" });
4139 },
4140 ast.Node.Id.If => {
4141 const if_node = @fieldParentPtr(ast.NodeIf, "base", base);
4142 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
4143
4144 switch (if_node.body.id) {
4145 ast.Node.Id.Block, ast.Node.Id.If,
4146 ast.Node.Id.For, ast.Node.Id.While,
4147 ast.Node.Id.Switch => {
4148 if (if_node.@"else") |@"else"| {
4149 try stack.append(RenderState { .Expression = &@"else".base });
4150
4151 if (if_node.body.id == ast.Node.Id.Block) {
4152 try stack.append(RenderState { .Text = " " });
4153 } else {
4154 try stack.append(RenderState.PrintIndent);
4155 try stack.append(RenderState { .Text = "\n" });
4156 }
4157 }
4158 },
4159 else => {
4160 if (if_node.@"else") |@"else"| {
4161 try stack.append(RenderState { .Expression = @"else".body });
4162
4163 if (@"else".payload) |payload| {
4164 try stack.append(RenderState { .Text = " " });
4165 try stack.append(RenderState { .Expression = payload });
4166 }
4167
4168 try stack.append(RenderState { .Text = " " });
4169 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) });
4170 try stack.append(RenderState { .Text = " " });
4171 }
4172 }
4173 }
4174
4175 try stack.append(RenderState { .Expression = if_node.body });
4176 try stack.append(RenderState { .Text = " " });
4177
4178 if (if_node.payload) |payload| {
4179 try stack.append(RenderState { .Expression = payload });
4180 try stack.append(RenderState { .Text = " " });
4181 }
4182
4183 try stack.append(RenderState { .Text = ")" });
4184 try stack.append(RenderState { .Expression = if_node.condition });
4185 try stack.append(RenderState { .Text = "(" });
4186 },
4187 ast.Node.Id.Asm => {
4188 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
4189 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
4190
4191 if (asm_node.volatile_token) |volatile_token| {
4192 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
4193 }
4194
4195 try stack.append(RenderState { .Indent = indent });
4196 try stack.append(RenderState { .Text = ")" });
4197 {
4198 const cloppers = asm_node.cloppers.toSliceConst();
4199 var i = cloppers.len;
4200 while (i != 0) {
4201 i -= 1;
4202 try stack.append(RenderState { .Expression = cloppers[i] });
4203
4204 if (i != 0) {
4205 try stack.append(RenderState { .Text = ", " });
4206 }
4207 }
4208 }
4209 try stack.append(RenderState { .Text = ": " });
4210 try stack.append(RenderState.PrintIndent);
4211 try stack.append(RenderState { .Indent = indent + indent_delta });
4212 try stack.append(RenderState { .Text = "\n" });
4213 {
4214 const inputs = asm_node.inputs.toSliceConst();
4215 var i = inputs.len;
4216 while (i != 0) {
4217 i -= 1;
4218 const node = inputs[i];
4219 try stack.append(RenderState { .Expression = &node.base});
4220
4221 if (i != 0) {
4222 try stack.append(RenderState.PrintIndent);
4223 try stack.append(RenderState {
4224 .Text = blk: {
4225 const prev_node = inputs[i - 1];
4226 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4227 if (loc.line >= 2) {
4228 break :blk "\n\n";
4229 }
4230 break :blk "\n";
4231 },
4232 });
4233 try stack.append(RenderState { .Text = "," });
4234 }
4235 }
4236 }
4237 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4238 try stack.append(RenderState { .Text = ": "});
4239 try stack.append(RenderState.PrintIndent);
4240 try stack.append(RenderState { .Indent = indent + indent_delta});
4241 try stack.append(RenderState { .Text = "\n" });
4242 {
4243 const outputs = asm_node.outputs.toSliceConst();
4244 var i = outputs.len;
4245 while (i != 0) {
4246 i -= 1;
4247 const node = outputs[i];
4248 try stack.append(RenderState { .Expression = &node.base});
4249
4250 if (i != 0) {
4251 try stack.append(RenderState.PrintIndent);
4252 try stack.append(RenderState {
4253 .Text = blk: {
4254 const prev_node = outputs[i - 1];
4255 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4256 if (loc.line >= 2) {
4257 break :blk "\n\n";
4258 }
4259 break :blk "\n";
4260 },
4261 });
4262 try stack.append(RenderState { .Text = "," });
4263 }
4264 }
4265 }
4266 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4267 try stack.append(RenderState { .Text = ": "});
4268 try stack.append(RenderState.PrintIndent);
4269 try stack.append(RenderState { .Indent = indent + indent_delta});
4270 try stack.append(RenderState { .Text = "\n" });
4271 try stack.append(RenderState { .Expression = asm_node.template });
4272 try stack.append(RenderState { .Text = "(" });
4273 },
4274 ast.Node.Id.AsmInput => {
4275 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
4276
4277 try stack.append(RenderState { .Text = ")"});
4278 try stack.append(RenderState { .Expression = asm_input.expr});
4279 try stack.append(RenderState { .Text = " ("});
4280 try stack.append(RenderState { .Expression = asm_input.constraint });
4281 try stack.append(RenderState { .Text = "] "});
4282 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
4283 try stack.append(RenderState { .Text = "["});
4284 },
4285 ast.Node.Id.AsmOutput => {
4286 const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base);
4287
4288 try stack.append(RenderState { .Text = ")"});
4289 switch (asm_output.kind) {
4290 ast.NodeAsmOutput.Kind.Variable => |variable_name| {
4291 try stack.append(RenderState { .Expression = &variable_name.base});
4292 },
4293 ast.NodeAsmOutput.Kind.Return => |return_type| {
4294 try stack.append(RenderState { .Expression = return_type});
4295 try stack.append(RenderState { .Text = "-> "});
4296 },
4297 }
4298 try stack.append(RenderState { .Text = " ("});
4299 try stack.append(RenderState { .Expression = asm_output.constraint });
4300 try stack.append(RenderState { .Text = "] "});
4301 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
4302 try stack.append(RenderState { .Text = "["});
4303 },
4304
4305 ast.Node.Id.StructField,
4306 ast.Node.Id.UnionTag,
4307 ast.Node.Id.EnumTag,
4308 ast.Node.Id.Root,
4309 ast.Node.Id.VarDecl,
4310 ast.Node.Id.Use,
4311 ast.Node.Id.TestDecl,
4312 ast.Node.Id.ParamDecl => unreachable,
4313 },
4314 RenderState.Statement => |base| {
4315 if (base.comment) |comment| {
4316 for (comment.lines.toSliceConst()) |line_token| {
4317 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
4318 try stream.writeByteNTimes(' ', indent);
4319 }
4320 }
4321 switch (base.id) {
4322 ast.Node.Id.VarDecl => {
4323 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base);
4324 try stack.append(RenderState { .VarDecl = var_decl});
4325 },
4326 else => {
4327 if (requireSemiColon(base)) {
4328 try stack.append(RenderState { .Text = ";" });
4329 }
4330 try stack.append(RenderState { .Expression = base });
4331 },
4332 }
4333 },
4334 RenderState.Indent => |new_indent| indent = new_indent,
4335 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
4336 }
4337 }
4338 }
4339
4340 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
4341 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
4342 self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
4343 const typed_slice = ([]T)(self.utility_bytes);
4344 return ArrayList(T) {
4345 .allocator = self.util_allocator,
4346 .items = typed_slice,
4347 .len = 0,
4348 };
4349 }
4350
4351 fn deinitUtilityArrayList(self: &Parser, list: var) void {
4352 self.utility_bytes = ([]align(utility_bytes_align) u8)(list.items);
4353 }
4354
4355};
4356
4357var fixed_buffer_mem: [100 * 1024]u8 = undefined;
4358
4359fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
4360 var tokenizer = Tokenizer.init(source);
4361 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");
4362 defer parser.deinit();
4363
4364 var tree = try parser.parse();
4365 defer tree.deinit();
4366
4367 var buffer = try std.Buffer.initSize(allocator, 0);
4368 errdefer buffer.deinit();
4369
4370 var buffer_out_stream = io.BufferOutStream.init(&buffer);
4371 try parser.renderSource(&buffer_out_stream.stream, tree.root_node);
4372 return buffer.toOwnedSlice();
4373}
4374
4375fn testCanonical(source: []const u8) !void {
4376 const needed_alloc_count = x: {
4377 // Try it once with unlimited memory, make sure it works
4378 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
4379 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
4380 const result_source = try testParse(source, &failing_allocator.allocator);
4381 if (!mem.eql(u8, result_source, source)) {
4382 warn("\n====== expected this output: =========\n");
4383 warn("{}", source);
4384 warn("\n======== instead found this: =========\n");
4385 warn("{}", result_source);
4386 warn("\n======================================\n");
4387 return error.TestFailed;
4388 }
4389 failing_allocator.allocator.free(result_source);
4390 break :x failing_allocator.index;
4391 };
4392
4393 var fail_index: usize = 0;
4394 while (fail_index < needed_alloc_count) : (fail_index += 1) {
4395 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
4396 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
4397 if (testParse(source, &failing_allocator.allocator)) |_| {
4398 return error.NondeterministicMemoryUsage;
4399 } else |err| switch (err) {
4400 error.OutOfMemory => {
4401 if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
4402 warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",
4403 fail_index, needed_alloc_count,
4404 failing_allocator.allocated_bytes, failing_allocator.freed_bytes,
4405 failing_allocator.index, failing_allocator.deallocations);
4406 return error.MemoryLeakDetected;
4407 }
4408 },
4409 error.ParseError => @panic("test failed"),
4410 }
4411 }
4412}
4413
4414test "zig fmt: get stdout or fail" {
4415 try testCanonical(
4416 \\const std = @import("std");
4417 \\
4418 \\pub fn main() !void {
4419 \\ // If this program is run without stdout attached, exit with an error.
4420 \\ // another comment
4421 \\ var stdout_file = try std.io.getStdOut;
4422 \\}
4423 \\
4424 );
4425}
4426
4427test "zig fmt: preserve spacing" {
4428 try testCanonical(
4429 \\const std = @import("std");
4430 \\
4431 \\pub fn main() !void {
4432 \\ var stdout_file = try std.io.getStdOut;
4433 \\ var stdout_file = try std.io.getStdOut;
4434 \\
4435 \\ var stdout_file = try std.io.getStdOut;
4436 \\ var stdout_file = try std.io.getStdOut;
4437 \\}
4438 \\
4439 );
4440}
4441
4442test "zig fmt: return types" {
4443 try testCanonical(
4444 \\pub fn main() !void {}
4445 \\pub fn main() var {}
4446 \\pub fn main() i32 {}
4447 \\
4448 );
4449}
4450
4451test "zig fmt: imports" {
4452 try testCanonical(
4453 \\const std = @import("std");
4454 \\const std = @import();
4455 \\
4456 );
4457}
4458
4459test "zig fmt: global declarations" {
4460 try testCanonical(
4461 \\const a = b;
4462 \\pub const a = b;
4463 \\var a = b;
4464 \\pub var a = b;
4465 \\const a: i32 = b;
4466 \\pub const a: i32 = b;
4467 \\var a: i32 = b;
4468 \\pub var a: i32 = b;
4469 \\extern const a: i32 = b;
4470 \\pub extern const a: i32 = b;
4471 \\extern var a: i32 = b;
4472 \\pub extern var a: i32 = b;
4473 \\extern "a" const a: i32 = b;
4474 \\pub extern "a" const a: i32 = b;
4475 \\extern "a" var a: i32 = b;
4476 \\pub extern "a" var a: i32 = b;
4477 \\
4478 );
4479}
4480
4481test "zig fmt: extern declaration" {
4482 try testCanonical(
4483 \\extern var foo: c_int;
4484 \\
4485 );
4486}
4487
4488test "zig fmt: alignment" {
4489 try testCanonical(
4490 \\var foo: c_int align(1);
4491 \\
4492 );
4493}
4494
4495test "zig fmt: C main" {
4496 try testCanonical(
4497 \\fn main(argc: c_int, argv: &&u8) c_int {
4498 \\ const a = b;
4499 \\}
4500 \\
4501 );
4502}
4503
4504test "zig fmt: return" {
4505 try testCanonical(
4506 \\fn foo(argc: c_int, argv: &&u8) c_int {
4507 \\ return 0;
4508 \\}
4509 \\
4510 \\fn bar() void {
4511 \\ return;
4512 \\}
4513 \\
4514 );
4515}
4516
4517test "zig fmt: pointer attributes" {
4518 try testCanonical(
4519 \\extern fn f1(s: &align(&u8) u8) c_int;
4520 \\extern fn f2(s: &&align(1) &const &volatile u8) c_int;
4521 \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int;
4522 \\extern fn f4(s: &align(1) const volatile u8) c_int;
4523 \\
4524 );
4525}
4526
4527test "zig fmt: slice attributes" {
4528 try testCanonical(
4529 \\extern fn f1(s: &align(&u8) u8) c_int;
4530 \\extern fn f2(s: &&align(1) &const &volatile u8) c_int;
4531 \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int;
4532 \\extern fn f4(s: &align(1) const volatile u8) c_int;
4533 \\
4534 );
4535}
4536
4537test "zig fmt: test declaration" {
4538 try testCanonical(
4539 \\test "test name" {
4540 \\ const a = 1;
4541 \\ var b = 1;
4542 \\}
4543 \\
4544 );
4545}
4546
4547test "zig fmt: infix operators" {
4548 try testCanonical(
4549 \\test "infix operators" {
4550 \\ var i = undefined;
4551 \\ i = 2;
4552 \\ i *= 2;
4553 \\ i |= 2;
4554 \\ i ^= 2;
4555 \\ i <<= 2;
4556 \\ i >>= 2;
4557 \\ i &= 2;
4558 \\ i *= 2;
4559 \\ i *%= 2;
4560 \\ i -= 2;
4561 \\ i -%= 2;
4562 \\ i += 2;
4563 \\ i +%= 2;
4564 \\ i /= 2;
4565 \\ i %= 2;
4566 \\ _ = i == i;
4567 \\ _ = i != i;
4568 \\ _ = i != i;
4569 \\ _ = i.i;
4570 \\ _ = i || i;
4571 \\ _ = i!i;
4572 \\ _ = i ** i;
4573 \\ _ = i ++ i;
4574 \\ _ = i ?? i;
4575 \\ _ = i % i;
4576 \\ _ = i / i;
4577 \\ _ = i *% i;
4578 \\ _ = i * i;
4579 \\ _ = i -% i;
4580 \\ _ = i - i;
4581 \\ _ = i +% i;
4582 \\ _ = i + i;
4583 \\ _ = i << i;
4584 \\ _ = i >> i;
4585 \\ _ = i & i;
4586 \\ _ = i ^ i;
4587 \\ _ = i | i;
4588 \\ _ = i >= i;
4589 \\ _ = i <= i;
4590 \\ _ = i > i;
4591 \\ _ = i < i;
4592 \\ _ = i and i;
4593 \\ _ = i or i;
4594 \\}
4595 \\
4596 );
4597}
4598
4599test "zig fmt: precedence" {
4600 try testCanonical(
4601 \\test "precedence" {
4602 \\ a!b();
4603 \\ (a!b)();
4604 \\ !a!b;
4605 \\ !(a!b);
4606 \\ !a{};
4607 \\ !(a{});
4608 \\ a + b{};
4609 \\ (a + b){};
4610 \\ a << b + c;
4611 \\ (a << b) + c;
4612 \\ a & b << c;
4613 \\ (a & b) << c;
4614 \\ a ^ b & c;
4615 \\ (a ^ b) & c;
4616 \\ a | b ^ c;
4617 \\ (a | b) ^ c;
4618 \\ a == b | c;
4619 \\ (a == b) | c;
4620 \\ a and b == c;
4621 \\ (a and b) == c;
4622 \\ a or b and c;
4623 \\ (a or b) and c;
4624 \\ (a or b) and c;
4625 \\}
4626 \\
4627 );
4628}
4629
4630test "zig fmt: prefix operators" {
4631 try testCanonical(
4632 \\test "prefix operators" {
4633 \\ try return --%~??!*&0;
4634 \\}
4635 \\
4636 );
4637}
4638
4639test "zig fmt: call expression" {
4640 try testCanonical(
4641 \\test "test calls" {
4642 \\ a();
4643 \\ a(1);
4644 \\ a(1, 2);
4645 \\ a(1, 2) + a(1, 2);
4646 \\}
4647 \\
4648 );
4649}
4650
4651test "zig fmt: var args" {
4652 try testCanonical(
4653 \\fn print(args: ...) void {}
4654 \\
4655 );
4656}
4657
4658test "zig fmt: var type" {
4659 try testCanonical(
4660 \\fn print(args: var) var {}
4661 \\const Var = var;
4662 \\const i: var = 0;
4663 \\
4664 );
4665}
4666
4667test "zig fmt: functions" {
4668 try testCanonical(
4669 \\extern fn puts(s: &const u8) c_int;
4670 \\extern "c" fn puts(s: &const u8) c_int;
4671 \\export fn puts(s: &const u8) c_int;
4672 \\inline fn puts(s: &const u8) c_int;
4673 \\pub extern fn puts(s: &const u8) c_int;
4674 \\pub extern "c" fn puts(s: &const u8) c_int;
4675 \\pub export fn puts(s: &const u8) c_int;
4676 \\pub inline fn puts(s: &const u8) c_int;
4677 \\pub extern fn puts(s: &const u8) align(2 + 2) c_int;
4678 \\pub extern "c" fn puts(s: &const u8) align(2 + 2) c_int;
4679 \\pub export fn puts(s: &const u8) align(2 + 2) c_int;
4680 \\pub inline fn puts(s: &const u8) align(2 + 2) c_int;
4681 \\
4682 );
4683}
4684
4685test "zig fmt: multiline string" {
4686 try testCanonical(
4687 \\const s =
4688 \\ \\ something
4689 \\ \\ something else
4690 \\ ;
4691 \\
4692 );
4693}
4694
4695test "zig fmt: values" {
4696 try testCanonical(
4697 \\test "values" {
4698 \\ 1;
4699 \\ 1.0;
4700 \\ "string";
4701 \\ c"cstring";
4702 \\ 'c';
4703 \\ true;
4704 \\ false;
4705 \\ null;
4706 \\ undefined;
4707 \\ error;
4708 \\ this;
4709 \\ unreachable;
4710 \\}
4711 \\
4712 );
4713}
4714
4715test "zig fmt: indexing" {
4716 try testCanonical(
4717 \\test "test index" {
4718 \\ a[0];
4719 \\ a[0 + 5];
4720 \\ a[0..];
4721 \\ a[0..5];
4722 \\ a[a[0]];
4723 \\ a[a[0..]];
4724 \\ a[a[0..5]];
4725 \\ a[a[0]..];
4726 \\ a[a[0..5]..];
4727 \\ a[a[0]..a[0]];
4728 \\ a[a[0..5]..a[0]];
4729 \\ a[a[0..5]..a[0..5]];
4730 \\}
4731 \\
4732 );
4733}
4734
4735test "zig fmt: struct declaration" {
4736 try testCanonical(
4737 \\const S = struct {
4738 \\ const Self = this;
4739 \\ f1: u8,
4740 \\ pub f3: u8,
4741 \\
4742 \\ fn method(self: &Self) Self {
4743 \\ return *self;
4744 \\ }
4745 \\
4746 \\ f2: u8,
4747 \\};
4748 \\
4749 \\const Ps = packed struct {
4750 \\ a: u8,
4751 \\ pub b: u8,
4752 \\
4753 \\ c: u8,
4754 \\};
4755 \\
4756 \\const Es = extern struct {
4757 \\ a: u8,
4758 \\ pub b: u8,
4759 \\
4760 \\ c: u8,
4761 \\};
4762 \\
4763 );
4764}
4765
4766test "zig fmt: enum declaration" {
4767 try testCanonical(
4768 \\const E = enum {
4769 \\ Ok,
4770 \\ SomethingElse = 0,
4771 \\};
4772 \\
4773 \\const E2 = enum(u8) {
4774 \\ Ok,
4775 \\ SomethingElse = 255,
4776 \\ SomethingThird,
4777 \\};
4778 \\
4779 \\const Ee = extern enum {
4780 \\ Ok,
4781 \\ SomethingElse,
4782 \\ SomethingThird,
4783 \\};
4784 \\
4785 \\const Ep = packed enum {
4786 \\ Ok,
4787 \\ SomethingElse,
4788 \\ SomethingThird,
4789 \\};
4790 \\
4791 );
4792}
4793
4794test "zig fmt: union declaration" {
4795 try testCanonical(
4796 \\const U = union {
4797 \\ Int: u8,
4798 \\ Float: f32,
4799 \\ None,
4800 \\ Bool: bool,
4801 \\};
4802 \\
4803 \\const Ue = union(enum) {
4804 \\ Int: u8,
4805 \\ Float: f32,
4806 \\ None,
4807 \\ Bool: bool,
4808 \\};
4809 \\
4810 \\const E = enum {
4811 \\ Int,
4812 \\ Float,
4813 \\ None,
4814 \\ Bool,
4815 \\};
4816 \\
4817 \\const Ue2 = union(E) {
4818 \\ Int: u8,
4819 \\ Float: f32,
4820 \\ None,
4821 \\ Bool: bool,
4822 \\};
4823 \\
4824 \\const Eu = extern union {
4825 \\ Int: u8,
4826 \\ Float: f32,
4827 \\ None,
4828 \\ Bool: bool,
4829 \\};
4830 \\
4831 );
4832}
4833
4834test "zig fmt: error set declaration" {
4835 try testCanonical(
4836 \\const E = error {
4837 \\ A,
4838 \\ B,
4839 \\
4840 \\ C,
4841 \\};
4842 \\
4843 );
4844}
4845
4846test "zig fmt: arrays" {
4847 try testCanonical(
4848 \\test "test array" {
4849 \\ const a: [2]u8 = [2]u8 {
4850 \\ 1,
4851 \\ 2,
4852 \\ };
4853 \\ const a: [2]u8 = []u8 {
4854 \\ 1,
4855 \\ 2,
4856 \\ };
4857 \\ const a: [0]u8 = []u8{};
4858 \\}
4859 \\
4860 );
4861}
4862
4863test "zig fmt: container initializers" {
4864 try testCanonical(
4865 \\const a1 = []u8{};
4866 \\const a2 = []u8 {
4867 \\ 1,
4868 \\ 2,
4869 \\ 3,
4870 \\ 4,
4871 \\};
4872 \\const s1 = S{};
4873 \\const s2 = S {
4874 \\ .a = 1,
4875 \\ .b = 2,
4876 \\};
4877 \\
4878 );
4879}
4880
4881test "zig fmt: catch" {
4882 try testCanonical(
4883 \\test "catch" {
4884 \\ const a: error!u8 = 0;
4885 \\ _ = a catch return;
4886 \\ _ = a catch |err| return;
4887 \\}
4888 \\
4889 );
4890}
4891
4892test "zig fmt: blocks" {
4893 try testCanonical(
4894 \\test "blocks" {
4895 \\ {
4896 \\ const a = 0;
4897 \\ const b = 0;
4898 \\ }
4899 \\
4900 \\ blk: {
4901 \\ const a = 0;
4902 \\ const b = 0;
4903 \\ }
4904 \\
4905 \\ const r = blk: {
4906 \\ const a = 0;
4907 \\ const b = 0;
4908 \\ };
4909 \\}
4910 \\
4911 );
4912}
4913
4914test "zig fmt: switch" {
4915 try testCanonical(
4916 \\test "switch" {
4917 \\ switch (0) {
4918 \\ 0 => {},
4919 \\ 1 => unreachable,
4920 \\ 2,
4921 \\ 3 => {},
4922 \\ 4 ... 7 => {},
4923 \\ 1 + 4 * 3 + 22 => {},
4924 \\ else => {
4925 \\ const a = 1;
4926 \\ const b = a;
4927 \\ },
4928 \\ }
4929 \\
4930 \\ const res = switch (0) {
4931 \\ 0 => 0,
4932 \\ 1 => 2,
4933 \\ 1 => a = 4,
4934 \\ else => 4,
4935 \\ };
4936 \\
4937 \\ const Union = union(enum) {
4938 \\ Int: i64,
4939 \\ Float: f64,
4940 \\ };
4941 \\
4942 \\ const u = Union {
4943 \\ .Int = 0,
4944 \\ };
4945 \\ switch (u) {
4946 \\ Union.Int => |int| {},
4947 \\ Union.Float => |*float| unreachable,
4948 \\ }
4949 \\}
4950 \\
4951 );
4952}
4953
4954test "zig fmt: while" {
4955 try testCanonical(
4956 \\test "while" {
4957 \\ while (10 < 1) {
4958 \\ unreachable;
4959 \\ }
4960 \\
4961 \\ while (10 < 1)
4962 \\ unreachable;
4963 \\
4964 \\ var i: usize = 0;
4965 \\ while (i < 10) : (i += 1) {
4966 \\ continue;
4967 \\ }
4968 \\
4969 \\ i = 0;
4970 \\ while (i < 10) : (i += 1)
4971 \\ continue;
4972 \\
4973 \\ i = 0;
4974 \\ var j: usize = 0;
4975 \\ while (i < 10) : ({
4976 \\ i += 1;
4977 \\ j += 1;
4978 \\ }) {
4979 \\ continue;
4980 \\ }
4981 \\
4982 \\ var a: ?u8 = 2;
4983 \\ while (a) |v| : (a = null) {
4984 \\ continue;
4985 \\ }
4986 \\
4987 \\ while (a) |v| : (a = null)
4988 \\ unreachable;
4989 \\
4990 \\ label: while (10 < 0) {
4991 \\ unreachable;
4992 \\ }
4993 \\
4994 \\ const res = while (0 < 10) {
4995 \\ break 7;
4996 \\ } else {
4997 \\ unreachable;
4998 \\ };
4999 \\
5000 \\ const res = while (0 < 10)
5001 \\ break 7
5002 \\ else
5003 \\ unreachable;
5004 \\
5005 \\ var a: error!u8 = 0;
5006 \\ while (a) |v| {
5007 \\ a = error.Err;
5008 \\ } else |err| {
5009 \\ i = 1;
5010 \\ }
5011 \\
5012 \\ comptime var k: usize = 0;
5013 \\ inline while (i < 10) : (i += 1)
5014 \\ j += 2;
5015 \\}
5016 \\
5017 );
5018}
5019
5020test "zig fmt: for" {
5021 try testCanonical(
5022 \\test "for" {
5023 \\ const a = []u8 {
5024 \\ 1,
5025 \\ 2,
5026 \\ 3,
5027 \\ };
5028 \\ for (a) |v| {
5029 \\ continue;
5030 \\ }
5031 \\
5032 \\ for (a) |v|
5033 \\ continue;
5034 \\
5035 \\ for (a) |*v|
5036 \\ continue;
5037 \\
5038 \\ for (a) |v, i| {
5039 \\ continue;
5040 \\ }
5041 \\
5042 \\ for (a) |v, i|
5043 \\ continue;
5044 \\
5045 \\ const res = for (a) |v, i| {
5046 \\ break v;
5047 \\ } else {
5048 \\ unreachable;
5049 \\ };
5050 \\
5051 \\ var num: usize = 0;
5052 \\ inline for (a) |v, i| {
5053 \\ num += v;
5054 \\ num += i;
5055 \\ }
5056 \\}
5057 \\
5058 );
5059}
5060
5061test "zig fmt: if" {
5062 try testCanonical(
5063 \\test "if" {
5064 \\ if (10 < 0) {
5065 \\ unreachable;
5066 \\ }
5067 \\
5068 \\ if (10 < 0) unreachable;
5069 \\
5070 \\ if (10 < 0) {
5071 \\ unreachable;
5072 \\ } else {
5073 \\ const a = 20;
5074 \\ }
5075 \\
5076 \\ if (10 < 0) {
5077 \\ unreachable;
5078 \\ } else if (5 < 0) {
5079 \\ unreachable;
5080 \\ } else {
5081 \\ const a = 20;
5082 \\ }
5083 \\
5084 \\ const is_world_broken = if (10 < 0) true else false;
5085 \\ const some_number = 1 + if (10 < 0) 2 else 3;
5086 \\
5087 \\ const a: ?u8 = 10;
5088 \\ const b: ?u8 = null;
5089 \\ if (a) |v| {
5090 \\ const some = v;
5091 \\ } else if (b) |*v| {
5092 \\ unreachable;
5093 \\ } else {
5094 \\ const some = 10;
5095 \\ }
5096 \\
5097 \\ const non_null_a = if (a) |v| v else 0;
5098 \\
5099 \\ const a_err: error!u8 = 0;
5100 \\ if (a_err) |v| {
5101 \\ const p = v;
5102 \\ } else |err| {
5103 \\ unreachable;
5104 \\ }
5105 \\}
5106 \\
5107 );
5108}
5109
5110test "zig fmt: defer" {
5111 try testCanonical(
5112 \\test "defer" {
5113 \\ var i: usize = 0;
5114 \\ defer i = 1;
5115 \\ defer {
5116 \\ i += 2;
5117 \\ i *= i;
5118 \\ }
5119 \\
5120 \\ errdefer i += 3;
5121 \\ errdefer {
5122 \\ i += 2;
5123 \\ i /= i;
5124 \\ }
5125 \\}
5126 \\
5127 );
5128}
5129
5130test "zig fmt: comptime" {
5131 try testCanonical(
5132 \\fn a() u8 {
5133 \\ return 5;
5134 \\}
5135 \\
5136 \\fn b(comptime i: u8) u8 {
5137 \\ return i;
5138 \\}
5139 \\
5140 \\const av = comptime a();
5141 \\const av2 = comptime blk: {
5142 \\ var res = a();
5143 \\ res *= b(2);
5144 \\ break :blk res;
5145 \\};
5146 \\
5147 \\comptime {
5148 \\ _ = a();
5149 \\}
5150 \\
5151 \\test "comptime" {
5152 \\ const av3 = comptime a();
5153 \\ const av4 = comptime blk: {
5154 \\ var res = a();
5155 \\ res *= a();
5156 \\ break :blk res;
5157 \\ };
5158 \\
5159 \\ comptime var i = 0;
5160 \\ comptime {
5161 \\ i = a();
5162 \\ i += b(i);
5163 \\ }
5164 \\}
5165 \\
5166 );
5167}
5168
5169test "zig fmt: fn type" {
5170 try testCanonical(
5171 \\fn a(i: u8) u8 {
5172 \\ return i + 1;
5173 \\}
5174 \\
5175 \\const a: fn(u8) u8 = undefined;
5176 \\const b: extern fn(u8) u8 = undefined;
5177 \\const c: nakedcc fn(u8) u8 = undefined;
5178 \\const ap: fn(u8) u8 = a;
5179 \\
5180 );
5181}
5182
5183test "zig fmt: inline asm" {
5184 try testCanonical(
5185 \\pub fn syscall1(number: usize, arg1: usize) usize {
5186 \\ return asm volatile ("syscall"
5187 \\ : [ret] "={rax}" (-> usize)
5188 \\ : [number] "{rax}" (number),
5189 \\ [arg1] "{rdi}" (arg1)
5190 \\ : "rcx", "r11");
5191 \\}
5192 \\
5193 );
5194}
5195
5196test "zig fmt: coroutines" {
5197 try testCanonical(
5198 \\async fn simpleAsyncFn() void {
5199 \\ const a = async a.b();
5200 \\ x += 1;
5201 \\ suspend;
5202 \\ x += 1;
5203 \\ suspend |p| {}
5204 \\ const p = async simpleAsyncFn() catch unreachable;
5205 \\ await p;
5206 \\}
5207 \\
5208 \\test "coroutine suspend, resume, cancel" {
5209 \\ const p = try async<std.debug.global_allocator> testAsyncSeq();
5210 \\ resume p;
5211 \\ cancel p;
5212 \\}
5213 \\
5214 );
5215}
5216
5217test "zig fmt: Block after if" {
5218 try testCanonical(
5219 \\test "Block after if" {
5220 \\ if (true) {
5221 \\ const a = 0;
5222 \\ }
5223 \\
5224 \\ {
5225 \\ const a = 0;
5226 \\ }
5227 \\}
5228 \\
5229 );
5230}
5231
5232test "zig fmt: use" {
5233 try testCanonical(
5234 \\use @import("std");
5235 \\pub use @import("std");
5236 \\
5237 );
5238}
5239
5240test "zig fmt: string identifier" {
5241 try testCanonical(
5242 \\const @"a b" = @"c d".@"e f";
5243 \\fn @"g h"() void {}
5244 \\
5245 );
5246}
5247
5248test "zig fmt: error return" {
5249 try testCanonical(
5250 \\fn err() error {
5251 \\ call();
5252 \\ return error.InvalidArgs;
5253 \\}
5254 \\
5255 );
5256}
5257
5258test "zig fmt: struct literals with fields on each line" {
5259 try testCanonical(
5260 \\var self = BufSet {
5261 \\ .hash_map = BufSetHashMap.init(a),
5262 \\};
5263 \\
5264 );
5265}
std/zig/parser_test.zig created+1945
......@@ -0,0 +1,1945 @@
1test "zig fmt: preserve space between async fn definitions" {
2 try testCanonical(
3 \\async fn a() void {}
4 \\
5 \\async fn b() void {}
6 \\
7 );
8}
9
10test "zig fmt: comment to disable/enable zig fmt first" {
11 try testCanonical(
12 \\// Test trailing comma syntax
13 \\// zig fmt: off
14 \\
15 \\const struct_trailing_comma = struct { x: i32, y: i32, };
16 );
17}
18
19test "zig fmt: comment to disable/enable zig fmt" {
20 try testTransform(
21 \\const a = b;
22 \\// zig fmt: off
23 \\const c = d;
24 \\// zig fmt: on
25 \\const e = f;
26 ,
27 \\const a = b;
28 \\// zig fmt: off
29 \\const c = d;
30 \\// zig fmt: on
31 \\const e = f;
32 \\
33 );
34}
35
36test "zig fmt: pointer of unknown length" {
37 try testCanonical(
38 \\fn foo(ptr: [*]u8) void {}
39 \\
40 );
41}
42
43test "zig fmt: spaces around slice operator" {
44 try testCanonical(
45 \\var a = b[c..d];
46 \\var a = b[c + 1 .. d];
47 \\var a = b[c + 1 ..];
48 \\var a = b[c .. d + 1];
49 \\var a = b[c.a..d.e];
50 \\
51 );
52}
53
54test "zig fmt: async call in if condition" {
55 try testCanonical(
56 \\comptime {
57 \\ if (async<a> b()) {
58 \\ a();
59 \\ }
60 \\}
61 \\
62 );
63}
64
65test "zig fmt: 2nd arg multiline string" {
66 try testCanonical(
67 \\comptime {
68 \\ cases.addAsm("hello world linux x86_64",
69 \\ \\.text
70 \\ , "Hello, world!\n");
71 \\}
72 \\
73 );
74}
75
76test "zig fmt: if condition wraps" {
77 try testTransform(
78 \\comptime {
79 \\ if (cond and
80 \\ cond) {
81 \\ return x;
82 \\ }
83 \\ while (cond and
84 \\ cond) {
85 \\ return x;
86 \\ }
87 \\ if (a == b and
88 \\ c) {
89 \\ a = b;
90 \\ }
91 \\ while (a == b and
92 \\ c) {
93 \\ a = b;
94 \\ }
95 \\ if ((cond and
96 \\ cond)) {
97 \\ return x;
98 \\ }
99 \\ while ((cond and
100 \\ cond)) {
101 \\ return x;
102 \\ }
103 \\ var a = if (a) |*f| x: {
104 \\ break :x &a.b;
105 \\ } else |err| err;
106 \\}
107 ,
108 \\comptime {
109 \\ if (cond and
110 \\ cond)
111 \\ {
112 \\ return x;
113 \\ }
114 \\ while (cond and
115 \\ cond)
116 \\ {
117 \\ return x;
118 \\ }
119 \\ if (a == b and
120 \\ c)
121 \\ {
122 \\ a = b;
123 \\ }
124 \\ while (a == b and
125 \\ c)
126 \\ {
127 \\ a = b;
128 \\ }
129 \\ if ((cond and
130 \\ cond))
131 \\ {
132 \\ return x;
133 \\ }
134 \\ while ((cond and
135 \\ cond))
136 \\ {
137 \\ return x;
138 \\ }
139 \\ var a = if (a) |*f| x: {
140 \\ break :x &a.b;
141 \\ } else |err| err;
142 \\}
143 \\
144 );
145}
146
147test "zig fmt: if condition has line break but must not wrap" {
148 try testCanonical(
149 \\comptime {
150 \\ if (self.user_input_options.put(name, UserInputOption{
151 \\ .name = name,
152 \\ .used = false,
153 \\ }) catch unreachable) |*prev_value| {
154 \\ foo();
155 \\ bar();
156 \\ }
157 \\ if (put(
158 \\ a,
159 \\ b,
160 \\ )) {
161 \\ foo();
162 \\ }
163 \\}
164 \\
165 );
166}
167
168test "zig fmt: same-line doc comment on variable declaration" {
169 try testTransform(
170 \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
171 \\pub const MAP_FILE = 0x0000; /// map from file (default)
172 \\
173 \\pub const EMEDIUMTYPE = 124; /// Wrong medium type
174 \\
175 \\// nameserver query return codes
176 \\pub const ENSROK = 0; /// DNS server returned answer with no data
177 ,
178 \\/// allocated from memory, swap space
179 \\pub const MAP_ANONYMOUS = 0x1000;
180 \\/// map from file (default)
181 \\pub const MAP_FILE = 0x0000;
182 \\
183 \\/// Wrong medium type
184 \\pub const EMEDIUMTYPE = 124;
185 \\
186 \\// nameserver query return codes
187 \\/// DNS server returned answer with no data
188 \\pub const ENSROK = 0;
189 \\
190 );
191}
192
193test "zig fmt: if-else with comment before else" {
194 try testCanonical(
195 \\comptime {
196 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
197 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
198 \\ return Complex(f32).new(y - y, y - y);
199 \\ } // cexp(-inf +- i inf|nan) = 0 + i0
200 \\ else if (hx & 0x80000000 != 0) {
201 \\ return Complex(f32).new(0, 0);
202 \\ } // cexp(+inf +- i inf|nan) = inf + i nan
203 \\ else {
204 \\ return Complex(f32).new(x, y - y);
205 \\ }
206 \\}
207 \\
208 );
209}
210
211test "zig fmt: respect line breaks in if-else" {
212 try testCanonical(
213 \\comptime {
214 \\ return if (cond) a else b;
215 \\ return if (cond)
216 \\ a
217 \\ else
218 \\ b;
219 \\ return if (cond)
220 \\ a
221 \\ else if (cond)
222 \\ b
223 \\ else
224 \\ c;
225 \\}
226 \\
227 );
228}
229
230test "zig fmt: respect line breaks after infix operators" {
231 try testCanonical(
232 \\comptime {
233 \\ self.crc =
234 \\ lookup_tables[0][p[7]] ^
235 \\ lookup_tables[1][p[6]] ^
236 \\ lookup_tables[2][p[5]] ^
237 \\ lookup_tables[3][p[4]] ^
238 \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
239 \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
240 \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
241 \\ lookup_tables[7][@truncate(u8, self.crc >> 0)];
242 \\}
243 \\
244 );
245}
246
247test "zig fmt: fn decl with trailing comma" {
248 try testTransform(
249 \\fn foo(a: i32, b: i32,) void {}
250 ,
251 \\fn foo(
252 \\ a: i32,
253 \\ b: i32,
254 \\) void {}
255 \\
256 );
257}
258
259test "zig fmt: enum decl with no trailing comma" {
260 try testTransform(
261 \\const StrLitKind = enum {Normal, C};
262 ,
263 \\const StrLitKind = enum {
264 \\ Normal,
265 \\ C,
266 \\};
267 \\
268 );
269}
270
271test "zig fmt: switch comment before prong" {
272 try testCanonical(
273 \\comptime {
274 \\ switch (a) {
275 \\ // hi
276 \\ 0 => {},
277 \\ }
278 \\}
279 \\
280 );
281}
282
283test "zig fmt: struct literal no trailing comma" {
284 try testTransform(
285 \\const a = foo{ .x = 1, .y = 2 };
286 \\const a = foo{ .x = 1,
287 \\ .y = 2 };
288 ,
289 \\const a = foo{ .x = 1, .y = 2 };
290 \\const a = foo{
291 \\ .x = 1,
292 \\ .y = 2,
293 \\};
294 \\
295 );
296}
297
298test "zig fmt: array literal with hint" {
299 try testTransform(
300 \\const a = []u8{
301 \\ 1, 2, //
302 \\ 3,
303 \\ 4,
304 \\ 5,
305 \\ 6,
306 \\ 7 };
307 \\const a = []u8{
308 \\ 1, 2, //
309 \\ 3,
310 \\ 4,
311 \\ 5,
312 \\ 6,
313 \\ 7, 8 };
314 \\const a = []u8{
315 \\ 1, 2, //
316 \\ 3,
317 \\ 4,
318 \\ 5,
319 \\ 6, // blah
320 \\ 7, 8 };
321 \\const a = []u8{
322 \\ 1, 2, //
323 \\ 3, //
324 \\ 4,
325 \\ 5,
326 \\ 6,
327 \\ 7 };
328 \\const a = []u8{
329 \\ 1,
330 \\ 2,
331 \\ 3, 4, //
332 \\ 5, 6, //
333 \\ 7, 8, //
334 \\};
335 ,
336 \\const a = []u8{
337 \\ 1, 2,
338 \\ 3, 4,
339 \\ 5, 6,
340 \\ 7,
341 \\};
342 \\const a = []u8{
343 \\ 1, 2,
344 \\ 3, 4,
345 \\ 5, 6,
346 \\ 7, 8,
347 \\};
348 \\const a = []u8{
349 \\ 1, 2,
350 \\ 3, 4,
351 \\ 5, 6, // blah
352 \\ 7, 8,
353 \\};
354 \\const a = []u8{
355 \\ 1, 2,
356 \\ 3, //
357 \\ 4,
358 \\ 5, 6,
359 \\ 7,
360 \\};
361 \\const a = []u8{
362 \\ 1,
363 \\ 2,
364 \\ 3,
365 \\ 4,
366 \\ 5,
367 \\ 6,
368 \\ 7,
369 \\ 8,
370 \\};
371 \\
372 );
373}
374
375test "zig fmt: multiline string with backslash at end of line" {
376 try testCanonical(
377 \\comptime {
378 \\ err(
379 \\ \\\
380 \\ );
381 \\}
382 \\
383 );
384}
385
386test "zig fmt: multiline string parameter in fn call with trailing comma" {
387 try testCanonical(
388 \\fn foo() void {
389 \\ try stdout.print(
390 \\ \\ZIG_CMAKE_BINARY_DIR {}
391 \\ \\ZIG_C_HEADER_FILES {}
392 \\ \\ZIG_DIA_GUIDS_LIB {}
393 \\ \\
394 \\ ,
395 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
396 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
397 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
398 \\ );
399 \\}
400 \\
401 );
402}
403
404test "zig fmt: trailing comma on fn call" {
405 try testCanonical(
406 \\comptime {
407 \\ var module = try Module.create(
408 \\ allocator,
409 \\ zig_lib_dir,
410 \\ full_cache_dir,
411 \\ );
412 \\}
413 \\
414 );
415}
416
417test "zig fmt: empty block with only comment" {
418 try testCanonical(
419 \\comptime {
420 \\ {
421 \\ // comment
422 \\ }
423 \\}
424 \\
425 );
426}
427
428test "zig fmt: no trailing comma on struct decl" {
429 try testTransform(
430 \\const RoundParam = struct {
431 \\ k: usize, s: u32, t: u32
432 \\};
433 ,
434 \\const RoundParam = struct {
435 \\ k: usize,
436 \\ s: u32,
437 \\ t: u32,
438 \\};
439 \\
440 );
441}
442
443test "zig fmt: simple asm" {
444 try testTransform(
445 \\comptime {
446 \\ asm volatile (
447 \\ \\.globl aoeu;
448 \\ \\.type aoeu, @function;
449 \\ \\.set aoeu, derp;
450 \\ );
451 \\
452 \\ asm ("not real assembly"
453 \\ :[a] "x" (x),);
454 \\ asm ("not real assembly"
455 \\ :[a] "x" (->i32),:[a] "x" (1),);
456 \\ asm ("still not real assembly"
457 \\ :::"a","b",);
458 \\}
459 ,
460 \\comptime {
461 \\ asm volatile (
462 \\ \\.globl aoeu;
463 \\ \\.type aoeu, @function;
464 \\ \\.set aoeu, derp;
465 \\ );
466 \\
467 \\ asm ("not real assembly"
468 \\ : [a] "x" (x)
469 \\ );
470 \\ asm ("not real assembly"
471 \\ : [a] "x" (-> i32)
472 \\ : [a] "x" (1)
473 \\ );
474 \\ asm ("still not real assembly"
475 \\ :
476 \\ :
477 \\ : "a", "b"
478 \\ );
479 \\}
480 \\
481 );
482}
483
484test "zig fmt: nested struct literal with one item" {
485 try testCanonical(
486 \\const a = foo{
487 \\ .item = bar{ .a = b },
488 \\};
489 \\
490 );
491}
492
493test "zig fmt: switch cases trailing comma" {
494 try testTransform(
495 \\fn switch_cases(x: i32) void {
496 \\ switch (x) {
497 \\ 1,2,3 => {},
498 \\ 4,5, => {},
499 \\ 6... 8, => {},
500 \\ else => {},
501 \\ }
502 \\}
503 ,
504 \\fn switch_cases(x: i32) void {
505 \\ switch (x) {
506 \\ 1, 2, 3 => {},
507 \\ 4,
508 \\ 5,
509 \\ => {},
510 \\ 6...8 => {},
511 \\ else => {},
512 \\ }
513 \\}
514 \\
515 );
516}
517
518test "zig fmt: slice align" {
519 try testCanonical(
520 \\const A = struct {
521 \\ items: []align(A) T,
522 \\};
523 \\
524 );
525}
526
527test "zig fmt: add trailing comma to array literal" {
528 try testTransform(
529 \\comptime {
530 \\ return []u16{'m', 's', 'y', 's', '-' // hi
531 \\ };
532 \\ return []u16{'m', 's', 'y', 's',
533 \\ '-'};
534 \\ return []u16{'m', 's', 'y', 's', '-'};
535 \\}
536 ,
537 \\comptime {
538 \\ return []u16{
539 \\ 'm', 's', 'y', 's', '-', // hi
540 \\ };
541 \\ return []u16{
542 \\ 'm', 's', 'y', 's',
543 \\ '-',
544 \\ };
545 \\ return []u16{ 'm', 's', 'y', 's', '-' };
546 \\}
547 \\
548 );
549}
550
551test "zig fmt: first thing in file is line comment" {
552 try testCanonical(
553 \\// Introspection and determination of system libraries needed by zig.
554 \\
555 \\// Introspection and determination of system libraries needed by zig.
556 \\
557 \\const std = @import("std");
558 \\
559 );
560}
561
562test "zig fmt: line comment after doc comment" {
563 try testCanonical(
564 \\/// doc comment
565 \\// line comment
566 \\fn foo() void {}
567 \\
568 );
569}
570
571test "zig fmt: float literal with exponent" {
572 try testCanonical(
573 \\test "bit field alignment" {
574 \\ assert(@typeOf(&blah.b) == *align(1:3:6) const u3);
575 \\}
576 \\
577 );
578}
579
580test "zig fmt: float literal with exponent" {
581 try testCanonical(
582 \\test "aoeu" {
583 \\ switch (state) {
584 \\ TermState.Start => switch (c) {
585 \\ '\x1b' => state = TermState.Escape,
586 \\ else => try out.writeByte(c),
587 \\ },
588 \\ }
589 \\}
590 \\
591 );
592}
593test "zig fmt: float literal with exponent" {
594 try testCanonical(
595 \\pub const f64_true_min = 4.94065645841246544177e-324;
596 \\const threshold = 0x1.a827999fcef32p+1022;
597 \\
598 );
599}
600
601test "zig fmt: if-else end of comptime" {
602 try testCanonical(
603 \\comptime {
604 \\ if (a) {
605 \\ b();
606 \\ } else {
607 \\ b();
608 \\ }
609 \\}
610 \\
611 );
612}
613
614test "zig fmt: nested blocks" {
615 try testCanonical(
616 \\comptime {
617 \\ {
618 \\ {
619 \\ {
620 \\ a();
621 \\ }
622 \\ }
623 \\ }
624 \\}
625 \\
626 );
627}
628
629test "zig fmt: block with same line comment after end brace" {
630 try testCanonical(
631 \\comptime {
632 \\ {
633 \\ b();
634 \\ } // comment
635 \\}
636 \\
637 );
638}
639
640test "zig fmt: statements with comment between" {
641 try testCanonical(
642 \\comptime {
643 \\ a = b;
644 \\ // comment
645 \\ a = b;
646 \\}
647 \\
648 );
649}
650
651test "zig fmt: statements with empty line between" {
652 try testCanonical(
653 \\comptime {
654 \\ a = b;
655 \\
656 \\ a = b;
657 \\}
658 \\
659 );
660}
661
662test "zig fmt: ptr deref operator and unwrap optional operator" {
663 try testCanonical(
664 \\const a = b.*;
665 \\const a = b.?;
666 \\
667 );
668}
669
670test "zig fmt: comment after if before another if" {
671 try testCanonical(
672 \\test "aoeu" {
673 \\ // comment
674 \\ if (x) {
675 \\ bar();
676 \\ }
677 \\}
678 \\
679 \\test "aoeu" {
680 \\ if (x) {
681 \\ foo();
682 \\ }
683 \\ // comment
684 \\ if (x) {
685 \\ bar();
686 \\ }
687 \\}
688 \\
689 );
690}
691
692test "zig fmt: line comment between if block and else keyword" {
693 try testCanonical(
694 \\test "aoeu" {
695 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
696 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
697 \\ return Complex(f32).new(y - y, y - y);
698 \\ }
699 \\ // cexp(-inf +- i inf|nan) = 0 + i0
700 \\ else if (hx & 0x80000000 != 0) {
701 \\ return Complex(f32).new(0, 0);
702 \\ }
703 \\ // cexp(+inf +- i inf|nan) = inf + i nan
704 \\ // another comment
705 \\ else {
706 \\ return Complex(f32).new(x, y - y);
707 \\ }
708 \\}
709 \\
710 );
711}
712
713test "zig fmt: same line comments in expression" {
714 try testCanonical(
715 \\test "aoeu" {
716 \\ const x = ( // a
717 \\ 0 // b
718 \\ ); // c
719 \\}
720 \\
721 );
722}
723
724test "zig fmt: add comma on last switch prong" {
725 try testTransform(
726 \\test "aoeu" {
727 \\switch (self.init_arg_expr) {
728 \\ InitArg.Type => |t| { },
729 \\ InitArg.None,
730 \\ InitArg.Enum => { }
731 \\}
732 \\ switch (self.init_arg_expr) {
733 \\ InitArg.Type => |t| { },
734 \\ InitArg.None,
735 \\ InitArg.Enum => { }//line comment
736 \\ }
737 \\}
738 ,
739 \\test "aoeu" {
740 \\ switch (self.init_arg_expr) {
741 \\ InitArg.Type => |t| {},
742 \\ InitArg.None, InitArg.Enum => {},
743 \\ }
744 \\ switch (self.init_arg_expr) {
745 \\ InitArg.Type => |t| {},
746 \\ InitArg.None, InitArg.Enum => {}, //line comment
747 \\ }
748 \\}
749 \\
750 );
751}
752
753test "zig fmt: same-line comment after a statement" {
754 try testCanonical(
755 \\test "" {
756 \\ a = b;
757 \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
758 \\ a = b;
759 \\}
760 \\
761 );
762}
763
764test "zig fmt: same-line comment after var decl in struct" {
765 try testCanonical(
766 \\pub const vfs_cap_data = extern struct {
767 \\ const Data = struct {}; // when on disk.
768 \\};
769 \\
770 );
771}
772
773test "zig fmt: same-line comment after field decl" {
774 try testCanonical(
775 \\pub const dirent = extern struct {
776 \\ d_name: u8,
777 \\ d_name: u8, // comment 1
778 \\ d_name: u8,
779 \\ d_name: u8, // comment 2
780 \\ d_name: u8,
781 \\};
782 \\
783 );
784}
785
786test "zig fmt: same-line comment after switch prong" {
787 try testCanonical(
788 \\test "" {
789 \\ switch (err) {
790 \\ error.PathAlreadyExists => {}, // comment 2
791 \\ else => return err, // comment 1
792 \\ }
793 \\}
794 \\
795 );
796}
797
798test "zig fmt: same-line comment after non-block if expression" {
799 try testCanonical(
800 \\comptime {
801 \\ if (sr > n_uword_bits - 1) // d > r
802 \\ return 0;
803 \\}
804 \\
805 );
806}
807
808test "zig fmt: same-line comment on comptime expression" {
809 try testCanonical(
810 \\test "" {
811 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
812 \\}
813 \\
814 );
815}
816
817test "zig fmt: switch with empty body" {
818 try testCanonical(
819 \\test "" {
820 \\ foo() catch |err| switch (err) {};
821 \\}
822 \\
823 );
824}
825
826test "zig fmt: line comments in struct initializer" {
827 try testCanonical(
828 \\fn foo() void {
829 \\ return Self{
830 \\ .a = b,
831 \\
832 \\ // Initialize these two fields to buffer_size so that
833 \\ // in `readFn` we treat the state as being able to read
834 \\ .start_index = buffer_size,
835 \\ .end_index = buffer_size,
836 \\
837 \\ // middle
838 \\
839 \\ .a = b,
840 \\
841 \\ // end
842 \\ };
843 \\}
844 \\
845 );
846}
847
848test "zig fmt: doc comments before struct field" {
849 try testCanonical(
850 \\pub const Allocator = struct {
851 \\ /// Allocate byte_count bytes and return them in a slice, with the
852 \\ /// slice's pointer aligned at least to alignment bytes.
853 \\ allocFn: fn () void,
854 \\};
855 \\
856 );
857}
858
859test "zig fmt: error set declaration" {
860 try testCanonical(
861 \\const E = error{
862 \\ A,
863 \\ B,
864 \\
865 \\ C,
866 \\};
867 \\
868 \\const Error = error{
869 \\ /// no more memory
870 \\ OutOfMemory,
871 \\};
872 \\
873 \\const Error = error{
874 \\ /// no more memory
875 \\ OutOfMemory,
876 \\
877 \\ /// another
878 \\ Another,
879 \\
880 \\ // end
881 \\};
882 \\
883 \\const Error = error{OutOfMemory};
884 \\const Error = error{};
885 \\
886 );
887}
888
889test "zig fmt: union(enum(u32)) with assigned enum values" {
890 try testCanonical(
891 \\const MultipleChoice = union(enum(u32)) {
892 \\ A = 20,
893 \\ B = 40,
894 \\ C = 60,
895 \\ D = 1000,
896 \\};
897 \\
898 );
899}
900
901test "zig fmt: resume from suspend block" {
902 try testCanonical(
903 \\fn foo() void {
904 \\ suspend {
905 \\ resume @handle();
906 \\ }
907 \\}
908 \\
909 );
910}
911
912test "zig fmt: comments before error set decl" {
913 try testCanonical(
914 \\const UnexpectedError = error{
915 \\ /// The Operating System returned an undocumented error code.
916 \\ Unexpected,
917 \\ // another
918 \\ Another,
919 \\
920 \\ // in between
921 \\
922 \\ // at end
923 \\};
924 \\
925 );
926}
927
928test "zig fmt: comments before switch prong" {
929 try testCanonical(
930 \\test "" {
931 \\ switch (err) {
932 \\ error.PathAlreadyExists => continue,
933 \\
934 \\ // comment 1
935 \\
936 \\ // comment 2
937 \\ else => return err,
938 \\ // at end
939 \\ }
940 \\}
941 \\
942 );
943}
944
945test "zig fmt: comments before var decl in struct" {
946 try testCanonical(
947 \\pub const vfs_cap_data = extern struct {
948 \\ // All of these are mandated as little endian
949 \\ // when on disk.
950 \\ const Data = struct {
951 \\ permitted: u32,
952 \\ inheritable: u32,
953 \\ };
954 \\
955 \\ // in between
956 \\
957 \\ /// All of these are mandated as little endian
958 \\ /// when on disk.
959 \\ const Data = struct {
960 \\ permitted: u32,
961 \\ inheritable: u32,
962 \\ };
963 \\
964 \\ // at end
965 \\};
966 \\
967 );
968}
969
970test "zig fmt: array literal with 1 item on 1 line" {
971 try testCanonical(
972 \\var s = []const u64{0} ** 25;
973 \\
974 );
975}
976
977test "zig fmt: comments before global variables" {
978 try testCanonical(
979 \\/// Foo copies keys and values before they go into the map, and
980 \\/// frees them when they get removed.
981 \\pub const Foo = struct {};
982 \\
983 );
984}
985
986test "zig fmt: comments in statements" {
987 try testCanonical(
988 \\test "std" {
989 \\ // statement comment
990 \\ _ = @import("foo/bar.zig");
991 \\
992 \\ // middle
993 \\ // middle2
994 \\
995 \\ // end
996 \\}
997 \\
998 );
999}
1000
1001test "zig fmt: comments before test decl" {
1002 try testCanonical(
1003 \\/// top level doc comment
1004 \\test "hi" {}
1005 \\
1006 \\// top level normal comment
1007 \\test "hi" {}
1008 \\
1009 \\// middle
1010 \\
1011 \\// end
1012 \\
1013 );
1014}
1015
1016test "zig fmt: preserve spacing" {
1017 try testCanonical(
1018 \\const std = @import("std");
1019 \\
1020 \\pub fn main() !void {
1021 \\ var stdout_file = try std.io.getStdOut;
1022 \\ var stdout_file = try std.io.getStdOut;
1023 \\
1024 \\ var stdout_file = try std.io.getStdOut;
1025 \\ var stdout_file = try std.io.getStdOut;
1026 \\}
1027 \\
1028 );
1029}
1030
1031test "zig fmt: return types" {
1032 try testCanonical(
1033 \\pub fn main() !void {}
1034 \\pub fn main() var {}
1035 \\pub fn main() i32 {}
1036 \\
1037 );
1038}
1039
1040test "zig fmt: imports" {
1041 try testCanonical(
1042 \\const std = @import("std");
1043 \\const std = @import();
1044 \\
1045 );
1046}
1047
1048test "zig fmt: global declarations" {
1049 try testCanonical(
1050 \\const a = b;
1051 \\pub const a = b;
1052 \\var a = b;
1053 \\pub var a = b;
1054 \\const a: i32 = b;
1055 \\pub const a: i32 = b;
1056 \\var a: i32 = b;
1057 \\pub var a: i32 = b;
1058 \\extern const a: i32 = b;
1059 \\pub extern const a: i32 = b;
1060 \\extern var a: i32 = b;
1061 \\pub extern var a: i32 = b;
1062 \\extern "a" const a: i32 = b;
1063 \\pub extern "a" const a: i32 = b;
1064 \\extern "a" var a: i32 = b;
1065 \\pub extern "a" var a: i32 = b;
1066 \\
1067 );
1068}
1069
1070test "zig fmt: extern declaration" {
1071 try testCanonical(
1072 \\extern var foo: c_int;
1073 \\
1074 );
1075}
1076
1077test "zig fmt: alignment" {
1078 try testCanonical(
1079 \\var foo: c_int align(1);
1080 \\
1081 );
1082}
1083
1084test "zig fmt: C main" {
1085 try testCanonical(
1086 \\fn main(argc: c_int, argv: **u8) c_int {
1087 \\ const a = b;
1088 \\}
1089 \\
1090 );
1091}
1092
1093test "zig fmt: return" {
1094 try testCanonical(
1095 \\fn foo(argc: c_int, argv: **u8) c_int {
1096 \\ return 0;
1097 \\}
1098 \\
1099 \\fn bar() void {
1100 \\ return;
1101 \\}
1102 \\
1103 );
1104}
1105
1106test "zig fmt: pointer attributes" {
1107 try testCanonical(
1108 \\extern fn f1(s: *align(*u8) u8) c_int;
1109 \\extern fn f2(s: **align(1) *const *volatile u8) c_int;
1110 \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
1111 \\extern fn f4(s: *align(1) const volatile u8) c_int;
1112 \\
1113 );
1114}
1115
1116test "zig fmt: slice attributes" {
1117 try testCanonical(
1118 \\extern fn f1(s: *align(*u8) u8) c_int;
1119 \\extern fn f2(s: **align(1) *const *volatile u8) c_int;
1120 \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
1121 \\extern fn f4(s: *align(1) const volatile u8) c_int;
1122 \\
1123 );
1124}
1125
1126test "zig fmt: test declaration" {
1127 try testCanonical(
1128 \\test "test name" {
1129 \\ const a = 1;
1130 \\ var b = 1;
1131 \\}
1132 \\
1133 );
1134}
1135
1136test "zig fmt: infix operators" {
1137 try testCanonical(
1138 \\test "infix operators" {
1139 \\ var i = undefined;
1140 \\ i = 2;
1141 \\ i *= 2;
1142 \\ i |= 2;
1143 \\ i ^= 2;
1144 \\ i <<= 2;
1145 \\ i >>= 2;
1146 \\ i &= 2;
1147 \\ i *= 2;
1148 \\ i *%= 2;
1149 \\ i -= 2;
1150 \\ i -%= 2;
1151 \\ i += 2;
1152 \\ i +%= 2;
1153 \\ i /= 2;
1154 \\ i %= 2;
1155 \\ _ = i == i;
1156 \\ _ = i != i;
1157 \\ _ = i != i;
1158 \\ _ = i.i;
1159 \\ _ = i || i;
1160 \\ _ = i!i;
1161 \\ _ = i ** i;
1162 \\ _ = i ++ i;
1163 \\ _ = i orelse i;
1164 \\ _ = i % i;
1165 \\ _ = i / i;
1166 \\ _ = i *% i;
1167 \\ _ = i * i;
1168 \\ _ = i -% i;
1169 \\ _ = i - i;
1170 \\ _ = i +% i;
1171 \\ _ = i + i;
1172 \\ _ = i << i;
1173 \\ _ = i >> i;
1174 \\ _ = i & i;
1175 \\ _ = i ^ i;
1176 \\ _ = i | i;
1177 \\ _ = i >= i;
1178 \\ _ = i <= i;
1179 \\ _ = i > i;
1180 \\ _ = i < i;
1181 \\ _ = i and i;
1182 \\ _ = i or i;
1183 \\}
1184 \\
1185 );
1186}
1187
1188test "zig fmt: precedence" {
1189 try testCanonical(
1190 \\test "precedence" {
1191 \\ a!b();
1192 \\ (a!b)();
1193 \\ !a!b;
1194 \\ !(a!b);
1195 \\ !a{};
1196 \\ !(a{});
1197 \\ a + b{};
1198 \\ (a + b){};
1199 \\ a << b + c;
1200 \\ (a << b) + c;
1201 \\ a & b << c;
1202 \\ (a & b) << c;
1203 \\ a ^ b & c;
1204 \\ (a ^ b) & c;
1205 \\ a | b ^ c;
1206 \\ (a | b) ^ c;
1207 \\ a == b | c;
1208 \\ (a == b) | c;
1209 \\ a and b == c;
1210 \\ (a and b) == c;
1211 \\ a or b and c;
1212 \\ (a or b) and c;
1213 \\ (a or b) and c;
1214 \\}
1215 \\
1216 );
1217}
1218
1219test "zig fmt: prefix operators" {
1220 try testCanonical(
1221 \\test "prefix operators" {
1222 \\ try return --%~!*&0;
1223 \\}
1224 \\
1225 );
1226}
1227
1228test "zig fmt: call expression" {
1229 try testCanonical(
1230 \\test "test calls" {
1231 \\ a();
1232 \\ a(1);
1233 \\ a(1, 2);
1234 \\ a(1, 2) + a(1, 2);
1235 \\}
1236 \\
1237 );
1238}
1239
1240test "zig fmt: var args" {
1241 try testCanonical(
1242 \\fn print(args: ...) void {}
1243 \\
1244 );
1245}
1246
1247test "zig fmt: var type" {
1248 try testCanonical(
1249 \\fn print(args: var) var {}
1250 \\const Var = var;
1251 \\const i: var = 0;
1252 \\
1253 );
1254}
1255
1256test "zig fmt: functions" {
1257 try testCanonical(
1258 \\extern fn puts(s: *const u8) c_int;
1259 \\extern "c" fn puts(s: *const u8) c_int;
1260 \\export fn puts(s: *const u8) c_int;
1261 \\inline fn puts(s: *const u8) c_int;
1262 \\pub extern fn puts(s: *const u8) c_int;
1263 \\pub extern "c" fn puts(s: *const u8) c_int;
1264 \\pub export fn puts(s: *const u8) c_int;
1265 \\pub inline fn puts(s: *const u8) c_int;
1266 \\pub extern fn puts(s: *const u8) align(2 + 2) c_int;
1267 \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int;
1268 \\pub export fn puts(s: *const u8) align(2 + 2) c_int;
1269 \\pub inline fn puts(s: *const u8) align(2 + 2) c_int;
1270 \\
1271 );
1272}
1273
1274test "zig fmt: multiline string" {
1275 try testCanonical(
1276 \\test "" {
1277 \\ const s1 =
1278 \\ \\one
1279 \\ \\two)
1280 \\ \\three
1281 \\ ;
1282 \\ const s2 =
1283 \\ c\\one
1284 \\ c\\two)
1285 \\ c\\three
1286 \\ ;
1287 \\ const s3 = // hi
1288 \\ \\one
1289 \\ \\two)
1290 \\ \\three
1291 \\ ;
1292 \\}
1293 \\
1294 );
1295}
1296
1297test "zig fmt: values" {
1298 try testCanonical(
1299 \\test "values" {
1300 \\ 1;
1301 \\ 1.0;
1302 \\ "string";
1303 \\ c"cstring";
1304 \\ 'c';
1305 \\ true;
1306 \\ false;
1307 \\ null;
1308 \\ undefined;
1309 \\ error;
1310 \\ this;
1311 \\ unreachable;
1312 \\}
1313 \\
1314 );
1315}
1316
1317test "zig fmt: indexing" {
1318 try testCanonical(
1319 \\test "test index" {
1320 \\ a[0];
1321 \\ a[0 + 5];
1322 \\ a[0..];
1323 \\ a[0..5];
1324 \\ a[a[0]];
1325 \\ a[a[0..]];
1326 \\ a[a[0..5]];
1327 \\ a[a[0]..];
1328 \\ a[a[0..5]..];
1329 \\ a[a[0]..a[0]];
1330 \\ a[a[0..5]..a[0]];
1331 \\ a[a[0..5]..a[0..5]];
1332 \\}
1333 \\
1334 );
1335}
1336
1337test "zig fmt: struct declaration" {
1338 try testCanonical(
1339 \\const S = struct {
1340 \\ const Self = this;
1341 \\ f1: u8,
1342 \\ pub f3: u8,
1343 \\
1344 \\ fn method(self: *Self) Self {
1345 \\ return self.*;
1346 \\ }
1347 \\
1348 \\ f2: u8,
1349 \\};
1350 \\
1351 \\const Ps = packed struct {
1352 \\ a: u8,
1353 \\ pub b: u8,
1354 \\
1355 \\ c: u8,
1356 \\};
1357 \\
1358 \\const Es = extern struct {
1359 \\ a: u8,
1360 \\ pub b: u8,
1361 \\
1362 \\ c: u8,
1363 \\};
1364 \\
1365 );
1366}
1367
1368test "zig fmt: enum declaration" {
1369 try testCanonical(
1370 \\const E = enum {
1371 \\ Ok,
1372 \\ SomethingElse = 0,
1373 \\};
1374 \\
1375 \\const E2 = enum(u8) {
1376 \\ Ok,
1377 \\ SomethingElse = 255,
1378 \\ SomethingThird,
1379 \\};
1380 \\
1381 \\const Ee = extern enum {
1382 \\ Ok,
1383 \\ SomethingElse,
1384 \\ SomethingThird,
1385 \\};
1386 \\
1387 \\const Ep = packed enum {
1388 \\ Ok,
1389 \\ SomethingElse,
1390 \\ SomethingThird,
1391 \\};
1392 \\
1393 );
1394}
1395
1396test "zig fmt: union declaration" {
1397 try testCanonical(
1398 \\const U = union {
1399 \\ Int: u8,
1400 \\ Float: f32,
1401 \\ None,
1402 \\ Bool: bool,
1403 \\};
1404 \\
1405 \\const Ue = union(enum) {
1406 \\ Int: u8,
1407 \\ Float: f32,
1408 \\ None,
1409 \\ Bool: bool,
1410 \\};
1411 \\
1412 \\const E = enum {
1413 \\ Int,
1414 \\ Float,
1415 \\ None,
1416 \\ Bool,
1417 \\};
1418 \\
1419 \\const Ue2 = union(E) {
1420 \\ Int: u8,
1421 \\ Float: f32,
1422 \\ None,
1423 \\ Bool: bool,
1424 \\};
1425 \\
1426 \\const Eu = extern union {
1427 \\ Int: u8,
1428 \\ Float: f32,
1429 \\ None,
1430 \\ Bool: bool,
1431 \\};
1432 \\
1433 );
1434}
1435
1436test "zig fmt: arrays" {
1437 try testCanonical(
1438 \\test "test array" {
1439 \\ const a: [2]u8 = [2]u8{
1440 \\ 1,
1441 \\ 2,
1442 \\ };
1443 \\ const a: [2]u8 = []u8{
1444 \\ 1,
1445 \\ 2,
1446 \\ };
1447 \\ const a: [0]u8 = []u8{};
1448 \\}
1449 \\
1450 );
1451}
1452
1453test "zig fmt: container initializers" {
1454 try testCanonical(
1455 \\const a0 = []u8{};
1456 \\const a1 = []u8{1};
1457 \\const a2 = []u8{
1458 \\ 1,
1459 \\ 2,
1460 \\ 3,
1461 \\ 4,
1462 \\};
1463 \\const s0 = S{};
1464 \\const s1 = S{ .a = 1 };
1465 \\const s2 = S{
1466 \\ .a = 1,
1467 \\ .b = 2,
1468 \\};
1469 \\
1470 );
1471}
1472
1473test "zig fmt: catch" {
1474 try testCanonical(
1475 \\test "catch" {
1476 \\ const a: error!u8 = 0;
1477 \\ _ = a catch return;
1478 \\ _ = a catch |err| return;
1479 \\}
1480 \\
1481 );
1482}
1483
1484test "zig fmt: blocks" {
1485 try testCanonical(
1486 \\test "blocks" {
1487 \\ {
1488 \\ const a = 0;
1489 \\ const b = 0;
1490 \\ }
1491 \\
1492 \\ blk: {
1493 \\ const a = 0;
1494 \\ const b = 0;
1495 \\ }
1496 \\
1497 \\ const r = blk: {
1498 \\ const a = 0;
1499 \\ const b = 0;
1500 \\ };
1501 \\}
1502 \\
1503 );
1504}
1505
1506test "zig fmt: switch" {
1507 try testCanonical(
1508 \\test "switch" {
1509 \\ switch (0) {
1510 \\ 0 => {},
1511 \\ 1 => unreachable,
1512 \\ 2, 3 => {},
1513 \\ 4...7 => {},
1514 \\ 1 + 4 * 3 + 22 => {},
1515 \\ else => {
1516 \\ const a = 1;
1517 \\ const b = a;
1518 \\ },
1519 \\ }
1520 \\
1521 \\ const res = switch (0) {
1522 \\ 0 => 0,
1523 \\ 1 => 2,
1524 \\ 1 => a = 4,
1525 \\ else => 4,
1526 \\ };
1527 \\
1528 \\ const Union = union(enum) {
1529 \\ Int: i64,
1530 \\ Float: f64,
1531 \\ };
1532 \\
1533 \\ switch (u) {
1534 \\ Union.Int => |int| {},
1535 \\ Union.Float => |*float| unreachable,
1536 \\ }
1537 \\}
1538 \\
1539 );
1540}
1541
1542test "zig fmt: while" {
1543 try testCanonical(
1544 \\test "while" {
1545 \\ while (10 < 1) {
1546 \\ unreachable;
1547 \\ }
1548 \\
1549 \\ while (10 < 1)
1550 \\ unreachable;
1551 \\
1552 \\ var i: usize = 0;
1553 \\ while (i < 10) : (i += 1) {
1554 \\ continue;
1555 \\ }
1556 \\
1557 \\ i = 0;
1558 \\ while (i < 10) : (i += 1)
1559 \\ continue;
1560 \\
1561 \\ i = 0;
1562 \\ var j: usize = 0;
1563 \\ while (i < 10) : ({
1564 \\ i += 1;
1565 \\ j += 1;
1566 \\ }) {
1567 \\ continue;
1568 \\ }
1569 \\
1570 \\ var a: ?u8 = 2;
1571 \\ while (a) |v| : (a = null) {
1572 \\ continue;
1573 \\ }
1574 \\
1575 \\ while (a) |v| : (a = null)
1576 \\ unreachable;
1577 \\
1578 \\ label: while (10 < 0) {
1579 \\ unreachable;
1580 \\ }
1581 \\
1582 \\ const res = while (0 < 10) {
1583 \\ break 7;
1584 \\ } else {
1585 \\ unreachable;
1586 \\ };
1587 \\
1588 \\ const res = while (0 < 10)
1589 \\ break 7
1590 \\ else
1591 \\ unreachable;
1592 \\
1593 \\ var a: error!u8 = 0;
1594 \\ while (a) |v| {
1595 \\ a = error.Err;
1596 \\ } else |err| {
1597 \\ i = 1;
1598 \\ }
1599 \\
1600 \\ comptime var k: usize = 0;
1601 \\ inline while (i < 10) : (i += 1)
1602 \\ j += 2;
1603 \\}
1604 \\
1605 );
1606}
1607
1608test "zig fmt: for" {
1609 try testCanonical(
1610 \\test "for" {
1611 \\ for (a) |v| {
1612 \\ continue;
1613 \\ }
1614 \\
1615 \\ for (a) |v|
1616 \\ continue;
1617 \\
1618 \\ for (a) |*v|
1619 \\ continue;
1620 \\
1621 \\ for (a) |v, i| {
1622 \\ continue;
1623 \\ }
1624 \\
1625 \\ for (a) |v, i|
1626 \\ continue;
1627 \\
1628 \\ const res = for (a) |v, i| {
1629 \\ break v;
1630 \\ } else {
1631 \\ unreachable;
1632 \\ };
1633 \\
1634 \\ var num: usize = 0;
1635 \\ inline for (a) |v, i| {
1636 \\ num += v;
1637 \\ num += i;
1638 \\ }
1639 \\}
1640 \\
1641 );
1642}
1643
1644test "zig fmt: if" {
1645 try testCanonical(
1646 \\test "if" {
1647 \\ if (10 < 0) {
1648 \\ unreachable;
1649 \\ }
1650 \\
1651 \\ if (10 < 0) unreachable;
1652 \\
1653 \\ if (10 < 0) {
1654 \\ unreachable;
1655 \\ } else {
1656 \\ const a = 20;
1657 \\ }
1658 \\
1659 \\ if (10 < 0) {
1660 \\ unreachable;
1661 \\ } else if (5 < 0) {
1662 \\ unreachable;
1663 \\ } else {
1664 \\ const a = 20;
1665 \\ }
1666 \\
1667 \\ const is_world_broken = if (10 < 0) true else false;
1668 \\ const some_number = 1 + if (10 < 0) 2 else 3;
1669 \\
1670 \\ const a: ?u8 = 10;
1671 \\ const b: ?u8 = null;
1672 \\ if (a) |v| {
1673 \\ const some = v;
1674 \\ } else if (b) |*v| {
1675 \\ unreachable;
1676 \\ } else {
1677 \\ const some = 10;
1678 \\ }
1679 \\
1680 \\ const non_null_a = if (a) |v| v else 0;
1681 \\
1682 \\ const a_err: error!u8 = 0;
1683 \\ if (a_err) |v| {
1684 \\ const p = v;
1685 \\ } else |err| {
1686 \\ unreachable;
1687 \\ }
1688 \\}
1689 \\
1690 );
1691}
1692
1693test "zig fmt: defer" {
1694 try testCanonical(
1695 \\test "defer" {
1696 \\ var i: usize = 0;
1697 \\ defer i = 1;
1698 \\ defer {
1699 \\ i += 2;
1700 \\ i *= i;
1701 \\ }
1702 \\
1703 \\ errdefer i += 3;
1704 \\ errdefer {
1705 \\ i += 2;
1706 \\ i /= i;
1707 \\ }
1708 \\}
1709 \\
1710 );
1711}
1712
1713test "zig fmt: comptime" {
1714 try testCanonical(
1715 \\fn a() u8 {
1716 \\ return 5;
1717 \\}
1718 \\
1719 \\fn b(comptime i: u8) u8 {
1720 \\ return i;
1721 \\}
1722 \\
1723 \\const av = comptime a();
1724 \\const av2 = comptime blk: {
1725 \\ var res = a();
1726 \\ res *= b(2);
1727 \\ break :blk res;
1728 \\};
1729 \\
1730 \\comptime {
1731 \\ _ = a();
1732 \\}
1733 \\
1734 \\test "comptime" {
1735 \\ const av3 = comptime a();
1736 \\ const av4 = comptime blk: {
1737 \\ var res = a();
1738 \\ res *= a();
1739 \\ break :blk res;
1740 \\ };
1741 \\
1742 \\ comptime var i = 0;
1743 \\ comptime {
1744 \\ i = a();
1745 \\ i += b(i);
1746 \\ }
1747 \\}
1748 \\
1749 );
1750}
1751
1752test "zig fmt: fn type" {
1753 try testCanonical(
1754 \\fn a(i: u8) u8 {
1755 \\ return i + 1;
1756 \\}
1757 \\
1758 \\const a: fn (u8) u8 = undefined;
1759 \\const b: extern fn (u8) u8 = undefined;
1760 \\const c: nakedcc fn (u8) u8 = undefined;
1761 \\const ap: fn (u8) u8 = a;
1762 \\
1763 );
1764}
1765
1766test "zig fmt: inline asm" {
1767 try testCanonical(
1768 \\pub fn syscall1(number: usize, arg1: usize) usize {
1769 \\ return asm volatile ("syscall"
1770 \\ : [ret] "={rax}" (-> usize)
1771 \\ : [number] "{rax}" (number),
1772 \\ [arg1] "{rdi}" (arg1)
1773 \\ : "rcx", "r11"
1774 \\ );
1775 \\}
1776 \\
1777 );
1778}
1779
1780test "zig fmt: coroutines" {
1781 try testCanonical(
1782 \\async fn simpleAsyncFn() void {
1783 \\ const a = async a.b();
1784 \\ x += 1;
1785 \\ suspend;
1786 \\ x += 1;
1787 \\ suspend;
1788 \\ const p: promise->void = async simpleAsyncFn() catch unreachable;
1789 \\ await p;
1790 \\}
1791 \\
1792 \\test "coroutine suspend, resume, cancel" {
1793 \\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();
1794 \\ resume p;
1795 \\ cancel p;
1796 \\}
1797 \\
1798 );
1799}
1800
1801test "zig fmt: Block after if" {
1802 try testCanonical(
1803 \\test "Block after if" {
1804 \\ if (true) {
1805 \\ const a = 0;
1806 \\ }
1807 \\
1808 \\ {
1809 \\ const a = 0;
1810 \\ }
1811 \\}
1812 \\
1813 );
1814}
1815
1816test "zig fmt: use" {
1817 try testCanonical(
1818 \\use @import("std");
1819 \\pub use @import("std");
1820 \\
1821 );
1822}
1823
1824test "zig fmt: string identifier" {
1825 try testCanonical(
1826 \\const @"a b" = @"c d".@"e f";
1827 \\fn @"g h"() void {}
1828 \\
1829 );
1830}
1831
1832test "zig fmt: error return" {
1833 try testCanonical(
1834 \\fn err() error {
1835 \\ call();
1836 \\ return error.InvalidArgs;
1837 \\}
1838 \\
1839 );
1840}
1841
1842const std = @import("std");
1843const mem = std.mem;
1844const warn = std.debug.warn;
1845const io = std.io;
1846
1847var fixed_buffer_mem: [100 * 1024]u8 = undefined;
1848
1849fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
1850 var stderr_file = try io.getStdErr();
1851 var stderr = &io.FileOutStream.init(&stderr_file).stream;
1852
1853 var tree = try std.zig.parse(allocator, source);
1854 defer tree.deinit();
1855
1856 var error_it = tree.errors.iterator(0);
1857 while (error_it.next()) |parse_error| {
1858 const token = tree.tokens.at(parse_error.loc());
1859 const loc = tree.tokenLocation(0, parse_error.loc());
1860 try stderr.print("(memory buffer):{}:{}: error: ", loc.line + 1, loc.column + 1);
1861 try tree.renderError(parse_error, stderr);
1862 try stderr.print("\n{}\n", source[loc.line_start..loc.line_end]);
1863 {
1864 var i: usize = 0;
1865 while (i < loc.column) : (i += 1) {
1866 try stderr.write(" ");
1867 }
1868 }
1869 {
1870 const caret_count = token.end - token.start;
1871 var i: usize = 0;
1872 while (i < caret_count) : (i += 1) {
1873 try stderr.write("~");
1874 }
1875 }
1876 try stderr.write("\n");
1877 }
1878 if (tree.errors.len != 0) {
1879 return error.ParseError;
1880 }
1881
1882 var buffer = try std.Buffer.initSize(allocator, 0);
1883 errdefer buffer.deinit();
1884
1885 var buffer_out_stream = io.BufferOutStream.init(&buffer);
1886 anything_changed.* = try std.zig.render(allocator, &buffer_out_stream.stream, &tree);
1887 return buffer.toOwnedSlice();
1888}
1889
1890fn testTransform(source: []const u8, expected_source: []const u8) !void {
1891 const needed_alloc_count = x: {
1892 // Try it once with unlimited memory, make sure it works
1893 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1894 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
1895 var anything_changed: bool = undefined;
1896 const result_source = try testParse(source, &failing_allocator.allocator, &anything_changed);
1897 if (!mem.eql(u8, result_source, expected_source)) {
1898 warn("\n====== expected this output: =========\n");
1899 warn("{}", expected_source);
1900 warn("\n======== instead found this: =========\n");
1901 warn("{}", result_source);
1902 warn("\n======================================\n");
1903 return error.TestFailed;
1904 }
1905 const changes_expected = source.ptr != expected_source.ptr;
1906 if (anything_changed != changes_expected) {
1907 warn("std.zig.render returned {} instead of {}\n", anything_changed, changes_expected);
1908 return error.TestFailed;
1909 }
1910 std.debug.assert(anything_changed == changes_expected);
1911 failing_allocator.allocator.free(result_source);
1912 break :x failing_allocator.index;
1913 };
1914
1915 var fail_index: usize = 0;
1916 while (fail_index < needed_alloc_count) : (fail_index += 1) {
1917 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1918 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1919 var anything_changed: bool = undefined;
1920 if (testParse(source, &failing_allocator.allocator, &anything_changed)) |_| {
1921 return error.NondeterministicMemoryUsage;
1922 } else |err| switch (err) {
1923 error.OutOfMemory => {
1924 if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
1925 warn(
1926 "\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",
1927 fail_index,
1928 needed_alloc_count,
1929 failing_allocator.allocated_bytes,
1930 failing_allocator.freed_bytes,
1931 failing_allocator.index,
1932 failing_allocator.deallocations,
1933 );
1934 return error.MemoryLeakDetected;
1935 }
1936 },
1937 error.ParseError => @panic("test failed"),
1938 else => @panic("test failed"),
1939 }
1940 }
1941}
1942
1943fn testCanonical(source: []const u8) !void {
1944 return testTransform(source, source);
1945}
std/zig/render.zig created+2015
......@@ -0,0 +1,2015 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const mem = std.mem;
5const ast = std.zig.ast;
6const Token = std.zig.Token;
7
8const indent_delta = 4;
9
10pub const Error = error{
11 /// Ran out of memory allocating call stack frames to complete rendering.
12 OutOfMemory,
13};
14
15/// Returns whether anything changed
16pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@typeOf(stream).Child.Error || Error)!bool {
17 comptime assert(@typeId(@typeOf(stream)) == builtin.TypeId.Pointer);
18
19 var anything_changed: bool = false;
20
21 // make a passthrough stream that checks whether something changed
22 const MyStream = struct {
23 const MyStream = this;
24 const StreamError = @typeOf(stream).Child.Error;
25 const Stream = std.io.OutStream(StreamError);
26
27 anything_changed_ptr: *bool,
28 child_stream: @typeOf(stream),
29 stream: Stream,
30 source_index: usize,
31 source: []const u8,
32
33 fn write(iface_stream: *Stream, bytes: []const u8) StreamError!void {
34 const self = @fieldParentPtr(MyStream, "stream", iface_stream);
35
36 if (!self.anything_changed_ptr.*) {
37 const end = self.source_index + bytes.len;
38 if (end > self.source.len) {
39 self.anything_changed_ptr.* = true;
40 } else {
41 const src_slice = self.source[self.source_index..end];
42 self.source_index += bytes.len;
43 if (!mem.eql(u8, bytes, src_slice)) {
44 self.anything_changed_ptr.* = true;
45 }
46 }
47 }
48
49 try self.child_stream.write(bytes);
50 }
51 };
52 var my_stream = MyStream{
53 .stream = MyStream.Stream{ .writeFn = MyStream.write },
54 .child_stream = stream,
55 .anything_changed_ptr = &anything_changed,
56 .source_index = 0,
57 .source = tree.source,
58 };
59
60 try renderRoot(allocator, &my_stream.stream, tree);
61
62 return anything_changed;
63}
64
65fn renderRoot(
66 allocator: *mem.Allocator,
67 stream: var,
68 tree: *ast.Tree,
69) (@typeOf(stream).Child.Error || Error)!void {
70 // render all the line comments at the beginning of the file
71 var tok_it = tree.tokens.iterator(0);
72 while (tok_it.next()) |token| {
73 if (token.id != Token.Id.LineComment) break;
74 try stream.print("{}\n", mem.trimRight(u8, tree.tokenSlicePtr(token), " "));
75 if (tok_it.peek()) |next_token| {
76 const loc = tree.tokenLocationPtr(token.end, next_token);
77 if (loc.line >= 2) {
78 try stream.writeByte('\n');
79 }
80 }
81 }
82
83 var start_col: usize = 0;
84 var it = tree.root_node.decls.iterator(0);
85 while (true) {
86 var decl = (it.next() orelse return).*;
87 // look for zig fmt: off comment
88 var start_token_index = decl.firstToken();
89 zig_fmt_loop: while (start_token_index != 0) {
90 start_token_index -= 1;
91 const start_token = tree.tokens.at(start_token_index);
92 switch (start_token.id) {
93 Token.Id.LineComment => {},
94 Token.Id.DocComment => continue,
95 else => break,
96 }
97 if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(start_token)[2..], " "), "zig fmt: off")) {
98 var end_token_index = start_token_index;
99 while (true) {
100 end_token_index += 1;
101 const end_token = tree.tokens.at(end_token_index);
102 switch (end_token.id) {
103 Token.Id.LineComment => {},
104 Token.Id.Eof => {
105 const start = tree.tokens.at(start_token_index + 1).start;
106 try stream.write(tree.source[start..]);
107 return;
108 },
109 else => continue,
110 }
111 if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(end_token)[2..], " "), "zig fmt: on")) {
112 const start = tree.tokens.at(start_token_index + 1).start;
113 try stream.print("{}\n", tree.source[start..end_token.end]);
114 while (tree.tokens.at(decl.firstToken()).start < end_token.end) {
115 decl = (it.next() orelse return).*;
116 }
117 break :zig_fmt_loop;
118 }
119 }
120 }
121 }
122
123 try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl);
124 if (it.peek()) |next_decl| {
125 try renderExtraNewline(tree, stream, &start_col, next_decl.*);
126 }
127 }
128}
129
130fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) !void {
131 const first_token = node.firstToken();
132 var prev_token = first_token;
133 while (tree.tokens.at(prev_token - 1).id == Token.Id.DocComment) {
134 prev_token -= 1;
135 }
136 const prev_token_end = tree.tokens.at(prev_token - 1).end;
137 const loc = tree.tokenLocation(prev_token_end, first_token);
138 if (loc.line >= 2) {
139 try stream.writeByte('\n');
140 start_col.* = 0;
141 }
142}
143
144fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@typeOf(stream).Child.Error || Error)!void {
145 switch (decl.id) {
146 ast.Node.Id.FnProto => {
147 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
148
149 try renderDocComments(tree, stream, fn_proto, indent, start_col);
150
151 if (fn_proto.body_node) |body_node| {
152 try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Space);
153 try renderExpression(allocator, stream, tree, indent, start_col, body_node, Space.Newline);
154 } else {
155 try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.None);
156 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, Space.Newline);
157 }
158 },
159
160 ast.Node.Id.Use => {
161 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
162
163 if (use_decl.visib_token) |visib_token| {
164 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
165 }
166 try renderToken(tree, stream, use_decl.use_token, indent, start_col, Space.Space); // use
167 try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, Space.None);
168 try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, Space.Newline); // ;
169 },
170
171 ast.Node.Id.VarDecl => {
172 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
173
174 try renderDocComments(tree, stream, var_decl, indent, start_col);
175 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
176 },
177
178 ast.Node.Id.TestDecl => {
179 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
180
181 try renderDocComments(tree, stream, test_decl, indent, start_col);
182 try renderToken(tree, stream, test_decl.test_token, indent, start_col, Space.Space);
183 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, Space.Space);
184 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, Space.Newline);
185 },
186
187 ast.Node.Id.StructField => {
188 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
189
190 try renderDocComments(tree, stream, field, indent, start_col);
191 if (field.visib_token) |visib_token| {
192 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
193 }
194 try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name
195 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // :
196 try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr, Space.Comma); // type,
197 },
198
199 ast.Node.Id.UnionTag => {
200 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
201
202 try renderDocComments(tree, stream, tag, indent, start_col);
203
204 if (tag.type_expr == null and tag.value_expr == null) {
205 return renderToken(tree, stream, tag.name_token, indent, start_col, Space.Comma); // name,
206 }
207
208 if (tag.type_expr == null) {
209 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.Space); // name
210 } else {
211 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.None); // name
212 }
213
214 if (tag.type_expr) |type_expr| {
215 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, start_col, Space.Space); // :
216
217 if (tag.value_expr == null) {
218 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.Comma); // type,
219 return;
220 } else {
221 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.Space); // type
222 }
223 }
224
225 const value_expr = tag.value_expr.?;
226 try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, start_col, Space.Space); // =
227 try renderExpression(allocator, stream, tree, indent, start_col, value_expr, Space.Comma); // value,
228 },
229
230 ast.Node.Id.EnumTag => {
231 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
232
233 try renderDocComments(tree, stream, tag, indent, start_col);
234
235 if (tag.value) |value| {
236 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.Space); // name
237
238 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, start_col, Space.Space); // =
239 try renderExpression(allocator, stream, tree, indent, start_col, value, Space.Comma);
240 } else {
241 try renderToken(tree, stream, tag.name_token, indent, start_col, Space.Comma); // name
242 }
243 },
244
245 ast.Node.Id.Comptime => {
246 assert(!decl.requireSemiColon());
247 try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Newline);
248 },
249 else => unreachable,
250 }
251}
252
253fn renderExpression(
254 allocator: *mem.Allocator,
255 stream: var,
256 tree: *ast.Tree,
257 indent: usize,
258 start_col: *usize,
259 base: *ast.Node,
260 space: Space,
261) (@typeOf(stream).Child.Error || Error)!void {
262 switch (base.id) {
263 ast.Node.Id.Identifier => {
264 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
265 return renderToken(tree, stream, identifier.token, indent, start_col, space);
266 },
267 ast.Node.Id.Block => {
268 const block = @fieldParentPtr(ast.Node.Block, "base", base);
269
270 if (block.label) |label| {
271 try renderToken(tree, stream, label, indent, start_col, Space.None);
272 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
273 }
274
275 if (block.statements.len == 0) {
276 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);
277 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
278 } else {
279 const block_indent = indent + indent_delta;
280 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);
281
282 var it = block.statements.iterator(0);
283 while (it.next()) |statement| {
284 try stream.writeByteNTimes(' ', block_indent);
285 try renderStatement(allocator, stream, tree, block_indent, start_col, statement.*);
286
287 if (it.peek()) |next_statement| {
288 try renderExtraNewline(tree, stream, start_col, next_statement.*);
289 }
290 }
291
292 try stream.writeByteNTimes(' ', indent);
293 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
294 }
295 },
296 ast.Node.Id.Defer => {
297 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
298
299 try renderToken(tree, stream, defer_node.defer_token, indent, start_col, Space.Space);
300 return renderExpression(allocator, stream, tree, indent, start_col, defer_node.expr, space);
301 },
302 ast.Node.Id.Comptime => {
303 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
304
305 try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space);
306 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
307 },
308
309 ast.Node.Id.AsyncAttribute => {
310 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
311
312 if (async_attr.allocator_type) |allocator_type| {
313 try renderToken(tree, stream, async_attr.async_token, indent, start_col, Space.None); // async
314
315 try renderToken(tree, stream, tree.nextToken(async_attr.async_token), indent, start_col, Space.None); // <
316 try renderExpression(allocator, stream, tree, indent, start_col, allocator_type, Space.None); // allocator
317 return renderToken(tree, stream, tree.nextToken(allocator_type.lastToken()), indent, start_col, space); // >
318 } else {
319 return renderToken(tree, stream, async_attr.async_token, indent, start_col, space); // async
320 }
321 },
322
323 ast.Node.Id.Suspend => {
324 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
325
326 if (suspend_node.body) |body| {
327 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
328 return renderExpression(allocator, stream, tree, indent, start_col, body, space);
329 } else {
330 return renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, space);
331 }
332 },
333
334 ast.Node.Id.InfixOp => {
335 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
336
337 const op_token = tree.tokens.at(infix_op_node.op_token);
338 const op_space = switch (infix_op_node.op) {
339 ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion, ast.Node.InfixOp.Op.Range => Space.None,
340 else => Space.Space,
341 };
342 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
343
344 const after_op_space = blk: {
345 const loc = tree.tokenLocation(tree.tokens.at(infix_op_node.op_token).end, tree.nextToken(infix_op_node.op_token));
346 break :blk if (loc.line == 0) op_space else Space.Newline;
347 };
348
349 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
350 if (after_op_space == Space.Newline) {
351 try stream.writeByteNTimes(' ', indent + indent_delta);
352 start_col.* = indent + indent_delta;
353 }
354
355 switch (infix_op_node.op) {
356 ast.Node.InfixOp.Op.Catch => |maybe_payload| if (maybe_payload) |payload| {
357 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
358 },
359 else => {},
360 }
361
362 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
363 },
364
365 ast.Node.Id.PrefixOp => {
366 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
367
368 switch (prefix_op_node.op) {
369 ast.Node.PrefixOp.Op.PtrType => |ptr_info| {
370 const star_offset = switch (tree.tokens.at(prefix_op_node.op_token).id) {
371 Token.Id.AsteriskAsterisk => usize(1),
372 else => usize(0),
373 };
374 try renderTokenOffset(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None, star_offset); // *
375 if (ptr_info.align_info) |align_info| {
376 const lparen_token = tree.prevToken(align_info.node.firstToken());
377 const align_token = tree.prevToken(lparen_token);
378
379 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
380 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
381
382 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
383
384 if (align_info.bit_range) |bit_range| {
385 const colon1 = tree.prevToken(bit_range.start.firstToken());
386 const colon2 = tree.prevToken(bit_range.end.firstToken());
387
388 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
389 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
390 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
391 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
392
393 const rparen_token = tree.nextToken(bit_range.end.lastToken());
394 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
395 } else {
396 const rparen_token = tree.nextToken(align_info.node.lastToken());
397 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
398 }
399 }
400 if (ptr_info.const_token) |const_token| {
401 try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const
402 }
403 if (ptr_info.volatile_token) |volatile_token| {
404 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
405 }
406 },
407
408 ast.Node.PrefixOp.Op.SliceType => |ptr_info| {
409 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
410 try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ]
411
412 if (ptr_info.align_info) |align_info| {
413 const lparen_token = tree.prevToken(align_info.node.firstToken());
414 const align_token = tree.prevToken(lparen_token);
415
416 try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
417 try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
418
419 try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
420
421 if (align_info.bit_range) |bit_range| {
422 const colon1 = tree.prevToken(bit_range.start.firstToken());
423 const colon2 = tree.prevToken(bit_range.end.firstToken());
424
425 try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
426 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
427 try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
428 try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
429
430 const rparen_token = tree.nextToken(bit_range.end.lastToken());
431 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
432 } else {
433 const rparen_token = tree.nextToken(align_info.node.lastToken());
434 try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
435 }
436 }
437 if (ptr_info.const_token) |const_token| {
438 try renderToken(tree, stream, const_token, indent, start_col, Space.Space);
439 }
440 if (ptr_info.volatile_token) |volatile_token| {
441 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);
442 }
443 },
444
445 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
446 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
447 try renderExpression(allocator, stream, tree, indent, start_col, array_index, Space.None);
448 try renderToken(tree, stream, tree.nextToken(array_index.lastToken()), indent, start_col, Space.None); // ]
449 },
450 ast.Node.PrefixOp.Op.BitNot,
451 ast.Node.PrefixOp.Op.BoolNot,
452 ast.Node.PrefixOp.Op.Negation,
453 ast.Node.PrefixOp.Op.NegationWrap,
454 ast.Node.PrefixOp.Op.OptionalType,
455 ast.Node.PrefixOp.Op.AddressOf,
456 => {
457 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None);
458 },
459
460 ast.Node.PrefixOp.Op.Try,
461 ast.Node.PrefixOp.Op.Await,
462 ast.Node.PrefixOp.Op.Cancel,
463 ast.Node.PrefixOp.Op.Resume,
464 => {
465 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
466 },
467 }
468
469 return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);
470 },
471
472 ast.Node.Id.SuffixOp => {
473 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
474
475 switch (suffix_op.op) {
476 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
477 if (call_info.async_attr) |async_attr| {
478 try renderExpression(allocator, stream, tree, indent, start_col, &async_attr.base, Space.Space);
479 }
480
481 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
482
483 const lparen = tree.nextToken(suffix_op.lhs.lastToken());
484
485 if (call_info.params.len == 0) {
486 try renderToken(tree, stream, lparen, indent, start_col, Space.None);
487 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
488 }
489
490 const src_has_trailing_comma = blk: {
491 const maybe_comma = tree.prevToken(suffix_op.rtoken);
492 break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
493 };
494
495 if (src_has_trailing_comma) {
496 const new_indent = indent + indent_delta;
497 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
498
499 var it = call_info.params.iterator(0);
500 while (true) {
501 const param_node = it.next().?;
502
503 const param_node_new_indent = if (param_node.*.id == ast.Node.Id.MultilineStringLiteral) blk: {
504 break :blk indent;
505 } else blk: {
506 try stream.writeByteNTimes(' ', new_indent);
507 break :blk new_indent;
508 };
509
510 if (it.peek()) |next_node| {
511 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.None);
512 const comma = tree.nextToken(param_node.*.lastToken());
513 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
514 try renderExtraNewline(tree, stream, start_col, next_node.*);
515 } else {
516 try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.Comma);
517 try stream.writeByteNTimes(' ', indent);
518 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
519 }
520 }
521 }
522
523 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
524
525 var it = call_info.params.iterator(0);
526 while (it.next()) |param_node| {
527 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None);
528
529 if (it.peek() != null) {
530 const comma = tree.nextToken(param_node.*.lastToken());
531 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
532 }
533 }
534 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
535 },
536
537 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
538 const lbracket = tree.prevToken(index_expr.firstToken());
539 const rbracket = tree.nextToken(index_expr.lastToken());
540
541 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
542 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
543 try renderExpression(allocator, stream, tree, indent, start_col, index_expr, Space.None);
544 return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
545 },
546
547 ast.Node.SuffixOp.Op.Deref, ast.Node.SuffixOp.Op.UnwrapOptional => {
548 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
549 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
550 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // * or ?
551 },
552
553 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
554 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
555
556 const lbracket = tree.prevToken(range.start.firstToken());
557 const dotdot = tree.nextToken(range.start.lastToken());
558
559 const after_start_space_bool = nodeCausesSliceOpSpace(range.start) or
560 (if (range.end) |end| nodeCausesSliceOpSpace(end) else false);
561 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
562 const after_op_space = if (range.end != null) after_start_space else Space.None;
563
564 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
565 try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);
566 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
567 if (range.end) |end| {
568 try renderExpression(allocator, stream, tree, indent, start_col, end, Space.None);
569 }
570 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
571 },
572
573 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
574 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
575
576 if (field_inits.len == 0) {
577 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
578 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
579 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
580 }
581
582 if (field_inits.len == 1) blk: {
583 const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?;
584
585 if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| {
586 if (nested_suffix_op.op == ast.Node.SuffixOp.Op.StructInitializer) {
587 break :blk;
588 }
589 }
590
591 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
592 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
593 try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space);
594 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
595 }
596
597 const src_has_trailing_comma = blk: {
598 const maybe_comma = tree.prevToken(suffix_op.rtoken);
599 break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
600 };
601
602 const src_same_line = blk: {
603 const loc = tree.tokenLocation(tree.tokens.at(lbrace).end, suffix_op.rtoken);
604 break :blk loc.line == 0;
605 };
606
607 if (!src_has_trailing_comma and src_same_line) {
608 // render all on one line, no trailing comma
609 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
610 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
611
612 var it = field_inits.iterator(0);
613 while (it.next()) |field_init| {
614 if (it.peek() != null) {
615 try renderExpression(allocator, stream, tree, indent, start_col, field_init.*, Space.None);
616
617 const comma = tree.nextToken(field_init.*.lastToken());
618 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
619 } else {
620 try renderExpression(allocator, stream, tree, indent, start_col, field_init.*, Space.Space);
621 }
622 }
623
624 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
625 }
626
627 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
628 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline);
629
630 const new_indent = indent + indent_delta;
631
632 var it = field_inits.iterator(0);
633 while (it.next()) |field_init| {
634 try stream.writeByteNTimes(' ', new_indent);
635
636 if (it.peek()) |next_field_init| {
637 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init.*, Space.None);
638
639 const comma = tree.nextToken(field_init.*.lastToken());
640 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline);
641
642 try renderExtraNewline(tree, stream, start_col, next_field_init.*);
643 } else {
644 try renderExpression(allocator, stream, tree, new_indent, start_col, field_init.*, Space.Comma);
645 }
646 }
647
648 try stream.writeByteNTimes(' ', indent);
649 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
650 },
651
652 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
653 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
654
655 if (exprs.len == 0) {
656 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
657 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
658 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
659 }
660 if (exprs.len == 1) {
661 const expr = exprs.at(0).*;
662
663 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
664 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
665 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
666 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
667 }
668
669 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
670
671 // scan to find row size
672 const maybe_row_size: ?usize = blk: {
673 var count: usize = 1;
674 var it = exprs.iterator(0);
675 while (true) {
676 const expr = it.next().?.*;
677 if (it.peek()) |next_expr| {
678 const expr_last_token = expr.*.lastToken() + 1;
679 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken());
680 if (loc.line != 0) break :blk count;
681 count += 1;
682 } else {
683 const expr_last_token = expr.*.lastToken();
684 const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, suffix_op.rtoken);
685 if (loc.line == 0) {
686 // all on one line
687 const src_has_trailing_comma = trailblk: {
688 const maybe_comma = tree.prevToken(suffix_op.rtoken);
689 break :trailblk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
690 };
691 if (src_has_trailing_comma) {
692 break :blk 1; // force row size 1
693 } else {
694 break :blk null; // no newlines
695 }
696 }
697 break :blk count;
698 }
699 }
700 };
701
702 if (maybe_row_size) |row_size| {
703 const new_indent = indent + indent_delta;
704 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
705 try stream.writeByteNTimes(' ', new_indent);
706
707 var it = exprs.iterator(0);
708 var i: usize = 1;
709 while (it.next()) |expr| {
710 if (it.peek()) |next_expr| {
711 try renderExpression(allocator, stream, tree, new_indent, start_col, expr.*, Space.None);
712
713 const comma = tree.nextToken(expr.*.lastToken());
714
715 if (i != row_size) {
716 try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // ,
717 i += 1;
718 continue;
719 }
720 i = 1;
721
722 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
723
724 try renderExtraNewline(tree, stream, start_col, next_expr.*);
725 try stream.writeByteNTimes(' ', new_indent);
726 } else {
727 try renderExpression(allocator, stream, tree, new_indent, start_col, expr.*, Space.Comma); // ,
728 }
729 }
730 try stream.writeByteNTimes(' ', indent);
731 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
732 } else {
733 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space);
734 var it = exprs.iterator(0);
735 while (it.next()) |expr| {
736 if (it.peek()) |next_expr| {
737 try renderExpression(allocator, stream, tree, indent, start_col, expr.*, Space.None);
738 const comma = tree.nextToken(expr.*.lastToken());
739 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
740 } else {
741 try renderExpression(allocator, stream, tree, indent, start_col, expr.*, Space.Space);
742 }
743 }
744
745 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
746 }
747 },
748 }
749 },
750
751 ast.Node.Id.ControlFlowExpression => {
752 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
753
754 switch (flow_expr.kind) {
755 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
756 if (maybe_label == null and flow_expr.rhs == null) {
757 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break
758 }
759
760 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break
761 if (maybe_label) |label| {
762 const colon = tree.nextToken(flow_expr.ltoken);
763 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
764
765 if (flow_expr.rhs == null) {
766 return renderExpression(allocator, stream, tree, indent, start_col, label, space); // label
767 }
768 try renderExpression(allocator, stream, tree, indent, start_col, label, Space.Space); // label
769 }
770 },
771 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
772 assert(flow_expr.rhs == null);
773
774 if (maybe_label == null and flow_expr.rhs == null) {
775 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue
776 }
777
778 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue
779 if (maybe_label) |label| {
780 const colon = tree.nextToken(flow_expr.ltoken);
781 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
782
783 return renderExpression(allocator, stream, tree, indent, start_col, label, space);
784 }
785 },
786 ast.Node.ControlFlowExpression.Kind.Return => {
787 if (flow_expr.rhs == null) {
788 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);
789 }
790 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);
791 },
792 }
793
794 return renderExpression(allocator, stream, tree, indent, start_col, flow_expr.rhs.?, space);
795 },
796
797 ast.Node.Id.Payload => {
798 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
799
800 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);
801 try renderExpression(allocator, stream, tree, indent, start_col, payload.error_symbol, Space.None);
802 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);
803 },
804
805 ast.Node.Id.PointerPayload => {
806 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
807
808 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);
809 if (payload.ptr_token) |ptr_token| {
810 try renderToken(tree, stream, ptr_token, indent, start_col, Space.None);
811 }
812 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);
813 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);
814 },
815
816 ast.Node.Id.PointerIndexPayload => {
817 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
818
819 try renderToken(tree, stream, payload.lpipe, indent, start_col, Space.None);
820 if (payload.ptr_token) |ptr_token| {
821 try renderToken(tree, stream, ptr_token, indent, start_col, Space.None);
822 }
823 try renderExpression(allocator, stream, tree, indent, start_col, payload.value_symbol, Space.None);
824
825 if (payload.index_symbol) |index_symbol| {
826 const comma = tree.nextToken(payload.value_symbol.lastToken());
827
828 try renderToken(tree, stream, comma, indent, start_col, Space.Space);
829 try renderExpression(allocator, stream, tree, indent, start_col, index_symbol, Space.None);
830 }
831
832 return renderToken(tree, stream, payload.rpipe, indent, start_col, space);
833 },
834
835 ast.Node.Id.GroupedExpression => {
836 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
837
838 try renderToken(tree, stream, grouped_expr.lparen, indent, start_col, Space.None);
839 try renderExpression(allocator, stream, tree, indent, start_col, grouped_expr.expr, Space.None);
840 return renderToken(tree, stream, grouped_expr.rparen, indent, start_col, space);
841 },
842
843 ast.Node.Id.FieldInitializer => {
844 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
845
846 try renderToken(tree, stream, field_init.period_token, indent, start_col, Space.None); // .
847 try renderToken(tree, stream, field_init.name_token, indent, start_col, Space.Space); // name
848 try renderToken(tree, stream, tree.nextToken(field_init.name_token), indent, start_col, Space.Space); // =
849 return renderExpression(allocator, stream, tree, indent, start_col, field_init.expr, space);
850 },
851
852 ast.Node.Id.IntegerLiteral => {
853 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
854 return renderToken(tree, stream, integer_literal.token, indent, start_col, space);
855 },
856 ast.Node.Id.FloatLiteral => {
857 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
858 return renderToken(tree, stream, float_literal.token, indent, start_col, space);
859 },
860 ast.Node.Id.StringLiteral => {
861 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
862 return renderToken(tree, stream, string_literal.token, indent, start_col, space);
863 },
864 ast.Node.Id.CharLiteral => {
865 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
866 return renderToken(tree, stream, char_literal.token, indent, start_col, space);
867 },
868 ast.Node.Id.BoolLiteral => {
869 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
870 return renderToken(tree, stream, bool_literal.token, indent, start_col, space);
871 },
872 ast.Node.Id.NullLiteral => {
873 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
874 return renderToken(tree, stream, null_literal.token, indent, start_col, space);
875 },
876 ast.Node.Id.ThisLiteral => {
877 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
878 return renderToken(tree, stream, this_literal.token, indent, start_col, space);
879 },
880 ast.Node.Id.Unreachable => {
881 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
882 return renderToken(tree, stream, unreachable_node.token, indent, start_col, space);
883 },
884 ast.Node.Id.ErrorType => {
885 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
886 return renderToken(tree, stream, error_type.token, indent, start_col, space);
887 },
888 ast.Node.Id.VarType => {
889 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
890 return renderToken(tree, stream, var_type.token, indent, start_col, space);
891 },
892 ast.Node.Id.ContainerDecl => {
893 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
894
895 if (container_decl.layout_token) |layout_token| {
896 try renderToken(tree, stream, layout_token, indent, start_col, Space.Space);
897 }
898
899 switch (container_decl.init_arg_expr) {
900 ast.Node.ContainerDecl.InitArg.None => {
901 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.Space); // union
902 },
903 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
904 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union
905
906 const lparen = tree.nextToken(container_decl.kind_token);
907 const enum_token = tree.nextToken(lparen);
908
909 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
910 try renderToken(tree, stream, enum_token, indent, start_col, Space.None); // enum
911
912 if (enum_tag_type) |expr| {
913 try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.None); // (
914 try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None);
915
916 const rparen = tree.nextToken(expr.lastToken());
917 try renderToken(tree, stream, rparen, indent, start_col, Space.None); // )
918 try renderToken(tree, stream, tree.nextToken(rparen), indent, start_col, Space.Space); // )
919 } else {
920 try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.Space); // )
921 }
922 },
923 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
924 try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union
925
926 const lparen = tree.nextToken(container_decl.kind_token);
927 const rparen = tree.nextToken(type_expr.lastToken());
928
929 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
930 try renderExpression(allocator, stream, tree, indent, start_col, type_expr, Space.None);
931 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
932 },
933 }
934
935 if (container_decl.fields_and_decls.len == 0) {
936 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // {
937 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }
938 } else {
939 const new_indent = indent + indent_delta;
940 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, Space.Newline); // {
941
942 var it = container_decl.fields_and_decls.iterator(0);
943 while (it.next()) |decl| {
944 try stream.writeByteNTimes(' ', new_indent);
945 try renderTopLevelDecl(allocator, stream, tree, new_indent, start_col, decl.*);
946
947 if (it.peek()) |next_decl| {
948 try renderExtraNewline(tree, stream, start_col, next_decl.*);
949 }
950 }
951
952 try stream.writeByteNTimes(' ', indent);
953 return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // }
954 }
955 },
956
957 ast.Node.Id.ErrorSetDecl => {
958 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
959
960 const lbrace = tree.nextToken(err_set_decl.error_token);
961
962 if (err_set_decl.decls.len == 0) {
963 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
964 try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
965 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
966 }
967
968 if (err_set_decl.decls.len == 1) blk: {
969 const node = err_set_decl.decls.at(0).*;
970
971 // if there are any doc comments or same line comments
972 // don't try to put it all on one line
973 if (node.cast(ast.Node.ErrorTag)) |tag| {
974 if (tag.doc_comments != null) break :blk;
975 } else {
976 break :blk;
977 }
978
979 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error
980 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
981 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
982 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
983 }
984
985 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error
986 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
987 const new_indent = indent + indent_delta;
988
989 var it = err_set_decl.decls.iterator(0);
990 while (it.next()) |node| {
991 try stream.writeByteNTimes(' ', new_indent);
992
993 if (it.peek()) |next_node| {
994 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None);
995 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // ,
996
997 try renderExtraNewline(tree, stream, start_col, next_node.*);
998 } else {
999 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma);
1000 }
1001 }
1002
1003 try stream.writeByteNTimes(' ', indent);
1004 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1005 },
1006
1007 ast.Node.Id.ErrorTag => {
1008 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
1009
1010 try renderDocComments(tree, stream, tag, indent, start_col);
1011 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
1012 },
1013
1014 ast.Node.Id.MultilineStringLiteral => {
1015 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
1016
1017 var skip_first_indent = true;
1018 if (tree.tokens.at(multiline_str_literal.firstToken() - 1).id != Token.Id.LineComment) {
1019 try stream.print("\n");
1020 skip_first_indent = false;
1021 }
1022
1023 var i: usize = 0;
1024 while (i < multiline_str_literal.lines.len) : (i += 1) {
1025 const t = multiline_str_literal.lines.at(i).*;
1026 if (!skip_first_indent) {
1027 try stream.writeByteNTimes(' ', indent + indent_delta);
1028 }
1029 try renderToken(tree, stream, t, indent, start_col, Space.None);
1030 skip_first_indent = false;
1031 }
1032 try stream.writeByteNTimes(' ', indent);
1033 },
1034 ast.Node.Id.UndefinedLiteral => {
1035 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
1036 return renderToken(tree, stream, undefined_literal.token, indent, start_col, space);
1037 },
1038
1039 ast.Node.Id.BuiltinCall => {
1040 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
1041
1042 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
1043 try renderToken(tree, stream, tree.nextToken(builtin_call.builtin_token), indent, start_col, Space.None); // (
1044
1045 var it = builtin_call.params.iterator(0);
1046 while (it.next()) |param_node| {
1047 try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None);
1048
1049 if (it.peek() != null) {
1050 const comma_token = tree.nextToken(param_node.*.lastToken());
1051 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1052 }
1053 }
1054 return renderToken(tree, stream, builtin_call.rparen_token, indent, start_col, space); // )
1055 },
1056
1057 ast.Node.Id.FnProto => {
1058 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
1059
1060 if (fn_proto.visib_token) |visib_token_index| {
1061 const visib_token = tree.tokens.at(visib_token_index);
1062 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
1063
1064 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
1065 }
1066
1067 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
1068 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export
1069 }
1070
1071 if (fn_proto.lib_name) |lib_name| {
1072 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
1073 }
1074
1075 if (fn_proto.cc_token) |cc_token| {
1076 try renderToken(tree, stream, cc_token, indent, start_col, Space.Space); // stdcallcc
1077 }
1078
1079 if (fn_proto.async_attr) |async_attr| {
1080 try renderExpression(allocator, stream, tree, indent, start_col, &async_attr.base, Space.Space);
1081 }
1082
1083 const lparen = if (fn_proto.name_token) |name_token| blk: {
1084 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1085 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
1086 break :blk tree.nextToken(name_token);
1087 } else blk: {
1088 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1089 break :blk tree.nextToken(fn_proto.fn_token);
1090 };
1091
1092 const rparen = tree.prevToken(switch (fn_proto.return_type) {
1093 ast.Node.FnProto.ReturnType.Explicit => |node| node.firstToken(),
1094 ast.Node.FnProto.ReturnType.InferErrorSet => |node| tree.prevToken(node.firstToken()),
1095 });
1096
1097 const src_params_trailing_comma = blk: {
1098 const maybe_comma = tree.prevToken(rparen);
1099 break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
1100 };
1101 const src_params_same_line = blk: {
1102 const loc = tree.tokenLocation(tree.tokens.at(lparen).end, rparen);
1103 break :blk loc.line == 0;
1104 };
1105
1106 if (!src_params_trailing_comma and src_params_same_line) {
1107 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1108
1109 // render all on one line, no trailing comma
1110 var it = fn_proto.params.iterator(0);
1111 while (it.next()) |param_decl_node| {
1112 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl_node.*, Space.None);
1113
1114 if (it.peek() != null) {
1115 const comma = tree.nextToken(param_decl_node.*.lastToken());
1116 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
1117 }
1118 }
1119 } else {
1120 // one param per line
1121 const new_indent = indent + indent_delta;
1122 try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
1123
1124 var it = fn_proto.params.iterator(0);
1125 while (it.next()) |param_decl_node| {
1126 try stream.writeByteNTimes(' ', new_indent);
1127 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl_node.*, Space.Comma);
1128 }
1129 try stream.writeByteNTimes(' ', indent);
1130 }
1131
1132 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1133
1134 if (fn_proto.align_expr) |align_expr| {
1135 const align_rparen = tree.nextToken(align_expr.lastToken());
1136 const align_lparen = tree.prevToken(align_expr.firstToken());
1137 const align_kw = tree.prevToken(align_lparen);
1138
1139 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
1140 try renderToken(tree, stream, align_lparen, indent, start_col, Space.None); // (
1141 try renderExpression(allocator, stream, tree, indent, start_col, align_expr, Space.None);
1142 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
1143 }
1144
1145 switch (fn_proto.return_type) {
1146 ast.Node.FnProto.ReturnType.Explicit => |node| {
1147 return renderExpression(allocator, stream, tree, indent, start_col, node, space);
1148 },
1149 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
1150 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, start_col, Space.None); // !
1151 return renderExpression(allocator, stream, tree, indent, start_col, node, space);
1152 },
1153 }
1154 },
1155
1156 ast.Node.Id.PromiseType => {
1157 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
1158
1159 if (promise_type.result) |result| {
1160 try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise
1161 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
1162 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
1163 } else {
1164 return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise
1165 }
1166 },
1167
1168 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
1169
1170 ast.Node.Id.Switch => {
1171 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
1172
1173 try renderToken(tree, stream, switch_node.switch_token, indent, start_col, Space.Space); // switch
1174 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), indent, start_col, Space.None); // (
1175
1176 const rparen = tree.nextToken(switch_node.expr.lastToken());
1177 const lbrace = tree.nextToken(rparen);
1178
1179 if (switch_node.cases.len == 0) {
1180 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
1181 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1182 try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
1183 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }
1184 }
1185
1186 try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
1187
1188 const new_indent = indent + indent_delta;
1189
1190 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1191 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
1192
1193 var it = switch_node.cases.iterator(0);
1194 while (it.next()) |node| {
1195 try stream.writeByteNTimes(' ', new_indent);
1196 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma);
1197
1198 if (it.peek()) |next_node| {
1199 try renderExtraNewline(tree, stream, start_col, next_node.*);
1200 }
1201 }
1202
1203 try stream.writeByteNTimes(' ', indent);
1204 return renderToken(tree, stream, switch_node.rbrace, indent, start_col, space); // }
1205 },
1206
1207 ast.Node.Id.SwitchCase => {
1208 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
1209
1210 assert(switch_case.items.len != 0);
1211 const src_has_trailing_comma = blk: {
1212 const last_node = switch_case.items.at(switch_case.items.len - 1).*;
1213 const maybe_comma = tree.nextToken(last_node.lastToken());
1214 break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
1215 };
1216
1217 if (switch_case.items.len == 1 or !src_has_trailing_comma) {
1218 var it = switch_case.items.iterator(0);
1219 while (it.next()) |node| {
1220 if (it.peek()) |next_node| {
1221 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
1222
1223 const comma_token = tree.nextToken(node.*.lastToken());
1224 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1225 try renderExtraNewline(tree, stream, start_col, next_node.*);
1226 } else {
1227 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space);
1228 }
1229 }
1230 } else {
1231 var it = switch_case.items.iterator(0);
1232 while (true) {
1233 const node = it.next().?;
1234 if (it.peek()) |next_node| {
1235 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
1236
1237 const comma_token = tree.nextToken(node.*.lastToken());
1238 try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // ,
1239 try renderExtraNewline(tree, stream, start_col, next_node.*);
1240 try stream.writeByteNTimes(' ', indent);
1241 } else {
1242 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma);
1243 try stream.writeByteNTimes(' ', indent);
1244 break;
1245 }
1246 }
1247 }
1248
1249 try renderToken(tree, stream, switch_case.arrow_token, indent, start_col, Space.Space); // =>
1250
1251 if (switch_case.payload) |payload| {
1252 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1253 }
1254
1255 return renderExpression(allocator, stream, tree, indent, start_col, switch_case.expr, space);
1256 },
1257 ast.Node.Id.SwitchElse => {
1258 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1259 return renderToken(tree, stream, switch_else.token, indent, start_col, space);
1260 },
1261 ast.Node.Id.Else => {
1262 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
1263
1264 const body_is_block = nodeIsBlock(else_node.body);
1265 const same_line = body_is_block or tree.tokensOnSameLine(else_node.else_token, else_node.body.lastToken());
1266
1267 const after_else_space = if (same_line or else_node.payload != null) Space.Space else Space.Newline;
1268 try renderToken(tree, stream, else_node.else_token, indent, start_col, after_else_space);
1269
1270 if (else_node.payload) |payload| {
1271 const payload_space = if (same_line) Space.Space else Space.Newline;
1272 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);
1273 }
1274
1275 if (same_line) {
1276 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);
1277 }
1278
1279 try stream.writeByteNTimes(' ', indent + indent_delta);
1280 start_col.* = indent + indent_delta;
1281 return renderExpression(allocator, stream, tree, indent, start_col, else_node.body, space);
1282 },
1283
1284 ast.Node.Id.While => {
1285 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
1286
1287 if (while_node.label) |label| {
1288 try renderToken(tree, stream, label, indent, start_col, Space.None); // label
1289 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :
1290 }
1291
1292 if (while_node.inline_token) |inline_token| {
1293 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline
1294 }
1295
1296 try renderToken(tree, stream, while_node.while_token, indent, start_col, Space.Space); // while
1297 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, start_col, Space.None); // (
1298 try renderExpression(allocator, stream, tree, indent, start_col, while_node.condition, Space.None);
1299
1300 const cond_rparen = tree.nextToken(while_node.condition.lastToken());
1301
1302 const body_is_block = nodeIsBlock(while_node.body);
1303
1304 var block_start_space: Space = undefined;
1305 var after_body_space: Space = undefined;
1306
1307 if (body_is_block) {
1308 block_start_space = Space.BlockStart;
1309 after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent;
1310 } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {
1311 block_start_space = Space.Space;
1312 after_body_space = if (while_node.@"else" == null) space else Space.Space;
1313 } else {
1314 block_start_space = Space.Newline;
1315 after_body_space = if (while_node.@"else" == null) space else Space.Newline;
1316 }
1317
1318 {
1319 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null) Space.Space else block_start_space;
1320 try renderToken(tree, stream, cond_rparen, indent, start_col, rparen_space); // )
1321 }
1322
1323 if (while_node.payload) |payload| {
1324 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
1325 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);
1326 }
1327
1328 if (while_node.continue_expr) |continue_expr| {
1329 const rparen = tree.nextToken(continue_expr.lastToken());
1330 const lparen = tree.prevToken(continue_expr.firstToken());
1331 const colon = tree.prevToken(lparen);
1332
1333 try renderToken(tree, stream, colon, indent, start_col, Space.Space); // :
1334 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1335
1336 try renderExpression(allocator, stream, tree, indent, start_col, continue_expr, Space.None);
1337
1338 try renderToken(tree, stream, rparen, indent, start_col, block_start_space); // )
1339 }
1340
1341 var new_indent = indent;
1342 if (block_start_space == Space.Newline) {
1343 new_indent += indent_delta;
1344 try stream.writeByteNTimes(' ', new_indent);
1345 start_col.* = new_indent;
1346 }
1347
1348 try renderExpression(allocator, stream, tree, indent, start_col, while_node.body, after_body_space);
1349
1350 if (while_node.@"else") |@"else"| {
1351 if (after_body_space == Space.Newline) {
1352 try stream.writeByteNTimes(' ', indent);
1353 start_col.* = indent;
1354 }
1355 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1356 }
1357 },
1358
1359 ast.Node.Id.For => {
1360 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
1361
1362 if (for_node.label) |label| {
1363 try renderToken(tree, stream, label, indent, start_col, Space.None); // label
1364 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); // :
1365 }
1366
1367 if (for_node.inline_token) |inline_token| {
1368 try renderToken(tree, stream, inline_token, indent, start_col, Space.Space); // inline
1369 }
1370
1371 try renderToken(tree, stream, for_node.for_token, indent, start_col, Space.Space); // for
1372 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, start_col, Space.None); // (
1373 try renderExpression(allocator, stream, tree, indent, start_col, for_node.array_expr, Space.None);
1374
1375 const rparen = tree.nextToken(for_node.array_expr.lastToken());
1376 const rparen_space = if (for_node.payload != null or
1377 for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1378 try renderToken(tree, stream, rparen, indent, start_col, rparen_space); // )
1379
1380 if (for_node.payload) |payload| {
1381 const payload_space = if (for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1382 try renderExpression(allocator, stream, tree, indent, start_col, payload, payload_space);
1383 }
1384
1385 const body_space = blk: {
1386 if (for_node.@"else" != null) {
1387 if (for_node.body.id == ast.Node.Id.Block) {
1388 break :blk Space.Space;
1389 } else {
1390 break :blk Space.Newline;
1391 }
1392 } else {
1393 break :blk space;
1394 }
1395 };
1396 if (for_node.body.id == ast.Node.Id.Block) {
1397 try renderExpression(allocator, stream, tree, indent, start_col, for_node.body, body_space);
1398 } else {
1399 try stream.writeByteNTimes(' ', indent + indent_delta);
1400 try renderExpression(allocator, stream, tree, indent, start_col, for_node.body, body_space);
1401 }
1402
1403 if (for_node.@"else") |@"else"| {
1404 if (for_node.body.id != ast.Node.Id.Block) {
1405 try stream.writeByteNTimes(' ', indent);
1406 }
1407
1408 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1409 }
1410 },
1411
1412 ast.Node.Id.If => {
1413 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1414
1415 const lparen = tree.prevToken(if_node.condition.firstToken());
1416 const rparen = tree.nextToken(if_node.condition.lastToken());
1417
1418 try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if
1419 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1420
1421 try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition
1422
1423 const body_is_block = nodeIsBlock(if_node.body);
1424
1425 if (body_is_block) {
1426 const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
1427 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )
1428
1429 if (if_node.payload) |payload| {
1430 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.BlockStart); // |x|
1431 }
1432
1433 if (if_node.@"else") |@"else"| {
1434 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.SpaceOrOutdent);
1435 return renderExpression(allocator, stream, tree, indent, start_col, &@"else".base, space);
1436 } else {
1437 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);
1438 }
1439 }
1440
1441 const src_has_newline = !tree.tokensOnSameLine(rparen, if_node.body.lastToken());
1442
1443 if (src_has_newline) {
1444 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1445 try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )
1446
1447 if (if_node.payload) |payload| {
1448 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);
1449 }
1450
1451 const new_indent = indent + indent_delta;
1452 try stream.writeByteNTimes(' ', new_indent);
1453
1454 if (if_node.@"else") |@"else"| {
1455 const else_is_block = nodeIsBlock(@"else".body);
1456 try renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, Space.Newline);
1457 try stream.writeByteNTimes(' ', indent);
1458
1459 if (else_is_block) {
1460 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space); // else
1461
1462 if (@"else".payload) |payload| {
1463 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1464 }
1465
1466 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);
1467 } else {
1468 const after_else_space = if (@"else".payload == null) Space.Newline else Space.Space;
1469 try renderToken(tree, stream, @"else".else_token, indent, start_col, after_else_space); // else
1470
1471 if (@"else".payload) |payload| {
1472 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Newline);
1473 }
1474 try stream.writeByteNTimes(' ', new_indent);
1475
1476 return renderExpression(allocator, stream, tree, new_indent, start_col, @"else".body, space);
1477 }
1478 } else {
1479 return renderExpression(allocator, stream, tree, new_indent, start_col, if_node.body, space);
1480 }
1481 }
1482
1483 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
1484
1485 if (if_node.payload) |payload| {
1486 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1487 }
1488
1489 if (if_node.@"else") |@"else"| {
1490 try renderExpression(allocator, stream, tree, indent, start_col, if_node.body, Space.Space);
1491 try renderToken(tree, stream, @"else".else_token, indent, start_col, Space.Space);
1492
1493 if (@"else".payload) |payload| {
1494 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
1495 }
1496
1497 return renderExpression(allocator, stream, tree, indent, start_col, @"else".body, space);
1498 } else {
1499 return renderExpression(allocator, stream, tree, indent, start_col, if_node.body, space);
1500 }
1501 },
1502
1503 ast.Node.Id.Asm => {
1504 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1505
1506 try renderToken(tree, stream, asm_node.asm_token, indent, start_col, Space.Space); // asm
1507
1508 if (asm_node.volatile_token) |volatile_token| {
1509 try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
1510 try renderToken(tree, stream, tree.nextToken(volatile_token), indent, start_col, Space.None); // (
1511 } else {
1512 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (
1513 }
1514
1515 if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1516 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);
1517 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
1518 }
1519
1520 try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.Newline);
1521
1522 const indent_once = indent + indent_delta;
1523 try stream.writeByteNTimes(' ', indent_once);
1524
1525 const colon1 = tree.nextToken(asm_node.template.lastToken());
1526 const indent_extra = indent_once + 2;
1527
1528 const colon2 = if (asm_node.outputs.len == 0) blk: {
1529 try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :
1530 try stream.writeByteNTimes(' ', indent_once);
1531
1532 break :blk tree.nextToken(colon1);
1533 } else blk: {
1534 try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
1535
1536 var it = asm_node.outputs.iterator(0);
1537 while (true) {
1538 const asm_output = it.next().?;
1539 const node = &(asm_output.*).base;
1540
1541 if (it.peek()) |next_asm_output| {
1542 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
1543 const next_node = &(next_asm_output.*).base;
1544
1545 const comma = tree.prevToken(next_asm_output.*.firstToken());
1546 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
1547 try renderExtraNewline(tree, stream, start_col, next_node);
1548
1549 try stream.writeByteNTimes(' ', indent_extra);
1550 } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
1551 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1552 try stream.writeByteNTimes(' ', indent);
1553 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
1554 } else {
1555 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1556 try stream.writeByteNTimes(' ', indent_once);
1557 const comma_or_colon = tree.nextToken(node.lastToken());
1558 break :blk switch (tree.tokens.at(comma_or_colon).id) {
1559 Token.Id.Comma => tree.nextToken(comma_or_colon),
1560 else => comma_or_colon,
1561 };
1562 }
1563 }
1564 };
1565
1566 const colon3 = if (asm_node.inputs.len == 0) blk: {
1567 try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :
1568 try stream.writeByteNTimes(' ', indent_once);
1569
1570 break :blk tree.nextToken(colon2);
1571 } else blk: {
1572 try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
1573
1574 var it = asm_node.inputs.iterator(0);
1575 while (true) {
1576 const asm_input = it.next().?;
1577 const node = &(asm_input.*).base;
1578
1579 if (it.peek()) |next_asm_input| {
1580 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
1581 const next_node = &(next_asm_input.*).base;
1582
1583 const comma = tree.prevToken(next_asm_input.*.firstToken());
1584 try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
1585 try renderExtraNewline(tree, stream, start_col, next_node);
1586
1587 try stream.writeByteNTimes(' ', indent_extra);
1588 } else if (asm_node.clobbers.len == 0) {
1589 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1590 try stream.writeByteNTimes(' ', indent);
1591 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
1592 } else {
1593 try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
1594 try stream.writeByteNTimes(' ', indent_once);
1595 const comma_or_colon = tree.nextToken(node.lastToken());
1596 break :blk switch (tree.tokens.at(comma_or_colon).id) {
1597 Token.Id.Comma => tree.nextToken(comma_or_colon),
1598 else => comma_or_colon,
1599 };
1600 }
1601 }
1602 };
1603
1604 try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
1605
1606 var it = asm_node.clobbers.iterator(0);
1607 while (true) {
1608 const clobber_token = it.next().?;
1609
1610 if (it.peek() == null) {
1611 try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.Newline);
1612 try stream.writeByteNTimes(' ', indent);
1613 return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
1614 } else {
1615 try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.None);
1616 const comma = tree.nextToken(clobber_token.*);
1617 try renderToken(tree, stream, comma, indent_once, start_col, Space.Space); // ,
1618 }
1619 }
1620 },
1621
1622 ast.Node.Id.AsmInput => {
1623 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1624
1625 try stream.write("[");
1626 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
1627 try stream.write("] ");
1628 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
1629 try stream.write(" (");
1630 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
1631 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
1632 },
1633
1634 ast.Node.Id.AsmOutput => {
1635 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1636
1637 try stream.write("[");
1638 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
1639 try stream.write("] ");
1640 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
1641 try stream.write(" (");
1642
1643 switch (asm_output.kind) {
1644 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1645 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
1646 },
1647 ast.Node.AsmOutput.Kind.Return => |return_type| {
1648 try stream.write("-> ");
1649 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
1650 },
1651 }
1652
1653 return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
1654 },
1655
1656 ast.Node.Id.StructField,
1657 ast.Node.Id.UnionTag,
1658 ast.Node.Id.EnumTag,
1659 ast.Node.Id.Root,
1660 ast.Node.Id.VarDecl,
1661 ast.Node.Id.Use,
1662 ast.Node.Id.TestDecl,
1663 ast.Node.Id.ParamDecl,
1664 => unreachable,
1665 }
1666}
1667
1668fn renderVarDecl(
1669 allocator: *mem.Allocator,
1670 stream: var,
1671 tree: *ast.Tree,
1672 indent: usize,
1673 start_col: *usize,
1674 var_decl: *ast.Node.VarDecl,
1675) (@typeOf(stream).Child.Error || Error)!void {
1676 if (var_decl.visib_token) |visib_token| {
1677 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
1678 }
1679
1680 if (var_decl.extern_export_token) |extern_export_token| {
1681 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern
1682
1683 if (var_decl.lib_name) |lib_name| {
1684 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
1685 }
1686 }
1687
1688 if (var_decl.comptime_token) |comptime_token| {
1689 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
1690 }
1691
1692 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var
1693
1694 const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or
1695 var_decl.init_node != null)) Space.Space else Space.None;
1696 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);
1697
1698 if (var_decl.type_node) |type_node| {
1699 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
1700 const s = if (var_decl.align_node != null or var_decl.init_node != null) Space.Space else Space.None;
1701 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
1702 }
1703
1704 if (var_decl.align_node) |align_node| {
1705 const lparen = tree.prevToken(align_node.firstToken());
1706 const align_kw = tree.prevToken(lparen);
1707 const rparen = tree.nextToken(align_node.lastToken());
1708 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
1709 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
1710 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);
1711 const s = if (var_decl.init_node != null) Space.Space else Space.None;
1712 try renderToken(tree, stream, rparen, indent, start_col, s); // )
1713 }
1714
1715 if (var_decl.init_node) |init_node| {
1716 const s = if (init_node.id == ast.Node.Id.MultilineStringLiteral) Space.None else Space.Space;
1717 try renderToken(tree, stream, var_decl.eq_token, indent, start_col, s); // =
1718 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
1719 }
1720
1721 try renderToken(tree, stream, var_decl.semicolon_token, indent, start_col, Space.Newline);
1722}
1723
1724fn renderParamDecl(
1725 allocator: *mem.Allocator,
1726 stream: var,
1727 tree: *ast.Tree,
1728 indent: usize,
1729 start_col: *usize,
1730 base: *ast.Node,
1731 space: Space,
1732) (@typeOf(stream).Child.Error || Error)!void {
1733 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
1734
1735 if (param_decl.comptime_token) |comptime_token| {
1736 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
1737 }
1738 if (param_decl.noalias_token) |noalias_token| {
1739 try renderToken(tree, stream, noalias_token, indent, start_col, Space.Space);
1740 }
1741 if (param_decl.name_token) |name_token| {
1742 try renderToken(tree, stream, name_token, indent, start_col, Space.None);
1743 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
1744 }
1745 if (param_decl.var_args_token) |var_args_token| {
1746 try renderToken(tree, stream, var_args_token, indent, start_col, space);
1747 } else {
1748 try renderExpression(allocator, stream, tree, indent, start_col, param_decl.type_node, space);
1749 }
1750}
1751
1752fn renderStatement(
1753 allocator: *mem.Allocator,
1754 stream: var,
1755 tree: *ast.Tree,
1756 indent: usize,
1757 start_col: *usize,
1758 base: *ast.Node,
1759) (@typeOf(stream).Child.Error || Error)!void {
1760 switch (base.id) {
1761 ast.Node.Id.VarDecl => {
1762 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1763 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
1764 },
1765 else => {
1766 if (base.requireSemiColon()) {
1767 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);
1768
1769 const semicolon_index = tree.nextToken(base.lastToken());
1770 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1771 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);
1772 } else {
1773 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);
1774 }
1775 },
1776 }
1777}
1778
1779const Space = enum {
1780 None,
1781 Newline,
1782 Comma,
1783 Space,
1784 SpaceOrOutdent,
1785 NoNewline,
1786 NoComment,
1787 BlockStart,
1788};
1789
1790fn renderTokenOffset(
1791 tree: *ast.Tree,
1792 stream: var,
1793 token_index: ast.TokenIndex,
1794 indent: usize,
1795 start_col: *usize,
1796 space: Space,
1797 token_skip_bytes: usize,
1798) (@typeOf(stream).Child.Error || Error)!void {
1799 if (space == Space.BlockStart) {
1800 if (start_col.* < indent + indent_delta)
1801 return renderToken(tree, stream, token_index, indent, start_col, Space.Space);
1802 try renderToken(tree, stream, token_index, indent, start_col, Space.Newline);
1803 try stream.writeByteNTimes(' ', indent);
1804 start_col.* = indent;
1805 return;
1806 }
1807
1808 var token = tree.tokens.at(token_index);
1809 try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
1810
1811 if (space == Space.NoComment)
1812 return;
1813
1814 var next_token = tree.tokens.at(token_index + 1);
1815
1816 if (space == Space.Comma) switch (next_token.id) {
1817 Token.Id.Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
1818 Token.Id.LineComment => {
1819 try stream.write(", ");
1820 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
1821 },
1822 else => {
1823 if (tree.tokens.at(token_index + 2).id == Token.Id.MultilineStringLiteralLine) {
1824 try stream.write(",");
1825 return;
1826 } else {
1827 try stream.write(",\n");
1828 start_col.* = 0;
1829 return;
1830 }
1831 },
1832 };
1833
1834 // Skip over same line doc comments
1835 var offset: usize = 1;
1836 if (next_token.id == Token.Id.DocComment) {
1837 const loc = tree.tokenLocationPtr(token.end, next_token);
1838 if (loc.line == 0) {
1839 offset += 1;
1840 next_token = tree.tokens.at(token_index + offset);
1841 }
1842 }
1843
1844 if (next_token.id != Token.Id.LineComment) blk: {
1845 switch (space) {
1846 Space.None, Space.NoNewline => return,
1847 Space.Newline => {
1848 if (next_token.id == Token.Id.MultilineStringLiteralLine) {
1849 return;
1850 } else {
1851 try stream.write("\n");
1852 start_col.* = 0;
1853 return;
1854 }
1855 },
1856 Space.Space, Space.SpaceOrOutdent => {
1857 if (next_token.id == Token.Id.MultilineStringLiteralLine)
1858 return;
1859 try stream.writeByte(' ');
1860 return;
1861 },
1862 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
1863 }
1864 }
1865
1866 const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2;
1867 if (comment_is_empty) {
1868 switch (space) {
1869 Space.Newline => {
1870 try stream.writeByte('\n');
1871 start_col.* = 0;
1872 return;
1873 },
1874 else => {},
1875 }
1876 }
1877
1878 var loc = tree.tokenLocationPtr(token.end, next_token);
1879 if (loc.line == 0) {
1880 try stream.print(" {}", mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
1881 offset = 2;
1882 token = next_token;
1883 next_token = tree.tokens.at(token_index + offset);
1884 if (next_token.id != Token.Id.LineComment) {
1885 switch (space) {
1886 Space.None, Space.Space => {
1887 try stream.writeByte('\n');
1888 const after_comment_token = tree.tokens.at(token_index + offset);
1889 const next_line_indent = switch (after_comment_token.id) {
1890 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,
1891 else => indent + indent_delta,
1892 };
1893 try stream.writeByteNTimes(' ', next_line_indent);
1894 start_col.* = next_line_indent;
1895 },
1896 Space.SpaceOrOutdent => {
1897 try stream.writeByte('\n');
1898 try stream.writeByteNTimes(' ', indent);
1899 start_col.* = indent;
1900 },
1901 Space.Newline => {
1902 if (next_token.id == Token.Id.MultilineStringLiteralLine) {
1903 return;
1904 } else {
1905 try stream.write("\n");
1906 start_col.* = 0;
1907 return;
1908 }
1909 },
1910 Space.NoNewline => {},
1911 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
1912 }
1913 return;
1914 }
1915 loc = tree.tokenLocationPtr(token.end, next_token);
1916 }
1917
1918 while (true) {
1919 assert(loc.line != 0);
1920 const newline_count = if (loc.line == 1) u8(1) else u8(2);
1921 try stream.writeByteNTimes('\n', newline_count);
1922 try stream.writeByteNTimes(' ', indent);
1923 try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
1924
1925 offset += 1;
1926 token = next_token;
1927 next_token = tree.tokens.at(token_index + offset);
1928 if (next_token.id != Token.Id.LineComment) {
1929 switch (space) {
1930 Space.Newline => {
1931 if (next_token.id == Token.Id.MultilineStringLiteralLine) {
1932 return;
1933 } else {
1934 try stream.write("\n");
1935 start_col.* = 0;
1936 return;
1937 }
1938 },
1939 Space.None, Space.Space => {
1940 try stream.writeByte('\n');
1941
1942 const after_comment_token = tree.tokens.at(token_index + offset);
1943 const next_line_indent = switch (after_comment_token.id) {
1944 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent - indent_delta,
1945 else => indent,
1946 };
1947 try stream.writeByteNTimes(' ', next_line_indent);
1948 start_col.* = next_line_indent;
1949 },
1950 Space.SpaceOrOutdent => {
1951 try stream.writeByte('\n');
1952 try stream.writeByteNTimes(' ', indent);
1953 start_col.* = indent;
1954 },
1955 Space.NoNewline => {},
1956 Space.NoComment, Space.Comma, Space.BlockStart => unreachable,
1957 }
1958 return;
1959 }
1960 loc = tree.tokenLocationPtr(token.end, next_token);
1961 }
1962}
1963
1964fn renderToken(
1965 tree: *ast.Tree,
1966 stream: var,
1967 token_index: ast.TokenIndex,
1968 indent: usize,
1969 start_col: *usize,
1970 space: Space,
1971) (@typeOf(stream).Child.Error || Error)!void {
1972 return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);
1973}
1974
1975fn renderDocComments(
1976 tree: *ast.Tree,
1977 stream: var,
1978 node: var,
1979 indent: usize,
1980 start_col: *usize,
1981) (@typeOf(stream).Child.Error || Error)!void {
1982 const comment = node.doc_comments orelse return;
1983 var it = comment.lines.iterator(0);
1984 const first_token = node.firstToken();
1985 while (it.next()) |line_token_index| {
1986 if (line_token_index.* < first_token) {
1987 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.Newline);
1988 try stream.writeByteNTimes(' ', indent);
1989 } else {
1990 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment);
1991 try stream.write("\n");
1992 try stream.writeByteNTimes(' ', indent);
1993 }
1994 }
1995}
1996
1997fn nodeIsBlock(base: *const ast.Node) bool {
1998 return switch (base.id) {
1999 ast.Node.Id.Block,
2000 ast.Node.Id.If,
2001 ast.Node.Id.For,
2002 ast.Node.Id.While,
2003 ast.Node.Id.Switch,
2004 => true,
2005 else => false,
2006 };
2007}
2008
2009fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2010 const infix_op = base.cast(ast.Node.InfixOp) orelse return false;
2011 return switch (infix_op.op) {
2012 ast.Node.InfixOp.Op.Period => false,
2013 else => true,
2014 };
2015}
std/zig/tokenizer.zig+368-190
......@@ -6,61 +6,64 @@ pub const Token = struct {
66 start: usize,
77 end: usize,
88
9 const KeywordId = struct {
9 pub const Keyword = struct {
1010 bytes: []const u8,
1111 id: Id,
1212 };
1313
14 const keywords = []KeywordId {
15 KeywordId{.bytes="align", .id = Id.Keyword_align},
16 KeywordId{.bytes="and", .id = Id.Keyword_and},
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},
21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},
22 KeywordId{.bytes="cancel", .id = Id.Keyword_cancel},
23 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},
24 KeywordId{.bytes="const", .id = Id.Keyword_const},
25 KeywordId{.bytes="continue", .id = Id.Keyword_continue},
26 KeywordId{.bytes="defer", .id = Id.Keyword_defer},
27 KeywordId{.bytes="else", .id = Id.Keyword_else},
28 KeywordId{.bytes="enum", .id = Id.Keyword_enum},
29 KeywordId{.bytes="errdefer", .id = Id.Keyword_errdefer},
30 KeywordId{.bytes="error", .id = Id.Keyword_error},
31 KeywordId{.bytes="export", .id = Id.Keyword_export},
32 KeywordId{.bytes="extern", .id = Id.Keyword_extern},
33 KeywordId{.bytes="false", .id = Id.Keyword_false},
34 KeywordId{.bytes="fn", .id = Id.Keyword_fn},
35 KeywordId{.bytes="for", .id = Id.Keyword_for},
36 KeywordId{.bytes="if", .id = Id.Keyword_if},
37 KeywordId{.bytes="inline", .id = Id.Keyword_inline},
38 KeywordId{.bytes="nakedcc", .id = Id.Keyword_nakedcc},
39 KeywordId{.bytes="noalias", .id = Id.Keyword_noalias},
40 KeywordId{.bytes="null", .id = Id.Keyword_null},
41 KeywordId{.bytes="or", .id = Id.Keyword_or},
42 KeywordId{.bytes="packed", .id = Id.Keyword_packed},
43 KeywordId{.bytes="pub", .id = Id.Keyword_pub},
44 KeywordId{.bytes="resume", .id = Id.Keyword_resume},
45 KeywordId{.bytes="return", .id = Id.Keyword_return},
46 KeywordId{.bytes="section", .id = Id.Keyword_section},
47 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},
48 KeywordId{.bytes="struct", .id = Id.Keyword_struct},
49 KeywordId{.bytes="suspend", .id = Id.Keyword_suspend},
50 KeywordId{.bytes="switch", .id = Id.Keyword_switch},
51 KeywordId{.bytes="test", .id = Id.Keyword_test},
52 KeywordId{.bytes="this", .id = Id.Keyword_this},
53 KeywordId{.bytes="true", .id = Id.Keyword_true},
54 KeywordId{.bytes="try", .id = Id.Keyword_try},
55 KeywordId{.bytes="undefined", .id = Id.Keyword_undefined},
56 KeywordId{.bytes="union", .id = Id.Keyword_union},
57 KeywordId{.bytes="unreachable", .id = Id.Keyword_unreachable},
58 KeywordId{.bytes="use", .id = Id.Keyword_use},
59 KeywordId{.bytes="var", .id = Id.Keyword_var},
60 KeywordId{.bytes="volatile", .id = Id.Keyword_volatile},
61 KeywordId{.bytes="while", .id = Id.Keyword_while},
14 pub const keywords = []Keyword{
15 Keyword{ .bytes = "align", .id = Id.Keyword_align },
16 Keyword{ .bytes = "and", .id = Id.Keyword_and },
17 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
18 Keyword{ .bytes = "async", .id = Id.Keyword_async },
19 Keyword{ .bytes = "await", .id = Id.Keyword_await },
20 Keyword{ .bytes = "break", .id = Id.Keyword_break },
21 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },
22 Keyword{ .bytes = "cancel", .id = Id.Keyword_cancel },
23 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },
24 Keyword{ .bytes = "const", .id = Id.Keyword_const },
25 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },
26 Keyword{ .bytes = "defer", .id = Id.Keyword_defer },
27 Keyword{ .bytes = "else", .id = Id.Keyword_else },
28 Keyword{ .bytes = "enum", .id = Id.Keyword_enum },
29 Keyword{ .bytes = "errdefer", .id = Id.Keyword_errdefer },
30 Keyword{ .bytes = "error", .id = Id.Keyword_error },
31 Keyword{ .bytes = "export", .id = Id.Keyword_export },
32 Keyword{ .bytes = "extern", .id = Id.Keyword_extern },
33 Keyword{ .bytes = "false", .id = Id.Keyword_false },
34 Keyword{ .bytes = "fn", .id = Id.Keyword_fn },
35 Keyword{ .bytes = "for", .id = Id.Keyword_for },
36 Keyword{ .bytes = "if", .id = Id.Keyword_if },
37 Keyword{ .bytes = "inline", .id = Id.Keyword_inline },
38 Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc },
39 Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias },
40 Keyword{ .bytes = "null", .id = Id.Keyword_null },
41 Keyword{ .bytes = "or", .id = Id.Keyword_or },
42 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
43 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
44 Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
45 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
46 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
47 Keyword{ .bytes = "return", .id = Id.Keyword_return },
48 Keyword{ .bytes = "section", .id = Id.Keyword_section },
49 Keyword{ .bytes = "stdcallcc", .id = Id.Keyword_stdcallcc },
50 Keyword{ .bytes = "struct", .id = Id.Keyword_struct },
51 Keyword{ .bytes = "suspend", .id = Id.Keyword_suspend },
52 Keyword{ .bytes = "switch", .id = Id.Keyword_switch },
53 Keyword{ .bytes = "test", .id = Id.Keyword_test },
54 Keyword{ .bytes = "this", .id = Id.Keyword_this },
55 Keyword{ .bytes = "true", .id = Id.Keyword_true },
56 Keyword{ .bytes = "try", .id = Id.Keyword_try },
57 Keyword{ .bytes = "undefined", .id = Id.Keyword_undefined },
58 Keyword{ .bytes = "union", .id = Id.Keyword_union },
59 Keyword{ .bytes = "unreachable", .id = Id.Keyword_unreachable },
60 Keyword{ .bytes = "use", .id = Id.Keyword_use },
61 Keyword{ .bytes = "var", .id = Id.Keyword_var },
62 Keyword{ .bytes = "volatile", .id = Id.Keyword_volatile },
63 Keyword{ .bytes = "while", .id = Id.Keyword_while },
6264 };
6365
66 // TODO perfect hash at comptime
6467 fn getKeyword(bytes: []const u8) ?Id {
6568 for (keywords) |kw| {
6669 if (mem.eql(u8, kw.bytes, bytes)) {
......@@ -70,7 +73,11 @@ pub const Token = struct {
7073 return null;
7174 }
7275
73 const StrLitKind = enum {Normal, C};
76 /// TODO remove this enum
77 const StrLitKind = enum {
78 Normal,
79 C,
80 };
7481
7582 pub const Id = union(enum) {
7683 Invalid,
......@@ -124,7 +131,6 @@ pub const Token = struct {
124131 Ampersand,
125132 AmpersandEqual,
126133 QuestionMark,
127 QuestionMarkQuestionMark,
128134 AngleBracketLeft,
129135 AngleBracketLeftEqual,
130136 AngleBracketAngleBracketLeft,
......@@ -137,6 +143,8 @@ pub const Token = struct {
137143 IntegerLiteral,
138144 FloatLiteral,
139145 LineComment,
146 DocComment,
147 BracketStarBracket,
140148 Keyword_align,
141149 Keyword_and,
142150 Keyword_asm,
......@@ -164,7 +172,9 @@ pub const Token = struct {
164172 Keyword_noalias,
165173 Keyword_null,
166174 Keyword_or,
175 Keyword_orelse,
167176 Keyword_packed,
177 Keyword_promise,
168178 Keyword_pub,
169179 Keyword_resume,
170180 Keyword_return,
......@@ -192,44 +202,13 @@ pub const Tokenizer = struct {
192202 index: usize,
193203 pending_invalid_token: ?Token,
194204
195 pub const Location = struct {
196 line: usize,
197 column: usize,
198 line_start: usize,
199 line_end: usize,
200 };
201
202 pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location {
203 var loc = Location {
204 .line = 0,
205 .column = 0,
206 .line_start = start_index,
207 .line_end = self.buffer.len,
208 };
209 for (self.buffer[start_index..]) |c, i| {
210 if (i + start_index == token.start) {
211 loc.line_end = i + start_index;
212 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
213 return loc;
214 }
215 if (c == '\n') {
216 loc.line += 1;
217 loc.column = 0;
218 loc.line_start = i + 1;
219 } else {
220 loc.column += 1;
221 }
222 }
223 return loc;
224 }
225
226205 /// For debugging purposes
227 pub fn dump(self: &Tokenizer, token: &const Token) void {
206 pub fn dump(self: *Tokenizer, token: *const Token) void {
228207 std.debug.warn("{} \"{}\"\n", @tagName(token.id), self.buffer[token.start..token.end]);
229208 }
230209
231210 pub fn init(buffer: []const u8) Tokenizer {
232 return Tokenizer {
211 return Tokenizer{
233212 .buffer = buffer,
234213 .index = 0,
235214 .pending_invalid_token = null,
......@@ -244,9 +223,10 @@ pub const Tokenizer = struct {
244223 StringLiteral,
245224 StringLiteralBackslash,
246225 MultilineStringLiteralLine,
247 MultilineStringLiteralLineBackslash,
248226 CharLiteral,
249227 CharLiteralBackslash,
228 CharLiteralEscape1,
229 CharLiteralEscape2,
250230 CharLiteralEnd,
251231 Backslash,
252232 Equal,
......@@ -257,18 +237,25 @@ pub const Tokenizer = struct {
257237 Asterisk,
258238 AsteriskPercent,
259239 Slash,
240 LineCommentStart,
260241 LineComment,
242 DocCommentStart,
243 DocComment,
261244 Zero,
262245 IntegerLiteral,
263246 IntegerLiteralWithRadix,
247 IntegerLiteralWithRadixHex,
264248 NumberDot,
249 NumberDotHex,
265250 FloatFraction,
251 FloatFractionHex,
266252 FloatExponentUnsigned,
253 FloatExponentUnsignedHex,
267254 FloatExponentNumber,
255 FloatExponentNumberHex,
268256 Ampersand,
269257 Caret,
270258 Percent,
271 QuestionMark,
272259 Plus,
273260 PlusPercent,
274261 AngleBracketLeft,
......@@ -278,16 +265,18 @@ pub const Tokenizer = struct {
278265 Period,
279266 Period2,
280267 SawAtSign,
268 LBracket,
269 LBracketStar,
281270 };
282271
283 pub fn next(self: &Tokenizer) Token {
272 pub fn next(self: *Tokenizer) Token {
284273 if (self.pending_invalid_token) |token| {
285274 self.pending_invalid_token = null;
286275 return token;
287276 }
288277 const start_index = self.index;
289278 var state = State.Start;
290 var result = Token {
279 var result = Token{
291280 .id = Token.Id.Eof,
292281 .start = self.index,
293282 .end = undefined,
......@@ -308,7 +297,7 @@ pub const Tokenizer = struct {
308297 },
309298 '"' => {
310299 state = State.StringLiteral;
311 result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal };
300 result.id = Token.Id{ .StringLiteral = Token.StrLitKind.Normal };
312301 },
313302 '\'' => {
314303 state = State.CharLiteral;
......@@ -340,9 +329,7 @@ pub const Tokenizer = struct {
340329 break;
341330 },
342331 '[' => {
343 result.id = Token.Id.LBracket;
344 self.index += 1;
345 break;
332 state = State.LBracket;
346333 },
347334 ']' => {
348335 result.id = Token.Id.RBracket;
......@@ -359,6 +346,11 @@ pub const Tokenizer = struct {
359346 self.index += 1;
360347 break;
361348 },
349 '?' => {
350 result.id = Token.Id.QuestionMark;
351 self.index += 1;
352 break;
353 },
362354 ':' => {
363355 result.id = Token.Id.Colon;
364356 self.index += 1;
......@@ -373,9 +365,6 @@ pub const Tokenizer = struct {
373365 '+' => {
374366 state = State.Plus;
375367 },
376 '?' => {
377 state = State.QuestionMark;
378 },
379368 '<' => {
380369 state = State.AngleBracketLeft;
381370 },
......@@ -387,7 +376,7 @@ pub const Tokenizer = struct {
387376 },
388377 '\\' => {
389378 state = State.Backslash;
390 result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.Normal };
379 result.id = Token.Id{ .MultilineStringLiteralLine = Token.StrLitKind.Normal };
391380 },
392381 '{' => {
393382 result.id = Token.Id.LBrace;
......@@ -444,6 +433,28 @@ pub const Tokenizer = struct {
444433 },
445434 },
446435
436 State.LBracket => switch (c) {
437 '*' => {
438 state = State.LBracketStar;
439 },
440 else => {
441 result.id = Token.Id.LBracket;
442 break;
443 },
444 },
445
446 State.LBracketStar => switch (c) {
447 ']' => {
448 result.id = Token.Id.BracketStarBracket;
449 self.index += 1;
450 break;
451 },
452 else => {
453 result.id = Token.Id.Invalid;
454 break;
455 },
456 },
457
447458 State.Ampersand => switch (c) {
448459 '=' => {
449460 result.id = Token.Id.AmpersandEqual;
......@@ -473,7 +484,7 @@ pub const Tokenizer = struct {
473484 else => {
474485 result.id = Token.Id.Asterisk;
475486 break;
476 }
487 },
477488 },
478489
479490 State.AsteriskPercent => switch (c) {
......@@ -485,18 +496,6 @@ pub const Tokenizer = struct {
485496 else => {
486497 result.id = Token.Id.AsteriskPercent;
487498 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;
500499 },
501500 },
502501
......@@ -553,7 +552,7 @@ pub const Tokenizer = struct {
553552 else => {
554553 result.id = Token.Id.Caret;
555554 break;
556 }
555 },
557556 },
558557
559558 State.Identifier => switch (c) {
......@@ -578,11 +577,11 @@ pub const Tokenizer = struct {
578577 State.C => switch (c) {
579578 '\\' => {
580579 state = State.Backslash;
581 result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.C };
580 result.id = Token.Id{ .MultilineStringLiteralLine = Token.StrLitKind.C };
582581 },
583582 '"' => {
584583 state = State.StringLiteral;
585 result.id = Token.Id { .StringLiteral = Token.StrLitKind.C };
584 result.id = Token.Id{ .StringLiteral = Token.StrLitKind.C };
586585 },
587586 'a'...'z', 'A'...'Z', '_', '0'...'9' => {
588587 state = State.Identifier;
......@@ -623,7 +622,7 @@ pub const Tokenizer = struct {
623622 }
624623
625624 state = State.CharLiteralEnd;
626 }
625 },
627626 },
628627
629628 State.CharLiteralBackslash => switch (c) {
......@@ -631,11 +630,34 @@ pub const Tokenizer = struct {
631630 result.id = Token.Id.Invalid;
632631 break;
633632 },
633 'x' => {
634 state = State.CharLiteralEscape1;
635 },
634636 else => {
635637 state = State.CharLiteralEnd;
636638 },
637639 },
638640
641 State.CharLiteralEscape1 => switch (c) {
642 '0'...'9', 'a'...'z', 'A'...'F' => {
643 state = State.CharLiteralEscape2;
644 },
645 else => {
646 result.id = Token.Id.Invalid;
647 break;
648 },
649 },
650
651 State.CharLiteralEscape2 => switch (c) {
652 '0'...'9', 'a'...'z', 'A'...'F' => {
653 state = State.CharLiteralEnd;
654 },
655 else => {
656 result.id = Token.Id.Invalid;
657 break;
658 },
659 },
660
639661 State.CharLiteralEnd => switch (c) {
640662 '\'' => {
641663 result.id = Token.Id.CharLiteral;
......@@ -649,9 +671,6 @@ pub const Tokenizer = struct {
649671 },
650672
651673 State.MultilineStringLiteralLine => switch (c) {
652 '\\' => {
653 state = State.MultilineStringLiteralLineBackslash;
654 },
655674 '\n' => {
656675 self.index += 1;
657676 break;
......@@ -659,13 +678,6 @@ pub const Tokenizer = struct {
659678 else => self.checkLiteralCharacter(),
660679 },
661680
662 State.MultilineStringLiteralLineBackslash => switch (c) {
663 '\n' => break, // Look for this error later.
664 else => {
665 state = State.MultilineStringLiteralLine;
666 },
667 },
668
669681 State.Bang => switch (c) {
670682 '=' => {
671683 result.id = Token.Id.BangEqual;
......@@ -741,7 +753,7 @@ pub const Tokenizer = struct {
741753 else => {
742754 result.id = Token.Id.MinusPercent;
743755 break;
744 }
756 },
745757 },
746758
747759 State.AngleBracketLeft => switch (c) {
......@@ -822,8 +834,8 @@ pub const Tokenizer = struct {
822834
823835 State.Slash => switch (c) {
824836 '/' => {
837 state = State.LineCommentStart;
825838 result.id = Token.Id.LineComment;
826 state = State.LineComment;
827839 },
828840 '=' => {
829841 result.id = Token.Id.SlashEqual;
......@@ -835,14 +847,41 @@ pub const Tokenizer = struct {
835847 break;
836848 },
837849 },
838 State.LineComment => switch (c) {
850 State.LineCommentStart => switch (c) {
851 '/' => {
852 state = State.DocCommentStart;
853 },
854 '\n' => break,
855 else => {
856 state = State.LineComment;
857 self.checkLiteralCharacter();
858 },
859 },
860 State.DocCommentStart => switch (c) {
861 '/' => {
862 state = State.LineComment;
863 },
864 '\n' => {
865 result.id = Token.Id.DocComment;
866 break;
867 },
868 else => {
869 state = State.DocComment;
870 result.id = Token.Id.DocComment;
871 self.checkLiteralCharacter();
872 },
873 },
874 State.LineComment, State.DocComment => switch (c) {
839875 '\n' => break,
840876 else => self.checkLiteralCharacter(),
841877 },
842878 State.Zero => switch (c) {
843 'b', 'o', 'x' => {
879 'b', 'o' => {
844880 state = State.IntegerLiteralWithRadix;
845881 },
882 'x' => {
883 state = State.IntegerLiteralWithRadixHex;
884 },
846885 else => {
847886 // reinterpret as a normal number
848887 self.index -= 1;
......@@ -863,8 +902,15 @@ pub const Tokenizer = struct {
863902 '.' => {
864903 state = State.NumberDot;
865904 },
905 '0'...'9' => {},
906 else => break,
907 },
908 State.IntegerLiteralWithRadixHex => switch (c) {
909 '.' => {
910 state = State.NumberDotHex;
911 },
866912 'p', 'P' => {
867 state = State.FloatExponentUnsigned;
913 state = State.FloatExponentUnsignedHex;
868914 },
869915 '0'...'9', 'a'...'f', 'A'...'F' => {},
870916 else => break,
......@@ -881,10 +927,29 @@ pub const Tokenizer = struct {
881927 state = State.FloatFraction;
882928 },
883929 },
930 State.NumberDotHex => switch (c) {
931 '.' => {
932 self.index -= 1;
933 state = State.Start;
934 break;
935 },
936 else => {
937 self.index -= 1;
938 result.id = Token.Id.FloatLiteral;
939 state = State.FloatFractionHex;
940 },
941 },
884942 State.FloatFraction => switch (c) {
885 'p', 'P' => {
943 'e', 'E' => {
886944 state = State.FloatExponentUnsigned;
887945 },
946 '0'...'9' => {},
947 else => break,
948 },
949 State.FloatFractionHex => switch (c) {
950 'p', 'P' => {
951 state = State.FloatExponentUnsignedHex;
952 },
888953 '0'...'9', 'a'...'f', 'A'...'F' => {},
889954 else => break,
890955 },
......@@ -896,9 +961,23 @@ pub const Tokenizer = struct {
896961 // reinterpret as a normal exponent number
897962 self.index -= 1;
898963 state = State.FloatExponentNumber;
899 }
964 },
965 },
966 State.FloatExponentUnsignedHex => switch (c) {
967 '+', '-' => {
968 state = State.FloatExponentNumberHex;
969 },
970 else => {
971 // reinterpret as a normal exponent number
972 self.index -= 1;
973 state = State.FloatExponentNumberHex;
974 },
900975 },
901976 State.FloatExponentNumber => switch (c) {
977 '0'...'9' => {},
978 else => break,
979 },
980 State.FloatExponentNumberHex => switch (c) {
902981 '0'...'9', 'a'...'f', 'A'...'F' => {},
903982 else => break,
904983 },
......@@ -909,30 +988,42 @@ pub const Tokenizer = struct {
909988 State.C,
910989 State.IntegerLiteral,
911990 State.IntegerLiteralWithRadix,
991 State.IntegerLiteralWithRadixHex,
912992 State.FloatFraction,
993 State.FloatFractionHex,
913994 State.FloatExponentNumber,
995 State.FloatExponentNumberHex,
914996 State.StringLiteral, // find this error later
915997 State.MultilineStringLiteralLine,
916 State.Builtin => {},
998 State.Builtin,
999 => {},
9171000
9181001 State.Identifier => {
9191002 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {
9201003 result.id = id;
9211004 }
9221005 },
923 State.LineComment => {
924 result.id = Token.Id.Eof;
1006 State.LineCommentStart, State.LineComment => {
1007 result.id = Token.Id.LineComment;
1008 },
1009 State.DocComment, State.DocCommentStart => {
1010 result.id = Token.Id.DocComment;
9251011 },
9261012
9271013 State.NumberDot,
1014 State.NumberDotHex,
9281015 State.FloatExponentUnsigned,
1016 State.FloatExponentUnsignedHex,
9291017 State.SawAtSign,
9301018 State.Backslash,
931 State.MultilineStringLiteralLineBackslash,
9321019 State.CharLiteral,
9331020 State.CharLiteralBackslash,
1021 State.CharLiteralEscape1,
1022 State.CharLiteralEscape2,
9341023 State.CharLiteralEnd,
935 State.StringLiteralBackslash => {
1024 State.StringLiteralBackslash,
1025 State.LBracketStar,
1026 => {
9361027 result.id = Token.Id.Invalid;
9371028 },
9381029
......@@ -948,6 +1039,9 @@ pub const Tokenizer = struct {
9481039 State.Slash => {
9491040 result.id = Token.Id.Slash;
9501041 },
1042 State.LBracket => {
1043 result.id = Token.Id.LBracket;
1044 },
9511045 State.Zero => {
9521046 result.id = Token.Id.IntegerLiteral;
9531047 },
......@@ -981,9 +1075,6 @@ pub const Tokenizer = struct {
9811075 State.Plus => {
9821076 result.id = Token.Id.Plus;
9831077 },
984 State.QuestionMark => {
985 result.id = Token.Id.QuestionMark;
986 },
9871078 State.Percent => {
9881079 result.id = Token.Id.Percent;
9891080 },
......@@ -1013,22 +1104,18 @@ pub const Tokenizer = struct {
10131104 return result;
10141105 }
10151106
1016 pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) []const u8 {
1017 return self.buffer[token.start..token.end];
1018 }
1019
1020 fn checkLiteralCharacter(self: &Tokenizer) void {
1107 fn checkLiteralCharacter(self: *Tokenizer) void {
10211108 if (self.pending_invalid_token != null) return;
10221109 const invalid_length = self.getInvalidCharacterLength();
10231110 if (invalid_length == 0) return;
1024 self.pending_invalid_token = Token {
1111 self.pending_invalid_token = Token{
10251112 .id = Token.Id.Invalid,
10261113 .start = self.index,
10271114 .end = self.index + invalid_length,
10281115 };
10291116 }
10301117
1031 fn getInvalidCharacterLength(self: &Tokenizer) u3 {
1118 fn getInvalidCharacterLength(self: *Tokenizer) u3 {
10321119 const c0 = self.buffer[self.index];
10331120 if (c0 < 0x80) {
10341121 if (c0 < 0x20 or c0 == 0x7f) {
......@@ -1042,9 +1129,9 @@ pub const Tokenizer = struct {
10421129 // check utf8-encoded character.
10431130 const length = std.unicode.utf8ByteSequenceLength(c0) catch return 1;
10441131 if (self.index + length > self.buffer.len) {
1045 return u3(self.buffer.len - self.index);
1132 return @intCast(u3, self.buffer.len - self.index);
10461133 }
1047 const bytes = self.buffer[self.index..self.index + length];
1134 const bytes = self.buffer[self.index .. self.index + length];
10481135 switch (length) {
10491136 2 => {
10501137 const value = std.unicode.utf8Decode2(bytes) catch return length;
......@@ -1066,84 +1153,147 @@ pub const Tokenizer = struct {
10661153 }
10671154};
10681155
1156test "tokenizer" {
1157 testTokenize("test", []Token.Id{Token.Id.Keyword_test});
1158}
10691159
1160test "tokenizer - unknown length pointer" {
1161 testTokenize(
1162 \\[*]u8
1163 , []Token.Id{
1164 Token.Id.BracketStarBracket,
1165 Token.Id.Identifier,
1166 });
1167}
10701168
1071test "tokenizer" {
1072 testTokenize("test", []Token.Id {
1073 Token.Id.Keyword_test,
1169test "tokenizer - char literal with hex escape" {
1170 testTokenize(
1171 \\'\x1b'
1172 , []Token.Id{Token.Id.CharLiteral});
1173}
1174
1175test "tokenizer - float literal e exponent" {
1176 testTokenize("a = 4.94065645841246544177e-324;\n", []Token.Id{
1177 Token.Id.Identifier,
1178 Token.Id.Equal,
1179 Token.Id.FloatLiteral,
1180 Token.Id.Semicolon,
1181 });
1182}
1183
1184test "tokenizer - float literal p exponent" {
1185 testTokenize("a = 0x1.a827999fcef32p+1022;\n", []Token.Id{
1186 Token.Id.Identifier,
1187 Token.Id.Equal,
1188 Token.Id.FloatLiteral,
1189 Token.Id.Semicolon,
10741190 });
10751191}
10761192
10771193test "tokenizer - chars" {
1078 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});
1194 testTokenize("'c'", []Token.Id{Token.Id.CharLiteral});
10791195}
10801196
10811197test "tokenizer - invalid token characters" {
10821198 testTokenize("#", []Token.Id{Token.Id.Invalid});
10831199 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});
1200 testTokenize("'c", []Token.Id{Token.Id.Invalid});
1201 testTokenize("'", []Token.Id{Token.Id.Invalid});
1202 testTokenize("''", []Token.Id{ Token.Id.Invalid, Token.Id.Invalid });
10871203}
10881204
10891205test "tokenizer - invalid literal/comment characters" {
1090 testTokenize("\"\x00\"", []Token.Id {
1091 Token.Id { .StringLiteral = Token.StrLitKind.Normal },
1206 testTokenize("\"\x00\"", []Token.Id{
1207 Token.Id{ .StringLiteral = Token.StrLitKind.Normal },
10921208 Token.Id.Invalid,
10931209 });
1094 testTokenize("//\x00", []Token.Id {
1210 testTokenize("//\x00", []Token.Id{
1211 Token.Id.LineComment,
10951212 Token.Id.Invalid,
10961213 });
1097 testTokenize("//\x1f", []Token.Id {
1214 testTokenize("//\x1f", []Token.Id{
1215 Token.Id.LineComment,
10981216 Token.Id.Invalid,
10991217 });
1100 testTokenize("//\x7f", []Token.Id {
1218 testTokenize("//\x7f", []Token.Id{
1219 Token.Id.LineComment,
11011220 Token.Id.Invalid,
11021221 });
11031222}
11041223
11051224test "tokenizer - utf8" {
1106 testTokenize("//\xc2\x80", []Token.Id{});
1107 testTokenize("//\xf4\x8f\xbf\xbf", []Token.Id{});
1225 testTokenize("//\xc2\x80", []Token.Id{Token.Id.LineComment});
1226 testTokenize("//\xf4\x8f\xbf\xbf", []Token.Id{Token.Id.LineComment});
11081227}
11091228
11101229test "tokenizer - invalid utf8" {
1111 testTokenize("//\x80", []Token.Id{Token.Id.Invalid});
1112 testTokenize("//\xbf", []Token.Id{Token.Id.Invalid});
1113 testTokenize("//\xf8", []Token.Id{Token.Id.Invalid});
1114 testTokenize("//\xff", []Token.Id{Token.Id.Invalid});
1115 testTokenize("//\xc2\xc0", []Token.Id{Token.Id.Invalid});
1116 testTokenize("//\xe0", []Token.Id{Token.Id.Invalid});
1117 testTokenize("//\xf0", []Token.Id{Token.Id.Invalid});
1118 testTokenize("//\xf0\x90\x80\xc0", []Token.Id{Token.Id.Invalid});
1230 testTokenize("//\x80", []Token.Id{
1231 Token.Id.LineComment,
1232 Token.Id.Invalid,
1233 });
1234 testTokenize("//\xbf", []Token.Id{
1235 Token.Id.LineComment,
1236 Token.Id.Invalid,
1237 });
1238 testTokenize("//\xf8", []Token.Id{
1239 Token.Id.LineComment,
1240 Token.Id.Invalid,
1241 });
1242 testTokenize("//\xff", []Token.Id{
1243 Token.Id.LineComment,
1244 Token.Id.Invalid,
1245 });
1246 testTokenize("//\xc2\xc0", []Token.Id{
1247 Token.Id.LineComment,
1248 Token.Id.Invalid,
1249 });
1250 testTokenize("//\xe0", []Token.Id{
1251 Token.Id.LineComment,
1252 Token.Id.Invalid,
1253 });
1254 testTokenize("//\xf0", []Token.Id{
1255 Token.Id.LineComment,
1256 Token.Id.Invalid,
1257 });
1258 testTokenize("//\xf0\x90\x80\xc0", []Token.Id{
1259 Token.Id.LineComment,
1260 Token.Id.Invalid,
1261 });
11191262}
11201263
11211264test "tokenizer - illegal unicode codepoints" {
11221265 // unicode newline characters.U+0085, U+2028, U+2029
1123 testTokenize("//\xc2\x84", []Token.Id{});
1124 testTokenize("//\xc2\x85", []Token.Id{Token.Id.Invalid});
1125 testTokenize("//\xc2\x86", []Token.Id{});
1126 testTokenize("//\xe2\x80\xa7", []Token.Id{});
1127 testTokenize("//\xe2\x80\xa8", []Token.Id{Token.Id.Invalid});
1128 testTokenize("//\xe2\x80\xa9", []Token.Id{Token.Id.Invalid});
1129 testTokenize("//\xe2\x80\xaa", []Token.Id{});
1266 testTokenize("//\xc2\x84", []Token.Id{Token.Id.LineComment});
1267 testTokenize("//\xc2\x85", []Token.Id{
1268 Token.Id.LineComment,
1269 Token.Id.Invalid,
1270 });
1271 testTokenize("//\xc2\x86", []Token.Id{Token.Id.LineComment});
1272 testTokenize("//\xe2\x80\xa7", []Token.Id{Token.Id.LineComment});
1273 testTokenize("//\xe2\x80\xa8", []Token.Id{
1274 Token.Id.LineComment,
1275 Token.Id.Invalid,
1276 });
1277 testTokenize("//\xe2\x80\xa9", []Token.Id{
1278 Token.Id.LineComment,
1279 Token.Id.Invalid,
1280 });
1281 testTokenize("//\xe2\x80\xaa", []Token.Id{Token.Id.LineComment});
11301282}
11311283
11321284test "tokenizer - string identifier and builtin fns" {
11331285 testTokenize(
11341286 \\const @"if" = @import("std");
1135 ,
1136 []Token.Id{
1137 Token.Id.Keyword_const,
1138 Token.Id.Identifier,
1139 Token.Id.Equal,
1140 Token.Id.Builtin,
1141 Token.Id.LParen,
1142 Token.Id {.StringLiteral = Token.StrLitKind.Normal},
1143 Token.Id.RParen,
1144 Token.Id.Semicolon,
1145 }
1146 );
1287 , []Token.Id{
1288 Token.Id.Keyword_const,
1289 Token.Id.Identifier,
1290 Token.Id.Equal,
1291 Token.Id.Builtin,
1292 Token.Id.LParen,
1293 Token.Id{ .StringLiteral = Token.StrLitKind.Normal },
1294 Token.Id.RParen,
1295 Token.Id.Semicolon,
1296 });
11471297}
11481298
11491299test "tokenizer - pipe and then invalid" {
......@@ -1153,14 +1303,42 @@ test "tokenizer - pipe and then invalid" {
11531303 });
11541304}
11551305
1306test "tokenizer - line comment and doc comment" {
1307 testTokenize("//", []Token.Id{Token.Id.LineComment});
1308 testTokenize("// a / b", []Token.Id{Token.Id.LineComment});
1309 testTokenize("// /", []Token.Id{Token.Id.LineComment});
1310 testTokenize("/// a", []Token.Id{Token.Id.DocComment});
1311 testTokenize("///", []Token.Id{Token.Id.DocComment});
1312 testTokenize("////", []Token.Id{Token.Id.LineComment});
1313}
1314
1315test "tokenizer - line comment followed by identifier" {
1316 testTokenize(
1317 \\ Unexpected,
1318 \\ // another
1319 \\ Another,
1320 , []Token.Id{
1321 Token.Id.Identifier,
1322 Token.Id.Comma,
1323 Token.Id.LineComment,
1324 Token.Id.Identifier,
1325 Token.Id.Comma,
1326 });
1327}
1328
11561329fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void {
11571330 var tokenizer = Tokenizer.init(source);
11581331 for (expected_tokens) |expected_token_id| {
11591332 const token = tokenizer.next();
1160 std.debug.assert(@TagType(Token.Id)(token.id) == @TagType(Token.Id)(expected_token_id));
1333 if (@TagType(Token.Id)(token.id) != @TagType(Token.Id)(expected_token_id)) {
1334 std.debug.panic("expected {}, found {}\n", @tagName(@TagType(Token.Id)(expected_token_id)), @tagName(@TagType(Token.Id)(token.id)));
1335 }
11611336 switch (expected_token_id) {
11621337 Token.Id.StringLiteral => |expected_kind| {
1163 std.debug.assert(expected_kind == switch (token.id) { Token.Id.StringLiteral => |kind| kind, else => unreachable });
1338 std.debug.assert(expected_kind == switch (token.id) {
1339 Token.Id.StringLiteral => |kind| kind,
1340 else => unreachable,
1341 });
11641342 },
11651343 else => {},
11661344 }
test/assemble_and_link.zig+1-1
......@@ -1,7 +1,7 @@
11const builtin = @import("builtin");
22const tests = @import("tests.zig");
33
4pub fn addCases(cases: &tests.CompareOutputContext) void {
4pub fn addCases(cases: *tests.CompareOutputContext) void {
55 if (builtin.os == builtin.Os.linux and builtin.arch == builtin.Arch.x86_64) {
66 cases.addAsm("hello world linux x86_64",
77 \\.text
test/behavior.zig+15
......@@ -8,12 +8,18 @@ comptime {
88 _ = @import("cases/atomics.zig");
99 _ = @import("cases/bitcast.zig");
1010 _ = @import("cases/bool.zig");
11 _ = @import("cases/bugs/1111.zig");
12 _ = @import("cases/bugs/1230.zig");
1113 _ = @import("cases/bugs/394.zig");
1214 _ = @import("cases/bugs/655.zig");
1315 _ = @import("cases/bugs/656.zig");
1416 _ = @import("cases/bugs/828.zig");
17 _ = @import("cases/bugs/920.zig");
18 _ = @import("cases/byval_arg_var.zig");
19 _ = @import("cases/cancel.zig");
1520 _ = @import("cases/cast.zig");
1621 _ = @import("cases/const_slice_child.zig");
22 _ = @import("cases/coroutine_await_struct.zig");
1723 _ = @import("cases/coroutines.zig");
1824 _ = @import("cases/defer.zig");
1925 _ = @import("cases/enum.zig");
......@@ -22,6 +28,7 @@ comptime {
2228 _ = @import("cases/eval.zig");
2329 _ = @import("cases/field_parent_ptr.zig");
2430 _ = @import("cases/fn.zig");
31 _ = @import("cases/fn_in_struct_in_comptime.zig");
2532 _ = @import("cases/for.zig");
2633 _ = @import("cases/generics.zig");
2734 _ = @import("cases/if.zig");
......@@ -29,9 +36,14 @@ comptime {
2936 _ = @import("cases/incomplete_struct_param_tld.zig");
3037 _ = @import("cases/ir_block_deps.zig");
3138 _ = @import("cases/math.zig");
39 _ = @import("cases/merge_error_sets.zig");
3240 _ = @import("cases/misc.zig");
3341 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
42 _ = @import("cases/new_stack_call.zig");
3443 _ = @import("cases/null.zig");
44 _ = @import("cases/optional.zig");
45 _ = @import("cases/pointers.zig");
46 _ = @import("cases/popcount.zig");
3547 _ = @import("cases/pub_enum/index.zig");
3648 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
3749 _ = @import("cases/reflection.zig");
......@@ -46,9 +58,12 @@ comptime {
4658 _ = @import("cases/syntax.zig");
4759 _ = @import("cases/this.zig");
4860 _ = @import("cases/try.zig");
61 _ = @import("cases/type_info.zig");
4962 _ = @import("cases/undefined.zig");
63 _ = @import("cases/underscore.zig");
5064 _ = @import("cases/union.zig");
5165 _ = @import("cases/var_args.zig");
5266 _ = @import("cases/void.zig");
5367 _ = @import("cases/while.zig");
68 _ = @import("cases/widening.zig");
5469}
test/build_examples.zig+13-3
......@@ -2,20 +2,30 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33const is_windows = builtin.os == builtin.Os.windows;
44
5pub fn addCases(cases: &tests.BuildExamplesContext) void {
5pub fn addCases(cases: *tests.BuildExamplesContext) void {
66 cases.add("example/hello_world/hello.zig");
77 cases.addC("example/hello_world/hello_libc.zig");
88 cases.add("example/cat/main.zig");
99 cases.add("example/guess_number/main.zig");
1010 if (!is_windows) {
1111 // TODO get this test passing on windows
12 // See https://github.com/zig-lang/zig/issues/538
12 // See https://github.com/ziglang/zig/issues/538
1313 cases.addBuildFile("example/shared_library/build.zig");
1414 cases.addBuildFile("example/mix_o_files/build.zig");
1515 }
16 cases.addBuildFile("test/standalone/issue_339/build.zig");
16 if (builtin.os != builtin.Os.macosx) {
17 // TODO https://github.com/ziglang/zig/issues/1126
18 cases.addBuildFile("test/standalone/issue_339/build.zig");
19 }
1720 cases.addBuildFile("test/standalone/issue_794/build.zig");
1821 cases.addBuildFile("test/standalone/pkg_import/build.zig");
1922 cases.addBuildFile("test/standalone/use_alias/build.zig");
2023 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
24 if (false) {
25 // TODO this test is disabled because it is failing on the CI server's linux. when this is fixed
26 // enable it for at least linux
27 // TODO hook up the DynLib API for windows using LoadLibraryA
28 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it
29 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
30 }
2131}
test/cases/align.zig+81-60
......@@ -5,34 +5,34 @@ var foo: u8 align(4) = 100;
55
66test "global variable alignment" {
77 assert(@typeOf(&foo).alignment == 4);
8 assert(@typeOf(&foo) == &align(4) u8);
9 const slice = (&foo)[0..1];
8 assert(@typeOf(&foo) == *align(4) u8);
9 const slice = (*[1]u8)(&foo)[0..];
1010 assert(@typeOf(slice) == []align(4) u8);
1111}
1212
13fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
13fn derp() align(@sizeOf(usize) * 2) i32 {
14 return 1234;
15}
1416fn noop1() align(1) void {}
1517fn noop4() align(4) void {}
1618
1719test "function alignment" {
1820 assert(derp() == 1234);
19 assert(@typeOf(noop1) == fn() align(1) void);
20 assert(@typeOf(noop4) == fn() align(4) void);
21 assert(@typeOf(noop1) == fn () align(1) void);
22 assert(@typeOf(noop4) == fn () align(4) void);
2123 noop1();
2224 noop4();
2325}
2426
25
2627var baz: packed struct {
2728 a: u32,
2829 b: u32,
2930} = undefined;
3031
3132test "packed struct alignment" {
32 assert(@typeOf(&baz.b) == &align(1) u32);
33 assert(@typeOf(&baz.b) == *align(1) u32);
3334}
3435
35
3636const blah: packed struct {
3737 a: u3,
3838 b: u3,
......@@ -40,11 +40,11 @@ const blah: packed struct {
4040} = undefined;
4141
4242test "bit field alignment" {
43 assert(@typeOf(&blah.b) == &align(1:3:6) const u3);
43 assert(@typeOf(&blah.b) == *align(1:3:6) const u3);
4444}
4545
4646test "default alignment allows unspecified in type syntax" {
47 assert(&u32 == &align(@alignOf(u32)) u32);
47 assert(*u32 == *align(@alignOf(u32)) u32);
4848}
4949
5050test "implicitly decreasing pointer alignment" {
......@@ -53,30 +53,44 @@ test "implicitly decreasing pointer alignment" {
5353 assert(addUnaligned(&a, &b) == 7);
5454}
5555
56fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) u32 { return *a + *b; }
56fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
57 return a.* + b.*;
58}
5759
5860test "implicitly decreasing slice alignment" {
5961 const a: u32 align(4) = 3;
6062 const b: u32 align(8) = 4;
61 assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
63 assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
64}
65fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
66 return a[0] + b[0];
6267}
63fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { return a[0] + b[0]; }
6468
6569test "specifying alignment allows pointer cast" {
6670 testBytesAlign(0x33);
6771}
6872fn testBytesAlign(b: u8) void {
69 var bytes align(4) = []u8{b, b, b, b};
70 const ptr = @ptrCast(&u32, &bytes[0]);
71 assert(*ptr == 0x33333333);
73 var bytes align(4) = []u8{
74 b,
75 b,
76 b,
77 b,
78 };
79 const ptr = @ptrCast(*u32, &bytes[0]);
80 assert(ptr.* == 0x33333333);
7281}
7382
7483test "specifying alignment allows slice cast" {
7584 testBytesAlignSlice(0x33);
7685}
7786fn testBytesAlignSlice(b: u8) void {
78 var bytes align(4) = []u8{b, b, b, b};
79 const slice = ([]u32)(bytes[0..]);
87 var bytes align(4) = []u8{
88 b,
89 b,
90 b,
91 b,
92 };
93 const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
8094 assert(slice[0] == 0x33333333);
8195}
8296
......@@ -85,15 +99,18 @@ test "@alignCast pointers" {
8599 expectsOnly1(&x);
86100 assert(x == 2);
87101}
88fn expectsOnly1(x: &align(1) u32) void {
102fn expectsOnly1(x: *align(1) u32) void {
89103 expects4(@alignCast(4, x));
90104}
91fn expects4(x: &align(4) u32) void {
92 *x += 1;
105fn expects4(x: *align(4) u32) void {
106 x.* += 1;
93107}
94108
95109test "@alignCast slices" {
96 var array align(4) = []u32{1, 1};
110 var array align(4) = []u32{
111 1,
112 1,
113 };
97114 const slice = array[0..];
98115 sliceExpectsOnly1(slice);
99116 assert(slice[0] == 2);
......@@ -105,7 +122,6 @@ fn sliceExpects4(slice: []align(4) u32) void {
105122 slice[0] += 1;
106123}
107124
108
109125test "implicitly decreasing fn alignment" {
110126 testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
111127 testImplicitlyDecreaseFnAlign(alignedBig, 5678);
......@@ -115,21 +131,25 @@ fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
115131 assert(ptr() == answer);
116132}
117133
118fn alignedSmall() align(8) i32 { return 1234; }
119fn alignedBig() align(16) i32 { return 5678; }
120
134fn alignedSmall() align(8) i32 {
135 return 1234;
136}
137fn alignedBig() align(16) i32 {
138 return 5678;
139}
121140
122141test "@alignCast functions" {
123142 assert(fnExpectsOnly1(simple4) == 0x19);
124143}
125fn fnExpectsOnly1(ptr: fn()align(1) i32) i32 {
144fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 {
126145 return fnExpects4(@alignCast(4, ptr));
127146}
128fn fnExpects4(ptr: fn()align(4) i32) i32 {
147fn fnExpects4(ptr: fn () align(4) i32) i32 {
129148 return ptr();
130149}
131fn simple4() align(4) i32 { return 0x19; }
132
150fn simple4() align(4) i32 {
151 return 0x19;
152}
133153
134154test "generic function with align param" {
135155 assert(whyWouldYouEverDoThis(1) == 0x1);
......@@ -137,52 +157,53 @@ test "generic function with align param" {
137157 assert(whyWouldYouEverDoThis(8) == 0x1);
138158}
139159
140fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { return 0x1; }
141
160fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
161 return 0x1;
162}
142163
143164test "@ptrCast preserves alignment of bigger source" {
144165 var x: u32 align(16) = 1234;
145 const ptr = @ptrCast(&u8, &x);
146 assert(@typeOf(ptr) == &align(16) u8);
166 const ptr = @ptrCast(*u8, &x);
167 assert(@typeOf(ptr) == *align(16) u8);
147168}
148169
149
150test "compile-time known array index has best alignment possible" {
170test "runtime known array index has best alignment possible" {
151171 // take full advantage of over-alignment
152 var array align(4) = []u8 {1, 2, 3, 4};
153 assert(@typeOf(&array[0]) == &align(4) u8);
154 assert(@typeOf(&array[1]) == &u8);
155 assert(@typeOf(&array[2]) == &align(2) u8);
156 assert(@typeOf(&array[3]) == &u8);
172 var array align(4) = []u8{ 1, 2, 3, 4 };
173 assert(@typeOf(&array[0]) == *align(4) u8);
174 assert(@typeOf(&array[1]) == *u8);
175 assert(@typeOf(&array[2]) == *align(2) u8);
176 assert(@typeOf(&array[3]) == *u8);
157177
158178 // because align is too small but we still figure out to use 2
159 var bigger align(2) = []u64{1, 2, 3, 4};
160 assert(@typeOf(&bigger[0]) == &align(2) u64);
161 assert(@typeOf(&bigger[1]) == &align(2) u64);
162 assert(@typeOf(&bigger[2]) == &align(2) u64);
163 assert(@typeOf(&bigger[3]) == &align(2) u64);
179 var bigger align(2) = []u64{ 1, 2, 3, 4 };
180 assert(@typeOf(&bigger[0]) == *align(2) u64);
181 assert(@typeOf(&bigger[1]) == *align(2) u64);
182 assert(@typeOf(&bigger[2]) == *align(2) u64);
183 assert(@typeOf(&bigger[3]) == *align(2) u64);
164184
165185 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
166 var smaller align(2) = []u32{1, 2, 3, 4};
167 testIndex(&smaller[0], 0, &align(2) u32);
168 testIndex(&smaller[0], 1, &align(2) u32);
169 testIndex(&smaller[0], 2, &align(2) u32);
170 testIndex(&smaller[0], 3, &align(2) u32);
186 var smaller align(2) = []u32{ 1, 2, 3, 4 };
187 comptime assert(@typeOf(smaller[0..]) == []align(2) u32);
188 comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
189 testIndex(smaller[0..].ptr, 0, *align(2) u32);
190 testIndex(smaller[0..].ptr, 1, *align(2) u32);
191 testIndex(smaller[0..].ptr, 2, *align(2) u32);
192 testIndex(smaller[0..].ptr, 3, *align(2) u32);
171193
172194 // has to use ABI alignment because index known at runtime only
173 testIndex2(&array[0], 0, &u8);
174 testIndex2(&array[0], 1, &u8);
175 testIndex2(&array[0], 2, &u8);
176 testIndex2(&array[0], 3, &u8);
195 testIndex2(array[0..].ptr, 0, *u8);
196 testIndex2(array[0..].ptr, 1, *u8);
197 testIndex2(array[0..].ptr, 2, *u8);
198 testIndex2(array[0..].ptr, 3, *u8);
177199}
178fn testIndex(smaller: &align(2) u32, index: usize, comptime T: type) void {
179 assert(@typeOf(&smaller[index]) == T);
200fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
201 comptime assert(@typeOf(&smaller[index]) == T);
180202}
181fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) void {
182 assert(@typeOf(&ptr[index]) == T);
203fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void {
204 comptime assert(@typeOf(&ptr[index]) == T);
183205}
184206
185
186207test "alignstack" {
187208 assert(fnWithAlignedStack() == 1234);
188209}
test/cases/alignof.zig+5-1
......@@ -1,7 +1,11 @@
11const assert = @import("std").debug.assert;
22const builtin = @import("builtin");
33
4const Foo = struct { x: u32, y: u32, z: u32, };
4const Foo = struct {
5 x: u32,
6 y: u32,
7 z: u32,
8};
59
610test "@alignOf(T) before referencing T" {
711 comptime assert(@alignOf(Foo) != @maxValue(usize));
test/cases/array.zig+74-10
......@@ -2,9 +2,9 @@ const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
33
44test "arrays" {
5 var array : [5]u32 = undefined;
5 var array: [5]u32 = undefined;
66
7 var i : u32 = 0;
7 var i: u32 = 0;
88 while (i < 5) {
99 array[i] = i + 1;
1010 i = array[i];
......@@ -34,24 +34,41 @@ test "void arrays" {
3434}
3535
3636test "array literal" {
37 const hex_mult = []u16{4096, 256, 16, 1};
37 const hex_mult = []u16{
38 4096,
39 256,
40 16,
41 1,
42 };
3843
3944 assert(hex_mult.len == 4);
4045 assert(hex_mult[1] == 256);
4146}
4247
4348test "array dot len const expr" {
44 assert(comptime x: {break :x some_array.len == 4;});
49 assert(comptime x: {
50 break :x some_array.len == 4;
51 });
4552}
4653
4754const ArrayDotLenConstExpr = struct {
4855 y: [some_array.len]u8,
4956};
50const some_array = []u8 {0, 1, 2, 3};
51
57const some_array = []u8{
58 0,
59 1,
60 2,
61 3,
62};
5263
5364test "nested arrays" {
54 const array_of_strings = [][]const u8 {"hello", "this", "is", "my", "thing"};
65 const array_of_strings = [][]const u8{
66 "hello",
67 "this",
68 "is",
69 "my",
70 "thing",
71 };
5572 for (array_of_strings) |s, i| {
5673 if (i == 0) assert(mem.eql(u8, s, "hello"));
5774 if (i == 1) assert(mem.eql(u8, s, "this"));
......@@ -61,7 +78,6 @@ test "nested arrays" {
6178 }
6279}
6380
64
6581var s_array: [8]Sub = undefined;
6682const Sub = struct {
6783 b: u8,
......@@ -70,7 +86,7 @@ const Str = struct {
7086 a: []Sub,
7187};
7288test "set global var array via slice embedded in struct" {
73 var s = Str { .a = s_array[0..]};
89 var s = Str{ .a = s_array[0..] };
7490
7591 s.a[0].b = 1;
7692 s.a[1].b = 2;
......@@ -82,7 +98,10 @@ test "set global var array via slice embedded in struct" {
8298}
8399
84100test "array literal with specified size" {
85 var array = [2]u8{1, 2};
101 var array = [2]u8{
102 1,
103 2,
104 };
86105 assert(array[0] == 1);
87106 assert(array[1] == 2);
88107}
......@@ -96,3 +115,48 @@ test "array len property" {
96115 var x: [5]i32 = undefined;
97116 assert(@typeOf(x).len == 5);
98117}
118
119test "array len field" {
120 var arr = [4]u8{ 0, 0, 0, 0 };
121 var ptr = &arr;
122 assert(arr.len == 4);
123 comptime assert(arr.len == 4);
124 assert(ptr.len == 4);
125 comptime assert(ptr.len == 4);
126}
127
128test "single-item pointer to array indexing and slicing" {
129 testSingleItemPtrArrayIndexSlice();
130 comptime testSingleItemPtrArrayIndexSlice();
131}
132
133fn testSingleItemPtrArrayIndexSlice() void {
134 var array = "aaaa";
135 doSomeMangling(&array);
136 assert(mem.eql(u8, "azya", array));
137}
138
139fn doSomeMangling(array: *[4]u8) void {
140 array[1] = 'z';
141 array[2..3][0] = 'y';
142}
143
144test "implicit cast single-item pointer" {
145 testImplicitCastSingleItemPtr();
146 comptime testImplicitCastSingleItemPtr();
147}
148
149fn testImplicitCastSingleItemPtr() void {
150 var byte: u8 = 100;
151 const slice = (*[1]u8)(&byte)[0..];
152 slice[0] += 1;
153 assert(byte == 101);
154}
155
156fn testArrayByValAtComptime(b: [2]u8) u8 { return b[0]; }
157
158test "comptime evalutating function that takes array by value" {
159 const arr = []u8{0,1};
160 _ = comptime testArrayByValAtComptime(arr);
161 _ = comptime testArrayByValAtComptime(arr);
162}
test/cases/atomics.zig+48-4
......@@ -1,12 +1,24 @@
1const assert = @import("std").debug.assert;
1const std = @import("std");
2const assert = std.debug.assert;
23const builtin = @import("builtin");
34const AtomicRmwOp = builtin.AtomicRmwOp;
45const AtomicOrder = builtin.AtomicOrder;
56
67test "cmpxchg" {
78 var x: i32 = 1234;
8 while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
9 if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
10 assert(x1 == 1234);
11 } else {
12 @panic("cmpxchg should have failed");
13 }
14
15 while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
16 assert(x1 == 1234);
17 }
918 assert(x == 5678);
19
20 assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
21 assert(x == 42);
1022}
1123
1224test "fence" {
......@@ -15,13 +27,45 @@ test "fence" {
1527 x = 5678;
1628}
1729
18test "atomicrmw" {
30test "atomicrmw and atomicload" {
1931 var data: u8 = 200;
2032 testAtomicRmw(&data);
2133 assert(data == 42);
34 testAtomicLoad(&data);
2235}
2336
24fn testAtomicRmw(ptr: &u8) void {
37fn testAtomicRmw(ptr: *u8) void {
2538 const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
2639 assert(prev_value == 200);
40 comptime {
41 var x: i32 = 1234;
42 const y: i32 = 12345;
43 assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
44 assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
45 }
46}
47
48fn testAtomicLoad(ptr: *u8) void {
49 const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
50 assert(x == 42);
51}
52
53test "cmpxchg with ptr" {
54 var data1: i32 = 1234;
55 var data2: i32 = 5678;
56 var data3: i32 = 9101;
57 var x: *i32 = &data1;
58 if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
59 assert(x1 == &data1);
60 } else {
61 @panic("cmpxchg should have failed");
62 }
63
64 while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
65 assert(x1 == &data1);
66 }
67 assert(x == &data3);
68
69 assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
70 assert(x == &data2);
2771}
test/cases/bitcast.zig+6-2
......@@ -10,5 +10,9 @@ fn testBitCast_i32_u32() void {
1010 assert(conv2(@maxValue(u32)) == -1);
1111}
1212
13fn conv(x: i32) u32 { return @bitCast(u32, x); }
14fn conv2(x: u32) i32 { return @bitCast(i32, x); }
13fn conv(x: i32) u32 {
14 return @bitCast(u32, x);
15}
16fn conv2(x: u32) i32 {
17 return @bitCast(i32, x);
18}
test/cases/bool.zig+4-4
......@@ -8,14 +8,14 @@ test "bool literals" {
88test "cast bool to int" {
99 const t = true;
1010 const f = false;
11 assert(i32(t) == i32(1));
12 assert(i32(f) == i32(0));
11 assert(@boolToInt(t) == u32(1));
12 assert(@boolToInt(f) == u32(0));
1313 nonConstCastBoolToInt(t, f);
1414}
1515
1616fn nonConstCastBoolToInt(t: bool, f: bool) void {
17 assert(i32(t) == i32(1));
18 assert(i32(f) == i32(0));
17 assert(@boolToInt(t) == u32(1));
18 assert(@boolToInt(f) == u32(0));
1919}
2020
2121test "bool cmp" {
test/cases/bugs/1111.zig created+12
......@@ -0,0 +1,12 @@
1const Foo = extern enum {
2 Bar = -1,
3};
4
5test "issue 1111 fixed" {
6 const v = Foo.Bar;
7
8 switch (v) {
9 Foo.Bar => return,
10 else => return,
11 }
12}
test/cases/bugs/1230.zig created+14
......@@ -0,0 +1,14 @@
1const assert = @import("std").debug.assert;
2
3const S = extern struct {
4 x: i32,
5};
6
7extern fn ret_struct() S {
8 return S{ .x = 42 };
9}
10
11test "extern return small struct (bug 1230)" {
12 const s = ret_struct();
13 assert(s.x == 42);
14}
test/cases/bugs/394.zig+12-3
......@@ -1,9 +1,18 @@
1const E = union(enum) { A: [9]u8, B: u64, };
2const S = struct { x: u8, y: E, };
1const E = union(enum) {
2 A: [9]u8,
3 B: u64,
4};
5const S = struct {
6 x: u8,
7 y: E,
8};
39
410const assert = @import("std").debug.assert;
511
612test "bug 394 fixed" {
7 const x = S { .x = 3, .y = E {.B = 1 } };
13 const x = S{
14 .x = 3,
15 .y = E{ .B = 1 },
16 };
817 assert(x.x == 3);
918}
test/cases/bugs/655.zig+3-3
......@@ -3,10 +3,10 @@ const other_file = @import("655_other_file.zig");
33
44test "function with &const parameter with type dereferenced by namespace" {
55 const x: other_file.Integer = 1234;
6 comptime std.debug.assert(@typeOf(&x) == &const other_file.Integer);
6 comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer);
77 foo(x);
88}
99
10fn foo(x: &const other_file.Integer) void {
11 std.debug.assert(*x == 1234);
10fn foo(x: *const other_file.Integer) void {
11 std.debug.assert(x.* == 1234);
1212}
test/cases/bugs/656.zig+6-5
......@@ -9,17 +9,18 @@ const Value = struct {
99 align_expr: ?u32,
1010};
1111
12test "nullable if after an if in a switch prong of a switch with 2 prongs in an else" {
12test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
1313 foo(false, true);
1414}
1515
1616fn foo(a: bool, b: bool) void {
17 var prefix_op = PrefixOp { .AddrOf = Value { .align_expr = 1234 } };
18 if (a) {
19 } else {
17 var prefix_op = PrefixOp{
18 .AddrOf = Value{ .align_expr = 1234 },
19 };
20 if (a) {} else {
2021 switch (prefix_op) {
2122 PrefixOp.AddrOf => |addr_of_info| {
22 if (b) { }
23 if (b) {}
2324 if (addr_of_info.align_expr) |align_expr| {
2425 assert(align_expr == 1234);
2526 }
test/cases/bugs/828.zig+10-14
......@@ -1,31 +1,27 @@
11const CountBy = struct {
22 a: usize,
3
4 const One = CountBy {
5 .a = 1,
6 };
7
8 pub fn counter(self: &const CountBy) Counter {
9 return Counter {
10 .i = 0,
11 };
3
4 const One = CountBy{ .a = 1 };
5
6 pub fn counter(self: *const CountBy) Counter {
7 return Counter{ .i = 0 };
128 }
139};
1410
1511const Counter = struct {
1612 i: usize,
17
18 pub fn count(self: &Counter) bool {
13
14 pub fn count(self: *Counter) bool {
1915 self.i += 1;
2016 return self.i <= 10;
2117 }
2218};
2319
24fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
20fn constCount(comptime cb: *const CountBy, comptime unused: u32) void {
2521 comptime {
2622 var cnt = cb.counter();
27 if(cnt.i != 0) @compileError("Counter instance reused!");
28 while(cnt.count()){}
23 if (cnt.i != 0) @compileError("Counter instance reused!");
24 while (cnt.count()) {}
2925 }
3026}
3127
test/cases/bugs/920.zig created+65
......@@ -0,0 +1,65 @@
1const std = @import("std");
2const math = std.math;
3const Random = std.rand.Random;
4
5const ZigTable = struct {
6 r: f64,
7 x: [257]f64,
8 f: [257]f64,
9
10 pdf: fn (f64) f64,
11 is_symmetric: bool,
12 zero_case: fn (*Random, f64) f64,
13};
14
15fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable {
16 var tables: ZigTable = undefined;
17
18 tables.is_symmetric = is_symmetric;
19 tables.r = r;
20 tables.pdf = f;
21 tables.zero_case = zero_case;
22
23 tables.x[0] = v / f(r);
24 tables.x[1] = r;
25
26 for (tables.x[2..256]) |*entry, i| {
27 const last = tables.x[2 + i - 1];
28 entry.* = f_inv(v / last + f(last));
29 }
30 tables.x[256] = 0;
31
32 for (tables.f[0..]) |*entry, i| {
33 entry.* = f(tables.x[i]);
34 }
35
36 return tables;
37}
38
39const norm_r = 3.6541528853610088;
40const norm_v = 0.00492867323399;
41
42fn norm_f(x: f64) f64 {
43 return math.exp(-x * x / 2.0);
44}
45fn norm_f_inv(y: f64) f64 {
46 return math.sqrt(-2.0 * math.ln(y));
47}
48fn norm_zero_case(random: *Random, u: f64) f64 {
49 return 0.0;
50}
51
52const NormalDist = blk: {
53 @setEvalBranchQuota(30000);
54 break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
55};
56
57test "bug 920 fixed" {
58 const NormalDist1 = blk: {
59 break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
60 };
61
62 for (NormalDist1.f) |_, i| {
63 std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]);
64 }
65}
test/cases/byval_arg_var.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("std");
2
3var result: []const u8 = "wrong";
4
5test "aoeu" {
6 start();
7 blowUpStack(10);
8
9 std.debug.assert(std.mem.eql(u8, result, "string literal"));
10}
11
12fn start() void {
13 foo("string literal");
14}
15
16fn foo(x: var) void {
17 bar(x);
18}
19
20fn bar(x: var) void {
21 result = x;
22}
23
24fn blowUpStack(x: u32) void {
25 if (x == 0) return;
26 blowUpStack(x - 1);
27}
test/cases/cancel.zig created+92
......@@ -0,0 +1,92 @@
1const std = @import("std");
2
3var defer_f1: bool = false;
4var defer_f2: bool = false;
5var defer_f3: bool = false;
6
7test "cancel forwards" {
8 var da = std.heap.DirectAllocator.init();
9 defer da.deinit();
10
11 const p = async<&da.allocator> f1() catch unreachable;
12 cancel p;
13 std.debug.assert(defer_f1);
14 std.debug.assert(defer_f2);
15 std.debug.assert(defer_f3);
16}
17
18async fn f1() void {
19 defer {
20 defer_f1 = true;
21 }
22 await (async f2() catch unreachable);
23}
24
25async fn f2() void {
26 defer {
27 defer_f2 = true;
28 }
29 await (async f3() catch unreachable);
30}
31
32async fn f3() void {
33 defer {
34 defer_f3 = true;
35 }
36 suspend;
37}
38
39var defer_b1: bool = false;
40var defer_b2: bool = false;
41var defer_b3: bool = false;
42var defer_b4: bool = false;
43
44test "cancel backwards" {
45 var da = std.heap.DirectAllocator.init();
46 defer da.deinit();
47
48 const p = async<&da.allocator> b1() catch unreachable;
49 cancel p;
50 std.debug.assert(defer_b1);
51 std.debug.assert(defer_b2);
52 std.debug.assert(defer_b3);
53 std.debug.assert(defer_b4);
54}
55
56async fn b1() void {
57 defer {
58 defer_b1 = true;
59 }
60 await (async b2() catch unreachable);
61}
62
63var b4_handle: promise = undefined;
64
65async fn b2() void {
66 const b3_handle = async b3() catch unreachable;
67 resume b4_handle;
68 cancel b4_handle;
69 defer {
70 defer_b2 = true;
71 }
72 const value = await b3_handle;
73 @panic("unreachable");
74}
75
76async fn b3() i32 {
77 defer {
78 defer_b3 = true;
79 }
80 await (async b4() catch unreachable);
81 return 1234;
82}
83
84async fn b4() void {
85 defer {
86 defer_b4 = true;
87 }
88 suspend {
89 b4_handle = @handle();
90 }
91 suspend;
92}
test/cases/cast.zig+181-81
......@@ -1,23 +1,24 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
34
45test "int to ptr cast" {
56 const x = usize(13);
6 const y = @intToPtr(&u8, x);
7 const y = @intToPtr(*u8, x);
78 const z = @ptrToInt(y);
89 assert(z == 13);
910}
1011
1112test "integer literal to pointer cast" {
12 const vga_mem = @intToPtr(&u16, 0xB8000);
13 const vga_mem = @intToPtr(*u16, 0xB8000);
1314 assert(@ptrToInt(vga_mem) == 0xB8000);
1415}
1516
1617test "pointer reinterpret const float to int" {
1718 const float: f64 = 5.99999999999994648725e-01;
1819 const float_ptr = &float;
19 const int_ptr = @ptrCast(&const i32, float_ptr);
20 const int_val = *int_ptr;
20 const int_ptr = @ptrCast(*const i32, float_ptr);
21 const int_val = int_ptr.*;
2122 assert(int_val == 858993411);
2223}
2324
......@@ -28,26 +29,26 @@ test "implicitly cast a pointer to a const pointer of it" {
2829 assert(x == 2);
2930}
3031
31fn funcWithConstPtrPtr(x: &const &i32) void {
32 **x += 1;
32fn funcWithConstPtrPtr(x: *const *i32) void {
33 x.*.* += 1;
3334}
3435
3536test "implicitly cast a container to a const pointer of it" {
36 const z = Struct(void) { .x = void{} };
37 const z = Struct(void){ .x = void{} };
3738 assert(0 == @sizeOf(@typeOf(z)));
3839 assert(void{} == Struct(void).pointer(z).x);
3940 assert(void{} == Struct(void).pointer(&z).x);
4041 assert(void{} == Struct(void).maybePointer(z).x);
4142 assert(void{} == Struct(void).maybePointer(&z).x);
4243 assert(void{} == Struct(void).maybePointer(null).x);
43 const s = Struct(u8) { .x = 42 };
44 const s = Struct(u8){ .x = 42 };
4445 assert(0 != @sizeOf(@typeOf(s)));
4546 assert(42 == Struct(u8).pointer(s).x);
4647 assert(42 == Struct(u8).pointer(&s).x);
4748 assert(42 == Struct(u8).maybePointer(s).x);
4849 assert(42 == Struct(u8).maybePointer(&s).x);
4950 assert(0 == Struct(u8).maybePointer(null).x);
50 const u = Union { .x = 42 };
51 const u = Union{ .x = 42 };
5152 assert(42 == Union.pointer(u).x);
5253 assert(42 == Union.pointer(&u).x);
5354 assert(42 == Union.maybePointer(u).x);
......@@ -66,13 +67,13 @@ fn Struct(comptime T: type) type {
6667 const Self = this;
6768 x: T,
6869
69 fn pointer(self: &const Self) Self {
70 return *self;
70 fn pointer(self: *const Self) Self {
71 return self.*;
7172 }
7273
73 fn maybePointer(self: ?&const Self) Self {
74 const none = Self { .x = if (T == void) void{} else 0 };
75 return *(self ?? &none);
74 fn maybePointer(self: ?*const Self) Self {
75 const none = Self{ .x = if (T == void) void{} else 0 };
76 return (self orelse &none).*;
7677 }
7778 };
7879}
......@@ -80,13 +81,13 @@ fn Struct(comptime T: type) type {
8081const Union = union {
8182 x: u8,
8283
83 fn pointer(self: &const Union) Union {
84 return *self;
84 fn pointer(self: *const Union) Union {
85 return self.*;
8586 }
8687
87 fn maybePointer(self: ?&const Union) Union {
88 const none = Union { .x = 0 };
89 return *(self ?? &none);
88 fn maybePointer(self: ?*const Union) Union {
89 const none = Union{ .x = 0 };
90 return (self orelse &none).*;
9091 }
9192};
9293
......@@ -94,12 +95,12 @@ const Enum = enum {
9495 None,
9596 Some,
9697
97 fn pointer(self: &const Enum) Enum {
98 return *self;
98 fn pointer(self: *const Enum) Enum {
99 return self.*;
99100 }
100101
101 fn maybePointer(self: ?&const Enum) Enum {
102 return *(self ?? &Enum.None);
102 fn maybePointer(self: ?*const Enum) Enum {
103 return (self orelse &Enum.None).*;
103104 }
104105};
105106
......@@ -107,20 +108,20 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
107108 const S = struct {
108109 const Self = this;
109110 x: u8,
110 fn constConst(p: &const &const Self) u8 {
111 return (*p).x;
111 fn constConst(p: *const *const Self) u8 {
112 return p.*.x;
112113 }
113 fn maybeConstConst(p: ?&const &const Self) u8 {
114 return (*??p).x;
114 fn maybeConstConst(p: ?*const *const Self) u8 {
115 return p.?.*.x;
115116 }
116 fn constConstConst(p: &const &const &const Self) u8 {
117 return (**p).x;
117 fn constConstConst(p: *const *const *const Self) u8 {
118 return p.*.*.x;
118119 }
119 fn maybeConstConstConst(p: ?&const &const &const Self) u8 {
120 return (**??p).x;
120 fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
121 return p.?.*.*.x;
121122 }
122123 };
123 const s = S { .x = 42 };
124 const s = S{ .x = 42 };
124125 const p = &s;
125126 const q = &p;
126127 const r = &q;
......@@ -139,8 +140,8 @@ test "explicit cast from integer to error type" {
139140 comptime testCastIntToErr(error.ItBroke);
140141}
141142fn testCastIntToErr(err: error) void {
142 const x = usize(err);
143 const y = error(x);
143 const x = @errorToInt(err);
144 const y = @intToError(x);
144145 assert(error.ItBroke == y);
145146}
146147
......@@ -154,7 +155,6 @@ fn boolToStr(b: bool) []const u8 {
154155 return if (b) "true" else "false";
155156}
156157
157
158158test "peer resolve array and const slice" {
159159 testPeerResolveArrayConstSlice(true);
160160 comptime testPeerResolveArrayConstSlice(true);
......@@ -167,67 +167,66 @@ fn testPeerResolveArrayConstSlice(b: bool) void {
167167}
168168
169169test "integer literal to &const int" {
170 const x: &const i32 = 3;
171 assert(*x == 3);
170 const x: *const i32 = 3;
171 assert(x.* == 3);
172172}
173173
174174test "string literal to &const []const u8" {
175 const x: &const []const u8 = "hello";
176 assert(mem.eql(u8, *x, "hello"));
175 const x: *const []const u8 = "hello";
176 assert(mem.eql(u8, x.*, "hello"));
177177}
178178
179179test "implicitly cast from T to error!?T" {
180 castToMaybeTypeError(1);
181 comptime castToMaybeTypeError(1);
180 castToOptionalTypeError(1);
181 comptime castToOptionalTypeError(1);
182182}
183183const A = struct {
184184 a: i32,
185185};
186fn castToMaybeTypeError(z: i32) void {
186fn castToOptionalTypeError(z: i32) void {
187187 const x = i32(1);
188188 const y: error!?i32 = x;
189 assert(??(try y) == 1);
189 assert((try y).? == 1);
190190
191191 const f = z;
192192 const g: error!?i32 = f;
193193
194194 const a = A{ .a = z };
195195 const b: error!?A = a;
196 assert((??(b catch unreachable)).a == 1);
196 assert((b catch unreachable).?.a == 1);
197197}
198198
199199test "implicitly cast from int to error!?T" {
200 implicitIntLitToMaybe();
201 comptime implicitIntLitToMaybe();
200 implicitIntLitToOptional();
201 comptime implicitIntLitToOptional();
202202}
203fn implicitIntLitToMaybe() void {
203fn implicitIntLitToOptional() void {
204204 const f: ?i32 = 1;
205205 const g: error!?i32 = 1;
206206}
207207
208
209208test "return null from fn() error!?&T" {
210 const a = returnNullFromMaybeTypeErrorRef();
211 const b = returnNullLitFromMaybeTypeErrorRef();
209 const a = returnNullFromOptionalTypeErrorRef();
210 const b = returnNullLitFromOptionalTypeErrorRef();
212211 assert((try a) == null and (try b) == null);
213212}
214fn returnNullFromMaybeTypeErrorRef() error!?&A {
215 const a: ?&A = null;
213fn returnNullFromOptionalTypeErrorRef() error!?*A {
214 const a: ?*A = null;
216215 return a;
217216}
218fn returnNullLitFromMaybeTypeErrorRef() error!?&A {
217fn returnNullLitFromOptionalTypeErrorRef() error!?*A {
219218 return null;
220219}
221220
222221test "peer type resolution: ?T and T" {
223 assert(??peerTypeTAndMaybeT(true, false) == 0);
224 assert(??peerTypeTAndMaybeT(false, false) == 3);
222 assert(peerTypeTAndOptionalT(true, false).? == 0);
223 assert(peerTypeTAndOptionalT(false, false).? == 3);
225224 comptime {
226 assert(??peerTypeTAndMaybeT(true, false) == 0);
227 assert(??peerTypeTAndMaybeT(false, false) == 3);
225 assert(peerTypeTAndOptionalT(true, false).? == 0);
226 assert(peerTypeTAndOptionalT(false, false).? == 3);
228227 }
229228}
230fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
229fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
231230 if (c) {
232231 return if (b) null else usize(0);
233232 }
......@@ -235,7 +234,6 @@ fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
235234 return usize(3);
236235}
237236
238
239237test "peer type resolution: [0]u8 and []const u8" {
240238 assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
241239 assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
......@@ -246,22 +244,21 @@ test "peer type resolution: [0]u8 and []const u8" {
246244}
247245fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
248246 if (a) {
249 return []const u8 {};
247 return []const u8{};
250248 }
251249
252250 return slice[0..1];
253251}
254252
255253test "implicitly cast from [N]T to ?[]const T" {
256 assert(mem.eql(u8, ??castToMaybeSlice(), "hi"));
257 comptime assert(mem.eql(u8, ??castToMaybeSlice(), "hi"));
254 assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
255 comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
258256}
259257
260fn castToMaybeSlice() ?[]const u8 {
258fn castToOptionalSlice() ?[]const u8 {
261259 return "hi";
262260}
263261
264
265262test "implicitly cast from [0]T to error![]T" {
266263 testCastZeroArrayToErrSliceMut();
267264 comptime testCastZeroArrayToErrSliceMut();
......@@ -316,25 +313,15 @@ test "implicit cast from &const [N]T to []const T" {
316313fn testCastConstArrayRefToConstSlice() void {
317314 const blah = "aoeu";
318315 const const_array_ref = &blah;
319 assert(@typeOf(const_array_ref) == &const [4]u8);
316 assert(@typeOf(const_array_ref) == *const [4]u8);
320317 const slice: []const u8 = const_array_ref;
321318 assert(mem.eql(u8, slice, "aoeu"));
322319}
323320
324test "var args implicitly casts by value arg to const ref" {
325 foo("hello");
326}
327
328fn foo(args: ...) void {
329 assert(@typeOf(args[0]) == &const [5]u8);
330}
331
332
333321test "peer type resolution: error and [N]T" {
334322 // TODO: implicit error!T to error!U where T can implicitly cast to U
335323 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
336324 //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
337
338325 assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
339326 comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
340327}
......@@ -353,11 +340,26 @@ fn testPeerErrorAndArray2(x: u8) error![]const u8 {
353340 };
354341}
355342
356test "explicit cast float number literal to integer if no fraction component" {
343test "@floatToInt" {
344 testFloatToInts();
345 comptime testFloatToInts();
346}
347
348fn testFloatToInts() void {
357349 const x = i32(1e4);
358350 assert(x == 10000);
359 const y = i32(f32(1e4));
351 const y = @floatToInt(i32, f32(1e4));
360352 assert(y == 10000);
353 expectFloatToInt(f16, 255.1, u8, 255);
354 expectFloatToInt(f16, 127.2, i8, 127);
355 expectFloatToInt(f16, -128.2, i8, -128);
356 expectFloatToInt(f32, 255.1, u8, 255);
357 expectFloatToInt(f32, 127.2, i8, 127);
358 expectFloatToInt(f32, -128.2, i8, -128);
359}
360
361fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
362 assert(@floatToInt(I, f) == i);
361363}
362364
363365test "cast u128 to f128 and back" {
......@@ -378,10 +380,108 @@ fn cast128Float(x: u128) f128 {
378380}
379381
380382test "const slice widen cast" {
381 const bytes align(4) = []u8{0x12, 0x12, 0x12, 0x12};
383 const bytes align(4) = []u8{
384 0x12,
385 0x12,
386 0x12,
387 0x12,
388 };
382389
383 const u32_value = ([]const u32)(bytes[0..])[0];
390 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
384391 assert(u32_value == 0x12121212);
385392
386393 assert(@bitCast(u32, bytes) == 0x12121212);
387394}
395
396test "single-item pointer of array to slice and to unknown length pointer" {
397 testCastPtrOfArrayToSliceAndPtr();
398 comptime testCastPtrOfArrayToSliceAndPtr();
399}
400
401fn testCastPtrOfArrayToSliceAndPtr() void {
402 var array = "ao" ++ "eu"; // TODO https://github.com/ziglang/zig/issues/1076
403 const x: [*]u8 = &array;
404 x[0] += 1;
405 assert(mem.eql(u8, array[0..], "boeu"));
406 const y: []u8 = &array;
407 y[0] += 1;
408 assert(mem.eql(u8, array[0..], "coeu"));
409}
410
411test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
412 const window_name = [1][*]const u8{c"window name"};
413 const x: [*]const ?[*]const u8 = &window_name;
414 assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
415}
416
417test "@intCast comptime_int" {
418 const result = @intCast(i32, 1234);
419 assert(@typeOf(result) == i32);
420 assert(result == 1234);
421}
422
423test "@floatCast comptime_int and comptime_float" {
424 {
425 const result = @floatCast(f16, 1234);
426 assert(@typeOf(result) == f16);
427 assert(result == 1234.0);
428 }
429 {
430 const result = @floatCast(f16, 1234.0);
431 assert(@typeOf(result) == f16);
432 assert(result == 1234.0);
433 }
434 {
435 const result = @floatCast(f32, 1234);
436 assert(@typeOf(result) == f32);
437 assert(result == 1234.0);
438 }
439 {
440 const result = @floatCast(f32, 1234.0);
441 assert(@typeOf(result) == f32);
442 assert(result == 1234.0);
443 }
444}
445
446test "comptime_int @intToFloat" {
447 {
448 const result = @intToFloat(f16, 1234);
449 assert(@typeOf(result) == f16);
450 assert(result == 1234.0);
451 }
452 {
453 const result = @intToFloat(f32, 1234);
454 assert(@typeOf(result) == f32);
455 assert(result == 1234.0);
456 }
457}
458
459test "@bytesToSlice keeps pointer alignment" {
460 var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
461 const numbers = @bytesToSlice(u32, bytes[0..]);
462 comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
463}
464
465test "@intCast i32 to u7" {
466 var x: u128 = @maxValue(u128);
467 var y: i32 = 120;
468 var z = x >> @intCast(u7, y);
469 assert(z == 0xff);
470}
471
472test "implicit cast undefined to optional" {
473 assert(MakeType(void).getNull() == null);
474 assert(MakeType(void).getNonNull() != null);
475}
476
477fn MakeType(comptime T: type) type {
478 return struct {
479 fn getNull() ?T {
480 return null;
481 }
482
483 fn getNonNull() ?T {
484 return T(undefined);
485 }
486 };
487}
test/cases/const_slice_child.zig+5-4
......@@ -1,15 +1,16 @@
11const debug = @import("std").debug;
22const assert = debug.assert;
33
4var argv: &const &const u8 = undefined;
4var argv: [*]const [*]const u8 = undefined;
55
66test "const slice child" {
7 const strs = ([]&const u8) {
7 const strs = ([][*]const u8){
88 c"one",
99 c"two",
1010 c"three",
1111 };
12 argv = &strs[0];
12 // TODO this should implicitly cast
13 argv = @ptrCast([*]const [*]const u8, &strs);
1314 bar(strs.len);
1415}
1516
......@@ -29,7 +30,7 @@ fn bar(argc: usize) void {
2930 foo(args);
3031}
3132
32fn strlen(ptr: &const u8) usize {
33fn strlen(ptr: [*]const u8) usize {
3334 var count: usize = 0;
3435 while (ptr[count] != 0) : (count += 1) {}
3536 return count;
test/cases/coroutine_await_struct.zig created+47
......@@ -0,0 +1,47 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4
5const Foo = struct {
6 x: i32,
7};
8
9var await_a_promise: promise = undefined;
10var await_final_result = Foo{ .x = 0 };
11
12test "coroutine await struct" {
13 var da = std.heap.DirectAllocator.init();
14 defer da.deinit();
15
16 await_seq('a');
17 const p = async<&da.allocator> await_amain() catch unreachable;
18 await_seq('f');
19 resume await_a_promise;
20 await_seq('i');
21 assert(await_final_result.x == 1234);
22 assert(std.mem.eql(u8, await_points, "abcdefghi"));
23}
24async fn await_amain() void {
25 await_seq('b');
26 const p = async await_another() catch unreachable;
27 await_seq('e');
28 await_final_result = await p;
29 await_seq('h');
30}
31async fn await_another() Foo {
32 await_seq('c');
33 suspend {
34 await_seq('d');
35 await_a_promise = @handle();
36 }
37 await_seq('g');
38 return Foo{ .x = 1234 };
39}
40
41var await_points = []u8{0} ** "abcdefghi".len;
42var await_seq_index: usize = 0;
43
44fn await_seq(c: u8) void {
45 await_points[await_seq_index] = c;
46 await_seq_index += 1;
47}
test/cases/coroutines.zig+70-38
......@@ -5,12 +5,14 @@ const assert = std.debug.assert;
55var x: i32 = 1;
66
77test "create a coroutine and cancel it" {
8 const p = try async<std.debug.global_allocator> simpleAsyncFn();
8 var da = std.heap.DirectAllocator.init();
9 defer da.deinit();
10
11 const p = try async<&da.allocator> simpleAsyncFn();
912 comptime assert(@typeOf(p) == promise->void);
1013 cancel p;
1114 assert(x == 2);
1215}
13
1416async fn simpleAsyncFn() void {
1517 x += 1;
1618 suspend;
......@@ -18,8 +20,11 @@ async fn simpleAsyncFn() void {
1820}
1921
2022test "coroutine suspend, resume, cancel" {
23 var da = std.heap.DirectAllocator.init();
24 defer da.deinit();
25
2126 seq('a');
22 const p = try async<std.debug.global_allocator> testAsyncSeq();
27 const p = try async<&da.allocator> testAsyncSeq();
2328 seq('c');
2429 resume p;
2530 seq('f');
......@@ -28,7 +33,6 @@ test "coroutine suspend, resume, cancel" {
2833
2934 assert(std.mem.eql(u8, points, "abcdefg"));
3035}
31
3236async fn testAsyncSeq() void {
3337 defer seq('e');
3438
......@@ -45,7 +49,10 @@ fn seq(c: u8) void {
4549}
4650
4751test "coroutine suspend with block" {
48 const p = try async<std.debug.global_allocator> testSuspendBlock();
52 var da = std.heap.DirectAllocator.init();
53 defer da.deinit();
54
55 const p = try async<&da.allocator> testSuspendBlock();
4956 std.debug.assert(!result);
5057 resume a_promise;
5158 std.debug.assert(result);
......@@ -54,12 +61,16 @@ test "coroutine suspend with block" {
5461
5562var a_promise: promise = undefined;
5663var result = false;
57
5864async fn testSuspendBlock() void {
59 suspend |p| {
60 comptime assert(@typeOf(p) == promise->void);
61 a_promise = p;
65 suspend {
66 comptime assert(@typeOf(@handle()) == promise->void);
67 a_promise = @handle();
6268 }
69
70 //Test to make sure that @handle() works as advertised (issue #1296)
71 //var our_handle: promise = @handle();
72 assert( a_promise == @handle() );
73
6374 result = true;
6475}
6576
......@@ -67,15 +78,17 @@ var await_a_promise: promise = undefined;
6778var await_final_result: i32 = 0;
6879
6980test "coroutine await" {
81 var da = std.heap.DirectAllocator.init();
82 defer da.deinit();
83
7084 await_seq('a');
71 const p = async<std.debug.global_allocator> await_amain() catch unreachable;
85 const p = async<&da.allocator> await_amain() catch unreachable;
7286 await_seq('f');
7387 resume await_a_promise;
7488 await_seq('i');
7589 assert(await_final_result == 1234);
7690 assert(std.mem.eql(u8, await_points, "abcdefghi"));
7791}
78
7992async fn await_amain() void {
8093 await_seq('b');
8194 const p = async await_another() catch unreachable;
......@@ -83,12 +96,11 @@ async fn await_amain() void {
8396 await_final_result = await p;
8497 await_seq('h');
8598}
86
8799async fn await_another() i32 {
88100 await_seq('c');
89 suspend |p| {
101 suspend {
90102 await_seq('d');
91 await_a_promise = p;
103 await_a_promise = @handle();
92104 }
93105 await_seq('g');
94106 return 1234;
......@@ -102,25 +114,25 @@ fn await_seq(c: u8) void {
102114 await_seq_index += 1;
103115}
104116
105
106117var early_final_result: i32 = 0;
107118
108119test "coroutine await early return" {
120 var da = std.heap.DirectAllocator.init();
121 defer da.deinit();
122
109123 early_seq('a');
110 const p = async<std.debug.global_allocator> early_amain() catch unreachable;
124 const p = async<&da.allocator> early_amain() catch @panic("out of memory");
111125 early_seq('f');
112126 assert(early_final_result == 1234);
113127 assert(std.mem.eql(u8, early_points, "abcdef"));
114128}
115
116129async fn early_amain() void {
117130 early_seq('b');
118 const p = async early_another() catch unreachable;
131 const p = async early_another() catch @panic("out of memory");
119132 early_seq('d');
120133 early_final_result = await p;
121134 early_seq('e');
122135}
123
124136async fn early_another() i32 {
125137 early_seq('c');
126138 return 1234;
......@@ -142,7 +154,6 @@ test "coro allocation failure" {
142154 error.OutOfMemory => {},
143155 }
144156}
145
146157async fn asyncFuncThatNeverGetsRun() void {
147158 @panic("coro frame allocation should fail");
148159}
......@@ -155,7 +166,9 @@ test "async function with dot syntax" {
155166 suspend;
156167 }
157168 };
158 const p = try async<std.debug.global_allocator> S.foo();
169 var da = std.heap.DirectAllocator.init();
170 defer da.deinit();
171 const p = try async<&da.allocator> S.foo();
159172 cancel p;
160173 assert(S.y == 2);
161174}
......@@ -163,29 +176,29 @@ test "async function with dot syntax" {
163176test "async fn pointer in a struct field" {
164177 var data: i32 = 1;
165178 const Foo = struct {
166 bar: async<&std.mem.Allocator> fn(&i32) void,
179 bar: async<*std.mem.Allocator> fn (*i32) void,
167180 };
168 var foo = Foo {
169 .bar = simpleAsyncFn2,
170 };
171 const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable;
181 var foo = Foo{ .bar = simpleAsyncFn2 };
182 var da = std.heap.DirectAllocator.init();
183 defer da.deinit();
184 const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
172185 assert(data == 2);
173186 cancel p;
174187 assert(data == 4);
175188}
176
177async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
178 defer *y += 2;
179 *y += 1;
189async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
190 defer y.* += 2;
191 y.* += 1;
180192 suspend;
181193}
182194
183195test "async fn with inferred error set" {
184 const p = (async<std.debug.global_allocator> failing()) catch unreachable;
196 var da = std.heap.DirectAllocator.init();
197 defer da.deinit();
198 const p = (async<&da.allocator> failing()) catch unreachable;
185199 resume p;
186200 cancel p;
187201}
188
189202async fn failing() !void {
190203 suspend;
191204 return error.Fail;
......@@ -194,7 +207,9 @@ async fn failing() !void {
194207test "error return trace across suspend points - early return" {
195208 const p = nonFailing();
196209 resume p;
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
210 var da = std.heap.DirectAllocator.init();
211 defer da.deinit();
212 const p2 = try async<&da.allocator> printTrace(p);
198213 cancel p2;
199214}
200215
......@@ -205,22 +220,39 @@ test "error return trace across suspend points - async return" {
205220 cancel p2;
206221}
207222
208fn nonFailing() promise->error!void {
223// TODO https://github.com/ziglang/zig/issues/760
224fn nonFailing() (promise->error!void) {
209225 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
210226}
211
212227async fn suspendThenFail() error!void {
213228 suspend;
214229 return error.Fail;
215230}
216
217231async fn printTrace(p: promise->error!void) void {
218232 (await p) catch |e| {
219233 std.debug.assert(e == error.Fail);
220234 if (@errorReturnTrace()) |trace| {
221235 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {
223 @panic("expected return trace");
236 } else switch (builtin.mode) {
237 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
238 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
224239 }
225240 };
226241}
242
243test "break from suspend" {
244 var buf: [500]u8 = undefined;
245 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
246 var my_result: i32 = 1;
247 const p = try async<a> testBreakFromSuspend(&my_result);
248 cancel p;
249 std.debug.assert(my_result == 2);
250}
251async fn testBreakFromSuspend(my_result: *i32) void {
252 suspend {
253 resume @handle();
254 }
255 my_result.* += 1;
256 suspend;
257 my_result.* += 1;
258}
test/cases/defer.zig+38-3
......@@ -5,9 +5,18 @@ var index: usize = undefined;
55
66fn runSomeErrorDefers(x: bool) !bool {
77 index = 0;
8 defer {result[index] = 'a'; index += 1;}
9 errdefer {result[index] = 'b'; index += 1;}
10 defer {result[index] = 'c'; index += 1;}
8 defer {
9 result[index] = 'a';
10 index += 1;
11 }
12 errdefer {
13 result[index] = 'b';
14 index += 1;
15 }
16 defer {
17 result[index] = 'c';
18 index += 1;
19 }
1120 return if (x) x else error.FalseNotAllowed;
1221}
1322
......@@ -41,3 +50,29 @@ fn testBreakContInDefer(x: usize) void {
4150 assert(i == 5);
4251 }
4352}
53
54test "defer and labeled break" {
55 var i = usize(0);
56
57 blk: {
58 defer i += 1;
59 break :blk;
60 }
61
62 assert(i == 1);
63}
64
65test "errdefer does not apply to fn inside fn" {
66 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
67}
68
69fn testNestedFnErrDefer() error!void {
70 var a: i32 = 0;
71 errdefer a += 1;
72 const S = struct {
73 fn baz() error {
74 return error.Bad;
75 }
76 };
77 return S.baz();
78}
test/cases/enum.zig+572-72
......@@ -2,8 +2,13 @@ const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
33
44test "enum type" {
5 const foo1 = Foo{ .One = 13};
6 const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};
5 const foo1 = Foo{ .One = 13 };
6 const foo2 = Foo{
7 .Two = Point{
8 .x = 1234,
9 .y = 5678,
10 },
11 };
712 const bar = Bar.B;
813
914 assert(bar == Bar.B);
......@@ -41,26 +46,25 @@ const Bar = enum {
4146};
4247
4348fn returnAnInt(x: i32) Foo {
44 return Foo { .One = x };
49 return Foo{ .One = x };
4550}
4651
47
4852test "constant enum with payload" {
49 var empty = AnEnumWithPayload {.Empty = {}};
50 var full = AnEnumWithPayload {.Full = 13};
53 var empty = AnEnumWithPayload{ .Empty = {} };
54 var full = AnEnumWithPayload{ .Full = 13 };
5155 shouldBeEmpty(empty);
5256 shouldBeNotEmpty(full);
5357}
5458
55fn shouldBeEmpty(x: &const AnEnumWithPayload) void {
56 switch (*x) {
59fn shouldBeEmpty(x: *const AnEnumWithPayload) void {
60 switch (x.*) {
5761 AnEnumWithPayload.Empty => {},
5862 else => unreachable,
5963 }
6064}
6165
62fn shouldBeNotEmpty(x: &const AnEnumWithPayload) void {
63 switch (*x) {
66fn shouldBeNotEmpty(x: *const AnEnumWithPayload) void {
67 switch (x.*) {
6468 AnEnumWithPayload.Empty => unreachable,
6569 else => {},
6670 }
......@@ -71,8 +75,6 @@ const AnEnumWithPayload = union(enum) {
7175 Full: i32,
7276};
7377
74
75
7678const Number = enum {
7779 Zero,
7880 One,
......@@ -90,15 +92,14 @@ test "enum to int" {
9092}
9193
9294fn shouldEqual(n: Number, expected: u3) void {
93 assert(u3(n) == expected);
95 assert(@enumToInt(n) == expected);
9496}
9597
96
9798test "int to enum" {
9899 testIntToEnumEval(3);
99100}
100101fn testIntToEnumEval(x: i32) void {
101 assert(IntToEnumNumber(u3(x)) == IntToEnumNumber.Three);
102 assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
102103}
103104const IntToEnumNumber = enum {
104105 Zero,
......@@ -108,7 +109,6 @@ const IntToEnumNumber = enum {
108109 Four,
109110};
110111
111
112112test "@tagName" {
113113 assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
114114 comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
......@@ -124,7 +124,6 @@ const BareNumber = enum {
124124 Three,
125125};
126126
127
128127test "enum alignment" {
129128 comptime {
130129 assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
......@@ -137,47 +136,529 @@ const AlignTestEnum = union(enum) {
137136 B: u64,
138137};
139138
140const ValueCount1 = enum { I0 };
141const ValueCount2 = enum { I0, I1 };
139const ValueCount1 = enum {
140 I0,
141};
142const ValueCount2 = enum {
143 I0,
144 I1,
145};
142146const ValueCount256 = enum {
143 I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
144 I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
145 I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
146 I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
147 I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
148 I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
149 I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
150 I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
151 I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
152 I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
153 I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
154 I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
155 I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
156 I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
157 I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
158 I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
159 I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
160 I250, I251, I252, I253, I254, I255
147 I0,
148 I1,
149 I2,
150 I3,
151 I4,
152 I5,
153 I6,
154 I7,
155 I8,
156 I9,
157 I10,
158 I11,
159 I12,
160 I13,
161 I14,
162 I15,
163 I16,
164 I17,
165 I18,
166 I19,
167 I20,
168 I21,
169 I22,
170 I23,
171 I24,
172 I25,
173 I26,
174 I27,
175 I28,
176 I29,
177 I30,
178 I31,
179 I32,
180 I33,
181 I34,
182 I35,
183 I36,
184 I37,
185 I38,
186 I39,
187 I40,
188 I41,
189 I42,
190 I43,
191 I44,
192 I45,
193 I46,
194 I47,
195 I48,
196 I49,
197 I50,
198 I51,
199 I52,
200 I53,
201 I54,
202 I55,
203 I56,
204 I57,
205 I58,
206 I59,
207 I60,
208 I61,
209 I62,
210 I63,
211 I64,
212 I65,
213 I66,
214 I67,
215 I68,
216 I69,
217 I70,
218 I71,
219 I72,
220 I73,
221 I74,
222 I75,
223 I76,
224 I77,
225 I78,
226 I79,
227 I80,
228 I81,
229 I82,
230 I83,
231 I84,
232 I85,
233 I86,
234 I87,
235 I88,
236 I89,
237 I90,
238 I91,
239 I92,
240 I93,
241 I94,
242 I95,
243 I96,
244 I97,
245 I98,
246 I99,
247 I100,
248 I101,
249 I102,
250 I103,
251 I104,
252 I105,
253 I106,
254 I107,
255 I108,
256 I109,
257 I110,
258 I111,
259 I112,
260 I113,
261 I114,
262 I115,
263 I116,
264 I117,
265 I118,
266 I119,
267 I120,
268 I121,
269 I122,
270 I123,
271 I124,
272 I125,
273 I126,
274 I127,
275 I128,
276 I129,
277 I130,
278 I131,
279 I132,
280 I133,
281 I134,
282 I135,
283 I136,
284 I137,
285 I138,
286 I139,
287 I140,
288 I141,
289 I142,
290 I143,
291 I144,
292 I145,
293 I146,
294 I147,
295 I148,
296 I149,
297 I150,
298 I151,
299 I152,
300 I153,
301 I154,
302 I155,
303 I156,
304 I157,
305 I158,
306 I159,
307 I160,
308 I161,
309 I162,
310 I163,
311 I164,
312 I165,
313 I166,
314 I167,
315 I168,
316 I169,
317 I170,
318 I171,
319 I172,
320 I173,
321 I174,
322 I175,
323 I176,
324 I177,
325 I178,
326 I179,
327 I180,
328 I181,
329 I182,
330 I183,
331 I184,
332 I185,
333 I186,
334 I187,
335 I188,
336 I189,
337 I190,
338 I191,
339 I192,
340 I193,
341 I194,
342 I195,
343 I196,
344 I197,
345 I198,
346 I199,
347 I200,
348 I201,
349 I202,
350 I203,
351 I204,
352 I205,
353 I206,
354 I207,
355 I208,
356 I209,
357 I210,
358 I211,
359 I212,
360 I213,
361 I214,
362 I215,
363 I216,
364 I217,
365 I218,
366 I219,
367 I220,
368 I221,
369 I222,
370 I223,
371 I224,
372 I225,
373 I226,
374 I227,
375 I228,
376 I229,
377 I230,
378 I231,
379 I232,
380 I233,
381 I234,
382 I235,
383 I236,
384 I237,
385 I238,
386 I239,
387 I240,
388 I241,
389 I242,
390 I243,
391 I244,
392 I245,
393 I246,
394 I247,
395 I248,
396 I249,
397 I250,
398 I251,
399 I252,
400 I253,
401 I254,
402 I255,
161403};
162404const ValueCount257 = enum {
163 I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,
164 I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,
165 I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,
166 I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,
167 I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,
168 I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,
169 I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,
170 I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,
171 I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,
172 I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,
173 I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,
174 I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,
175 I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,
176 I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,
177 I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,
178 I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,
179 I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,
180 I250, I251, I252, I253, I254, I255, I256
405 I0,
406 I1,
407 I2,
408 I3,
409 I4,
410 I5,
411 I6,
412 I7,
413 I8,
414 I9,
415 I10,
416 I11,
417 I12,
418 I13,
419 I14,
420 I15,
421 I16,
422 I17,
423 I18,
424 I19,
425 I20,
426 I21,
427 I22,
428 I23,
429 I24,
430 I25,
431 I26,
432 I27,
433 I28,
434 I29,
435 I30,
436 I31,
437 I32,
438 I33,
439 I34,
440 I35,
441 I36,
442 I37,
443 I38,
444 I39,
445 I40,
446 I41,
447 I42,
448 I43,
449 I44,
450 I45,
451 I46,
452 I47,
453 I48,
454 I49,
455 I50,
456 I51,
457 I52,
458 I53,
459 I54,
460 I55,
461 I56,
462 I57,
463 I58,
464 I59,
465 I60,
466 I61,
467 I62,
468 I63,
469 I64,
470 I65,
471 I66,
472 I67,
473 I68,
474 I69,
475 I70,
476 I71,
477 I72,
478 I73,
479 I74,
480 I75,
481 I76,
482 I77,
483 I78,
484 I79,
485 I80,
486 I81,
487 I82,
488 I83,
489 I84,
490 I85,
491 I86,
492 I87,
493 I88,
494 I89,
495 I90,
496 I91,
497 I92,
498 I93,
499 I94,
500 I95,
501 I96,
502 I97,
503 I98,
504 I99,
505 I100,
506 I101,
507 I102,
508 I103,
509 I104,
510 I105,
511 I106,
512 I107,
513 I108,
514 I109,
515 I110,
516 I111,
517 I112,
518 I113,
519 I114,
520 I115,
521 I116,
522 I117,
523 I118,
524 I119,
525 I120,
526 I121,
527 I122,
528 I123,
529 I124,
530 I125,
531 I126,
532 I127,
533 I128,
534 I129,
535 I130,
536 I131,
537 I132,
538 I133,
539 I134,
540 I135,
541 I136,
542 I137,
543 I138,
544 I139,
545 I140,
546 I141,
547 I142,
548 I143,
549 I144,
550 I145,
551 I146,
552 I147,
553 I148,
554 I149,
555 I150,
556 I151,
557 I152,
558 I153,
559 I154,
560 I155,
561 I156,
562 I157,
563 I158,
564 I159,
565 I160,
566 I161,
567 I162,
568 I163,
569 I164,
570 I165,
571 I166,
572 I167,
573 I168,
574 I169,
575 I170,
576 I171,
577 I172,
578 I173,
579 I174,
580 I175,
581 I176,
582 I177,
583 I178,
584 I179,
585 I180,
586 I181,
587 I182,
588 I183,
589 I184,
590 I185,
591 I186,
592 I187,
593 I188,
594 I189,
595 I190,
596 I191,
597 I192,
598 I193,
599 I194,
600 I195,
601 I196,
602 I197,
603 I198,
604 I199,
605 I200,
606 I201,
607 I202,
608 I203,
609 I204,
610 I205,
611 I206,
612 I207,
613 I208,
614 I209,
615 I210,
616 I211,
617 I212,
618 I213,
619 I214,
620 I215,
621 I216,
622 I217,
623 I218,
624 I219,
625 I220,
626 I221,
627 I222,
628 I223,
629 I224,
630 I225,
631 I226,
632 I227,
633 I228,
634 I229,
635 I230,
636 I231,
637 I232,
638 I233,
639 I234,
640 I235,
641 I236,
642 I237,
643 I238,
644 I239,
645 I240,
646 I241,
647 I242,
648 I243,
649 I244,
650 I245,
651 I246,
652 I247,
653 I248,
654 I249,
655 I250,
656 I251,
657 I252,
658 I253,
659 I254,
660 I255,
661 I256,
181662};
182663
183664test "enum sizes" {
......@@ -189,11 +670,11 @@ test "enum sizes" {
189670 }
190671}
191672
192const Small2 = enum (u2) {
673const Small2 = enum(u2) {
193674 One,
194675 Two,
195676};
196const Small = enum (u2) {
677const Small = enum(u2) {
197678 One,
198679 Two,
199680 Three,
......@@ -213,8 +694,7 @@ test "set enum tag type" {
213694 }
214695}
215696
216
217const A = enum (u3) {
697const A = enum(u3) {
218698 One,
219699 Two,
220700 Three,
......@@ -225,7 +705,7 @@ const A = enum (u3) {
225705 Four2,
226706};
227707
228const B = enum (u3) {
708const B = enum(u3) {
229709 One3,
230710 Two3,
231711 Three3,
......@@ -236,7 +716,7 @@ const B = enum (u3) {
236716 Four23,
237717};
238718
239const C = enum (u2) {
719const C = enum(u2) {
240720 One4,
241721 Two4,
242722 Three4,
......@@ -249,7 +729,7 @@ const BitFieldOfEnums = packed struct {
249729 c: C,
250730};
251731
252const bit_field_1 = BitFieldOfEnums {
732const bit_field_1 = BitFieldOfEnums{
253733 .a = A.Two,
254734 .b = B.Three3,
255735 .c = C.Four4,
......@@ -270,15 +750,15 @@ test "bit field access with enum fields" {
270750 assert(data.b == B.Four3);
271751}
272752
273fn getA(data: &const BitFieldOfEnums) A {
753fn getA(data: *const BitFieldOfEnums) A {
274754 return data.a;
275755}
276756
277fn getB(data: &const BitFieldOfEnums) B {
757fn getB(data: *const BitFieldOfEnums) B {
278758 return data.b;
279759}
280760
281fn getC(data: &const BitFieldOfEnums) C {
761fn getC(data: *const BitFieldOfEnums) C {
282762 return data.c;
283763}
284764
......@@ -288,7 +768,7 @@ test "casting enum to its tag type" {
288768}
289769
290770fn testCastEnumToTagType(value: Small2) void {
291 assert(u2(value) == 1);
771 assert(@enumToInt(value) == 1);
292772}
293773
294774const MultipleChoice = enum(u32) {
......@@ -304,7 +784,7 @@ test "enum with specified tag values" {
304784}
305785
306786fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
307 assert(u32(x) == 60);
787 assert(@enumToInt(x) == 60);
308788 assert(1234 == switch (x) {
309789 MultipleChoice.A => 1,
310790 MultipleChoice.B => 2,
......@@ -331,7 +811,7 @@ test "enum with specified and unspecified tag values" {
331811}
332812
333813fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
334 assert(u32(x) == 1000);
814 assert(@enumToInt(x) == 1000);
335815 assert(1234 == switch (x) {
336816 MultipleChoice2.A => 1,
337817 MultipleChoice2.B => 2,
......@@ -346,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
346826}
347827
348828test "cast integer literal to enum" {
349 assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1);
350 assert(MultipleChoice2(40) == MultipleChoice2.B);
829 assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
830 assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
351831}
352832
353833const EnumWithOneMember = enum {
......@@ -385,10 +865,30 @@ const EnumWithTagValues = enum(u4) {
385865 D = 1 << 3,
386866};
387867test "enum with tag values don't require parens" {
388 assert(u4(EnumWithTagValues.C) == 0b0100);
868 assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
389869}
390870
391871test "enum with 1 field but explicit tag type should still have the tag type" {
392 const Enum = enum(u8) { B = 2 };
872 const Enum = enum(u8) {
873 B = 2,
874 };
393875 comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
394876}
877
878test "empty extern enum with members" {
879 const E = extern enum {
880 A,
881 B,
882 C,
883 };
884 assert(@sizeOf(E) == @sizeOf(c_int));
885}
886
887test "aoeu" {
888 const LocalFoo = enum {
889 A = 1,
890 B = 0,
891 };
892 var b = LocalFoo.B;
893 assert(mem.eql(u8, @tagName(b), "B"));
894}
test/cases/enum_with_members.zig+4-4
......@@ -6,8 +6,8 @@ const ET = union(enum) {
66 SINT: i32,
77 UINT: u32,
88
9 pub fn print(a: &const ET, buf: []u8) error!usize {
10 return switch (*a) {
9 pub fn print(a: *const ET, buf: []u8) error!usize {
10 return switch (a.*) {
1111 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
1212 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
1313 };
......@@ -15,8 +15,8 @@ const ET = union(enum) {
1515};
1616
1717test "enum with members" {
18 const a = ET { .SINT = -42 };
19 const b = ET { .UINT = 42 };
18 const a = ET{ .SINT = -42 };
19 const b = ET{ .UINT = 42 };
2020 var buf: [20]u8 = undefined;
2121
2222 assert((a.print(buf[0..]) catch unreachable) == 3);
test/cases/error.zig+90-22
......@@ -30,14 +30,12 @@ test "@errorName" {
3030 assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
3131}
3232
33
3433test "error values" {
35 const a = i32(error.err1);
36 const b = i32(error.err2);
34 const a = @errorToInt(error.err1);
35 const b = @errorToInt(error.err2);
3736 assert(a != b);
3837}
3938
40
4139test "redefinition of error values allowed" {
4240 shouldBeNotEqual(error.AnError, error.SecondError);
4341}
......@@ -45,7 +43,6 @@ fn shouldBeNotEqual(a: error, b: error) void {
4543 if (a == b) unreachable;
4644}
4745
48
4946test "error binary operator" {
5047 const a = errBinaryOperatorG(true) catch 3;
5148 const b = errBinaryOperatorG(false) catch 3;
......@@ -56,20 +53,20 @@ fn errBinaryOperatorG(x: bool) error!isize {
5653 return if (x) error.ItBroke else isize(10);
5754}
5855
59
6056test "unwrap simple value from error" {
6157 const i = unwrapSimpleValueFromErrorDo() catch unreachable;
6258 assert(i == 13);
6359}
64fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }
65
60fn unwrapSimpleValueFromErrorDo() error!isize {
61 return 13;
62}
6663
6764test "error return in assignment" {
6865 doErrReturnInAssignment() catch unreachable;
6966}
7067
7168fn doErrReturnInAssignment() error!void {
72 var x : i32 = undefined;
69 var x: i32 = undefined;
7370 x = try makeANonErr();
7471}
7572
......@@ -95,7 +92,10 @@ test "error set type " {
9592 comptime testErrorSetType();
9693}
9794
98const MyErrSet = error {OutOfMemory, FileNotFound};
95const MyErrSet = error{
96 OutOfMemory,
97 FileNotFound,
98};
9999
100100fn testErrorSetType() void {
101101 assert(@memberCount(MyErrSet) == 2);
......@@ -109,18 +109,23 @@ fn testErrorSetType() void {
109109 }
110110}
111111
112
113112test "explicit error set cast" {
114113 testExplicitErrorSetCast(Set1.A);
115114 comptime testExplicitErrorSetCast(Set1.A);
116115}
117116
118const Set1 = error{A, B};
119const Set2 = error{A, C};
117const Set1 = error{
118 A,
119 B,
120};
121const Set2 = error{
122 A,
123 C,
124};
120125
121126fn testExplicitErrorSetCast(set1: Set1) void {
122 var x = Set2(set1);
123 var y = Set1(x);
127 var x = @errSetCast(Set2, set1);
128 var y = @errSetCast(Set1, x);
124129 assert(y == error.A);
125130}
126131
......@@ -129,24 +134,27 @@ test "comptime test error for empty error set" {
129134 comptime testComptimeTestErrorEmptySet(1234);
130135}
131136
132const EmptyErrorSet = error {};
137const EmptyErrorSet = error{};
133138
134139fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
135140 if (x) |v| assert(v == 1234) else |err| @compileError("bad");
136141}
137142
138test "syntax: nullable operator in front of error union operator" {
143test "syntax: optional operator in front of error union operator" {
139144 comptime {
140145 assert(?error!i32 == ?(error!i32));
141146 }
142147}
143148
144149test "comptime err to int of error set with only 1 possible value" {
145 testErrToIntWithOnePossibleValue(error.A, u32(error.A));
146 comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
147}
148fn testErrToIntWithOnePossibleValue(x: error{A}, comptime value: u32) void {
149 if (u32(x) != value) {
150 testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
151 comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
152}
153fn testErrToIntWithOnePossibleValue(
154 x: error{A},
155 comptime value: u32,
156) void {
157 if (@errorToInt(x) != value) {
150158 @compileError("bad");
151159 }
152160}
......@@ -175,3 +183,63 @@ fn baz_1() !i32 {
175183fn quux_1() !i32 {
176184 return error.C;
177185}
186
187test "error: fn returning empty error set can be passed as fn returning any error" {
188 entry();
189 comptime entry();
190}
191
192fn entry() void {
193 foo2(bar2);
194}
195
196fn foo2(f: fn () error!void) void {
197 const x = f();
198}
199
200fn bar2() (error{}!void) {}
201
202test "error: Zero sized error set returned with value payload crash" {
203 _ = foo3(0);
204 _ = comptime foo3(0);
205}
206
207const Error = error{};
208fn foo3(b: usize) Error!usize {
209 return b;
210}
211
212test "error: Infer error set from literals" {
213 _ = nullLiteral("n") catch |err| handleErrors(err);
214 _ = floatLiteral("n") catch |err| handleErrors(err);
215 _ = intLiteral("n") catch |err| handleErrors(err);
216 _ = comptime nullLiteral("n") catch |err| handleErrors(err);
217 _ = comptime floatLiteral("n") catch |err| handleErrors(err);
218 _ = comptime intLiteral("n") catch |err| handleErrors(err);
219}
220
221fn handleErrors(err: var) noreturn {
222 switch (err) {
223 error.T => {},
224 }
225
226 unreachable;
227}
228
229fn nullLiteral(str: []const u8) !?i64 {
230 if (str[0] == 'n') return null;
231
232 return error.T;
233}
234
235fn floatLiteral(str: []const u8) !?f64 {
236 if (str[0] == 'n') return 1.0;
237
238 return error.T;
239}
240
241fn intLiteral(str: []const u8) !?i64 {
242 if (str[0] == 'n') return 1;
243
244 return error.T;
245}
test/cases/eval.zig+209-70
......@@ -5,16 +5,14 @@ const builtin = @import("builtin");
55test "compile time recursion" {
66 assert(some_data.len == 21);
77}
8var some_data: [usize(fibonacci(7))]u8 = undefined;
8var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
99fn fibonacci(x: i32) i32 {
1010 if (x <= 1) return 1;
1111 return fibonacci(x - 1) + fibonacci(x - 2);
1212}
1313
14
15
1614fn unwrapAndAddOne(blah: ?i32) i32 {
17 return ??blah + 1;
15 return blah.? + 1;
1816}
1917const should_be_1235 = unwrapAndAddOne(1234);
2018test "static add one" {
......@@ -40,13 +38,13 @@ test "inline variable gets result of const if" {
4038 assert(gimme1or2(false) == 2);
4139}
4240
43
4441test "static function evaluation" {
4542 assert(statically_added_number == 3);
4643}
4744const statically_added_number = staticAdd(1, 2);
48fn staticAdd(a: i32, b: i32) i32 { return a + b; }
49
45fn staticAdd(a: i32, b: i32) i32 {
46 return a + b;
47}
5048
5149test "const expr eval on single expr blocks" {
5250 assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
......@@ -64,9 +62,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
6462 return result;
6563}
6664
67
68
69
7065test "statically initialized list" {
7166 assert(static_point_list[0].x == 1);
7267 assert(static_point_list[0].y == 2);
......@@ -77,15 +72,17 @@ const Point = struct {
7772 x: i32,
7873 y: i32,
7974};
80const static_point_list = []Point { makePoint(1, 2), makePoint(3, 4) };
75const static_point_list = []Point{
76 makePoint(1, 2),
77 makePoint(3, 4),
78};
8179fn makePoint(x: i32, y: i32) Point {
82 return Point {
80 return Point{
8381 .x = x,
8482 .y = y,
8583 };
8684}
8785
88
8986test "static eval list init" {
9087 assert(static_vec3.data[2] == 1.0);
9188 assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
......@@ -95,18 +92,18 @@ pub const Vec3 = struct {
9592 data: [3]f32,
9693};
9794pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
98 return Vec3 {
99 .data = []f32 { x, y, z, },
100 };
95 return Vec3{ .data = []f32{
96 x,
97 y,
98 z,
99 } };
101100}
102101
103
104102test "constant expressions" {
105 var array : [array_size]u8 = undefined;
103 var array: [array_size]u8 = undefined;
106104 assert(@sizeOf(@typeOf(array)) == 20);
107105}
108const array_size : u8 = 20;
109
106const array_size: u8 = 20;
110107
111108test "constant struct with negation" {
112109 assert(vertices[0].x == -0.6);
......@@ -118,13 +115,30 @@ const Vertex = struct {
118115 g: f32,
119116 b: f32,
120117};
121const vertices = []Vertex {
122 Vertex { .x = -0.6, .y = -0.4, .r = 1.0, .g = 0.0, .b = 0.0 },
123 Vertex { .x = 0.6, .y = -0.4, .r = 0.0, .g = 1.0, .b = 0.0 },
124 Vertex { .x = 0.0, .y = 0.6, .r = 0.0, .g = 0.0, .b = 1.0 },
118const vertices = []Vertex{
119 Vertex{
120 .x = -0.6,
121 .y = -0.4,
122 .r = 1.0,
123 .g = 0.0,
124 .b = 0.0,
125 },
126 Vertex{
127 .x = 0.6,
128 .y = -0.4,
129 .r = 0.0,
130 .g = 1.0,
131 .b = 0.0,
132 },
133 Vertex{
134 .x = 0.0,
135 .y = 0.6,
136 .r = 0.0,
137 .g = 0.0,
138 .b = 1.0,
139 },
125140};
126141
127
128142test "statically initialized struct" {
129143 st_init_str_foo.x += 1;
130144 assert(st_init_str_foo.x == 14);
......@@ -133,15 +147,21 @@ const StInitStrFoo = struct {
133147 x: i32,
134148 y: bool,
135149};
136var st_init_str_foo = StInitStrFoo { .x = 13, .y = true, };
137
150var st_init_str_foo = StInitStrFoo{
151 .x = 13,
152 .y = true,
153};
138154
139155test "statically initalized array literal" {
140 const y : [4]u8 = st_init_arr_lit_x;
156 const y: [4]u8 = st_init_arr_lit_x;
141157 assert(y[3] == 4);
142158}
143const st_init_arr_lit_x = []u8{1,2,3,4};
144
159const st_init_arr_lit_x = []u8{
160 1,
161 2,
162 3,
163 4,
164};
145165
146166test "const slice" {
147167 comptime {
......@@ -195,17 +215,32 @@ test "inlined block and runtime block phi" {
195215
196216const CmdFn = struct {
197217 name: []const u8,
198 func: fn(i32) i32,
218 func: fn (i32) i32,
199219};
200220
201221const cmd_fns = []CmdFn{
202 CmdFn {.name = "one", .func = one},
203 CmdFn {.name = "two", .func = two},
204 CmdFn {.name = "three", .func = three},
222 CmdFn{
223 .name = "one",
224 .func = one,
225 },
226 CmdFn{
227 .name = "two",
228 .func = two,
229 },
230 CmdFn{
231 .name = "three",
232 .func = three,
233 },
205234};
206fn one(value: i32) i32 { return value + 1; }
207fn two(value: i32) i32 { return value + 2; }
208fn three(value: i32) i32 { return value + 3; }
235fn one(value: i32) i32 {
236 return value + 1;
237}
238fn two(value: i32) i32 {
239 return value + 2;
240}
241fn three(value: i32) i32 {
242 return value + 3;
243}
209244
210245fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
211246 var result: i32 = start_value;
......@@ -229,7 +264,7 @@ test "eval @setRuntimeSafety at compile-time" {
229264 assert(result == 1234);
230265}
231266
232fn fnWithSetRuntimeSafety() i32{
267fn fnWithSetRuntimeSafety() i32 {
233268 @setRuntimeSafety(true);
234269 return 1234;
235270}
......@@ -244,16 +279,15 @@ fn fnWithFloatMode() f32 {
244279 return 1234.0;
245280}
246281
247
248282const SimpleStruct = struct {
249283 field: i32,
250284
251 fn method(self: &const SimpleStruct) i32 {
285 fn method(self: *const SimpleStruct) i32 {
252286 return self.field + 3;
253287 }
254288};
255289
256var simple_struct = SimpleStruct{ .field = 1234, };
290var simple_struct = SimpleStruct{ .field = 1234 };
257291
258292const bound_fn = simple_struct.method;
259293
......@@ -261,8 +295,6 @@ test "call method on bound fn referring to var instance" {
261295 assert(bound_fn() == 1237);
262296}
263297
264
265
266298test "ptr to local array argument at comptime" {
267299 comptime {
268300 var bytes: [10]u8 = undefined;
......@@ -277,7 +309,6 @@ fn modifySomeBytes(bytes: []u8) void {
277309 bytes[9] = 'b';
278310}
279311
280
281312test "comparisons 0 <= uint and 0 > uint should be comptime" {
282313 testCompTimeUIntComparisons(1234);
283314}
......@@ -296,8 +327,6 @@ fn testCompTimeUIntComparisons(x: u32) void {
296327 }
297328}
298329
299
300
301330test "const ptr to variable data changes at runtime" {
302331 assert(foo_ref.name[0] == 'a');
303332 foo_ref.name = "b";
......@@ -308,11 +337,9 @@ const Foo = struct {
308337 name: []const u8,
309338};
310339
311var foo_contents = Foo { .name = "a", };
340var foo_contents = Foo{ .name = "a" };
312341const foo_ref = &foo_contents;
313342
314
315
316343test "create global array with for loop" {
317344 assert(global_array[5] == 5 * 5);
318345 assert(global_array[9] == 9 * 9);
......@@ -321,7 +348,7 @@ test "create global array with for loop" {
321348const global_array = x: {
322349 var result: [10]usize = undefined;
323350 for (result) |*item, index| {
324 *item = index * index;
351 item.* = index * index;
325352 }
326353 break :x result;
327354};
......@@ -329,7 +356,7 @@ const global_array = x: {
329356test "compile-time downcast when the bits fit" {
330357 comptime {
331358 const spartan_count: u16 = 255;
332 const byte = u8(spartan_count);
359 const byte = @intCast(u8, spartan_count);
333360 assert(byte == 255);
334361 }
335362}
......@@ -340,7 +367,7 @@ test "const global shares pointer with other same one" {
340367 assertEqualPtrs(&hi1[0], &hi2[0]);
341368 comptime assert(&hi1[0] == &hi2[0]);
342369}
343fn assertEqualPtrs(ptr1: &const u8, ptr2: &const u8) void {
370fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void {
344371 assert(ptr1 == ptr2);
345372}
346373
......@@ -379,7 +406,7 @@ test "f128 at compile time is lossy" {
379406
380407pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
381408 return struct {
382 pub const Node = struct { };
409 pub const Node = struct {};
383410 };
384411}
385412
......@@ -391,9 +418,9 @@ test "string literal used as comptime slice is memoized" {
391418}
392419
393420test "comptime slice of undefined pointer of length 0" {
394 const slice1 = (&i32)(undefined)[0..0];
421 const slice1 = ([*]i32)(undefined)[0..0];
395422 assert(slice1.len == 0);
396 const slice2 = (&i32)(undefined)[100..100];
423 const slice2 = ([*]i32)(undefined)[100..100];
397424 assert(slice2.len == 0);
398425}
399426
......@@ -401,10 +428,10 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
401428 comptime var i: usize = 0;
402429 inline while (i < 4) : (i += 1) {
403430 s[i] = 0;
404 s[i] |= u32(b[i*4+0]) << 24;
405 s[i] |= u32(b[i*4+1]) << 16;
406 s[i] |= u32(b[i*4+2]) << 8;
407 s[i] |= u32(b[i*4+3]) << 0;
431 s[i] |= u32(b[i * 4 + 0]) << 24;
432 s[i] |= u32(b[i * 4 + 1]) << 16;
433 s[i] |= u32(b[i * 4 + 2]) << 8;
434 s[i] |= u32(b[i * 4 + 3]) << 0;
408435 }
409436}
410437
......@@ -413,7 +440,7 @@ test "binary math operator in partially inlined function" {
413440 var b: [16]u8 = undefined;
414441
415442 for (b) |*r, i|
416 *r = u8(i + 1);
443 r.* = @intCast(u8, i + 1);
417444
418445 copyWithPartialInline(s[0..], b[0..]);
419446 assert(s[0] == 0x1020304);
......@@ -422,7 +449,6 @@ test "binary math operator in partially inlined function" {
422449 assert(s[3] == 0xd0e0f10);
423450}
424451
425
426452test "comptime function with the same args is memoized" {
427453 comptime {
428454 assert(MakeType(i32) == MakeType(i32));
......@@ -446,15 +472,15 @@ test "comptime function with mutable pointer is not memoized" {
446472 }
447473}
448474
449fn increment(value: &i32) void {
450 *value += 1;
475fn increment(value: *i32) void {
476 value.* += 1;
451477}
452478
453479fn generateTable(comptime T: type) [1010]T {
454 var res : [1010]T = undefined;
455 var i : usize = 0;
480 var res: [1010]T = undefined;
481 var i: usize = 0;
456482 while (i < 1010) : (i += 1) {
457 res[i] = T(i);
483 res[i] = @intCast(T, i);
458484 }
459485 return res;
460486}
......@@ -482,7 +508,7 @@ test "comptime slice of slice preserves comptime var" {
482508test "comptime slice of pointer preserves comptime var" {
483509 comptime {
484510 var buff: [10]u8 = undefined;
485 var a = &buff[0];
511 var a = buff[0..].ptr;
486512 a[0..1][0] = 1;
487513 assert(buff[0..][0..][0] == 1);
488514 }
......@@ -491,14 +517,13 @@ test "comptime slice of pointer preserves comptime var" {
491517const SingleFieldStruct = struct {
492518 x: i32,
493519
494 fn read_x(self: &const SingleFieldStruct) i32 {
520 fn read_x(self: *const SingleFieldStruct) i32 {
495521 return self.x;
496522 }
497523};
498524test "const ptr to comptime mutable data is not memoized" {
499
500525 comptime {
501 var foo = SingleFieldStruct {.x = 1};
526 var foo = SingleFieldStruct{ .x = 1 };
502527 assert(foo.read_x() == 1);
503528 foo.x = 2;
504529 assert(foo.read_x() == 2);
......@@ -513,3 +538,117 @@ test "array concat of slices gives slice" {
513538 assert(std.mem.eql(u8, c, "aoeuasdf"));
514539 }
515540}
541
542test "comptime shlWithOverflow" {
543 const ct_shifted: u64 = comptime amt: {
544 var amt = u64(0);
545 _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
546 break :amt amt;
547 };
548
549 const rt_shifted: u64 = amt: {
550 var amt = u64(0);
551 _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
552 break :amt amt;
553 };
554
555 assert(ct_shifted == rt_shifted);
556}
557
558test "runtime 128 bit integer division" {
559 var a: u128 = 152313999999999991610955792383;
560 var b: u128 = 10000000000000000000;
561 var c = a / b;
562 assert(c == 15231399999);
563}
564
565pub const Info = struct {
566 version: u8,
567};
568
569pub const diamond_info = Info{ .version = 0 };
570
571test "comptime modification of const struct field" {
572 comptime {
573 var res = diamond_info;
574 res.version = 1;
575 assert(diamond_info.version == 0);
576 assert(res.version == 1);
577 }
578}
579
580test "pointer to type" {
581 comptime {
582 var T: type = i32;
583 assert(T == i32);
584 var ptr = &T;
585 assert(@typeOf(ptr) == *type);
586 ptr.* = f32;
587 assert(T == f32);
588 assert(*T == *f32);
589 }
590}
591
592test "slice of type" {
593 comptime {
594 var types_array = []type{ i32, f64, type };
595 for (types_array) |T, i| {
596 switch (i) {
597 0 => assert(T == i32),
598 1 => assert(T == f64),
599 2 => assert(T == type),
600 else => unreachable,
601 }
602 }
603 for (types_array[0..]) |T, i| {
604 switch (i) {
605 0 => assert(T == i32),
606 1 => assert(T == f64),
607 2 => assert(T == type),
608 else => unreachable,
609 }
610 }
611 }
612}
613
614const Wrapper = struct {
615 T: type,
616};
617
618fn wrap(comptime T: type) Wrapper {
619 return Wrapper{ .T = T };
620}
621
622test "function which returns struct with type field causes implicit comptime" {
623 const ty = wrap(i32).T;
624 assert(ty == i32);
625}
626
627test "call method with comptime pass-by-non-copying-value self parameter" {
628 const S = struct {
629 a: u8,
630
631 fn b(comptime s: this) u8 {
632 return s.a;
633 }
634 };
635
636 const s = S{ .a = 2 };
637 var b = s.b();
638 assert(b == 2);
639}
640
641test "@tagName of @typeId" {
642 const str = @tagName(@typeId(u8));
643 assert(std.mem.eql(u8, str, "Int"));
644}
645
646test "setting backward branch quota just before a generic fn call" {
647 @setEvalBranchQuota(1001);
648 loopNTimes(1001);
649}
650
651fn loopNTimes(comptime n: usize) void {
652 comptime var i = 0;
653 inline while (i < n) : (i += 1) {}
654}
test/cases/field_parent_ptr.zig+3-3
......@@ -17,14 +17,14 @@ const Foo = struct {
1717 d: i32,
1818};
1919
20const foo = Foo {
20const foo = Foo{
2121 .a = true,
2222 .b = 0.123,
2323 .c = 1234,
2424 .d = -10,
2525};
2626
27fn testParentFieldPtr(c: &const i32) void {
27fn testParentFieldPtr(c: *const i32) void {
2828 assert(c == &foo.c);
2929
3030 const base = @fieldParentPtr(Foo, "c", c);
......@@ -32,7 +32,7 @@ fn testParentFieldPtr(c: &const i32) void {
3232 assert(&base.c == c);
3333}
3434
35fn testParentFieldPtrFirst(a: &const bool) void {
35fn testParentFieldPtrFirst(a: *const bool) void {
3636 assert(a == &foo.a);
3737
3838 const base = @fieldParentPtr(Foo, "a", a);
test/cases/fn.zig+84-19
......@@ -7,7 +7,6 @@ fn testParamsAdd(a: i32, b: i32) i32 {
77 return a + b;
88}
99
10
1110test "local variables" {
1211 testLocVars(2);
1312}
......@@ -16,7 +15,6 @@ fn testLocVars(b: i32) void {
1615 if (a + b != 3) unreachable;
1716}
1817
19
2018test "void parameters" {
2119 voidFun(1, void{}, 2, {});
2220}
......@@ -27,9 +25,8 @@ fn voidFun(a: i32, b: void, c: i32, d: void) void {
2725 return vv;
2826}
2927
30
3128test "mutable local variables" {
32 var zero : i32 = 0;
29 var zero: i32 = 0;
3330 assert(zero == 0);
3431
3532 var i = i32(0);
......@@ -41,7 +38,7 @@ test "mutable local variables" {
4138
4239test "separate block scopes" {
4340 {
44 const no_conflict : i32 = 5;
41 const no_conflict: i32 = 5;
4542 assert(no_conflict == 5);
4643 }
4744
......@@ -56,8 +53,7 @@ test "call function with empty string" {
5653 acceptsString("");
5754}
5855
59fn acceptsString(foo: []u8) void { }
60
56fn acceptsString(foo: []u8) void {}
6157
6258fn @"weird function name"() i32 {
6359 return 1234;
......@@ -70,31 +66,43 @@ test "implicit cast function unreachable return" {
7066 wantsFnWithVoid(fnWithUnreachable);
7167}
7268
73fn wantsFnWithVoid(f: fn() void) void { }
69fn wantsFnWithVoid(f: fn () void) void {}
7470
7571fn fnWithUnreachable() noreturn {
7672 unreachable;
7773}
7874
79
8075test "function pointers" {
81 const fns = []@typeOf(fn1) { fn1, fn2, fn3, fn4, };
76 const fns = []@typeOf(fn1){
77 fn1,
78 fn2,
79 fn3,
80 fn4,
81 };
8282 for (fns) |f, i| {
83 assert(f() == u32(i) + 5);
83 assert(f() == @intCast(u32, i) + 5);
8484 }
8585}
86fn fn1() u32 {return 5;}
87fn fn2() u32 {return 6;}
88fn fn3() u32 {return 7;}
89fn fn4() u32 {return 8;}
90
86fn fn1() u32 {
87 return 5;
88}
89fn fn2() u32 {
90 return 6;
91}
92fn fn3() u32 {
93 return 7;
94}
95fn fn4() u32 {
96 return 8;
97}
9198
9299test "inline function call" {
93100 assert(@inlineCall(add, 3, 9) == 12);
94101}
95102
96fn add(a: i32, b: i32) i32 { return a + b; }
97
103fn add(a: i32, b: i32) i32 {
104 return a + b;
105}
98106
99107test "number literal as an argument" {
100108 numberLiteralArg(3);
......@@ -110,4 +118,61 @@ test "assign inline fn to const variable" {
110118 a();
111119}
112120
113inline fn inlineFn() void { }
121inline fn inlineFn() void {}
122
123test "pass by non-copying value" {
124 assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
125}
126
127const Point = struct {
128 x: i32,
129 y: i32,
130};
131
132fn addPointCoords(pt: Point) i32 {
133 return pt.x + pt.y;
134}
135
136test "pass by non-copying value through var arg" {
137 assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
138}
139
140fn addPointCoordsVar(pt: var) i32 {
141 comptime assert(@typeOf(pt) == Point);
142 return pt.x + pt.y;
143}
144
145test "pass by non-copying value as method" {
146 var pt = Point2{ .x = 1, .y = 2 };
147 assert(pt.addPointCoords() == 3);
148}
149
150const Point2 = struct {
151 x: i32,
152 y: i32,
153
154 fn addPointCoords(self: Point2) i32 {
155 return self.x + self.y;
156 }
157};
158
159test "pass by non-copying value as method, which is generic" {
160 var pt = Point3{ .x = 1, .y = 2 };
161 assert(pt.addPointCoords(i32) == 3);
162}
163
164const Point3 = struct {
165 x: i32,
166 y: i32,
167
168 fn addPointCoords(self: Point3, comptime T: type) i32 {
169 return self.x + self.y;
170 }
171};
172
173test "pass by non-copying value as method, at comptime" {
174 comptime {
175 var pt = Point2{ .x = 1, .y = 2 };
176 assert(pt.addPointCoords() == 3);
177 }
178}
test/cases/fn_in_struct_in_comptime.zig created+17
......@@ -0,0 +1,17 @@
1const assert = @import("std").debug.assert;
2
3fn get_foo() fn (*u8) usize {
4 comptime {
5 return struct {
6 fn func(ptr: *u8) usize {
7 var u = @ptrToInt(ptr);
8 return u;
9 }
10 }.func;
11 }
12}
13
14test "define a function in an anonymous struct in comptime" {
15 const foo = get_foo();
16 assert(foo(@intToPtr(*u8, 12345)) == 12345);
17}
test/cases/for.zig+17-9
......@@ -3,8 +3,14 @@ const assert = std.debug.assert;
33const mem = std.mem;
44
55test "continue in for loop" {
6 const array = []i32 {1, 2, 3, 4, 5};
7 var sum : i32 = 0;
6 const array = []i32{
7 1,
8 2,
9 3,
10 4,
11 5,
12 };
13 var sum: i32 = 0;
814 for (array) |x| {
915 sum += x;
1016 if (x < 3) {
......@@ -24,23 +30,23 @@ test "for loop with pointer elem var" {
2430}
2531fn mangleString(s: []u8) void {
2632 for (s) |*c| {
27 *c += 1;
33 c.* += 1;
2834 }
2935}
3036
3137test "basic for loop" {
32 const expected_result = []u8{9, 8, 7, 6, 0, 1, 2, 3, 9, 8, 7, 6, 0, 1, 2, 3 };
38 const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3, 9, 8, 7, 6, 0, 1, 2, 3 };
3339
3440 var buffer: [expected_result.len]u8 = undefined;
3541 var buf_index: usize = 0;
3642
37 const array = []u8 {9, 8, 7, 6};
43 const array = []u8{ 9, 8, 7, 6 };
3844 for (array) |item| {
3945 buffer[buf_index] = item;
4046 buf_index += 1;
4147 }
4248 for (array) |item, index| {
43 buffer[buf_index] = u8(index);
49 buffer[buf_index] = @intCast(u8, index);
4450 buf_index += 1;
4551 }
4652 const unknown_size: []const u8 = array;
......@@ -49,7 +55,7 @@ test "basic for loop" {
4955 buf_index += 1;
5056 }
5157 for (unknown_size) |item, index| {
52 buffer[buf_index] = u8(index);
58 buffer[buf_index] = @intCast(u8, index);
5359 buf_index += 1;
5460 }
5561
......@@ -65,7 +71,8 @@ fn testBreakOuter() void {
6571 var array = "aoeu";
6672 var count: usize = 0;
6773 outer: for (array) |_| {
68 for (array) |_2| { // TODO shouldn't get error for redeclaring "_"
74 // TODO shouldn't get error for redeclaring "_"
75 for (array) |_2| {
6976 count += 1;
7077 break :outer;
7178 }
......@@ -82,7 +89,8 @@ fn testContinueOuter() void {
8289 var array = "aoeu";
8390 var counter: usize = 0;
8491 outer: for (array) |_| {
85 for (array) |_2| { // TODO shouldn't get error for redeclaring "_"
92 // TODO shouldn't get error for redeclaring "_"
93 for (array) |_2| {
8694 counter += 1;
8795 continue :outer;
8896 }
test/cases/generics.zig+31-17
......@@ -37,7 +37,6 @@ test "fn with comptime args" {
3737 assert(sameButWithFloats(0.43, 0.49) == 0.49);
3838}
3939
40
4140test "var params" {
4241 assert(max_i32(12, 34) == 34);
4342 assert(max_f64(1.2, 3.4) == 3.4);
......@@ -60,7 +59,6 @@ fn max_f64(a: f64, b: f64) f64 {
6059 return max_var(a, b);
6160}
6261
63
6462pub fn List(comptime T: type) type {
6563 return SmallList(T, 8);
6664}
......@@ -82,10 +80,15 @@ test "function with return type type" {
8280 assert(list2.prealloc_items.len == 8);
8381}
8482
85
8683test "generic struct" {
87 var a1 = GenNode(i32) {.value = 13, .next = null,};
88 var b1 = GenNode(bool) {.value = true, .next = null,};
84 var a1 = GenNode(i32){
85 .value = 13,
86 .next = null,
87 };
88 var b1 = GenNode(bool){
89 .value = true,
90 .next = null,
91 };
8992 assert(a1.value == 13);
9093 assert(a1.value == a1.getVal());
9194 assert(b1.getVal());
......@@ -93,8 +96,10 @@ test "generic struct" {
9396fn GenNode(comptime T: type) type {
9497 return struct {
9598 value: T,
96 next: ?&GenNode(T),
97 fn getVal(n: &const GenNode(T)) T { return n.value; }
99 next: ?*GenNode(T),
100 fn getVal(n: *const GenNode(T)) T {
101 return n.value;
102 }
98103 };
99104}
100105
......@@ -107,7 +112,6 @@ fn GenericDataThing(comptime count: isize) type {
107112 };
108113}
109114
110
111115test "use generic param in generic param" {
112116 assert(aGenericFn(i32, 3, 4) == 7);
113117}
......@@ -115,21 +119,31 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
115119 return a + b;
116120}
117121
118
119122test "generic fn with implicit cast" {
120 assert(getFirstByte(u8, []u8 {13}) == 13);
121 assert(getFirstByte(u16, []u16 {0, 13}) == 0);
123 assert(getFirstByte(u8, []u8{13}) == 13);
124 assert(getFirstByte(u16, []u16{
125 0,
126 13,
127 }) == 0);
128}
129fn getByte(ptr: ?*const u8) u8 {
130 return ptr.?.*;
122131}
123fn getByte(ptr: ?&const u8) u8 {return *??ptr;}
124132fn getFirstByte(comptime T: type, mem: []const T) u8 {
125 return getByte(@ptrCast(&const u8, &mem[0]));
133 return getByte(@ptrCast(*const u8, &mem[0]));
126134}
127135
136const foos = []fn (var) bool{
137 foo1,
138 foo2,
139};
128140
129const foos = []fn(var) bool { foo1, foo2 };
130
131fn foo1(arg: var) bool { return arg; }
132fn foo2(arg: var) bool { return !arg; }
141fn foo1(arg: var) bool {
142 return arg;
143}
144fn foo2(arg: var) bool {
145 return !arg;
146}
133147
134148test "array of generic fns" {
135149 assert(foos[0](true));
test/cases/if.zig-1
......@@ -23,7 +23,6 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
2323 }
2424}
2525
26
2726test "else if expression" {
2827 assert(elseIfExpressionF(1) == 1);
2928}
test/cases/import/a_namespace.zig+3-1
......@@ -1 +1,3 @@
1pub fn foo() i32 { return 1234; }
1pub fn foo() i32 {
2 return 1234;
3}
test/cases/incomplete_struct_param_tld.zig+5-7
......@@ -11,21 +11,19 @@ const B = struct {
1111const C = struct {
1212 x: i32,
1313
14 fn d(c: &const C) i32 {
14 fn d(c: *const C) i32 {
1515 return c.x;
1616 }
1717};
1818
19fn foo(a: &const A) i32 {
19fn foo(a: *const A) i32 {
2020 return a.b.c.d();
2121}
2222
2323test "incomplete struct param top level declaration" {
24 const a = A {
25 .b = B {
26 .c = C {
27 .x = 13,
28 },
24 const a = A{
25 .b = B{
26 .c = C{ .x = 13 },
2927 },
3028 };
3129 assert(foo(a) == 13);
test/cases/ir_block_deps.zig+3-1
......@@ -11,7 +11,9 @@ fn foo(id: u64) !i32 {
1111 };
1212}
1313
14fn getErrInt() error!i32 { return 0; }
14fn getErrInt() error!i32 {
15 return 0;
16}
1517
1618test "ir block deps" {
1719 assert((foo(1) catch unreachable) == 0);
test/cases/math.zig+148-55
......@@ -6,15 +6,20 @@ test "division" {
66}
77fn testDivision() void {
88 assert(div(u32, 13, 3) == 4);
9 assert(div(f16, 1.0, 2.0) == 0.5);
910 assert(div(f32, 1.0, 2.0) == 0.5);
1011
1112 assert(divExact(u32, 55, 11) == 5);
1213 assert(divExact(i32, -55, 11) == -5);
14 assert(divExact(f16, 55.0, 11.0) == 5.0);
15 assert(divExact(f16, -55.0, 11.0) == -5.0);
1316 assert(divExact(f32, 55.0, 11.0) == 5.0);
1417 assert(divExact(f32, -55.0, 11.0) == -5.0);
1518
1619 assert(divFloor(i32, 5, 3) == 1);
1720 assert(divFloor(i32, -5, 3) == -2);
21 assert(divFloor(f16, 5.0, 3.0) == 1.0);
22 assert(divFloor(f16, -5.0, 3.0) == -2.0);
1823 assert(divFloor(f32, 5.0, 3.0) == 1.0);
1924 assert(divFloor(f32, -5.0, 3.0) == -2.0);
2025 assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
......@@ -24,30 +29,35 @@ fn testDivision() void {
2429
2530 assert(divTrunc(i32, 5, 3) == 1);
2631 assert(divTrunc(i32, -5, 3) == -1);
32 assert(divTrunc(f16, 5.0, 3.0) == 1.0);
33 assert(divTrunc(f16, -5.0, 3.0) == -1.0);
2734 assert(divTrunc(f32, 5.0, 3.0) == 1.0);
2835 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
36 assert(divTrunc(f64, 5.0, 3.0) == 1.0);
37 assert(divTrunc(f64, -5.0, 3.0) == -1.0);
2938
3039 comptime {
3140 assert(
32 1194735857077236777412821811143690633098347576 %
33 508740759824825164163191790951174292733114988 ==
34 177254337427586449086438229241342047632117600);
35 assert(@rem(-1194735857077236777412821811143690633098347576,
36 508740759824825164163191790951174292733114988) ==
37 -177254337427586449086438229241342047632117600);
38 assert(1194735857077236777412821811143690633098347576 /
39 508740759824825164163191790951174292733114988 ==
40 2);
41 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
42 508740759824825164163191790951174292733114988) ==
43 -2);
44 assert(@divTrunc(1194735857077236777412821811143690633098347576,
45 -508740759824825164163191790951174292733114988) ==
46 -2);
47 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
48 -508740759824825164163191790951174292733114988) ==
49 2);
50 assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
41 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600,
42 );
43 assert(
44 @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600,
45 );
46 assert(
47 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2,
48 );
49 assert(
50 @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2,
51 );
52 assert(
53 @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2,
54 );
55 assert(
56 @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2,
57 );
58 assert(
59 4126227191251978491697987544882340798050766755606969681711 % 10 == 1,
60 );
5161 }
5262}
5363fn div(comptime T: type, a: T, b: T) T {
......@@ -114,18 +124,28 @@ fn ctz(x: var) usize {
114124
115125test "assignment operators" {
116126 var i: u32 = 0;
117 i += 5; assert(i == 5);
118 i -= 2; assert(i == 3);
119 i *= 20; assert(i == 60);
120 i /= 3; assert(i == 20);
121 i %= 11; assert(i == 9);
122 i <<= 1; assert(i == 18);
123 i >>= 2; assert(i == 4);
127 i += 5;
128 assert(i == 5);
129 i -= 2;
130 assert(i == 3);
131 i *= 20;
132 assert(i == 60);
133 i /= 3;
134 assert(i == 20);
135 i %= 11;
136 assert(i == 9);
137 i <<= 1;
138 assert(i == 18);
139 i >>= 2;
140 assert(i == 4);
124141 i = 6;
125 i &= 5; assert(i == 4);
126 i ^= 6; assert(i == 2);
142 i &= 5;
143 assert(i == 4);
144 i ^= 6;
145 assert(i == 2);
127146 i = 6;
128 i |= 3; assert(i == 7);
147 i |= 3;
148 assert(i == 7);
129149}
130150
131151test "three expr in a row" {
......@@ -138,7 +158,7 @@ fn testThreeExprInARow(f: bool, t: bool) void {
138158 assertFalse(1 | 2 | 4 != 7);
139159 assertFalse(3 ^ 6 ^ 8 != 13);
140160 assertFalse(7 & 14 & 28 != 4);
141 assertFalse(9 << 1 << 2 != 9 << 3);
161 assertFalse(9 << 1 << 2 != 9 << 3);
142162 assertFalse(90 >> 1 >> 2 != 90 >> 3);
143163 assertFalse(100 - 1 + 1000 != 1099);
144164 assertFalse(5 * 4 / 2 % 3 != 1);
......@@ -150,7 +170,6 @@ fn assertFalse(b: bool) void {
150170 assert(!b);
151171}
152172
153
154173test "const number literal" {
155174 const one = 1;
156175 const eleven = ten + one;
......@@ -159,8 +178,6 @@ test "const number literal" {
159178}
160179const ten = 10;
161180
162
163
164181test "unsigned wrapping" {
165182 testUnsignedWrappingEval(@maxValue(u32));
166183 comptime testUnsignedWrappingEval(@maxValue(u32));
......@@ -203,7 +220,7 @@ fn test_u64_div() void {
203220 assert(result.remainder == 100663296);
204221}
205222fn divWithResult(a: u64, b: u64) DivResult {
206 return DivResult {
223 return DivResult{
207224 .quotient = a / b,
208225 .remainder = a % b,
209226 };
......@@ -214,8 +231,12 @@ const DivResult = struct {
214231};
215232
216233test "binary not" {
217 assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});
218 assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});
234 assert(comptime x: {
235 break :x ~u16(0b1010101010101010) == 0b0101010101010101;
236 });
237 assert(comptime x: {
238 break :x ~u64(2147483647) == 18446744071562067968;
239 });
219240 testBinaryNot(0b1010101010101010);
220241}
221242
......@@ -275,6 +296,14 @@ test "quad hex float literal parsing in range" {
275296 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
276297}
277298
299test "quad hex float literal parsing accurate" {
300 const a: f128 = 0x1.1111222233334444555566667777p+0;
301
302 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
303 const expected: u128 = 0x3fff1111222233334444555566667777;
304 assert(@bitCast(u128, a) == expected);
305}
306
278307test "hex float literal within range" {
279308 const a = 0x1.0p16383;
280309 const b = 0x0.1p16387;
......@@ -317,38 +346,55 @@ fn testShrExact(x: u8) void {
317346 assert(shifted == 0b00101101);
318347}
319348
320test "big number addition" {
349test "comptime_int addition" {
321350 comptime {
322 assert(
323 35361831660712422535336160538497375248 +
324 101752735581729509668353361206450473702 ==
325 137114567242441932203689521744947848950);
326 assert(
327 594491908217841670578297176641415611445982232488944558774612 +
328 390603545391089362063884922208143568023166603618446395589768 ==
329 985095453608931032642182098849559179469148836107390954364380);
351 assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
352 assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
330353 }
331354}
332355
333test "big number multiplication" {
356test "comptime_int multiplication" {
334357 comptime {
335358 assert(
336 45960427431263824329884196484953148229 *
337 128339149605334697009938835852565949723 ==
338 5898522172026096622534201617172456926982464453350084962781392314016180490567);
359 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
360 );
339361 assert(
340 594491908217841670578297176641415611445982232488944558774612 *
341 390603545391089362063884922208143568023166603618446395589768 ==
342 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
362 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
363 );
343364 }
344365}
345366
346test "big number shifting" {
367test "comptime_int shifting" {
347368 comptime {
348369 assert((u128(1) << 127) == 0x80000000000000000000000000000000);
349370 }
350371}
351372
373test "comptime_int multi-limb shift and mask" {
374 comptime {
375 var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
376
377 assert(u32(a & 0xffffffff) == 0xaaaaaaab);
378 a >>= 32;
379 assert(u32(a & 0xffffffff) == 0xeeeeeeef);
380 a >>= 32;
381 assert(u32(a & 0xffffffff) == 0xa0000001);
382 a >>= 32;
383 assert(u32(a & 0xffffffff) == 0xefffffff);
384 a >>= 32;
385
386 assert(a == 0);
387 }
388}
389
390test "comptime_int multi-limb partial shift right" {
391 comptime {
392 var a = 0x1ffffffffeeeeeeee;
393 a >>= 16;
394 assert(a == 0x1ffffffffeeee);
395 }
396}
397
352398test "xor" {
353399 test_xor();
354400 comptime test_xor();
......@@ -362,7 +408,7 @@ fn test_xor() void {
362408 assert(0xFF ^ 0xFF == 0x00);
363409}
364410
365test "big number xor" {
411test "comptime_int xor" {
366412 comptime {
367413 assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
368414 assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
......@@ -380,7 +426,9 @@ test "f128" {
380426 comptime test_f128();
381427}
382428
383fn make_f128(x: f128) f128 { return x; }
429fn make_f128(x: f128) f128 {
430 return x;
431}
384432
385433fn test_f128() void {
386434 assert(@sizeOf(f128) == 16);
......@@ -402,3 +450,48 @@ test "comptime float rem int" {
402450 assert(x == 1.0);
403451 }
404452}
453
454test "remainder division" {
455 comptime remdiv(f16);
456 comptime remdiv(f32);
457 comptime remdiv(f64);
458 comptime remdiv(f128);
459 remdiv(f16);
460 remdiv(f64);
461 remdiv(f128);
462}
463
464fn remdiv(comptime T: type) void {
465 assert(T(1) == T(1) % T(2));
466 assert(T(1) == T(7) % T(3));
467}
468
469test "@sqrt" {
470 testSqrt(f64, 12.0);
471 comptime testSqrt(f64, 12.0);
472 testSqrt(f32, 13.0);
473 comptime testSqrt(f32, 13.0);
474 testSqrt(f16, 13.0);
475 comptime testSqrt(f16, 13.0);
476
477 const x = 14.0;
478 const y = x * x;
479 const z = @sqrt(@typeOf(y), y);
480 comptime assert(z == x);
481}
482
483fn testSqrt(comptime T: type, x: T) void {
484 assert(@sqrt(T, x * x) == x);
485}
486
487test "comptime_int param and return" {
488 const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
489 assert(a == 137114567242441932203689521744947848950);
490
491 const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
492 assert(b == 985095453608931032642182098849559179469148836107390954364380);
493}
494
495fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
496 return a + b;
497}
test/cases/merge_error_sets.zig created+21
......@@ -0,0 +1,21 @@
1const A = error{
2 PathNotFound,
3 NotDir,
4};
5const B = error{OutOfMemory};
6
7const C = A || B;
8
9fn foo() C!void {
10 return error.NotDir;
11}
12
13test "merge error sets" {
14 if (foo()) {
15 @panic("unexpected");
16 } else |err| switch (err) {
17 error.OutOfMemory => @panic("unexpected"),
18 error.PathNotFound => @panic("unexpected"),
19 error.NotDir => {},
20 }
21}
test/cases/misc.zig+169-134
......@@ -4,6 +4,7 @@ const cstr = @import("std").cstr;
44const builtin = @import("builtin");
55
66// normal comment
7
78/// this is a documentation comment
89/// doc comment line 2
910fn emptyFunctionWithComments() void {}
......@@ -16,8 +17,7 @@ comptime {
1617 @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
1718}
1819
19extern fn disabledExternFn() void {
20}
20extern fn disabledExternFn() void {}
2121
2222test "call disabled extern fn" {
2323 disabledExternFn();
......@@ -53,15 +53,11 @@ test "@IntType builtin" {
5353}
5454
5555test "floating point primitive bit counts" {
56 assert(f16.bit_count == 16);
5657 assert(f32.bit_count == 32);
5758 assert(f64.bit_count == 64);
5859}
5960
60const u1 = @IntType(false, 1);
61const u63 = @IntType(false, 63);
62const i1 = @IntType(true, 1);
63const i63 = @IntType(true, 63);
64
6561test "@minValue and @maxValue" {
6662 assert(@maxValue(u1) == 1);
6763 assert(@maxValue(u8) == 255);
......@@ -110,17 +106,29 @@ fn testShortCircuit(f: bool, t: bool) void {
110106 var hit_3 = f;
111107 var hit_4 = f;
112108
113 if (t or x: {assert(f); break :x f;}) {
109 if (t or x: {
110 assert(f);
111 break :x f;
112 }) {
114113 hit_1 = t;
115114 }
116 if (f or x: { hit_2 = t; break :x f; }) {
115 if (f or x: {
116 hit_2 = t;
117 break :x f;
118 }) {
117119 assert(f);
118120 }
119121
120 if (t and x: { hit_3 = t; break :x f; }) {
122 if (t and x: {
123 hit_3 = t;
124 break :x f;
125 }) {
121126 assert(f);
122127 }
123 if (f and x: {assert(f); break :x f;}) {
128 if (f and x: {
129 assert(f);
130 break :x f;
131 }) {
124132 assert(f);
125133 } else {
126134 hit_4 = t;
......@@ -146,8 +154,8 @@ test "return string from function" {
146154 assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
147155}
148156
149const g1 : i32 = 1233 + 1;
150var g2 : i32 = 0;
157const g1: i32 = 1233 + 1;
158var g2: i32 = 0;
151159
152160test "global variables" {
153161 assert(g2 == 0);
......@@ -155,24 +163,25 @@ test "global variables" {
155163 assert(g2 == 1234);
156164}
157165
158
159166test "memcpy and memset intrinsics" {
160 var foo : [20]u8 = undefined;
161 var bar : [20]u8 = undefined;
167 var foo: [20]u8 = undefined;
168 var bar: [20]u8 = undefined;
162169
163 @memset(&foo[0], 'A', foo.len);
164 @memcpy(&bar[0], &foo[0], bar.len);
170 @memset(foo[0..].ptr, 'A', foo.len);
171 @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len);
165172
166173 if (bar[11] != 'A') unreachable;
167174}
168175
169176test "builtin static eval" {
170 const x : i32 = comptime x: {break :x 1 + 2 + 3;};
177 const x: i32 = comptime x: {
178 break :x 1 + 2 + 3;
179 };
171180 assert(x == comptime 6);
172181}
173182
174183test "slicing" {
175 var array : [20]i32 = undefined;
184 var array: [20]i32 = undefined;
176185
177186 array[5] = 1234;
178187
......@@ -181,21 +190,21 @@ test "slicing" {
181190 if (slice.len != 5) unreachable;
182191
183192 const ptr = &slice[0];
184 if (ptr[0] != 1234) unreachable;
193 if (ptr.* != 1234) unreachable;
185194
186195 var slice_rest = array[10..];
187196 if (slice_rest.len != 10) unreachable;
188197}
189198
190
191199test "constant equal function pointers" {
192200 const alias = emptyFn;
193 assert(comptime x: {break :x emptyFn == alias;});
201 assert(comptime x: {
202 break :x emptyFn == alias;
203 });
194204}
195205
196206fn emptyFn() void {}
197207
198
199208test "hex escape" {
200209 assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
201210}
......@@ -238,35 +247,32 @@ test "multiline C string" {
238247 assert(cstr.cmp(s1, s2) == 0);
239248}
240249
241
242250test "type equality" {
243 assert(&const u8 != &u8);
251 assert(*const u8 != *u8);
244252}
245253
246
247254const global_a: i32 = 1234;
248const global_b: &const i32 = &global_a;
249const global_c: &const f32 = @ptrCast(&const f32, global_b);
255const global_b: *const i32 = &global_a;
256const global_c: *const f32 = @ptrCast(*const f32, global_b);
250257test "compile time global reinterpret" {
251 const d = @ptrCast(&const i32, global_c);
252 assert(*d == 1234);
258 const d = @ptrCast(*const i32, global_c);
259 assert(d.* == 1234);
253260}
254261
255262test "explicit cast maybe pointers" {
256 const a: ?&i32 = undefined;
257 const b: ?&f32 = @ptrCast(?&f32, a);
263 const a: ?*i32 = undefined;
264 const b: ?*f32 = @ptrCast(?*f32, a);
258265}
259266
260267test "generic malloc free" {
261268 const a = memAlloc(u8, 10) catch unreachable;
262269 memFree(u8, a);
263270}
264var some_mem : [100]u8 = undefined;
271var some_mem: [100]u8 = undefined;
265272fn memAlloc(comptime T: type, n: usize) error![]T {
266 return @ptrCast(&T, &some_mem[0])[0..n];
273 return @ptrCast([*]T, &some_mem[0])[0..n];
267274}
268fn memFree(comptime T: type, memory: []T) void { }
269
275fn memFree(comptime T: type, memory: []T) void {}
270276
271277test "cast undefined" {
272278 const array: [100]u8 = undefined;
......@@ -275,32 +281,35 @@ test "cast undefined" {
275281}
276282fn testCastUndefined(x: []const u8) void {}
277283
278
279284test "cast small unsigned to larger signed" {
280285 assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
281286 assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
282287}
283fn castSmallUnsignedToLargerSigned1(x: u8) i16 { return x; }
284fn castSmallUnsignedToLargerSigned2(x: u16) i64 { return x; }
285
288fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
289 return x;
290}
291fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
292 return x;
293}
286294
287295test "implicit cast after unreachable" {
288296 assert(outer() == 1234);
289297}
290fn inner() i32 { return 1234; }
298fn inner() i32 {
299 return 1234;
300}
291301fn outer() i64 {
292302 return inner();
293303}
294304
295
296305test "pointer dereferencing" {
297306 var x = i32(3);
298307 const y = &x;
299308
300 *y += 1;
309 y.* += 1;
301310
302311 assert(x == 4);
303 assert(*y == 4);
312 assert(y.* == 4);
304313}
305314
306315test "call result of if else expression" {
......@@ -310,9 +319,12 @@ test "call result of if else expression" {
310319fn f2(x: bool) []const u8 {
311320 return (if (x) fA else fB)();
312321}
313fn fA() []const u8 { return "a"; }
314fn fB() []const u8 { return "b"; }
315
322fn fA() []const u8 {
323 return "a";
324}
325fn fB() []const u8 {
326 return "b";
327}
316328
317329test "const expression eval handling of variables" {
318330 var x = true;
......@@ -321,8 +333,6 @@ test "const expression eval handling of variables" {
321333 }
322334}
323335
324
325
326336test "constant enum initialization with differing sizes" {
327337 test3_1(test3_foo);
328338 test3_2(test3_bar);
......@@ -336,10 +346,15 @@ const Test3Point = struct {
336346 x: i32,
337347 y: i32,
338348};
339const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
340const test3_bar = Test3Foo { .Two = 13};
341fn test3_1(f: &const Test3Foo) void {
342 switch (*f) {
349const test3_foo = Test3Foo{
350 .Three = Test3Point{
351 .x = 3,
352 .y = 4,
353 },
354};
355const test3_bar = Test3Foo{ .Two = 13 };
356fn test3_1(f: *const Test3Foo) void {
357 switch (f.*) {
343358 Test3Foo.Three => |pt| {
344359 assert(pt.x == 3);
345360 assert(pt.y == 4);
......@@ -347,8 +362,8 @@ fn test3_1(f: &const Test3Foo) void {
347362 else => unreachable,
348363 }
349364}
350fn test3_2(f: &const Test3Foo) void {
351 switch (*f) {
365fn test3_2(f: *const Test3Foo) void {
366 switch (f.*) {
352367 Test3Foo.Two => |x| {
353368 assert(x == 13);
354369 },
......@@ -356,58 +371,61 @@ fn test3_2(f: &const Test3Foo) void {
356371 }
357372}
358373
359
360374test "character literals" {
361375 assert('\'' == single_quote);
362376}
363377const single_quote = '\'';
364378
365
366
367379test "take address of parameter" {
368380 testTakeAddressOfParameter(12.34);
369381}
370382fn testTakeAddressOfParameter(f: f32) void {
371383 const f_ptr = &f;
372 assert(*f_ptr == 12.34);
384 assert(f_ptr.* == 12.34);
373385}
374386
375
376387test "pointer comparison" {
377388 const a = ([]const u8)("a");
378389 const b = &a;
379390 assert(ptrEql(b, b));
380391}
381fn ptrEql(a: &const []const u8, b: &const []const u8) bool {
392fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
382393 return a == b;
383394}
384395
385
386396test "C string concatenation" {
387397 const a = c"OK" ++ c" IT " ++ c"WORKED";
388398 const b = c"OK IT WORKED";
389399
390400 const len = cstr.len(b);
391401 const len_with_null = len + 1;
392 {var i: u32 = 0; while (i < len_with_null) : (i += 1) {
393 assert(a[i] == b[i]);
394 }}
402 {
403 var i: u32 = 0;
404 while (i < len_with_null) : (i += 1) {
405 assert(a[i] == b[i]);
406 }
407 }
395408 assert(a[len] == 0);
396409 assert(b[len] == 0);
397410}
398411
399412test "cast slice to u8 slice" {
400413 assert(@sizeOf(i32) == 4);
401 var big_thing_array = []i32{1, 2, 3, 4};
414 var big_thing_array = []i32{
415 1,
416 2,
417 3,
418 4,
419 };
402420 const big_thing_slice: []i32 = big_thing_array[0..];
403 const bytes = ([]u8)(big_thing_slice);
421 const bytes = @sliceToBytes(big_thing_slice);
404422 assert(bytes.len == 4 * 4);
405423 bytes[4] = 0;
406424 bytes[5] = 0;
407425 bytes[6] = 0;
408426 bytes[7] = 0;
409427 assert(big_thing_slice[1] == 0);
410 const big_thing_again = ([]align(1) i32)(bytes);
428 const big_thing_again = @bytesToSlice(i32, bytes);
411429 assert(big_thing_again[2] == 3);
412430 big_thing_again[2] = -1;
413431 assert(bytes[8] == @maxValue(u8));
......@@ -421,39 +439,48 @@ test "pointer to void return type" {
421439}
422440fn testPointerToVoidReturnType() error!void {
423441 const a = testPointerToVoidReturnType2();
424 return *a;
442 return a.*;
425443}
426444const test_pointer_to_void_return_type_x = void{};
427fn testPointerToVoidReturnType2() &const void {
445fn testPointerToVoidReturnType2() *const void {
428446 return &test_pointer_to_void_return_type_x;
429447}
430448
431
432449test "non const ptr to aliased type" {
433450 const int = i32;
434 assert(?&int == ?&i32);
451 assert(?*int == ?*i32);
435452}
436453
437
438
439454test "array 2D const double ptr" {
440 const rect_2d_vertexes = [][1]f32 {
455 const rect_2d_vertexes = [][1]f32{
441456 []f32{1.0},
442457 []f32{2.0},
443458 };
444459 testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
445460}
446461
447fn testArray2DConstDoublePtr(ptr: &const f32) void {
448 assert(ptr[0] == 1.0);
449 assert(ptr[1] == 2.0);
462fn testArray2DConstDoublePtr(ptr: *const f32) void {
463 const ptr2 = @ptrCast([*]const f32, ptr);
464 assert(ptr2[0] == 1.0);
465 assert(ptr2[1] == 2.0);
450466}
451467
452468const Tid = builtin.TypeId;
453const AStruct = struct { x: i32, };
454const AnEnum = enum { One, Two, };
455const AUnionEnum = union(enum) { One: i32, Two: void, };
456const AUnion = union { One: void, Two: void };
469const AStruct = struct {
470 x: i32,
471};
472const AnEnum = enum {
473 One,
474 Two,
475};
476const AUnionEnum = union(enum) {
477 One: i32,
478 Two: void,
479};
480const AUnion = union {
481 One: void,
482 Two: void,
483};
457484
458485test "@typeId" {
459486 comptime {
......@@ -467,40 +494,33 @@ test "@typeId" {
467494 assert(@typeId(u64) == Tid.Int);
468495 assert(@typeId(f32) == Tid.Float);
469496 assert(@typeId(f64) == Tid.Float);
470 assert(@typeId(&f32) == Tid.Pointer);
497 assert(@typeId(*f32) == Tid.Pointer);
471498 assert(@typeId([2]u8) == Tid.Array);
472499 assert(@typeId(AStruct) == Tid.Struct);
473 assert(@typeId(@typeOf(1)) == Tid.IntLiteral);
474 assert(@typeId(@typeOf(1.0)) == Tid.FloatLiteral);
475 assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);
476 assert(@typeId(@typeOf(null)) == Tid.NullLiteral);
477 assert(@typeId(?i32) == Tid.Nullable);
500 assert(@typeId(@typeOf(1)) == Tid.ComptimeInt);
501 assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
502 assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
503 assert(@typeId(@typeOf(null)) == Tid.Null);
504 assert(@typeId(?i32) == Tid.Optional);
478505 assert(@typeId(error!i32) == Tid.ErrorUnion);
479506 assert(@typeId(error) == Tid.ErrorSet);
480507 assert(@typeId(AnEnum) == Tid.Enum);
481508 assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
482509 assert(@typeId(AUnionEnum) == Tid.Union);
483510 assert(@typeId(AUnion) == Tid.Union);
484 assert(@typeId(fn()void) == Tid.Fn);
511 assert(@typeId(fn () void) == Tid.Fn);
485512 assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
486 assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);
513 assert(@typeId(@typeOf(x: {
514 break :x this;
515 })) == Tid.Block);
487516 // TODO bound fn
488517 // TODO arg tuple
489518 // TODO opaque
490519 }
491520}
492521
493test "@canImplicitCast" {
494 comptime {
495 assert(@canImplicitCast(i64, i32(3)));
496 assert(!@canImplicitCast(i32, f32(1.234)));
497 assert(@canImplicitCast([]const u8, "aoeu"));
498 }
499}
500
501522test "@typeName" {
502 const Struct = struct {
503 };
523 const Struct = struct {};
504524 const Union = union {
505525 unused: u8,
506526 };
......@@ -509,8 +529,8 @@ test "@typeName" {
509529 };
510530 comptime {
511531 assert(mem.eql(u8, @typeName(i64), "i64"));
512 assert(mem.eql(u8, @typeName(&usize), "&usize"));
513 // https://github.com/zig-lang/zig/issues/675
532 assert(mem.eql(u8, @typeName(*usize), "*usize"));
533 // https://github.com/ziglang/zig/issues/675
514534 assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
515535 assert(mem.eql(u8, @typeName(Struct), "Struct"));
516536 assert(mem.eql(u8, @typeName(Union), "Union"));
......@@ -524,15 +544,20 @@ fn TypeFromFn(comptime T: type) type {
524544
525545test "volatile load and store" {
526546 var number: i32 = 1234;
527 const ptr = (&volatile i32)(&number);
528 *ptr += 1;
529 assert(*ptr == 1235);
547 const ptr = (*volatile i32)(&number);
548 ptr.* += 1;
549 assert(ptr.* == 1235);
530550}
531551
532552test "slice string literal has type []const u8" {
533553 comptime {
534554 assert(@typeOf("aoeu"[0..]) == []const u8);
535 const array = []i32{1, 2, 3, 4};
555 const array = []i32{
556 1,
557 2,
558 3,
559 4,
560 };
536561 assert(@typeOf(array[0..]) == []const i32);
537562 }
538563}
......@@ -543,37 +568,36 @@ test "global variable initialized to global variable array element" {
543568const GDTEntry = struct {
544569 field: i32,
545570};
546var gdt = []GDTEntry {
547 GDTEntry {.field = 1},
548 GDTEntry {.field = 2},
571var gdt = []GDTEntry{
572 GDTEntry{ .field = 1 },
573 GDTEntry{ .field = 2 },
549574};
550575var global_ptr = &gdt[0];
551576
552
553577// can't really run this test but we can make sure it has no compile error
554578// and generates code
555const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];
579const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000];
556580export fn writeToVRam() void {
557581 vram[0] = 'X';
558582}
559583
560584test "pointer child field" {
561 assert((&u32).Child == u32);
585 assert((*u32).Child == u32);
562586}
563587
564588const OpaqueA = @OpaqueType();
565589const OpaqueB = @OpaqueType();
566590test "@OpaqueType" {
567 assert(&OpaqueA != &OpaqueB);
591 assert(*OpaqueA != *OpaqueB);
568592 assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
569593 assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
570594}
571595
572596test "variable is allowed to be a pointer to an opaque type" {
573597 var x: i32 = 1234;
574 _ = hereIsAnOpaqueType(@ptrCast(&OpaqueA, &x));
598 _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
575599}
576fn hereIsAnOpaqueType(ptr: &OpaqueA) &OpaqueA {
600fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
577601 var a = ptr;
578602 return a;
579603}
......@@ -584,7 +608,7 @@ test "comptime if inside runtime while which unconditionally breaks" {
584608}
585609fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
586610 while (cond) {
587 if (false) { }
611 if (false) {}
588612 break;
589613 }
590614}
......@@ -607,7 +631,7 @@ fn testStructInFn() void {
607631 kind: BlockKind,
608632 };
609633
610 var block = Block { .kind = 1234 };
634 var block = Block{ .kind = 1234 };
611635
612636 block.kind += 1;
613637
......@@ -617,7 +641,9 @@ fn testStructInFn() void {
617641fn fnThatClosesOverLocalConst() type {
618642 const c = 1;
619643 return struct {
620 fn g() i32 { return c; }
644 fn g() i32 {
645 return c;
646 }
621647 };
622648}
623649
......@@ -635,22 +661,27 @@ fn thisIsAColdFn() void {
635661 @setCold(true);
636662}
637663
638
639const PackedStruct = packed struct { a: u8, b: u8, };
640const PackedUnion = packed union { a: u8, b: u32, };
641const PackedEnum = packed enum { A, B, };
664const PackedStruct = packed struct {
665 a: u8,
666 b: u8,
667};
668const PackedUnion = packed union {
669 a: u8,
670 b: u32,
671};
672const PackedEnum = packed enum {
673 A,
674 B,
675};
642676
643677test "packed struct, enum, union parameters in extern function" {
644 testPackedStuff(
645 PackedStruct{.a = 1, .b = 2},
646 PackedUnion{.a = 1},
647 PackedEnum.A,
648 );
649}
650
651export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {
678 testPackedStuff(PackedStruct{
679 .a = 1,
680 .b = 2,
681 }, PackedUnion{ .a = 1 }, PackedEnum.A);
652682}
653683
684export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {}
654685
655686test "slicing zero length array" {
656687 const s1 = ""[0..];
......@@ -661,9 +692,13 @@ test "slicing zero length array" {
661692 assert(mem.eql(u32, s2, []u32{}));
662693}
663694
664
665const addr1 = @ptrCast(&const u8, emptyFn);
695const addr1 = @ptrCast(*const u8, emptyFn);
666696test "comptime cast fn to ptr" {
667 const addr2 = @ptrCast(&const u8, emptyFn);
697 const addr2 = @ptrCast(*const u8, emptyFn);
668698 comptime assert(addr1 == addr2);
669699}
700
701test "equality compare fn ptrs" {
702 var a = emptyFn;
703 assert(a == a);
704}
test/cases/namespace_depends_on_compile_var/index.zig+1-1
......@@ -8,7 +8,7 @@ test "namespace depends on compile var" {
88 assert(!some_namespace.a_bool);
99 }
1010}
11const some_namespace = switch(builtin.os) {
11const some_namespace = switch (builtin.os) {
1212 builtin.Os.linux => @import("a.zig"),
1313 else => @import("b.zig"),
1414};
test/cases/new_stack_call.zig created+26
......@@ -0,0 +1,26 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4var new_stack_bytes: [1024]u8 = undefined;
5
6test "calling a function with a new stack" {
7 const arg = 1234;
8
9 const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
10 const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
11 _ = targetFunction(arg);
12
13 assert(arg == 1234);
14 assert(a < b);
15}
16
17fn targetFunction(x: i32) usize {
18 assert(x == 1234);
19
20 var local_variable: i32 = 42;
21 const ptr = &local_variable;
22 ptr.* += 1;
23
24 assert(local_variable == 43);
25 return @ptrToInt(ptr);
26}
test/cases/null.zig+46-40
......@@ -1,7 +1,7 @@
11const assert = @import("std").debug.assert;
22
3test "nullable type" {
4 const x : ?bool = true;
3test "optional type" {
4 const x: ?bool = true;
55
66 if (x) |y| {
77 if (y) {
......@@ -13,15 +13,15 @@ test "nullable type" {
1313 unreachable;
1414 }
1515
16 const next_x : ?i32 = null;
16 const next_x: ?i32 = null;
1717
18 const z = next_x ?? 1234;
18 const z = next_x orelse 1234;
1919
2020 assert(z == 1234);
2121
22 const final_x : ?i32 = 13;
22 const final_x: ?i32 = 13;
2323
24 const num = final_x ?? unreachable;
24 const num = final_x orelse unreachable;
2525
2626 assert(num == 13);
2727}
......@@ -30,42 +30,43 @@ test "test maybe object and get a pointer to the inner value" {
3030 var maybe_bool: ?bool = true;
3131
3232 if (maybe_bool) |*b| {
33 *b = false;
33 b.* = false;
3434 }
3535
36 assert(??maybe_bool == false);
36 assert(maybe_bool.? == false);
3737}
3838
39
4039test "rhs maybe unwrap return" {
4140 const x: ?bool = true;
42 const y = x ?? return;
41 const y = x orelse return;
4342}
4443
45
4644test "maybe return" {
4745 maybeReturnImpl();
4846 comptime maybeReturnImpl();
4947}
5048
5149fn maybeReturnImpl() void {
52 assert(??foo(1235));
53 if (foo(null) != null)
54 unreachable;
55 assert(!??foo(1234));
50 assert(foo(1235).?);
51 if (foo(null) != null) unreachable;
52 assert(!foo(1234).?);
5653}
5754
5855fn foo(x: ?i32) ?bool {
59 const value = x ?? return null;
56 const value = x orelse return null;
6057 return value > 1234;
6158}
6259
63
6460test "if var maybe pointer" {
65 assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);
66}
67fn shouldBeAPlus1(p: &const Particle) u64 {
68 var maybe_particle: ?Particle = *p;
61 assert(shouldBeAPlus1(Particle{
62 .a = 14,
63 .b = 1,
64 .c = 1,
65 .d = 1,
66 }) == 15);
67}
68fn shouldBeAPlus1(p: *const Particle) u64 {
69 var maybe_particle: ?Particle = p.*;
6970 if (maybe_particle) |*particle| {
7071 particle.a += 1;
7172 }
......@@ -81,7 +82,6 @@ const Particle = struct {
8182 d: u64,
8283};
8384
84
8585test "null literal outside function" {
8686 const is_null = here_is_a_null_literal.context == null;
8787 assert(is_null);
......@@ -92,10 +92,7 @@ test "null literal outside function" {
9292const SillyStruct = struct {
9393 context: ?i32,
9494};
95const here_is_a_null_literal = SillyStruct {
96 .context = null,
97};
98
95const here_is_a_null_literal = SillyStruct{ .context = null };
9996
10097test "test null runtime" {
10198 testTestNullRuntime(null);
......@@ -105,12 +102,12 @@ fn testTestNullRuntime(x: ?i32) void {
105102 assert(!(x != null));
106103}
107104
108test "nullable void" {
109 nullableVoidImpl();
110 comptime nullableVoidImpl();
105test "optional void" {
106 optionalVoidImpl();
107 comptime optionalVoidImpl();
111108}
112109
113fn nullableVoidImpl() void {
110fn optionalVoidImpl() void {
114111 assert(bar(null) == null);
115112 assert(bar({}) != null);
116113}
......@@ -123,21 +120,19 @@ fn bar(x: ?void) ?void {
123120 }
124121}
125122
126
127
128const StructWithNullable = struct {
123const StructWithOptional = struct {
129124 field: ?i32,
130125};
131126
132var struct_with_nullable: StructWithNullable = undefined;
127var struct_with_optional: StructWithOptional = undefined;
133128
134test "unwrap nullable which is field of global var" {
135 struct_with_nullable.field = null;
136 if (struct_with_nullable.field) |payload| {
129test "unwrap optional which is field of global var" {
130 struct_with_optional.field = null;
131 if (struct_with_optional.field) |payload| {
137132 unreachable;
138133 }
139 struct_with_nullable.field = 1234;
140 if (struct_with_nullable.field) |payload| {
134 struct_with_optional.field = 1234;
135 if (struct_with_optional.field) |payload| {
141136 assert(payload == 1234);
142137 } else {
143138 unreachable;
......@@ -145,6 +140,17 @@ test "unwrap nullable which is field of global var" {
145140}
146141
147142test "null with default unwrap" {
148 const x: i32 = null ?? 1;
143 const x: i32 = null orelse 1;
149144 assert(x == 1);
150145}
146
147test "optional types" {
148 comptime {
149 const opt_type_struct = StructWithOptionalType{ .t = u8 };
150 assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
151 }
152}
153
154const StructWithOptionalType = struct {
155 t: ?type,
156};
test/cases/optional.zig created+30
......@@ -0,0 +1,30 @@
1const assert = @import("std").debug.assert;
2
3pub const EmptyStruct = struct {};
4
5test "optional pointer to size zero struct" {
6 var e = EmptyStruct{};
7 var o: ?*EmptyStruct = &e;
8 assert(o != null);
9}
10
11test "equality compare nullable pointers" {
12 testNullPtrsEql();
13 comptime testNullPtrsEql();
14}
15
16fn testNullPtrsEql() void {
17 var number: i32 = 1234;
18
19 var x: ?*i32 = null;
20 var y: ?*i32 = null;
21 assert(x == y);
22 y = &number;
23 assert(x != y);
24 assert(x != &number);
25 assert(&number != x);
26 x = &number;
27 assert(x == y);
28 assert(x == &number);
29 assert(&number == x);
30}
test/cases/pointers.zig created+44
......@@ -0,0 +1,44 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4test "dereference pointer" {
5 comptime testDerefPtr();
6 testDerefPtr();
7}
8
9fn testDerefPtr() void {
10 var x: i32 = 1234;
11 var y = &x;
12 y.* += 1;
13 assert(x == 1235);
14}
15
16test "pointer arithmetic" {
17 var ptr = c"abcd";
18
19 assert(ptr[0] == 'a');
20 ptr += 1;
21 assert(ptr[0] == 'b');
22 ptr += 1;
23 assert(ptr[0] == 'c');
24 ptr += 1;
25 assert(ptr[0] == 'd');
26 ptr += 1;
27 assert(ptr[0] == 0);
28 ptr -= 1;
29 assert(ptr[0] == 'd');
30 ptr -= 1;
31 assert(ptr[0] == 'c');
32 ptr -= 1;
33 assert(ptr[0] == 'b');
34 ptr -= 1;
35 assert(ptr[0] == 'a');
36}
37
38test "double pointer parsing" {
39 comptime assert(PtrOf(PtrOf(i32)) == **i32);
40}
41
42fn PtrOf(comptime T: type) type {
43 return *T;
44}
test/cases/popcount.zig created+24
......@@ -0,0 +1,24 @@
1const assert = @import("std").debug.assert;
2
3test "@popCount" {
4 comptime testPopCount();
5 testPopCount();
6}
7
8fn testPopCount() void {
9 {
10 var x: u32 = 0xaa;
11 assert(@popCount(x) == 4);
12 }
13 {
14 var x: u32 = 0xaaaaaaaa;
15 assert(@popCount(x) == 16);
16 }
17 {
18 var x: i16 = -1;
19 assert(@popCount(x) == 16);
20 }
21 comptime {
22 assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
23 }
24}
test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig+1-1
......@@ -23,7 +23,7 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
2323 if (c) {
2424 const output_path = b;
2525
26 if (c2) { }
26 if (c2) {}
2727
2828 a(output_path);
2929 }
test/cases/reflection.zig+28-3
......@@ -1,10 +1,11 @@
11const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
3const reflection = this;
34
4test "reflection: array, pointer, nullable, error union type child" {
5test "reflection: array, pointer, optional, error union type child" {
56 comptime {
67 assert(([10]u8).Child == u8);
7 assert((&u8).Child == u8);
8 assert((*u8).Child == u8);
89 assert((error!u8).Payload == u8);
910 assert((?u8).Child == u8);
1011 }
......@@ -22,7 +23,9 @@ test "reflection: function return type, var args, and param types" {
2223 }
2324}
2425
25fn dummy(a: bool, b: i32, c: f32) i32 { return 1234; }
26fn dummy(a: bool, b: i32, c: f32) i32 {
27 return 1234;
28}
2629fn dummy_varargs(args: ...) void {}
2730
2831test "reflection: struct member types and names" {
......@@ -53,10 +56,32 @@ test "reflection: enum member types and names" {
5356 assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
5457 assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
5558 }
59}
5660
61test "reflection: @field" {
62 var f = Foo{
63 .one = 42,
64 .two = true,
65 .three = void{},
66 };
67
68 assert(f.one == f.one);
69 assert(@field(f, "o" ++ "ne") == f.one);
70 assert(@field(f, "t" ++ "wo") == f.two);
71 assert(@field(f, "th" ++ "ree") == f.three);
72 assert(@field(Foo, "const" ++ "ant") == Foo.constant);
73 assert(@field(Bar, "O" ++ "ne") == Bar.One);
74 assert(@field(Bar, "T" ++ "wo") == Bar.Two);
75 assert(@field(Bar, "Th" ++ "ree") == Bar.Three);
76 assert(@field(Bar, "F" ++ "our") == Bar.Four);
77 assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
78 @field(f, "o" ++ "ne") = 4;
79 assert(f.one == 4);
5780}
5881
5982const Foo = struct {
83 const constant = 52;
84
6085 one: i32,
6186 two: bool,
6287 three: void,
test/cases/slice.zig+7-3
......@@ -1,7 +1,7 @@
11const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
33
4const x = @intToPtr(&i32, 0x1000)[0..0x500];
4const x = @intToPtr([*]i32, 0x1000)[0..0x500];
55const y = x[0x100..];
66test "compile time slice of pointer to hard coded address" {
77 assert(@ptrToInt(x.ptr) == 0x1000);
......@@ -18,7 +18,11 @@ test "slice child property" {
1818}
1919
2020test "runtime safety lets us slice from len..len" {
21 var an_array = []u8{1, 2, 3};
21 var an_array = []u8{
22 1,
23 2,
24 3,
25 };
2226 assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
2327}
2428
......@@ -27,7 +31,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
2731}
2832
2933test "implicitly cast array of size 0 to slice" {
30 var msg = []u8 {};
34 var msg = []u8{};
3135 assertLenIsZero(msg);
3236}
3337
test/cases/struct.zig+75-56
......@@ -2,9 +2,11 @@ const assert = @import("std").debug.assert;
22const builtin = @import("builtin");
33
44const StructWithNoFields = struct {
5 fn add(a: i32, b: i32) i32 { return a + b; }
5 fn add(a: i32, b: i32) i32 {
6 return a + b;
7 }
68};
7const empty_global_instance = StructWithNoFields {};
9const empty_global_instance = StructWithNoFields{};
810
911test "call struct static method" {
1012 const result = StructWithNoFields.add(3, 4);
......@@ -25,7 +27,7 @@ test "invake static method in global scope" {
2527}
2628
2729test "void struct fields" {
28 const foo = VoidStructFieldsFoo {
30 const foo = VoidStructFieldsFoo{
2931 .a = void{},
3032 .b = 1,
3133 .c = void{},
......@@ -34,15 +36,14 @@ test "void struct fields" {
3436 assert(@sizeOf(VoidStructFieldsFoo) == 4);
3537}
3638const VoidStructFieldsFoo = struct {
37 a : void,
38 b : i32,
39 c : void,
39 a: void,
40 b: i32,
41 c: void,
4042};
4143
42
4344test "structs" {
4445 var foo: StructFoo = undefined;
45 @memset(@ptrCast(&u8, &foo), 0, @sizeOf(StructFoo));
46 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
4647 foo.a += 1;
4748 foo.b = foo.a == 1;
4849 testFoo(foo);
......@@ -50,21 +51,20 @@ test "structs" {
5051 assert(foo.c == 100);
5152}
5253const StructFoo = struct {
53 a : i32,
54 b : bool,
55 c : f32,
54 a: i32,
55 b: bool,
56 c: f32,
5657};
57fn testFoo(foo: &const StructFoo) void {
58fn testFoo(foo: *const StructFoo) void {
5859 assert(foo.b);
5960}
60fn testMutation(foo: &StructFoo) void {
61fn testMutation(foo: *StructFoo) void {
6162 foo.c = 100;
6263}
6364
64
6565const Node = struct {
6666 val: Val,
67 next: &Node,
67 next: *Node,
6868};
6969
7070const Val = struct {
......@@ -72,10 +72,10 @@ const Val = struct {
7272};
7373
7474test "struct point to self" {
75 var root : Node = undefined;
75 var root: Node = undefined;
7676 root.val.x = 1;
7777
78 var node : Node = undefined;
78 var node: Node = undefined;
7979 node.next = &root;
8080 node.val.x = 2;
8181
......@@ -85,8 +85,8 @@ test "struct point to self" {
8585}
8686
8787test "struct byval assign" {
88 var foo1 : StructFoo = undefined;
89 var foo2 : StructFoo = undefined;
88 var foo1: StructFoo = undefined;
89 var foo2: StructFoo = undefined;
9090
9191 foo1.a = 1234;
9292 foo2.a = 0;
......@@ -96,51 +96,52 @@ test "struct byval assign" {
9696}
9797
9898fn structInitializer() void {
99 const val = Val { .x = 42 };
99 const val = Val{ .x = 42 };
100100 assert(val.x == 42);
101101}
102102
103
104103test "fn call of struct field" {
105 assert(callStructField(Foo {.ptr = aFunc,}) == 13);
104 assert(callStructField(Foo{ .ptr = aFunc }) == 13);
106105}
107106
108107const Foo = struct {
109 ptr: fn() i32,
108 ptr: fn () i32,
110109};
111110
112fn aFunc() i32 { return 13; }
111fn aFunc() i32 {
112 return 13;
113}
113114
114fn callStructField(foo: &const Foo) i32 {
115fn callStructField(foo: *const Foo) i32 {
115116 return foo.ptr();
116117}
117118
118
119119test "store member function in variable" {
120 const instance = MemberFnTestFoo { .x = 1234, };
120 const instance = MemberFnTestFoo{ .x = 1234 };
121121 const memberFn = MemberFnTestFoo.member;
122122 const result = memberFn(instance);
123123 assert(result == 1234);
124124}
125125const MemberFnTestFoo = struct {
126126 x: i32,
127 fn member(foo: &const MemberFnTestFoo) i32 { return foo.x; }
127 fn member(foo: *const MemberFnTestFoo) i32 {
128 return foo.x;
129 }
128130};
129131
130
131132test "call member function directly" {
132 const instance = MemberFnTestFoo { .x = 1234, };
133 const instance = MemberFnTestFoo{ .x = 1234 };
133134 const result = MemberFnTestFoo.member(instance);
134135 assert(result == 1234);
135136}
136137
137138test "member functions" {
138 const r = MemberFnRand {.seed = 1234};
139 const r = MemberFnRand{ .seed = 1234 };
139140 assert(r.getSeed() == 1234);
140141}
141142const MemberFnRand = struct {
142143 seed: u32,
143 pub fn getSeed(r: &const MemberFnRand) u32 {
144 pub fn getSeed(r: *const MemberFnRand) u32 {
144145 return r.seed;
145146 }
146147};
......@@ -154,7 +155,7 @@ const Bar = struct {
154155 y: i32,
155156};
156157fn makeBar(x: i32, y: i32) Bar {
157 return Bar {
158 return Bar{
158159 .x = x,
159160 .y = y,
160161 };
......@@ -165,22 +166,21 @@ test "empty struct method call" {
165166 assert(es.method() == 1234);
166167}
167168const EmptyStruct = struct {
168 fn method(es: &const EmptyStruct) i32 {
169 fn method(es: *const EmptyStruct) i32 {
169170 return 1234;
170171 }
171172};
172173
173
174174test "return empty struct from fn" {
175175 _ = testReturnEmptyStructFromFn();
176176}
177177const EmptyStruct2 = struct {};
178178fn testReturnEmptyStructFromFn() EmptyStruct2 {
179 return EmptyStruct2 {};
179 return EmptyStruct2{};
180180}
181181
182182test "pass slice of empty struct to fn" {
183 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
183 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
184184}
185185fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
186186 return slice.len;
......@@ -192,7 +192,7 @@ const APackedStruct = packed struct {
192192};
193193
194194test "packed struct" {
195 var foo = APackedStruct {
195 var foo = APackedStruct{
196196 .x = 1,
197197 .y = 2,
198198 };
......@@ -201,14 +201,13 @@ test "packed struct" {
201201 assert(four == 4);
202202}
203203
204
205204const BitField1 = packed struct {
206205 a: u3,
207206 b: u3,
208207 c: u2,
209208};
210209
211const bit_field_1 = BitField1 {
210const bit_field_1 = BitField1{
212211 .a = 1,
213212 .b = 2,
214213 .c = 3,
......@@ -229,19 +228,18 @@ test "bit field access" {
229228 assert(data.b == 3);
230229}
231230
232fn getA(data: &const BitField1) u3 {
231fn getA(data: *const BitField1) u3 {
233232 return data.a;
234233}
235234
236fn getB(data: &const BitField1) u3 {
235fn getB(data: *const BitField1) u3 {
237236 return data.b;
238237}
239238
240fn getC(data: &const BitField1) u2 {
239fn getC(data: *const BitField1) u2 {
241240 return data.c;
242241}
243242
244const u24 = @IntType(false, 24);
245243const Foo24Bits = packed struct {
246244 field: u24,
247245};
......@@ -258,7 +256,7 @@ test "packed struct 24bits" {
258256 assert(@sizeOf(Foo96Bits) == 12);
259257 }
260258
261 var value = Foo96Bits {
259 var value = Foo96Bits{
262260 .a = 0,
263261 .b = 0,
264262 .c = 0,
......@@ -303,7 +301,7 @@ test "packed array 24bits" {
303301
304302 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
305303 bytes[bytes.len - 1] = 0xaa;
306 const ptr = &([]FooArray24Bits)(bytes[0..bytes.len - 1])[0];
304 const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
307305 assert(ptr.a == 0);
308306 assert(ptr.b[0].field == 0);
309307 assert(ptr.b[1].field == 0);
......@@ -352,7 +350,7 @@ test "aligned array of packed struct" {
352350 }
353351
354352 var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
355 const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
353 const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
356354
357355 assert(ptr.a[0].a == 0xbb);
358356 assert(ptr.a[0].b == 0xbb);
......@@ -360,16 +358,20 @@ test "aligned array of packed struct" {
360358 assert(ptr.a[1].b == 0xbb);
361359}
362360
363
364
365361test "runtime struct initialization of bitfield" {
366 const s1 = Nibbles { .x = x1, .y = x1 };
367 const s2 = Nibbles { .x = u4(x2), .y = u4(x2) };
362 const s1 = Nibbles{
363 .x = x1,
364 .y = x1,
365 };
366 const s2 = Nibbles{
367 .x = @intCast(u4, x2),
368 .y = @intCast(u4, x2),
369 };
368370
369371 assert(s1.x == x1);
370372 assert(s1.y == x1);
371 assert(s2.x == u4(x2));
372 assert(s2.y == u4(x2));
373 assert(s2.x == @intCast(u4, x2));
374 assert(s2.y == @intCast(u4, x2));
373375}
374376
375377var x1 = u4(1);
......@@ -393,8 +395,8 @@ const Bitfields = packed struct {
393395test "native bit field understands endianness" {
394396 var all: u64 = 0x7765443322221111;
395397 var bytes: [8]u8 = undefined;
396 @memcpy(&bytes[0], @ptrCast(&u8, &all), 8);
397 var bitfields = *@ptrCast(&Bitfields, &bytes[0]);
398 @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);
399 var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;
398400
399401 assert(bitfields.f1 == 0x1111);
400402 assert(bitfields.f2 == 0x2222);
......@@ -412,9 +414,26 @@ test "align 1 field before self referential align 8 field as slice return type"
412414
413415const Expr = union(enum) {
414416 Literal: u8,
415 Question: &Expr,
417 Question: *Expr,
416418};
417419
418420fn alloc(comptime T: type) []T {
419421 return []T{};
420422}
423
424test "call method with mutable reference to struct with no fields" {
425 const S = struct {
426 fn doC(s: *const this) bool {
427 return true;
428 }
429 fn do(s: *this) bool {
430 return true;
431 }
432 };
433
434 var s = S{};
435 assert(S.doC(&s));
436 assert(s.doC());
437 assert(S.do(&s));
438 assert(s.do());
439}
test/cases/struct_contains_null_ptr_itself.zig+2-3
......@@ -2,13 +2,13 @@ const std = @import("std");
22const assert = std.debug.assert;
33
44test "struct contains null pointer which contains original struct" {
5 var x: ?&NodeLineComment = null;
5 var x: ?*NodeLineComment = null;
66 assert(x == null);
77}
88
99pub const Node = struct {
1010 id: Id,
11 comment: ?&NodeLineComment,
11 comment: ?*NodeLineComment,
1212
1313 pub const Id = enum {
1414 Root,
......@@ -19,4 +19,3 @@ pub const Node = struct {
1919pub const NodeLineComment = struct {
2020 base: Node,
2121};
22
test/cases/struct_contains_slice_of_itself.zig+7-7
......@@ -7,30 +7,30 @@ const Node = struct {
77
88test "struct contains slice of itself" {
99 var other_nodes = []Node{
10 Node {
10 Node{
1111 .payload = 31,
1212 .children = []Node{},
1313 },
14 Node {
14 Node{
1515 .payload = 32,
1616 .children = []Node{},
1717 },
1818 };
19 var nodes = []Node {
20 Node {
19 var nodes = []Node{
20 Node{
2121 .payload = 1,
2222 .children = []Node{},
2323 },
24 Node {
24 Node{
2525 .payload = 2,
2626 .children = []Node{},
2727 },
28 Node {
28 Node{
2929 .payload = 3,
3030 .children = other_nodes[0..],
3131 },
3232 };
33 const root = Node {
33 const root = Node{
3434 .payload = 1234,
3535 .children = nodes[0..],
3636 };
test/cases/switch.zig+15-18
......@@ -6,7 +6,7 @@ test "switch with numbers" {
66
77fn testSwitchWithNumbers(x: u32) void {
88 const result = switch (x) {
9 1, 2, 3, 4 ... 8 => false,
9 1, 2, 3, 4...8 => false,
1010 13 => true,
1111 else => false,
1212 };
......@@ -22,9 +22,9 @@ test "switch with all ranges" {
2222
2323fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
2424 return switch (x) {
25 0 ... 100 => 1,
26 101 ... 200 => 2,
27 201 ... 300 => 3,
25 0...100 => 1,
26 101...200 => 2,
27 201...300 => 3,
2828 else => y,
2929 };
3030}
......@@ -61,7 +61,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {
6161 }
6262}
6363
64
6564test "switch statement" {
6665 nonConstSwitch(SwitchStatmentFoo.C);
6766}
......@@ -81,19 +80,18 @@ const SwitchStatmentFoo = enum {
8180 D,
8281};
8382
84
8583test "switch prong with variable" {
86 switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13});
87 switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0});
88 switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}});
84 switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
85 switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
86 switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
8987}
9088const SwitchProngWithVarEnum = union(enum) {
9189 One: i32,
9290 Two: f32,
9391 Meh: void,
9492};
95fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) void {
96 switch(*a) {
93fn switchProngWithVarFn(a: *const SwitchProngWithVarEnum) void {
94 switch (a.*) {
9795 SwitchProngWithVarEnum.One => |x| {
9896 assert(x == 13);
9997 },
......@@ -112,9 +110,9 @@ test "switch on enum using pointer capture" {
112110}
113111
114112fn testSwitchEnumPtrCapture() void {
115 var value = SwitchProngWithVarEnum { .One = 1234 };
113 var value = SwitchProngWithVarEnum{ .One = 1234 };
116114 switch (value) {
117 SwitchProngWithVarEnum.One => |*x| *x += 1,
115 SwitchProngWithVarEnum.One => |*x| x.* += 1,
118116 else => unreachable,
119117 }
120118 switch (value) {
......@@ -135,14 +133,13 @@ fn returnsFive() i32 {
135133 return 5;
136134}
137135
138
139136const Number = union(enum) {
140137 One: u64,
141138 Two: u8,
142139 Three: f32,
143140};
144141
145const number = Number { .Three = 1.23 };
142const number = Number{ .Three = 1.23 };
146143
147144fn returnsFalse() bool {
148145 switch (number) {
......@@ -196,11 +193,11 @@ fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
196193
197194fn testSwitchHandleAllCasesRange(x: u8) u8 {
198195 return switch (x) {
199 0 ... 100 => u8(0),
200 101 ... 200 => 1,
196 0...100 => u8(0),
197 101...200 => 1,
201198 201, 203 => 2,
202199 202 => 4,
203 204 ... 255 => 3,
200 204...255 => 3,
204201 };
205202}
206203
test/cases/switch_prong_err_enum.zig+4-2
......@@ -14,14 +14,16 @@ const FormValue = union(enum) {
1414
1515fn doThing(form_id: u64) error!FormValue {
1616 return switch (form_id) {
17 17 => FormValue { .Address = try readOnce() },
17 17 => FormValue{ .Address = try readOnce() },
1818 else => error.InvalidDebugInfo,
1919 };
2020}
2121
2222test "switch prong returns error enum" {
2323 switch (doThing(17) catch unreachable) {
24 FormValue.Address => |payload| { assert(payload == 1); },
24 FormValue.Address => |payload| {
25 assert(payload == 1);
26 },
2527 else => unreachable,
2628 }
2729 assert(read_count == 1);
test/cases/switch_prong_implicit_cast.zig+2-2
......@@ -7,8 +7,8 @@ const FormValue = union(enum) {
77
88fn foo(id: u64) !FormValue {
99 return switch (id) {
10 2 => FormValue { .Two = true },
11 1 => FormValue { .One = {} },
10 2 => FormValue{ .Two = true },
11 1 => FormValue{ .One = {} },
1212 else => return error.Whatever,
1313 };
1414}
test/cases/syntax.zig+1-7
......@@ -1,12 +1,11 @@
11// Test trailing comma syntax
2// zig fmt: off
23
34const struct_trailing_comma = struct { x: i32, y: i32, };
45const struct_no_comma = struct { x: i32, y: i32 };
5const struct_no_comma_void_type = struct { x: i32, y };
66const struct_fn_no_comma = struct { fn m() void {} y: i32 };
77
88const enum_no_comma = enum { A, B };
9const enum_no_comma_type = enum { A, B: i32 };
109
1110fn container_init() void {
1211 const S = struct { x: i32, y: i32 };
......@@ -36,16 +35,11 @@ fn switch_prongs(x: i32) void {
3635
3736const fn_no_comma = fn(i32, i32)void;
3837const fn_trailing_comma = fn(i32, i32,)void;
39const fn_vararg_trailing_comma = fn(i32, i32, ...,)void;
4038
4139fn fn_calls() void {
4240 fn add(x: i32, y: i32,) i32 { x + y };
4341 _ = add(1, 2);
4442 _ = add(1, 2,);
45
46 fn swallow(x: ...,) void {};
47 _ = swallow(1,2,3,);
48 _ = swallow();
4943}
5044
5145fn asm_lists() void {
test/cases/this.zig+2-2
......@@ -8,7 +8,7 @@ fn Point(comptime T: type) type {
88 x: T,
99 y: T,
1010
11 fn addOne(self: &Self) void {
11 fn addOne(self: *Self) void {
1212 self.x += 1;
1313 self.y += 1;
1414 }
......@@ -29,7 +29,7 @@ test "this refer to module call private fn" {
2929}
3030
3131test "this refer to container" {
32 var pt = Point(i32) {
32 var pt = Point(i32){
3333 .x = 12,
3434 .y = 34,
3535 };
test/cases/try.zig+1-4
......@@ -3,13 +3,10 @@ const assert = @import("std").debug.assert;
33test "try on error union" {
44 tryOnErrorUnionImpl();
55 comptime tryOnErrorUnionImpl();
6
76}
87
98fn tryOnErrorUnionImpl() void {
10 const x = if (returnsTen()) |val|
11 val + 1
12 else |err| switch (err) {
9 const x = if (returnsTen()) |val| val + 1 else |err| switch (err) {
1310 error.ItBroke, error.NoMem => 1,
1411 error.CrappedOut => i32(2),
1512 else => unreachable,
test/cases/type_info.zig created+259
......@@ -0,0 +1,259 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
3const TypeInfo = @import("builtin").TypeInfo;
4const TypeId = @import("builtin").TypeId;
5
6test "type info: tag type, void info" {
7 testBasic();
8 comptime testBasic();
9}
10
11fn testBasic() void {
12 assert(@TagType(TypeInfo) == TypeId);
13 const void_info = @typeInfo(void);
14 assert(TypeId(void_info) == TypeId.Void);
15 assert(void_info.Void == {});
16}
17
18test "type info: integer, floating point type info" {
19 testIntFloat();
20 comptime testIntFloat();
21}
22
23fn testIntFloat() void {
24 const u8_info = @typeInfo(u8);
25 assert(TypeId(u8_info) == TypeId.Int);
26 assert(!u8_info.Int.is_signed);
27 assert(u8_info.Int.bits == 8);
28
29 const f64_info = @typeInfo(f64);
30 assert(TypeId(f64_info) == TypeId.Float);
31 assert(f64_info.Float.bits == 64);
32}
33
34test "type info: pointer type info" {
35 testPointer();
36 comptime testPointer();
37}
38
39fn testPointer() void {
40 const u32_ptr_info = @typeInfo(*u32);
41 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
42 assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
43 assert(u32_ptr_info.Pointer.is_const == false);
44 assert(u32_ptr_info.Pointer.is_volatile == false);
45 assert(u32_ptr_info.Pointer.alignment == @alignOf(u32));
46 assert(u32_ptr_info.Pointer.child == u32);
47}
48
49test "type info: unknown length pointer type info" {
50 testUnknownLenPtr();
51 comptime testUnknownLenPtr();
52}
53
54fn testUnknownLenPtr() void {
55 const u32_ptr_info = @typeInfo([*]const volatile f64);
56 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
57 assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
58 assert(u32_ptr_info.Pointer.is_const == true);
59 assert(u32_ptr_info.Pointer.is_volatile == true);
60 assert(u32_ptr_info.Pointer.alignment == @alignOf(f64));
61 assert(u32_ptr_info.Pointer.child == f64);
62}
63
64test "type info: slice type info" {
65 testSlice();
66 comptime testSlice();
67}
68
69fn testSlice() void {
70 const u32_slice_info = @typeInfo([]u32);
71 assert(TypeId(u32_slice_info) == TypeId.Pointer);
72 assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
73 assert(u32_slice_info.Pointer.is_const == false);
74 assert(u32_slice_info.Pointer.is_volatile == false);
75 assert(u32_slice_info.Pointer.alignment == 4);
76 assert(u32_slice_info.Pointer.child == u32);
77}
78
79test "type info: array type info" {
80 testArray();
81 comptime testArray();
82}
83
84fn testArray() void {
85 const arr_info = @typeInfo([42]bool);
86 assert(TypeId(arr_info) == TypeId.Array);
87 assert(arr_info.Array.len == 42);
88 assert(arr_info.Array.child == bool);
89}
90
91test "type info: optional type info" {
92 testOptional();
93 comptime testOptional();
94}
95
96fn testOptional() void {
97 const null_info = @typeInfo(?void);
98 assert(TypeId(null_info) == TypeId.Optional);
99 assert(null_info.Optional.child == void);
100}
101
102test "type info: promise info" {
103 testPromise();
104 comptime testPromise();
105}
106
107fn testPromise() void {
108 const null_promise_info = @typeInfo(promise);
109 assert(TypeId(null_promise_info) == TypeId.Promise);
110 assert(null_promise_info.Promise.child == null);
111
112 const promise_info = @typeInfo(promise->usize);
113 assert(TypeId(promise_info) == TypeId.Promise);
114 assert(promise_info.Promise.child.? == usize);
115}
116
117test "type info: error set, error union info" {
118 testErrorSet();
119 comptime testErrorSet();
120}
121
122fn testErrorSet() void {
123 const TestErrorSet = error{
124 First,
125 Second,
126 Third,
127 };
128
129 const error_set_info = @typeInfo(TestErrorSet);
130 assert(TypeId(error_set_info) == TypeId.ErrorSet);
131 assert(error_set_info.ErrorSet.errors.len == 3);
132 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
133 assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
134
135 const error_union_info = @typeInfo(TestErrorSet!usize);
136 assert(TypeId(error_union_info) == TypeId.ErrorUnion);
137 assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
138 assert(error_union_info.ErrorUnion.payload == usize);
139}
140
141test "type info: enum info" {
142 testEnum();
143 comptime testEnum();
144}
145
146fn testEnum() void {
147 const Os = @import("builtin").Os;
148
149 const os_info = @typeInfo(Os);
150 assert(TypeId(os_info) == TypeId.Enum);
151 assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
152 assert(os_info.Enum.fields.len == 32);
153 assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
154 assert(os_info.Enum.fields[10].value == 10);
155 assert(os_info.Enum.tag_type == u5);
156 assert(os_info.Enum.defs.len == 0);
157}
158
159test "type info: union info" {
160 testUnion();
161 comptime testUnion();
162}
163
164fn testUnion() void {
165 const typeinfo_info = @typeInfo(TypeInfo);
166 assert(TypeId(typeinfo_info) == TypeId.Union);
167 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
168 assert(typeinfo_info.Union.tag_type.? == TypeId);
169 assert(typeinfo_info.Union.fields.len == 25);
170 assert(typeinfo_info.Union.fields[4].enum_field != null);
171 assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
172 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
173 assert(typeinfo_info.Union.defs.len == 20);
174
175 const TestNoTagUnion = union {
176 Foo: void,
177 Bar: u32,
178 };
179
180 const notag_union_info = @typeInfo(TestNoTagUnion);
181 assert(TypeId(notag_union_info) == TypeId.Union);
182 assert(notag_union_info.Union.tag_type == null);
183 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
184 assert(notag_union_info.Union.fields.len == 2);
185 assert(notag_union_info.Union.fields[0].enum_field == null);
186 assert(notag_union_info.Union.fields[1].field_type == u32);
187
188 const TestExternUnion = extern union {
189 foo: *c_void,
190 };
191
192 const extern_union_info = @typeInfo(TestExternUnion);
193 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
194 assert(extern_union_info.Union.tag_type == null);
195 assert(extern_union_info.Union.fields[0].enum_field == null);
196 assert(extern_union_info.Union.fields[0].field_type == *c_void);
197}
198
199test "type info: struct info" {
200 testStruct();
201 comptime testStruct();
202}
203
204fn testStruct() void {
205 const struct_info = @typeInfo(TestStruct);
206 assert(TypeId(struct_info) == TypeId.Struct);
207 assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
208 assert(struct_info.Struct.fields.len == 3);
209 assert(struct_info.Struct.fields[1].offset == null);
210 assert(struct_info.Struct.fields[2].field_type == *TestStruct);
211 assert(struct_info.Struct.defs.len == 2);
212 assert(struct_info.Struct.defs[0].is_pub);
213 assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
214 assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
215 assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
216 assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
217}
218
219const TestStruct = packed struct {
220 const Self = this;
221
222 fieldA: usize,
223 fieldB: void,
224 fieldC: *Self,
225
226 pub fn foo(self: *const Self) void {}
227};
228
229test "type info: function type info" {
230 testFunction();
231 comptime testFunction();
232}
233
234fn testFunction() void {
235 const fn_info = @typeInfo(@typeOf(foo));
236 assert(TypeId(fn_info) == TypeId.Fn);
237 assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
238 assert(fn_info.Fn.is_generic);
239 assert(fn_info.Fn.args.len == 2);
240 assert(fn_info.Fn.is_var_args);
241 assert(fn_info.Fn.return_type == null);
242 assert(fn_info.Fn.async_allocator_type == null);
243
244 const test_instance: TestStruct = undefined;
245 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
246 assert(TypeId(bound_fn_info) == TypeId.BoundFn);
247 assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
248}
249
250fn foo(comptime a: usize, b: bool, args: ...) usize {
251 return 0;
252}
253
254test "typeInfo with comptime parameter in struct fn def" {
255 const S = struct {
256 pub fn func(comptime x: f32) void {}
257 };
258 comptime var info = @typeInfo(S);
259}
test/cases/undefined.zig+4-4
......@@ -27,12 +27,12 @@ test "init static array to undefined" {
2727const Foo = struct {
2828 x: i32,
2929
30 fn setFooXMethod(foo: &Foo) void {
30 fn setFooXMethod(foo: *Foo) void {
3131 foo.x = 3;
3232 }
3333};
3434
35fn setFooX(foo: &Foo) void {
35fn setFooX(foo: *Foo) void {
3636 foo.x = 2;
3737}
3838
......@@ -63,6 +63,6 @@ test "assign undefined to struct with method" {
6363}
6464
6565test "type name of undefined" {
66 const x = undefined;
67 assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
66 const x = undefined;
67 assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
6868}
test/cases/underscore.zig created+28
......@@ -0,0 +1,28 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4test "ignore lval with underscore" {
5 _ = false;
6}
7
8test "ignore lval with underscore (for loop)" {
9 for ([]void{}) |_, i| {
10 for ([]void{}) |_, j| {
11 break;
12 }
13 break;
14 }
15}
16
17test "ignore lval with underscore (while loop)" {
18 while (optionalReturnError()) |_| {
19 while (optionalReturnError()) |_| {
20 break;
21 } else |_| { }
22 break;
23 } else |_| { }
24}
25
26fn optionalReturnError() !?u32 {
27 return error.optionalReturnError;
28}
test/cases/union.zig+94-45
......@@ -10,41 +10,54 @@ const Agg = struct {
1010 val2: Value,
1111};
1212
13const v1 = Value { .Int = 1234 };
14const v2 = Value { .Array = []u8{3} ** 9 };
13const v1 = Value{ .Int = 1234 };
14const v2 = Value{ .Array = []u8{3} ** 9 };
1515
16const err = (error!Agg)(Agg {
16const err = (error!Agg)(Agg{
1717 .val1 = v1,
1818 .val2 = v2,
1919});
2020
21const array = []Value { v1, v2, v1, v2};
22
21const array = []Value{
22 v1,
23 v2,
24 v1,
25 v2,
26};
2327
2428test "unions embedded in aggregate types" {
2529 switch (array[1]) {
2630 Value.Array => |arr| assert(arr[4] == 3),
2731 else => unreachable,
2832 }
29 switch((err catch unreachable).val1) {
33 switch ((err catch unreachable).val1) {
3034 Value.Int => |x| assert(x == 1234),
3135 else => unreachable,
3236 }
3337}
3438
35
3639const Foo = union {
3740 float: f64,
3841 int: i32,
3942};
4043
4144test "basic unions" {
42 var foo = Foo { .int = 1 };
45 var foo = Foo{ .int = 1 };
4346 assert(foo.int == 1);
44 foo = Foo {.float = 12.34};
47 foo = Foo{ .float = 12.34 };
4548 assert(foo.float == 12.34);
4649}
4750
51test "comptime union field access" {
52 comptime {
53 var foo = Foo{ .int = 0 };
54 assert(foo.int == 0);
55
56 foo = Foo{ .float = 42.42 };
57 assert(foo.float == 42.42);
58 }
59}
60
4861test "init union with runtime value" {
4962 var foo: Foo = undefined;
5063
......@@ -55,12 +68,12 @@ test "init union with runtime value" {
5568 assert(foo.int == 42);
5669}
5770
58fn setFloat(foo: &Foo, x: f64) void {
59 *foo = Foo { .float = x };
71fn setFloat(foo: *Foo, x: f64) void {
72 foo.* = Foo{ .float = x };
6073}
6174
62fn setInt(foo: &Foo, x: i32) void {
63 *foo = Foo { .int = x };
75fn setInt(foo: *Foo, x: i32) void {
76 foo.* = Foo{ .int = x };
6477}
6578
6679const FooExtern = extern union {
......@@ -69,13 +82,12 @@ const FooExtern = extern union {
6982};
7083
7184test "basic extern unions" {
72 var foo = FooExtern { .int = 1 };
85 var foo = FooExtern{ .int = 1 };
7386 assert(foo.int == 1);
7487 foo.float = 12.34;
7588 assert(foo.float == 12.34);
7689}
7790
78
7991const Letter = enum {
8092 A,
8193 B,
......@@ -93,12 +105,12 @@ test "union with specified enum tag" {
93105}
94106
95107fn doTest() void {
96 assert(bar(Payload {.A = 1234}) == -10);
108 assert(bar(Payload{ .A = 1234 }) == -10);
97109}
98110
99fn bar(value: &const Payload) i32 {
100 assert(Letter(*value) == Letter.A);
101 return switch (*value) {
111fn bar(value: *const Payload) i32 {
112 assert(Letter(value.*) == Letter.A);
113 return switch (value.*) {
102114 Payload.A => |x| return x - 1244,
103115 Payload.B => |x| if (x == 12.34) i32(20) else 21,
104116 Payload.C => |x| if (x) i32(30) else 31,
......@@ -114,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {
114126test "simple union(enum(u32))" {
115127 var x = MultipleChoice.C;
116128 assert(x == MultipleChoice.C);
117 assert(u32(@TagType(MultipleChoice)(x)) == 60);
129 assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
118130}
119131
120132const MultipleChoice2 = union(enum(u32)) {
......@@ -131,13 +143,13 @@ const MultipleChoice2 = union(enum(u32)) {
131143
132144test "union(enum(u32)) with specified and unspecified tag values" {
133145 comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
134 testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123});
135 comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} );
146 testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
147 comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
136148}
137149
138fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void {
139 assert(u32(@TagType(MultipleChoice2)(*x)) == 60);
140 assert(1123 == switch (*x) {
150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: *const MultipleChoice2) void {
151 assert(@enumToInt(@TagType(MultipleChoice2)(x.*)) == 60);
152 assert(1123 == switch (x.*) {
141153 MultipleChoice2.A => 1,
142154 MultipleChoice2.B => 2,
143155 MultipleChoice2.C => |v| i32(1000) + v,
......@@ -150,18 +162,17 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void
150162 });
151163}
152164
153
154165const ExternPtrOrInt = extern union {
155 ptr: &u8,
156 int: u64
166 ptr: *u8,
167 int: u64,
157168};
158169test "extern union size" {
159170 comptime assert(@sizeOf(ExternPtrOrInt) == 8);
160171}
161172
162173const PackedPtrOrInt = packed union {
163 ptr: &u8,
164 int: u64
174 ptr: *u8,
175 int: u64,
165176};
166177test "extern union size" {
167178 comptime assert(@sizeOf(PackedPtrOrInt) == 8);
......@@ -174,8 +185,16 @@ test "union with only 1 field which is void should be zero bits" {
174185 comptime assert(@sizeOf(ZeroBits) == 0);
175186}
176187
177const TheTag = enum {A, B, C};
178const TheUnion = union(TheTag) { A: i32, B: i32, C: i32 };
188const TheTag = enum {
189 A,
190 B,
191 C,
192};
193const TheUnion = union(TheTag) {
194 A: i32,
195 B: i32,
196 C: i32,
197};
179198test "union field access gives the enum values" {
180199 assert(TheUnion.A == TheTag.A);
181200 assert(TheUnion.B == TheTag.B);
......@@ -183,20 +202,28 @@ test "union field access gives the enum values" {
183202}
184203
185204test "cast union to tag type of union" {
186 testCastUnionToTagType(TheUnion {.B = 1234});
187 comptime testCastUnionToTagType(TheUnion {.B = 1234});
205 testCastUnionToTagType(TheUnion{ .B = 1234 });
206 comptime testCastUnionToTagType(TheUnion{ .B = 1234 });
188207}
189208
190fn testCastUnionToTagType(x: &const TheUnion) void {
191 assert(TheTag(*x) == TheTag.B);
209fn testCastUnionToTagType(x: *const TheUnion) void {
210 assert(TheTag(x.*) == TheTag.B);
192211}
193212
194213test "cast tag type of union to union" {
195214 var x: Value2 = Letter2.B;
196215 assert(Letter2(x) == Letter2.B);
197216}
198const Letter2 = enum { A, B, C };
199const Value2 = union(Letter2) { A: i32, B, C, };
217const Letter2 = enum {
218 A,
219 B,
220 C,
221};
222const Value2 = union(Letter2) {
223 A: i32,
224 B,
225 C,
226};
200227
201228test "implicit cast union to its tag type" {
202229 var x: Value2 = Letter2.B;
......@@ -216,20 +243,17 @@ const TheUnion2 = union(enum) {
216243 Item2: i32,
217244};
218245
219fn assertIsTheUnion2Item1(value: &const TheUnion2) void {
220 assert(*value == TheUnion2.Item1);
246fn assertIsTheUnion2Item1(value: *const TheUnion2) void {
247 assert(value.* == TheUnion2.Item1);
221248}
222249
223
224250pub const PackThis = union(enum) {
225251 Invalid: bool,
226252 StringLiteral: u2,
227253};
228254
229255test "constant packed union" {
230 testConstPackedUnion([]PackThis {
231 PackThis { .StringLiteral = 1 },
232 });
256 testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }});
233257}
234258
235259fn testConstPackedUnion(expected_tokens: []const PackThis) void {
......@@ -242,7 +266,7 @@ test "switch on union with only 1 field" {
242266 switch (r) {
243267 PartialInst.Compiled => {
244268 var z: PartialInstWithPayload = undefined;
245 z = PartialInstWithPayload { .Compiled = 1234 };
269 z = PartialInstWithPayload{ .Compiled = 1234 };
246270 switch (z) {
247271 PartialInstWithPayload.Compiled => |x| {
248272 assert(x == 1234);
......@@ -262,3 +286,28 @@ const PartialInstWithPayload = union(enum) {
262286 Compiled: i32,
263287};
264288
289test "access a member of tagged union with conflicting enum tag name" {
290 const Bar = union(enum) {
291 A: A,
292 B: B,
293
294 const A = u8;
295 const B = void;
296 };
297
298 comptime assert(Bar.A == u8);
299}
300
301test "tagged union initialization with runtime void" {
302 assert(testTaggedUnionInit({}));
303}
304
305const TaggedUnionWithAVoid = union(enum) {
306 A,
307 B: i32,
308};
309
310fn testTaggedUnionInit(x: var) bool {
311 const y = TaggedUnionWithAVoid{ .A = x };
312 return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A;
313}
test/cases/var_args.zig+16-21
......@@ -2,9 +2,12 @@ const assert = @import("std").debug.assert;
22
33fn add(args: ...) i32 {
44 var sum = i32(0);
5 {comptime var i: usize = 0; inline while (i < args.len) : (i += 1) {
6 sum += args[i];
7 }}
5 {
6 comptime var i: usize = 0;
7 inline while (i < args.len) : (i += 1) {
8 sum += args[i];
9 }
10 }
811 return sum;
912}
1013
......@@ -55,31 +58,23 @@ fn extraFn(extra: u32, args: ...) usize {
5558 return args.len;
5659}
5760
61const foos = []fn (...) bool{
62 foo1,
63 foo2,
64};
5865
59const foos = []fn(...) bool { foo1, foo2 };
60
61fn foo1(args: ...) bool { return true; }
62fn foo2(args: ...) bool { return false; }
66fn foo1(args: ...) bool {
67 return true;
68}
69fn foo2(args: ...) bool {
70 return false;
71}
6372
6473test "array of var args functions" {
6574 assert(foos[0]());
6675 assert(!foos[1]());
6776}
6877
69
70test "pass array and slice of same array to var args should have same pointers" {
71 const array = "hi";
72 const slice: []const u8 = array;
73 return assertSlicePtrsEql(array, slice);
74}
75
76fn assertSlicePtrsEql(args: ...) void {
77 const s1 = ([]const u8)(args[0]);
78 const s2 = args[1];
79 assert(s1.ptr == s2.ptr);
80}
81
82
8378test "pass zero length array to var args param" {
8479 doNothingWithFirstArg("");
8580}
test/cases/void.zig+13-1
......@@ -8,7 +8,7 @@ const Foo = struct {
88
99test "compare void with void compile time known" {
1010 comptime {
11 const foo = Foo {
11 const foo = Foo{
1212 .a = {},
1313 .b = 1,
1414 .c = {},
......@@ -16,3 +16,15 @@ test "compare void with void compile time known" {
1616 assert(foo.a == {});
1717 }
1818}
19
20test "iterate over a void slice" {
21 var j: usize = 0;
22 for (times(10)) |_, i| {
23 assert(i == j);
24 j += 1;
25 }
26}
27
28fn times(n: usize) []const void {
29 return ([*]void)(undefined)[0..n];
30}
test/cases/while.zig+46-29
......@@ -1,7 +1,7 @@
11const assert = @import("std").debug.assert;
22
33test "while loop" {
4 var i : i32 = 0;
4 var i: i32 = 0;
55 while (i < 4) {
66 i += 1;
77 }
......@@ -35,7 +35,7 @@ test "continue and break" {
3535}
3636var continue_and_break_counter: i32 = 0;
3737fn runContinueAndBreakTest() void {
38 var i : i32 = 0;
38 var i: i32 = 0;
3939 while (true) {
4040 continue_and_break_counter += 2;
4141 i += 1;
......@@ -58,10 +58,13 @@ fn returnWithImplicitCastFromWhileLoopTest() error!void {
5858
5959test "while with continue expression" {
6060 var sum: i32 = 0;
61 {var i: i32 = 0; while (i < 10) : (i += 1) {
62 if (i == 5) continue;
63 sum += i;
64 }}
61 {
62 var i: i32 = 0;
63 while (i < 10) : (i += 1) {
64 if (i == 5) continue;
65 sum += i;
66 }
67 }
6568 assert(sum == 40);
6669}
6770
......@@ -78,7 +81,7 @@ test "while with else" {
7881 assert(got_else == 1);
7982}
8083
81test "while with nullable as condition" {
84test "while with optional as condition" {
8285 numbers_left = 10;
8386 var sum: i32 = 0;
8487 while (getNumberOrNull()) |value| {
......@@ -87,7 +90,7 @@ test "while with nullable as condition" {
8790 assert(sum == 45);
8891}
8992
90test "while with nullable as condition with else" {
93test "while with optional as condition with else" {
9194 numbers_left = 10;
9295 var sum: i32 = 0;
9396 var got_else: i32 = 0;
......@@ -117,61 +120,63 @@ test "while with error union condition" {
117120
118121var numbers_left: i32 = undefined;
119122fn getNumberOrErr() error!i32 {
120 return if (numbers_left == 0)
121 error.OutOfNumbers
122 else x: {
123 return if (numbers_left == 0) error.OutOfNumbers else x: {
123124 numbers_left -= 1;
124125 break :x numbers_left;
125126 };
126127}
127128fn getNumberOrNull() ?i32 {
128 return if (numbers_left == 0)
129 null
130 else x: {
129 return if (numbers_left == 0) null else x: {
131130 numbers_left -= 1;
132131 break :x numbers_left;
133132 };
134133}
135134
136test "while on nullable with else result follow else prong" {
135test "while on optional with else result follow else prong" {
137136 const result = while (returnNull()) |value| {
138137 break value;
139 } else i32(2);
138 } else
139 i32(2);
140140 assert(result == 2);
141141}
142142
143test "while on nullable with else result follow break prong" {
144 const result = while (returnMaybe(10)) |value| {
143test "while on optional with else result follow break prong" {
144 const result = while (returnOptional(10)) |value| {
145145 break value;
146 } else i32(2);
146 } else
147 i32(2);
147148 assert(result == 10);
148149}
149150
150151test "while on error union with else result follow else prong" {
151152 const result = while (returnError()) |value| {
152153 break value;
153 } else |err| i32(2);
154 } else |err|
155 i32(2);
154156 assert(result == 2);
155157}
156158
157159test "while on error union with else result follow break prong" {
158160 const result = while (returnSuccess(10)) |value| {
159161 break value;
160 } else |err| i32(2);
162 } else |err|
163 i32(2);
161164 assert(result == 10);
162165}
163166
164167test "while on bool with else result follow else prong" {
165168 const result = while (returnFalse()) {
166169 break i32(10);
167 } else i32(2);
170 } else
171 i32(2);
168172 assert(result == 2);
169173}
170174
171175test "while on bool with else result follow break prong" {
172176 const result = while (returnTrue()) {
173177 break i32(10);
174 } else i32(2);
178 } else
179 i32(2);
175180 assert(result == 10);
176181}
177182
......@@ -202,9 +207,21 @@ fn testContinueOuter() void {
202207 }
203208}
204209
205fn returnNull() ?i32 { return null; }
206fn returnMaybe(x: i32) ?i32 { return x; }
207fn returnError() error!i32 { return error.YouWantedAnError; }
208fn returnSuccess(x: i32) error!i32 { return x; }
209fn returnFalse() bool { return false; }
210fn returnTrue() bool { return true; }
210fn returnNull() ?i32 {
211 return null;
212}
213fn returnOptional(x: i32) ?i32 {
214 return x;
215}
216fn returnError() error!i32 {
217 return error.YouWantedAnError;
218}
219fn returnSuccess(x: i32) error!i32 {
220 return x;
221}
222fn returnFalse() bool {
223 return false;
224}
225fn returnTrue() bool {
226 return true;
227}
test/cases/widening.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
4
5test "integer widening" {
6 var a: u8 = 250;
7 var b: u16 = a;
8 var c: u32 = b;
9 var d: u64 = c;
10 var e: u64 = d;
11 var f: u128 = e;
12 assert(f == a);
13}
14
15test "implicit unsigned integer to signed integer" {
16 var a: u8 = 250;
17 var b: i16 = a;
18 assert(b == 250);
19}
20
21test "float widening" {
22 var a: f16 = 12.34;
23 var b: f32 = a;
24 var c: f64 = b;
25 var d: f128 = c;
26 assert(d == a);
27}
test/compare_output.zig+19-19
......@@ -3,10 +3,10 @@ const std = @import("std");
33const os = std.os;
44const tests = @import("tests.zig");
55
6pub fn addCases(cases: &tests.CompareOutputContext) void {
6pub fn addCases(cases: *tests.CompareOutputContext) void {
77 cases.addC("hello world with libc",
88 \\const c = @cImport(@cInclude("stdio.h"));
9 \\export fn main(argc: c_int, argv: &&u8) c_int {
9 \\export fn main(argc: c_int, argv: [*][*]u8) c_int {
1010 \\ _ = c.puts(c"Hello, world!");
1111 \\ return 0;
1212 \\}
......@@ -131,7 +131,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
131131 \\const is_windows = builtin.os == builtin.Os.windows;
132132 \\const c = @cImport({
133133 \\ if (is_windows) {
134 \\ // See https://github.com/zig-lang/zig/issues/515
134 \\ // See https://github.com/ziglang/zig/issues/515
135135 \\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
136136 \\ @cInclude("io.h");
137137 \\ @cInclude("fcntl.h");
......@@ -139,7 +139,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
139139 \\ @cInclude("stdio.h");
140140 \\});
141141 \\
142 \\export fn main(argc: c_int, argv: &&u8) c_int {
142 \\export fn main(argc: c_int, argv: [*][*]u8) c_int {
143143 \\ if (is_windows) {
144144 \\ // we want actual \n, not \r\n
145145 \\ _ = c._setmode(1, c._O_BINARY);
......@@ -284,12 +284,12 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
284284 cases.addC("expose function pointer to C land",
285285 \\const c = @cImport(@cInclude("stdlib.h"));
286286 \\
287 \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) c_int {
288 \\ const a_int = @ptrCast(&align(1) const i32, a ?? unreachable);
289 \\ const b_int = @ptrCast(&align(1) const i32, b ?? unreachable);
290 \\ if (*a_int < *b_int) {
287 \\export fn compare_fn(a: ?*const c_void, b: ?*const c_void) c_int {
288 \\ const a_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), a));
289 \\ const b_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), b));
290 \\ if (a_int.* < b_int.*) {
291291 \\ return -1;
292 \\ } else if (*a_int > *b_int) {
292 \\ } else if (a_int.* > b_int.*) {
293293 \\ return 1;
294294 \\ } else {
295295 \\ return 0;
......@@ -297,9 +297,9 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
297297 \\}
298298 \\
299299 \\export fn main() c_int {
300 \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
300 \\ var array = []u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
301301 \\
302 \\ c.qsort(@ptrCast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
302 \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);
303303 \\
304304 \\ for (array) |item, i| {
305305 \\ if (item != i) {
......@@ -316,7 +316,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
316316 \\const is_windows = builtin.os == builtin.Os.windows;
317317 \\const c = @cImport({
318318 \\ if (is_windows) {
319 \\ // See https://github.com/zig-lang/zig/issues/515
319 \\ // See https://github.com/ziglang/zig/issues/515
320320 \\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
321321 \\ @cInclude("io.h");
322322 \\ @cInclude("fcntl.h");
......@@ -324,15 +324,15 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
324324 \\ @cInclude("stdio.h");
325325 \\});
326326 \\
327 \\export fn main(argc: c_int, argv: &&u8) c_int {
327 \\export fn main(argc: c_int, argv: [*][*]u8) c_int {
328328 \\ if (is_windows) {
329329 \\ // we want actual \n, not \r\n
330330 \\ _ = c._setmode(1, c._O_BINARY);
331331 \\ }
332332 \\ const small: f32 = 3.25;
333333 \\ const x: f64 = small;
334 \\ const y = i32(x);
335 \\ const z = f64(y);
334 \\ const y = @floatToInt(i32, x);
335 \\ const z = @intToFloat(f64, y);
336336 \\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4));
337337 \\ return 0;
338338 \\}
......@@ -344,13 +344,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
344344 \\const Foo = struct {
345345 \\ field1: Bar,
346346 \\
347 \\ fn method(a: &const Foo) bool { return true; }
347 \\ fn method(a: *const Foo) bool { return true; }
348348 \\};
349349 \\
350350 \\const Bar = struct {
351351 \\ field2: i32,
352352 \\
353 \\ fn method(b: &const Bar) bool { return true; }
353 \\ fn method(b: *const Bar) bool { return true; }
354354 \\};
355355 \\
356356 \\pub fn main() void {
......@@ -475,7 +475,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
475475 \\
476476 );
477477
478 tc.setCommandLineArgs([][]const u8 {
478 tc.setCommandLineArgs([][]const u8{
479479 "first arg",
480480 "'a' 'b' \\",
481481 "bare",
......@@ -516,7 +516,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
516516 \\
517517 );
518518
519 tc.setCommandLineArgs([][]const u8 {
519 tc.setCommandLineArgs([][]const u8{
520520 "first arg",
521521 "'a' 'b' \\",
522522 "bare",
test/compile_errors.zig+2537-889
......@@ -1,25 +1,484 @@
11const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("assign inline fn to non-comptime var",
3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "@handle() called outside of function definition",
6 \\var handle_undef: promise = undefined;
7 \\var handle_dummy: promise = @handle();
8 \\export fn entry() bool {
9 \\ return handle_undef == handle_dummy;
10 \\}
11 ,
12 ".tmp_source.zig:2:29: error: @handle() called outside of function definition",
13 );
14
15 cases.add(
16 "@handle() in non-async function",
17 \\export fn entry() bool {
18 \\ var handle_undef: promise = undefined;
19 \\ return handle_undef == @handle();
20 \\}
21 ,
22 ".tmp_source.zig:3:28: error: @handle() in non-async function",
23 );
24
25 cases.add(
26 "`_` is not a declarable symbol",
27 \\export fn f1() usize {
28 \\ var _: usize = 2;
29 \\ return _;
30 \\}
31 ,
32 ".tmp_source.zig:2:5: error: `_` is not a declarable symbol",
33 ".tmp_source.zig:3:12: error: use of undeclared identifier '_'",
34 );
35
36 cases.add(
37 "`_` should not be usable inside for",
38 \\export fn returns() void {
39 \\ for ([]void{}) |_, i| {
40 \\ for ([]void{}) |_, j| {
41 \\ return _;
42 \\ }
43 \\ }
44 \\}
45 ,
46 ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",
47 );
48
49 cases.add(
50 "`_` should not be usable inside while",
51 \\export fn returns() void {
52 \\ while (optionalReturn()) |_| {
53 \\ while (optionalReturn()) |_| {
54 \\ return _;
55 \\ }
56 \\ }
57 \\}
58 \\fn optionalReturn() ?u32 {
59 \\ return 1;
60 \\}
61 ,
62 ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",
63 );
64
65 cases.add(
66 "`_` should not be usable inside while else",
67 \\export fn returns() void {
68 \\ while (optionalReturnError()) |_| {
69 \\ while (optionalReturnError()) |_| {
70 \\ return;
71 \\ } else |_| {
72 \\ if (_ == error.optionalReturnError) return;
73 \\ }
74 \\ }
75 \\}
76 \\fn optionalReturnError() !?u32 {
77 \\ return error.optionalReturnError;
78 \\}
79 ,
80 ".tmp_source.zig:6:17: error: use of undeclared identifier '_'",
81 );
82
83 cases.add(
84 "while loop body expression ignored",
85 \\fn returns() usize {
86 \\ return 2;
87 \\}
88 \\export fn f1() void {
89 \\ while (true) returns();
90 \\}
91 \\export fn f2() void {
92 \\ var x: ?i32 = null;
93 \\ while (x) |_| returns();
94 \\}
95 \\export fn f3() void {
96 \\ var x: error!i32 = error.Bad;
97 \\ while (x) |_| returns() else |_| unreachable;
98 \\}
99 ,
100 ".tmp_source.zig:5:25: error: expression value is ignored",
101 ".tmp_source.zig:9:26: error: expression value is ignored",
102 ".tmp_source.zig:13:26: error: expression value is ignored",
103 );
104
105 cases.add(
106 "missing parameter name of generic function",
107 \\fn dump(var) void {}
108 \\export fn entry() void {
109 \\ var a: u8 = 9;
110 \\ dump(a);
111 \\}
112 ,
113 ".tmp_source.zig:1:9: error: missing parameter name",
114 );
115
116 cases.add(
117 "non-inline for loop on a type that requires comptime",
118 \\const Foo = struct {
119 \\ name: []const u8,
120 \\ T: type,
121 \\};
122 \\export fn entry() void {
123 \\ const xx: [2]Foo = undefined;
124 \\ for (xx) |f| {}
125 \\}
126 ,
127 ".tmp_source.zig:7:15: error: variable of type 'Foo' must be const or comptime",
128 );
129
130 cases.add(
131 "generic fn as parameter without comptime keyword",
132 \\fn f(_: fn (var) void) void {}
133 \\fn g(_: var) void {}
134 \\export fn entry() void {
135 \\ f(g);
136 \\}
137 ,
138 ".tmp_source.zig:1:9: error: parameter of type 'fn(var)var' must be declared comptime",
139 );
140
141 cases.add(
142 "optional pointer to void in extern struct",
143 \\comptime {
144 \\ _ = @IntType(false, @maxValue(u32) + 1);
145 \\}
146 ,
147 ".tmp_source.zig:2:40: error: integer value 4294967296 cannot be implicitly casted to type 'u32'",
148 );
149
150 cases.add(
151 "optional pointer to void in extern struct",
152 \\const Foo = extern struct {
153 \\ x: ?*const void,
154 \\};
155 \\const Bar = extern struct {
156 \\ foo: Foo,
157 \\ y: i32,
158 \\};
159 \\export fn entry(bar: *Bar) void {}
160 ,
161 ".tmp_source.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
162 );
163
164 cases.add(
165 "use of comptime-known undefined function value",
166 \\const Cmd = struct {
167 \\ exec: fn () void,
168 \\};
169 \\export fn entry() void {
170 \\ const command = Cmd{ .exec = undefined };
171 \\ command.exec();
172 \\}
173 ,
174 ".tmp_source.zig:6:12: error: use of undefined value",
175 );
176
177 cases.add(
178 "use of comptime-known undefined function value",
179 \\const Cmd = struct {
180 \\ exec: fn () void,
181 \\};
182 \\export fn entry() void {
183 \\ const command = Cmd{ .exec = undefined };
184 \\ command.exec();
185 \\}
186 ,
187 ".tmp_source.zig:6:12: error: use of undefined value",
188 );
189
190 cases.add(
191 "bad @alignCast at comptime",
192 \\comptime {
193 \\ const ptr = @intToPtr(*i32, 0x1);
194 \\ const aligned = @alignCast(4, ptr);
195 \\}
196 ,
197 ".tmp_source.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",
198 );
199
200 cases.add(
201 "@ptrToInt on *void",
202 \\export fn entry() bool {
203 \\ return @ptrToInt(&{}) == @ptrToInt(&{});
204 \\}
205 ,
206 ".tmp_source.zig:2:23: error: pointer to size 0 type has no address",
207 );
208
209 cases.add(
210 "@popCount - non-integer",
211 \\export fn entry(x: f32) u32 {
212 \\ return @popCount(x);
213 \\}
214 ,
215 ".tmp_source.zig:2:22: error: expected integer type, found 'f32'",
216 );
217
218 cases.add(
219 "@popCount - negative comptime_int",
220 \\comptime {
221 \\ _ = @popCount(-1);
222 \\}
223 ,
224 ".tmp_source.zig:2:9: error: @popCount on negative comptime_int value -1",
225 );
226
227 cases.addCase(x: {
228 const tc = cases.create(
229 "wrong same named struct",
230 \\const a = @import("a.zig");
231 \\const b = @import("b.zig");
232 \\
233 \\export fn entry() void {
234 \\ var a1: a.Foo = undefined;
235 \\ bar(&a1);
236 \\}
237 \\
238 \\fn bar(x: *b.Foo) void {}
239 ,
240 ".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'",
241 ".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'",
242 "a.zig:1:17: note: Foo declared here",
243 "b.zig:1:17: note: Foo declared here",
244 );
245
246 tc.addSourceFile("a.zig",
247 \\pub const Foo = struct {
248 \\ x: i32,
249 \\};
250 );
251
252 tc.addSourceFile("b.zig",
253 \\pub const Foo = struct {
254 \\ z: f64,
255 \\};
256 );
257
258 break :x tc;
259 });
260
261 cases.add(
262 "enum field value references enum",
263 \\pub const Foo = extern enum {
264 \\ A = Foo.B,
265 \\ C = D,
266 \\};
267 \\export fn entry() void {
268 \\ var s: Foo = Foo.E;
269 \\}
270 ,
271 ".tmp_source.zig:1:17: error: 'Foo' depends on itself",
272 );
273
274 cases.add(
275 "@floatToInt comptime safety",
276 \\comptime {
277 \\ _ = @floatToInt(i8, f32(-129.1));
278 \\}
279 \\comptime {
280 \\ _ = @floatToInt(u8, f32(-1.1));
281 \\}
282 \\comptime {
283 \\ _ = @floatToInt(u8, f32(256.1));
284 \\}
285 ,
286 ".tmp_source.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",
287 ".tmp_source.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",
288 ".tmp_source.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
289 );
290
291 cases.add(
292 "use c_void as return type of fn ptr",
293 \\export fn entry() void {
294 \\ const a: fn () c_void = undefined;
295 \\}
296 ,
297 ".tmp_source.zig:2:20: error: return type cannot be opaque",
298 );
299
300 cases.add(
301 "non int passed to @intToFloat",
302 \\export fn entry() void {
303 \\ const x = @intToFloat(f32, 1.1);
304 \\}
305 ,
306 ".tmp_source.zig:2:32: error: expected int type, found 'comptime_float'",
307 );
308
309 cases.add(
310 "use implicit casts to assign null to non-nullable pointer",
311 \\export fn entry() void {
312 \\ var x: i32 = 1234;
313 \\ var p: *i32 = &x;
314 \\ var pp: *?*i32 = &p;
315 \\ pp.* = null;
316 \\ var y = p.*;
317 \\}
318 ,
319 ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'",
320 );
321
322 cases.add(
323 "attempted implicit cast from T to [*]const T",
324 \\export fn entry() void {
325 \\ const x: [*]const bool = true;
326 \\}
327 ,
328 ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'",
329 );
330
331 cases.add(
332 "dereference unknown length pointer",
333 \\export fn entry(x: [*]i32) i32 {
334 \\ return x.*;
335 \\}
336 ,
337 ".tmp_source.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
338 );
339
340 cases.add(
341 "field access of unknown length pointer",
342 \\const Foo = extern struct {
343 \\ a: i32,
344 \\};
345 \\
346 \\export fn entry(foo: [*]Foo) void {
347 \\ foo.a += 1;
348 \\}
349 ,
350 ".tmp_source.zig:6:8: error: type '[*]Foo' does not support field access",
351 );
352
353 cases.add(
354 "unknown length pointer to opaque",
355 \\export const T = [*]@OpaqueType();
356 ,
357 ".tmp_source.zig:1:18: error: unknown-length pointer to opaque",
358 );
359
360 cases.add(
361 "error when evaluating return type",
362 \\const Foo = struct {
363 \\ map: i32(i32),
364 \\
365 \\ fn init() Foo {
366 \\ return undefined;
367 \\ }
368 \\};
369 \\export fn entry() void {
370 \\ var rule_set = try Foo.init();
371 \\}
372 ,
373 ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'",
374 );
375
376 cases.add(
377 "slicing single-item pointer",
378 \\export fn entry(ptr: *i32) void {
379 \\ const slice = ptr[0..2];
380 \\}
381 ,
382 ".tmp_source.zig:2:22: error: slice of single-item pointer",
383 );
384
385 cases.add(
386 "indexing single-item pointer",
387 \\export fn entry(ptr: *i32) i32 {
388 \\ return ptr[1];
389 \\}
390 ,
391 ".tmp_source.zig:2:15: error: index of single-item pointer",
392 );
393
394 cases.add(
395 "nested error set mismatch",
396 \\const NextError = error{NextError};
397 \\const OtherError = error{OutOfMemory};
398 \\
399 \\export fn entry() void {
400 \\ const a: ?NextError!i32 = foo();
401 \\}
402 \\
403 \\fn foo() ?OtherError!i32 {
404 \\ return null;
405 \\}
406 ,
407 ".tmp_source.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",
408 ".tmp_source.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",
409 ".tmp_source.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",
410 ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
411 );
412
413 cases.add(
414 "invalid deref on switch target",
415 \\comptime {
416 \\ var tile = Tile.Empty;
417 \\ switch (tile.*) {
418 \\ Tile.Empty => {},
419 \\ Tile.Filled => {},
420 \\ }
421 \\}
422 \\const Tile = enum {
423 \\ Empty,
424 \\ Filled,
425 \\};
426 ,
427 ".tmp_source.zig:3:17: error: invalid deref on switch target",
428 );
429
430 cases.add(
431 "invalid field access in comptime",
432 \\comptime { var x = doesnt_exist.whatever; }
433 ,
434 ".tmp_source.zig:1:20: error: use of undeclared identifier 'doesnt_exist'",
435 );
436
437 cases.add(
438 "suspend inside suspend block",
439 \\const std = @import("std",);
440 \\
441 \\export fn entry() void {
442 \\ var buf: [500]u8 = undefined;
443 \\ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
444 \\ const p = (async<a> foo()) catch unreachable;
445 \\ cancel p;
446 \\}
447 \\
448 \\async fn foo() void {
449 \\ suspend {
450 \\ suspend {
451 \\ }
452 \\ }
453 \\}
454 ,
455 ".tmp_source.zig:12:9: error: cannot suspend inside suspend block",
456 ".tmp_source.zig:11:5: note: other suspend block here",
457 );
458
459 cases.add(
460 "assign inline fn to non-comptime var",
5461 \\export fn entry() void {
6462 \\ var a = b;
7463 \\}
8464 \\inline fn b() void { }
9465 ,
10466 ".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",
11 ".tmp_source.zig:4:8: note: declared here");
467 ".tmp_source.zig:4:8: note: declared here",
468 );
12469
13 cases.add("wrong type passed to @panic",
470 cases.add(
471 "wrong type passed to @panic",
14472 \\export fn entry() void {
15473 \\ var e = error.Foo;
16474 \\ @panic(e);
17475 \\}
18476 ,
19 ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'");
477 ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'",
478 );
20479
21
22 cases.add("@tagName used on union with no associated enum tag",
480 cases.add(
481 "@tagName used on union with no associated enum tag",
23482 \\const FloatInt = extern union {
24483 \\ Float: f32,
25484 \\ Int: i32,
......@@ -30,10 +489,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30489 \\}
31490 ,
32491 ".tmp_source.zig:7:19: error: union has no associated enum",
33 ".tmp_source.zig:1:18: note: declared here");
492 ".tmp_source.zig:1:18: note: declared here",
493 );
34494
35 cases.add("returning error from void async function",
36 \\const std = @import("std");
495 cases.add(
496 "returning error from void async function",
497 \\const std = @import("std",);
37498 \\export fn entry() void {
38499 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;
39500 \\}
......@@ -41,32 +502,40 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
41502 \\ return error.ShouldBeCompileError;
42503 \\}
43504 ,
44 ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'");
505 ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
506 );
45507
46 cases.add("var not allowed in structs",
508 cases.add(
509 "var not allowed in structs",
47510 \\export fn entry() void {
48511 \\ var s = (struct{v: var}){.v=i32(10)};
49512 \\}
50513 ,
51 ".tmp_source.zig:2:23: error: invalid token: 'var'");
514 ".tmp_source.zig:2:23: error: invalid token: 'var'",
515 );
52516
53 cases.add("@ptrCast discards const qualifier",
517 cases.add(
518 "@ptrCast discards const qualifier",
54519 \\export fn entry() void {
55520 \\ const x: i32 = 1234;
56 \\ const y = @ptrCast(&i32, &x);
521 \\ const y = @ptrCast(*i32, &x);
57522 \\}
58523 ,
59 ".tmp_source.zig:3:15: error: cast discards const qualifier");
524 ".tmp_source.zig:3:15: error: cast discards const qualifier",
525 );
60526
61 cases.add("comptime slice of undefined pointer non-zero len",
527 cases.add(
528 "comptime slice of undefined pointer non-zero len",
62529 \\export fn entry() void {
63 \\ const slice = (&i32)(undefined)[0..1];
530 \\ const slice = ([*]i32)(undefined)[0..1];
64531 \\}
65532 ,
66 ".tmp_source.zig:2:36: error: non-zero length slice of undefined pointer");
533 ".tmp_source.zig:2:38: error: non-zero length slice of undefined pointer",
534 );
67535
68 cases.add("type checking function pointers",
69 \\fn a(b: fn (&const u8) void) void {
536 cases.add(
537 "type checking function pointers",
538 \\fn a(b: fn (*const u8) void) void {
70539 \\ b('a');
71540 \\}
72541 \\fn c(d: u8) void {
......@@ -76,9 +545,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
76545 \\ a(c);
77546 \\}
78547 ,
79 ".tmp_source.zig:8:7: error: expected type 'fn(&const u8) void', found 'fn(u8) void'");
548 ".tmp_source.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'",
549 );
80550
81 cases.add("no else prong on switch on global error set",
551 cases.add(
552 "no else prong on switch on global error set",
82553 \\export fn entry() void {
83554 \\ foo(error.A);
84555 \\}
......@@ -88,18 +559,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
88559 \\ }
89560 \\}
90561 ,
91 ".tmp_source.zig:5:5: error: else prong required when switching on type 'error'");
562 ".tmp_source.zig:5:5: error: else prong required when switching on type 'error'",
563 );
92564
93 cases.add("inferred error set with no returned error",
565 cases.add(
566 "inferred error set with no returned error",
94567 \\export fn entry() void {
95568 \\ foo() catch unreachable;
96569 \\}
97570 \\fn foo() !void {
98571 \\}
99572 ,
100 ".tmp_source.zig:4:11: error: function with inferred error set must return at least one possible error");
573 ".tmp_source.zig:4:11: error: function with inferred error set must return at least one possible error",
574 );
101575
102 cases.add("error not handled in switch",
576 cases.add(
577 "error not handled in switch",
103578 \\export fn entry() void {
104579 \\ foo(452) catch |err| switch (err) {
105580 \\ error.Foo => {},
......@@ -115,9 +590,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
115590 \\}
116591 ,
117592 ".tmp_source.zig:2:26: error: error.Baz not handled in switch",
118 ".tmp_source.zig:2:26: error: error.Bar not handled in switch");
593 ".tmp_source.zig:2:26: error: error.Bar not handled in switch",
594 );
119595
120 cases.add("duplicate error in switch",
596 cases.add(
597 "duplicate error in switch",
121598 \\export fn entry() void {
122599 \\ foo(452) catch |err| switch (err) {
123600 \\ error.Foo => {},
......@@ -135,9 +612,25 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
135612 \\}
136613 ,
137614 ".tmp_source.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
138 ".tmp_source.zig:3:14: note: other value is here");
615 ".tmp_source.zig:3:14: note: other value is here",
616 );
617
618 cases.add("invalid cast from integral type to enum",
619 \\const E = enum(usize) { One, Two };
620 \\
621 \\export fn entry() void {
622 \\ foo(1);
623 \\}
624 \\
625 \\fn foo(x: usize) void {
626 \\ switch (x) {
627 \\ E.One => {},
628 \\ }
629 \\}
630 , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'");
139631
140 cases.add("range operator in switch used on error set",
632 cases.add(
633 "range operator in switch used on error set",
141634 \\export fn entry() void {
142635 \\ try foo(452) catch |err| switch (err) {
143636 \\ error.A ... error.B => {},
......@@ -152,31 +645,39 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
152645 \\ }
153646 \\}
154647 ,
155 ".tmp_source.zig:3:17: error: operator not allowed for errors");
648 ".tmp_source.zig:3:17: error: operator not allowed for errors",
649 );
156650
157 cases.add("inferring error set of function pointer",
651 cases.add(
652 "inferring error set of function pointer",
158653 \\comptime {
159654 \\ const z: ?fn()!void = null;
160655 \\}
161656 ,
162 ".tmp_source.zig:2:15: error: inferring error set of return type valid only for function definitions");
657 ".tmp_source.zig:2:15: error: inferring error set of return type valid only for function definitions",
658 );
163659
164 cases.add("access non-existent member of error set",
660 cases.add(
661 "access non-existent member of error set",
165662 \\const Foo = error{A};
166663 \\comptime {
167664 \\ const z = Foo.Bar;
168665 \\}
169666 ,
170 ".tmp_source.zig:3:18: error: no error named 'Bar' in 'Foo'");
667 ".tmp_source.zig:3:18: error: no error named 'Bar' in 'Foo'",
668 );
171669
172 cases.add("error union operator with non error set LHS",
670 cases.add(
671 "error union operator with non error set LHS",
173672 \\comptime {
174673 \\ const z = i32!i32;
175674 \\}
176675 ,
177 ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'");
676 ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'",
677 );
178678
179 cases.add("error equality but sets have no common members",
679 cases.add(
680 "error equality but sets have no common members",
180681 \\const Set1 = error{A, C};
181682 \\const Set2 = error{B, D};
182683 \\export fn entry() void {
......@@ -188,26 +689,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
188689 \\ }
189690 \\}
190691 ,
191 ".tmp_source.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors");
692 ".tmp_source.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors",
693 );
192694
193 cases.add("only equality binary operator allowed for error sets",
695 cases.add(
696 "only equality binary operator allowed for error sets",
194697 \\comptime {
195698 \\ const z = error.A > error.B;
196699 \\}
197700 ,
198 ".tmp_source.zig:2:23: error: operator not allowed for errors");
701 ".tmp_source.zig:2:23: error: operator not allowed for errors",
702 );
199703
200 cases.add("explicit error set cast known at comptime violates error sets",
704 cases.add(
705 "explicit error set cast known at comptime violates error sets",
201706 \\const Set1 = error {A, B};
202707 \\const Set2 = error {A, C};
203708 \\comptime {
204709 \\ var x = Set1.B;
205 \\ var y = Set2(x);
710 \\ var y = @errSetCast(Set2, x);
206711 \\}
207712 ,
208 ".tmp_source.zig:5:17: error: error.B not a member of error set 'Set2'");
713 ".tmp_source.zig:5:13: error: error.B not a member of error set 'Set2'",
714 );
209715
210 cases.add("cast error union of global error set to error union of smaller error set",
716 cases.add(
717 "cast error union of global error set to error union of smaller error set",
211718 \\const SmallErrorSet = error{A};
212719 \\export fn entry() void {
213720 \\ var x: SmallErrorSet!i32 = foo();
......@@ -216,10 +723,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
216723 \\ return error.B;
217724 \\}
218725 ,
219 ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32', found 'error!i32'",
220 ".tmp_source.zig:3:35: note: unable to cast global error set into smaller set");
726 ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'error!i32'",
727 ".tmp_source.zig:3:35: note: error set 'error' cannot cast into error set 'SmallErrorSet'",
728 ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set",
729 );
221730
222 cases.add("cast global error set to error set",
731 cases.add(
732 "cast global error set to error set",
223733 \\const SmallErrorSet = error{A};
224734 \\export fn entry() void {
225735 \\ var x: SmallErrorSet = foo();
......@@ -228,10 +738,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
228738 \\ return error.B;
229739 \\}
230740 ,
231 ".tmp_source.zig:3:31: error: expected 'SmallErrorSet', found 'error'",
232 ".tmp_source.zig:3:31: note: unable to cast global error set into smaller set");
741 ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'error'",
742 ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set",
743 );
233744
234 cases.add("recursive inferred error set",
745 cases.add(
746 "recursive inferred error set",
235747 \\export fn entry() void {
236748 \\ foo() catch unreachable;
237749 \\}
......@@ -239,9 +751,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
239751 \\ try foo();
240752 \\}
241753 ,
242 ".tmp_source.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet");
754 ".tmp_source.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet",
755 );
243756
244 cases.add("implicit cast of error set not a subset",
757 cases.add(
758 "implicit cast of error set not a subset",
245759 \\const Set1 = error{A, B};
246760 \\const Set2 = error{A, C};
247761 \\export fn entry() void {
......@@ -251,36 +765,53 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
251765 \\ var x: Set2 = set1;
252766 \\}
253767 ,
254 ".tmp_source.zig:7:19: error: expected 'Set2', found 'Set1'",
255 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set");
768 ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'",
769 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set",
770 );
256771
257 cases.add("int to err global invalid number",
258 \\const Set1 = error{A, B};
772 cases.add(
773 "int to err global invalid number",
774 \\const Set1 = error{
775 \\ A,
776 \\ B,
777 \\};
259778 \\comptime {
260 \\ var x: usize = 3;
261 \\ var y = error(x);
779 \\ var x: u16 = 3;
780 \\ var y = @intToError(x);
262781 \\}
263782 ,
264 ".tmp_source.zig:4:18: error: integer value 3 represents no error");
783 ".tmp_source.zig:7:13: error: integer value 3 represents no error",
784 );
265785
266 cases.add("int to err non global invalid number",
267 \\const Set1 = error{A, B};
268 \\const Set2 = error{A, C};
786 cases.add(
787 "int to err non global invalid number",
788 \\const Set1 = error{
789 \\ A,
790 \\ B,
791 \\};
792 \\const Set2 = error{
793 \\ A,
794 \\ C,
795 \\};
269796 \\comptime {
270 \\ var x = usize(Set1.B);
271 \\ var y = Set2(x);
797 \\ var x = @errorToInt(Set1.B);
798 \\ var y = @errSetCast(Set2, @intToError(x));
272799 \\}
273800 ,
274 ".tmp_source.zig:5:17: error: integer value 2 represents no error in 'Set2'");
801 ".tmp_source.zig:11:13: error: error.B not a member of error set 'Set2'",
802 );
275803
276 cases.add("@memberCount of error",
804 cases.add(
805 "@memberCount of error",
277806 \\comptime {
278807 \\ _ = @memberCount(error);
279808 \\}
280809 ,
281 ".tmp_source.zig:2:9: error: global error set member count not available at comptime");
810 ".tmp_source.zig:2:9: error: global error set member count not available at comptime",
811 );
282812
283 cases.add("duplicate error value in error set",
813 cases.add(
814 "duplicate error value in error set",
284815 \\const Foo = error {
285816 \\ Bar,
286817 \\ Bar,
......@@ -290,22 +821,30 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
290821 \\}
291822 ,
292823 ".tmp_source.zig:3:5: error: duplicate error: 'Bar'",
293 ".tmp_source.zig:2:5: note: other error here");
824 ".tmp_source.zig:2:5: note: other error here",
825 );
294826
295 cases.add("cast negative integer literal to usize",
827 cases.add(
828 "cast negative integer literal to usize",
296829 \\export fn entry() void {
297830 \\ const x = usize(-10);
298831 \\}
299 , ".tmp_source.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'");
832 ,
833 ".tmp_source.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'",
834 );
300835
301 cases.add("use invalid number literal as array index",
836 cases.add(
837 "use invalid number literal as array index",
302838 \\var v = 25;
303839 \\export fn entry() void {
304840 \\ var arr: [v]u8 = undefined;
305841 \\}
306 , ".tmp_source.zig:1:1: error: unable to infer variable type");
842 ,
843 ".tmp_source.zig:1:1: error: unable to infer variable type",
844 );
307845
308 cases.add("duplicate struct field",
846 cases.add(
847 "duplicate struct field",
309848 \\const Foo = struct {
310849 \\ Bar: i32,
311850 \\ Bar: usize,
......@@ -315,9 +854,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
315854 \\}
316855 ,
317856 ".tmp_source.zig:3:5: error: duplicate struct field: 'Bar'",
318 ".tmp_source.zig:2:5: note: other field here");
857 ".tmp_source.zig:2:5: note: other field here",
858 );
319859
320 cases.add("duplicate union field",
860 cases.add(
861 "duplicate union field",
321862 \\const Foo = union {
322863 \\ Bar: i32,
323864 \\ Bar: usize,
......@@ -327,9 +868,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
327868 \\}
328869 ,
329870 ".tmp_source.zig:3:5: error: duplicate union field: 'Bar'",
330 ".tmp_source.zig:2:5: note: other field here");
871 ".tmp_source.zig:2:5: note: other field here",
872 );
331873
332 cases.add("duplicate enum field",
874 cases.add(
875 "duplicate enum field",
333876 \\const Foo = enum {
334877 \\ Bar,
335878 \\ Bar,
......@@ -340,77 +883,108 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
340883 \\}
341884 ,
342885 ".tmp_source.zig:3:5: error: duplicate enum field: 'Bar'",
343 ".tmp_source.zig:2:5: note: other field here");
886 ".tmp_source.zig:2:5: note: other field here",
887 );
344888
345 cases.add("calling function with naked calling convention",
889 cases.add(
890 "calling function with naked calling convention",
346891 \\export fn entry() void {
347892 \\ foo();
348893 \\}
349894 \\nakedcc fn foo() void { }
350895 ,
351896 ".tmp_source.zig:2:5: error: unable to call function with naked calling convention",
352 ".tmp_source.zig:4:9: note: declared here");
897 ".tmp_source.zig:4:9: note: declared here",
898 );
353899
354 cases.add("function with invalid return type",
900 cases.add(
901 "function with invalid return type",
355902 \\export fn foo() boid {}
356 , ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'");
903 ,
904 ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'",
905 );
357906
358 cases.add("function with non-extern non-packed enum parameter",
907 cases.add(
908 "function with non-extern non-packed enum parameter",
359909 \\const Foo = enum { A, B, C };
360910 \\export fn entry(foo: Foo) void { }
361 , ".tmp_source.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'");
911 ,
912 ".tmp_source.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
913 );
362914
363 cases.add("function with non-extern non-packed struct parameter",
915 cases.add(
916 "function with non-extern non-packed struct parameter",
364917 \\const Foo = struct {
365918 \\ A: i32,
366919 \\ B: f32,
367920 \\ C: bool,
368921 \\};
369922 \\export fn entry(foo: Foo) void { }
370 , ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'");
923 ,
924 ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
925 );
371926
372 cases.add("function with non-extern non-packed union parameter",
927 cases.add(
928 "function with non-extern non-packed union parameter",
373929 \\const Foo = union {
374930 \\ A: i32,
375931 \\ B: f32,
376932 \\ C: bool,
377933 \\};
378934 \\export fn entry(foo: Foo) void { }
379 , ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'");
935 ,
936 ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
937 );
380938
381 cases.add("switch on enum with 1 field with no prongs",
939 cases.add(
940 "switch on enum with 1 field with no prongs",
382941 \\const Foo = enum { M };
383942 \\
384943 \\export fn entry() void {
385944 \\ var f = Foo.M;
386945 \\ switch (f) {}
387946 \\}
388 , ".tmp_source.zig:5:5: error: enumeration value 'Foo.M' not handled in switch");
947 ,
948 ".tmp_source.zig:5:5: error: enumeration value 'Foo.M' not handled in switch",
949 );
389950
390 cases.add("shift by negative comptime integer",
951 cases.add(
952 "shift by negative comptime integer",
391953 \\comptime {
392954 \\ var a = 1 >> -1;
393955 \\}
394 , ".tmp_source.zig:2:18: error: shift by negative value -1");
956 ,
957 ".tmp_source.zig:2:18: error: shift by negative value -1",
958 );
395959
396 cases.add("@panic called at compile time",
960 cases.add(
961 "@panic called at compile time",
397962 \\export fn entry() void {
398963 \\ comptime {
399 \\ @panic("aoeu");
964 \\ @panic("aoeu",);
400965 \\ }
401966 \\}
402 , ".tmp_source.zig:3:9: error: encountered @panic at compile-time");
967 ,
968 ".tmp_source.zig:3:9: error: encountered @panic at compile-time",
969 );
403970
404 cases.add("wrong return type for main",
971 cases.add(
972 "wrong return type for main",
405973 \\pub fn main() f32 { }
406 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
974 ,
975 "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'",
976 );
407977
408 cases.add("double ?? on main return value",
978 cases.add(
979 "double ?? on main return value",
409980 \\pub fn main() ??void {
410981 \\}
411 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
982 ,
983 "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'",
984 );
412985
413 cases.add("bad identifier in function with struct defined inside function which references local const",
986 cases.add(
987 "bad identifier in function with struct defined inside function which references local const",
414988 \\export fn entry() void {
415989 \\ const BlockKind = u32;
416990 \\
......@@ -420,9 +994,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
420994 \\
421995 \\ bogus;
422996 \\}
423 , ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'");
997 ,
998 ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'",
999 );
4241000
425 cases.add("labeled break not found",
1001 cases.add(
1002 "labeled break not found",
4261003 \\export fn entry() void {
4271004 \\ blah: while (true) {
4281005 \\ while (true) {
......@@ -430,9 +1007,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
4301007 \\ }
4311008 \\ }
4321009 \\}
433 , ".tmp_source.zig:4:13: error: label not found: 'outer'");
1010 ,
1011 ".tmp_source.zig:4:13: error: label not found: 'outer'",
1012 );
4341013
435 cases.add("labeled continue not found",
1014 cases.add(
1015 "labeled continue not found",
4361016 \\export fn entry() void {
4371017 \\ var i: usize = 0;
4381018 \\ blah: while (i < 10) : (i += 1) {
......@@ -441,400 +1021,554 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
4411021 \\ }
4421022 \\ }
4431023 \\}
444 , ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'");
1024 ,
1025 ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'",
1026 );
4451027
446 cases.add("attempt to use 0 bit type in extern fn",
447 \\extern fn foo(ptr: extern fn(&void) void) void;
1028 cases.add(
1029 "attempt to use 0 bit type in extern fn",
1030 \\extern fn foo(ptr: extern fn(*void) void) void;
4481031 \\
4491032 \\export fn entry() void {
4501033 \\ foo(bar);
4511034 \\}
4521035 \\
453 \\extern fn bar(x: &void) void { }
454 , ".tmp_source.zig:7:18: error: parameter of type '&void' has 0 bits; not allowed in function with calling convention 'ccc'");
1036 \\extern fn bar(x: *void) void { }
1037 ,
1038 ".tmp_source.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
1039 );
4551040
456 cases.add("implicit semicolon - block statement",
1041 cases.add(
1042 "implicit semicolon - block statement",
4571043 \\export fn entry() void {
4581044 \\ {}
4591045 \\ var good = {};
4601046 \\ ({})
4611047 \\ var bad = {};
4621048 \\}
463 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1049 ,
1050 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1051 );
4641052
465 cases.add("implicit semicolon - block expr",
1053 cases.add(
1054 "implicit semicolon - block expr",
4661055 \\export fn entry() void {
4671056 \\ _ = {};
4681057 \\ var good = {};
4691058 \\ _ = {}
4701059 \\ var bad = {};
4711060 \\}
472 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1061 ,
1062 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1063 );
4731064
474 cases.add("implicit semicolon - comptime statement",
1065 cases.add(
1066 "implicit semicolon - comptime statement",
4751067 \\export fn entry() void {
4761068 \\ comptime {}
4771069 \\ var good = {};
4781070 \\ comptime ({})
4791071 \\ var bad = {};
4801072 \\}
481 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1073 ,
1074 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1075 );
4821076
483 cases.add("implicit semicolon - comptime expression",
1077 cases.add(
1078 "implicit semicolon - comptime expression",
4841079 \\export fn entry() void {
4851080 \\ _ = comptime {};
4861081 \\ var good = {};
4871082 \\ _ = comptime {}
4881083 \\ var bad = {};
4891084 \\}
490 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1085 ,
1086 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1087 );
4911088
492 cases.add("implicit semicolon - defer",
1089 cases.add(
1090 "implicit semicolon - defer",
4931091 \\export fn entry() void {
4941092 \\ defer {}
4951093 \\ var good = {};
4961094 \\ defer ({})
4971095 \\ var bad = {};
4981096 \\}
499 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1097 ,
1098 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1099 );
5001100
501 cases.add("implicit semicolon - if statement",
1101 cases.add(
1102 "implicit semicolon - if statement",
5021103 \\export fn entry() void {
5031104 \\ if(true) {}
5041105 \\ var good = {};
5051106 \\ if(true) ({})
5061107 \\ var bad = {};
5071108 \\}
508 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1109 ,
1110 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1111 );
5091112
510 cases.add("implicit semicolon - if expression",
1113 cases.add(
1114 "implicit semicolon - if expression",
5111115 \\export fn entry() void {
5121116 \\ _ = if(true) {};
5131117 \\ var good = {};
5141118 \\ _ = if(true) {}
5151119 \\ var bad = {};
5161120 \\}
517 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1121 ,
1122 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1123 );
5181124
519 cases.add("implicit semicolon - if-else statement",
1125 cases.add(
1126 "implicit semicolon - if-else statement",
5201127 \\export fn entry() void {
5211128 \\ if(true) {} else {}
5221129 \\ var good = {};
5231130 \\ if(true) ({}) else ({})
5241131 \\ var bad = {};
5251132 \\}
526 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1133 ,
1134 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1135 );
5271136
528 cases.add("implicit semicolon - if-else expression",
1137 cases.add(
1138 "implicit semicolon - if-else expression",
5291139 \\export fn entry() void {
5301140 \\ _ = if(true) {} else {};
5311141 \\ var good = {};
5321142 \\ _ = if(true) {} else {}
5331143 \\ var bad = {};
5341144 \\}
535 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1145 ,
1146 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1147 );
5361148
537 cases.add("implicit semicolon - if-else-if statement",
1149 cases.add(
1150 "implicit semicolon - if-else-if statement",
5381151 \\export fn entry() void {
5391152 \\ if(true) {} else if(true) {}
5401153 \\ var good = {};
5411154 \\ if(true) ({}) else if(true) ({})
5421155 \\ var bad = {};
5431156 \\}
544 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1157 ,
1158 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1159 );
5451160
546 cases.add("implicit semicolon - if-else-if expression",
1161 cases.add(
1162 "implicit semicolon - if-else-if expression",
5471163 \\export fn entry() void {
5481164 \\ _ = if(true) {} else if(true) {};
5491165 \\ var good = {};
5501166 \\ _ = if(true) {} else if(true) {}
5511167 \\ var bad = {};
5521168 \\}
553 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1169 ,
1170 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1171 );
5541172
555 cases.add("implicit semicolon - if-else-if-else statement",
1173 cases.add(
1174 "implicit semicolon - if-else-if-else statement",
5561175 \\export fn entry() void {
5571176 \\ if(true) {} else if(true) {} else {}
5581177 \\ var good = {};
5591178 \\ if(true) ({}) else if(true) ({}) else ({})
5601179 \\ var bad = {};
5611180 \\}
562 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1181 ,
1182 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1183 );
5631184
564 cases.add("implicit semicolon - if-else-if-else expression",
1185 cases.add(
1186 "implicit semicolon - if-else-if-else expression",
5651187 \\export fn entry() void {
5661188 \\ _ = if(true) {} else if(true) {} else {};
5671189 \\ var good = {};
5681190 \\ _ = if(true) {} else if(true) {} else {}
5691191 \\ var bad = {};
5701192 \\}
571 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1193 ,
1194 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1195 );
5721196
573 cases.add("implicit semicolon - test statement",
1197 cases.add(
1198 "implicit semicolon - test statement",
5741199 \\export fn entry() void {
5751200 \\ if (foo()) |_| {}
5761201 \\ var good = {};
5771202 \\ if (foo()) |_| ({})
5781203 \\ var bad = {};
5791204 \\}
580 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1205 ,
1206 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1207 );
5811208
582 cases.add("implicit semicolon - test expression",
1209 cases.add(
1210 "implicit semicolon - test expression",
5831211 \\export fn entry() void {
5841212 \\ _ = if (foo()) |_| {};
5851213 \\ var good = {};
5861214 \\ _ = if (foo()) |_| {}
5871215 \\ var bad = {};
5881216 \\}
589 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1217 ,
1218 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1219 );
5901220
591 cases.add("implicit semicolon - while statement",
1221 cases.add(
1222 "implicit semicolon - while statement",
5921223 \\export fn entry() void {
5931224 \\ while(true) {}
5941225 \\ var good = {};
5951226 \\ while(true) ({})
5961227 \\ var bad = {};
5971228 \\}
598 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1229 ,
1230 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1231 );
5991232
600 cases.add("implicit semicolon - while expression",
1233 cases.add(
1234 "implicit semicolon - while expression",
6011235 \\export fn entry() void {
6021236 \\ _ = while(true) {};
6031237 \\ var good = {};
6041238 \\ _ = while(true) {}
6051239 \\ var bad = {};
6061240 \\}
607 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1241 ,
1242 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1243 );
6081244
609 cases.add("implicit semicolon - while-continue statement",
1245 cases.add(
1246 "implicit semicolon - while-continue statement",
6101247 \\export fn entry() void {
6111248 \\ while(true):({}) {}
6121249 \\ var good = {};
6131250 \\ while(true):({}) ({})
6141251 \\ var bad = {};
6151252 \\}
616 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1253 ,
1254 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1255 );
6171256
618 cases.add("implicit semicolon - while-continue expression",
1257 cases.add(
1258 "implicit semicolon - while-continue expression",
6191259 \\export fn entry() void {
6201260 \\ _ = while(true):({}) {};
6211261 \\ var good = {};
6221262 \\ _ = while(true):({}) {}
6231263 \\ var bad = {};
6241264 \\}
625 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1265 ,
1266 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1267 );
6261268
627 cases.add("implicit semicolon - for statement",
1269 cases.add(
1270 "implicit semicolon - for statement",
6281271 \\export fn entry() void {
6291272 \\ for(foo()) {}
6301273 \\ var good = {};
6311274 \\ for(foo()) ({})
6321275 \\ var bad = {};
6331276 \\}
634 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1277 ,
1278 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1279 );
6351280
636 cases.add("implicit semicolon - for expression",
1281 cases.add(
1282 "implicit semicolon - for expression",
6371283 \\export fn entry() void {
6381284 \\ _ = for(foo()) {};
6391285 \\ var good = {};
6401286 \\ _ = for(foo()) {}
6411287 \\ var bad = {};
6421288 \\}
643 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
1289 ,
1290 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
1291 );
6441292
645 cases.add("multiple function definitions",
1293 cases.add(
1294 "multiple function definitions",
6461295 \\fn a() void {}
6471296 \\fn a() void {}
6481297 \\export fn entry() void { a(); }
649 , ".tmp_source.zig:2:1: error: redefinition of 'a'");
1298 ,
1299 ".tmp_source.zig:2:1: error: redefinition of 'a'",
1300 );
6501301
651 cases.add("unreachable with return",
1302 cases.add(
1303 "unreachable with return",
6521304 \\fn a() noreturn {return;}
6531305 \\export fn entry() void { a(); }
654 , ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'");
1306 ,
1307 ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'",
1308 );
6551309
656 cases.add("control reaches end of non-void function",
1310 cases.add(
1311 "control reaches end of non-void function",
6571312 \\fn a() i32 {}
6581313 \\export fn entry() void { _ = a(); }
659 , ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'");
1314 ,
1315 ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'",
1316 );
6601317
661 cases.add("undefined function call",
1318 cases.add(
1319 "undefined function call",
6621320 \\export fn a() void {
6631321 \\ b();
6641322 \\}
665 , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'");
1323 ,
1324 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
1325 );
6661326
667 cases.add("wrong number of arguments",
1327 cases.add(
1328 "wrong number of arguments",
6681329 \\export fn a() void {
6691330 \\ b(1);
6701331 \\}
6711332 \\fn b(a: i32, b: i32, c: i32) void { }
672 , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1");
1333 ,
1334 ".tmp_source.zig:2:6: error: expected 3 arguments, found 1",
1335 );
6731336
674 cases.add("invalid type",
1337 cases.add(
1338 "invalid type",
6751339 \\fn a() bogus {}
6761340 \\export fn entry() void { _ = a(); }
677 , ".tmp_source.zig:1:8: error: use of undeclared identifier 'bogus'");
1341 ,
1342 ".tmp_source.zig:1:8: error: use of undeclared identifier 'bogus'",
1343 );
6781344
679 cases.add("pointer to noreturn",
680 \\fn a() &noreturn {}
1345 cases.add(
1346 "pointer to noreturn",
1347 \\fn a() *noreturn {}
6811348 \\export fn entry() void { _ = a(); }
682 , ".tmp_source.zig:1:9: error: pointer to noreturn not allowed");
1349 ,
1350 ".tmp_source.zig:1:8: error: pointer to noreturn not allowed",
1351 );
6831352
684 cases.add("unreachable code",
1353 cases.add(
1354 "unreachable code",
6851355 \\export fn a() void {
6861356 \\ return;
6871357 \\ b();
6881358 \\}
6891359 \\
6901360 \\fn b() void {}
691 , ".tmp_source.zig:3:5: error: unreachable code");
1361 ,
1362 ".tmp_source.zig:3:5: error: unreachable code",
1363 );
6921364
693 cases.add("bad import",
694 \\const bogus = @import("bogus-does-not-exist.zig");
1365 cases.add(
1366 "bad import",
1367 \\const bogus = @import("bogus-does-not-exist.zig",);
6951368 \\export fn entry() void { bogus.bogo(); }
696 , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'");
1369 ,
1370 ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
1371 );
6971372
698 cases.add("undeclared identifier",
1373 cases.add(
1374 "undeclared identifier",
6991375 \\export fn a() void {
7001376 \\ return
7011377 \\ b +
7021378 \\ c;
7031379 \\}
7041380 ,
705 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
706 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'");
1381 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
1382 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'",
1383 );
7071384
708 cases.add("parameter redeclaration",
1385 cases.add(
1386 "parameter redeclaration",
7091387 \\fn f(a : i32, a : i32) void {
7101388 \\}
7111389 \\export fn entry() void { f(1, 2); }
712 , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'");
1390 ,
1391 ".tmp_source.zig:1:15: error: redeclaration of variable 'a'",
1392 );
7131393
714 cases.add("local variable redeclaration",
1394 cases.add(
1395 "local variable redeclaration",
7151396 \\export fn f() void {
7161397 \\ const a : i32 = 0;
7171398 \\ const a = 0;
7181399 \\}
719 , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'");
1400 ,
1401 ".tmp_source.zig:3:5: error: redeclaration of variable 'a'",
1402 );
7201403
721 cases.add("local variable redeclares parameter",
1404 cases.add(
1405 "local variable redeclares parameter",
7221406 \\fn f(a : i32) void {
7231407 \\ const a = 0;
7241408 \\}
7251409 \\export fn entry() void { f(1); }
726 , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'");
1410 ,
1411 ".tmp_source.zig:2:5: error: redeclaration of variable 'a'",
1412 );
7271413
728 cases.add("variable has wrong type",
1414 cases.add(
1415 "variable has wrong type",
7291416 \\export fn f() i32 {
7301417 \\ const a = c"a";
7311418 \\ return a;
7321419 \\}
733 , ".tmp_source.zig:3:12: error: expected type 'i32', found '&const u8'");
1420 ,
1421 ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'",
1422 );
7341423
735 cases.add("if condition is bool, not int",
1424 cases.add(
1425 "if condition is bool, not int",
7361426 \\export fn f() void {
7371427 \\ if (0) {}
7381428 \\}
739 , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'");
1429 ,
1430 ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'",
1431 );
7401432
741 cases.add("assign unreachable",
1433 cases.add(
1434 "assign unreachable",
7421435 \\export fn f() void {
7431436 \\ const a = return;
7441437 \\}
745 , ".tmp_source.zig:2:5: error: unreachable code");
1438 ,
1439 ".tmp_source.zig:2:5: error: unreachable code",
1440 );
7461441
747 cases.add("unreachable variable",
1442 cases.add(
1443 "unreachable variable",
7481444 \\export fn f() void {
7491445 \\ const a: noreturn = {};
7501446 \\}
751 , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed");
1447 ,
1448 ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed",
1449 );
7521450
753 cases.add("unreachable parameter",
1451 cases.add(
1452 "unreachable parameter",
7541453 \\fn f(a: noreturn) void {}
7551454 \\export fn entry() void { f(); }
756 , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed");
1455 ,
1456 ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed",
1457 );
7571458
758 cases.add("bad assignment target",
1459 cases.add(
1460 "bad assignment target",
7591461 \\export fn f() void {
7601462 \\ 3 = 3;
7611463 \\}
762 , ".tmp_source.zig:2:7: error: cannot assign to constant");
1464 ,
1465 ".tmp_source.zig:2:7: error: cannot assign to constant",
1466 );
7631467
764 cases.add("assign to constant variable",
1468 cases.add(
1469 "assign to constant variable",
7651470 \\export fn f() void {
7661471 \\ const a = 3;
7671472 \\ a = 4;
7681473 \\}
769 , ".tmp_source.zig:3:7: error: cannot assign to constant");
1474 ,
1475 ".tmp_source.zig:3:7: error: cannot assign to constant",
1476 );
7701477
771 cases.add("use of undeclared identifier",
1478 cases.add(
1479 "use of undeclared identifier",
7721480 \\export fn f() void {
7731481 \\ b = 3;
7741482 \\}
775 , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'");
1483 ,
1484 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
1485 );
7761486
777 cases.add("const is a statement, not an expression",
1487 cases.add(
1488 "const is a statement, not an expression",
7781489 \\export fn f() void {
7791490 \\ (const a = 0);
7801491 \\}
781 , ".tmp_source.zig:2:6: error: invalid token: 'const'");
1492 ,
1493 ".tmp_source.zig:2:6: error: invalid token: 'const'",
1494 );
7821495
783 cases.add("array access of undeclared identifier",
1496 cases.add(
1497 "array access of undeclared identifier",
7841498 \\export fn f() void {
7851499 \\ i[i] = i[i];
7861500 \\}
787 , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
788 ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'");
1501 ,
1502 ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
1503 ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'",
1504 );
7891505
790 cases.add("array access of non array",
1506 cases.add(
1507 "array access of non array",
7911508 \\export fn f() void {
7921509 \\ var bad : bool = undefined;
7931510 \\ bad[bad] = bad[bad];
7941511 \\}
795 , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'",
796 ".tmp_source.zig:3:19: error: array access of non-array type 'bool'");
1512 ,
1513 ".tmp_source.zig:3:8: error: array access of non-array type 'bool'",
1514 ".tmp_source.zig:3:19: error: array access of non-array type 'bool'",
1515 );
7971516
798 cases.add("array access with non integer index",
1517 cases.add(
1518 "array access with non integer index",
7991519 \\export fn f() void {
8001520 \\ var array = "aoeu";
8011521 \\ var bad = false;
8021522 \\ array[bad] = array[bad];
8031523 \\}
804 , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'",
805 ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'");
1524 ,
1525 ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'",
1526 ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'",
1527 );
8061528
807 cases.add("write to const global variable",
1529 cases.add(
1530 "write to const global variable",
8081531 \\const x : i32 = 99;
8091532 \\fn f() void {
8101533 \\ x = 1;
8111534 \\}
8121535 \\export fn entry() void { f(); }
813 , ".tmp_source.zig:3:7: error: cannot assign to constant");
814
1536 ,
1537 ".tmp_source.zig:3:7: error: cannot assign to constant",
1538 );
8151539
816 cases.add("missing else clause",
1540 cases.add(
1541 "missing else clause",
8171542 \\fn f(b: bool) void {
8181543 \\ const x : i32 = if (b) h: { break :h 1; };
8191544 \\ const y = if (b) h: { break :h i32(1); };
8201545 \\}
8211546 \\export fn entry() void { f(true); }
822 , ".tmp_source.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
823 ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'");
1547 ,
1548 ".tmp_source.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
1549 ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'",
1550 );
8241551
825 cases.add("direct struct loop",
1552 cases.add(
1553 "direct struct loop",
8261554 \\const A = struct { a : A, };
8271555 \\export fn entry() usize { return @sizeOf(A); }
828 , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
1556 ,
1557 ".tmp_source.zig:1:11: error: struct 'A' contains itself",
1558 );
8291559
830 cases.add("indirect struct loop",
1560 cases.add(
1561 "indirect struct loop",
8311562 \\const A = struct { b : B, };
8321563 \\const B = struct { c : C, };
8331564 \\const C = struct { a : A, };
8341565 \\export fn entry() usize { return @sizeOf(A); }
835 , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
1566 ,
1567 ".tmp_source.zig:1:11: error: struct 'A' contains itself",
1568 );
8361569
837 cases.add("invalid struct field",
1570 cases.add(
1571 "invalid struct field",
8381572 \\const A = struct { x : i32, };
8391573 \\export fn f() void {
8401574 \\ var a : A = undefined;
......@@ -842,27 +1576,37 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
8421576 \\ const y = a.bar;
8431577 \\}
8441578 ,
845 ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",
846 ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'");
1579 ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",
1580 ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'",
1581 );
8471582
848 cases.add("redefinition of struct",
1583 cases.add(
1584 "redefinition of struct",
8491585 \\const A = struct { x : i32, };
8501586 \\const A = struct { y : i32, };
851 , ".tmp_source.zig:2:1: error: redefinition of 'A'");
1587 ,
1588 ".tmp_source.zig:2:1: error: redefinition of 'A'",
1589 );
8521590
853 cases.add("redefinition of enums",
1591 cases.add(
1592 "redefinition of enums",
8541593 \\const A = enum {};
8551594 \\const A = enum {};
856 , ".tmp_source.zig:2:1: error: redefinition of 'A'");
1595 ,
1596 ".tmp_source.zig:2:1: error: redefinition of 'A'",
1597 );
8571598
858 cases.add("redefinition of global variables",
1599 cases.add(
1600 "redefinition of global variables",
8591601 \\var a : i32 = 1;
8601602 \\var a : i32 = 2;
8611603 ,
862 ".tmp_source.zig:2:1: error: redefinition of 'a'",
863 ".tmp_source.zig:1:1: note: previous definition is here");
1604 ".tmp_source.zig:2:1: error: redefinition of 'a'",
1605 ".tmp_source.zig:1:1: note: previous definition is here",
1606 );
8641607
865 cases.add("duplicate field in struct value expression",
1608 cases.add(
1609 "duplicate field in struct value expression",
8661610 \\const A = struct {
8671611 \\ x : i32,
8681612 \\ y : i32,
......@@ -876,9 +1620,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
8761620 \\ .z = 4,
8771621 \\ };
8781622 \\}
879 , ".tmp_source.zig:11:9: error: duplicate field");
1623 ,
1624 ".tmp_source.zig:11:9: error: duplicate field",
1625 );
8801626
881 cases.add("missing field in struct value expression",
1627 cases.add(
1628 "missing field in struct value expression",
8821629 \\const A = struct {
8831630 \\ x : i32,
8841631 \\ y : i32,
......@@ -892,9 +1639,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
8921639 \\ .y = 2,
8931640 \\ };
8941641 \\}
895 , ".tmp_source.zig:9:17: error: missing field: 'x'");
1642 ,
1643 ".tmp_source.zig:9:17: error: missing field: 'x'",
1644 );
8961645
897 cases.add("invalid field in struct value expression",
1646 cases.add(
1647 "invalid field in struct value expression",
8981648 \\const A = struct {
8991649 \\ x : i32,
9001650 \\ y : i32,
......@@ -907,66 +1657,95 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
9071657 \\ .foo = 42,
9081658 \\ };
9091659 \\}
910 , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'");
1660 ,
1661 ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'",
1662 );
9111663
912 cases.add("invalid break expression",
1664 cases.add(
1665 "invalid break expression",
9131666 \\export fn f() void {
9141667 \\ break;
9151668 \\}
916 , ".tmp_source.zig:2:5: error: break expression outside loop");
1669 ,
1670 ".tmp_source.zig:2:5: error: break expression outside loop",
1671 );
9171672
918 cases.add("invalid continue expression",
1673 cases.add(
1674 "invalid continue expression",
9191675 \\export fn f() void {
9201676 \\ continue;
9211677 \\}
922 , ".tmp_source.zig:2:5: error: continue expression outside loop");
1678 ,
1679 ".tmp_source.zig:2:5: error: continue expression outside loop",
1680 );
9231681
924 cases.add("invalid maybe type",
1682 cases.add(
1683 "invalid maybe type",
9251684 \\export fn f() void {
9261685 \\ if (true) |x| { }
9271686 \\}
928 , ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'");
1687 ,
1688 ".tmp_source.zig:2:9: error: expected optional type, found 'bool'",
1689 );
9291690
930 cases.add("cast unreachable",
1691 cases.add(
1692 "cast unreachable",
9311693 \\fn f() i32 {
9321694 \\ return i32(return 1);
9331695 \\}
9341696 \\export fn entry() void { _ = f(); }
935 , ".tmp_source.zig:2:15: error: unreachable code");
1697 ,
1698 ".tmp_source.zig:2:15: error: unreachable code",
1699 );
9361700
937 cases.add("invalid builtin fn",
1701 cases.add(
1702 "invalid builtin fn",
9381703 \\fn f() @bogus(foo) {
9391704 \\}
9401705 \\export fn entry() void { _ = f(); }
941 , ".tmp_source.zig:1:8: error: invalid builtin function: 'bogus'");
1706 ,
1707 ".tmp_source.zig:1:8: error: invalid builtin function: 'bogus'",
1708 );
9421709
943 cases.add("top level decl dependency loop",
1710 cases.add(
1711 "top level decl dependency loop",
9441712 \\const a : @typeOf(b) = 0;
9451713 \\const b : @typeOf(a) = 0;
9461714 \\export fn entry() void {
9471715 \\ const c = a + b;
9481716 \\}
949 , ".tmp_source.zig:1:1: error: 'a' depends on itself");
1717 ,
1718 ".tmp_source.zig:1:1: error: 'a' depends on itself",
1719 );
9501720
951 cases.add("noalias on non pointer param",
1721 cases.add(
1722 "noalias on non pointer param",
9521723 \\fn f(noalias x: i32) void {}
9531724 \\export fn entry() void { f(1234); }
954 , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter");
1725 ,
1726 ".tmp_source.zig:1:6: error: noalias on non-pointer parameter",
1727 );
9551728
956 cases.add("struct init syntax for array",
1729 cases.add(
1730 "struct init syntax for array",
9571731 \\const foo = []u16{.x = 1024,};
9581732 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
959 , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax");
1733 ,
1734 ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax",
1735 );
9601736
961 cases.add("type variables must be constant",
1737 cases.add(
1738 "type variables must be constant",
9621739 \\var foo = u8;
9631740 \\export fn entry() foo {
9641741 \\ return 1;
9651742 \\}
966 , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant");
967
1743 ,
1744 ".tmp_source.zig:1:1: error: variable of type 'type' must be constant",
1745 );
9681746
969 cases.add("variables shadowing types",
1747 cases.add(
1748 "variables shadowing types",
9701749 \\const Foo = struct {};
9711750 \\const Bar = struct {};
9721751 \\
......@@ -978,12 +1757,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
9781757 \\ f(1234);
9791758 \\}
9801759 ,
981 ".tmp_source.zig:4:6: error: redefinition of 'Foo'",
982 ".tmp_source.zig:1:1: note: previous definition is here",
983 ".tmp_source.zig:5:5: error: redefinition of 'Bar'",
984 ".tmp_source.zig:2:1: note: previous definition is here");
1760 ".tmp_source.zig:4:6: error: redefinition of 'Foo'",
1761 ".tmp_source.zig:1:1: note: previous definition is here",
1762 ".tmp_source.zig:5:5: error: redefinition of 'Bar'",
1763 ".tmp_source.zig:2:1: note: previous definition is here",
1764 );
9851765
986 cases.add("switch expression - missing enumeration prong",
1766 cases.add(
1767 "switch expression - missing enumeration prong",
9871768 \\const Number = enum {
9881769 \\ One,
9891770 \\ Two,
......@@ -999,9 +1780,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
9991780 \\}
10001781 \\
10011782 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1002 , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch");
1783 ,
1784 ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch",
1785 );
10031786
1004 cases.add("switch expression - duplicate enumeration prong",
1787 cases.add(
1788 "switch expression - duplicate enumeration prong",
10051789 \\const Number = enum {
10061790 \\ One,
10071791 \\ Two,
......@@ -1019,10 +1803,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
10191803 \\}
10201804 \\
10211805 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1022 , ".tmp_source.zig:13:15: error: duplicate switch value",
1023 ".tmp_source.zig:10:15: note: other value is here");
1806 ,
1807 ".tmp_source.zig:13:15: error: duplicate switch value",
1808 ".tmp_source.zig:10:15: note: other value is here",
1809 );
10241810
1025 cases.add("switch expression - duplicate enumeration prong when else present",
1811 cases.add(
1812 "switch expression - duplicate enumeration prong when else present",
10261813 \\const Number = enum {
10271814 \\ One,
10281815 \\ Two,
......@@ -1041,10 +1828,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
10411828 \\}
10421829 \\
10431830 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1044 , ".tmp_source.zig:13:15: error: duplicate switch value",
1045 ".tmp_source.zig:10:15: note: other value is here");
1831 ,
1832 ".tmp_source.zig:13:15: error: duplicate switch value",
1833 ".tmp_source.zig:10:15: note: other value is here",
1834 );
10461835
1047 cases.add("switch expression - multiple else prongs",
1836 cases.add(
1837 "switch expression - multiple else prongs",
10481838 \\fn f(x: u32) void {
10491839 \\ const value: bool = switch (x) {
10501840 \\ 1234 => false,
......@@ -1055,9 +1845,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
10551845 \\export fn entry() void {
10561846 \\ f(1234);
10571847 \\}
1058 , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression");
1848 ,
1849 ".tmp_source.zig:5:9: error: multiple else prongs in switch expression",
1850 );
10591851
1060 cases.add("switch expression - non exhaustive integer prongs",
1852 cases.add(
1853 "switch expression - non exhaustive integer prongs",
10611854 \\fn foo(x: u8) void {
10621855 \\ switch (x) {
10631856 \\ 0 => {},
......@@ -1065,9 +1858,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
10651858 \\}
10661859 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
10671860 ,
1068 ".tmp_source.zig:2:5: error: switch must handle all possibilities");
1861 ".tmp_source.zig:2:5: error: switch must handle all possibilities",
1862 );
10691863
1070 cases.add("switch expression - duplicate or overlapping integer value",
1864 cases.add(
1865 "switch expression - duplicate or overlapping integer value",
10711866 \\fn foo(x: u8) u8 {
10721867 \\ return switch (x) {
10731868 \\ 0 ... 100 => u8(0),
......@@ -1079,10 +1874,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
10791874 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
10801875 ,
10811876 ".tmp_source.zig:6:9: error: duplicate switch value",
1082 ".tmp_source.zig:5:14: note: previous value is here");
1877 ".tmp_source.zig:5:14: note: previous value is here",
1878 );
10831879
1084 cases.add("switch expression - switch on pointer type with no else",
1085 \\fn foo(x: &u8) void {
1880 cases.add(
1881 "switch expression - switch on pointer type with no else",
1882 \\fn foo(x: *u8) void {
10861883 \\ switch (x) {
10871884 \\ &y => {},
10881885 \\ }
......@@ -1090,62 +1887,97 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
10901887 \\const y: u8 = 100;
10911888 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
10921889 ,
1093 ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'");
1890 ".tmp_source.zig:2:5: error: else prong required when switching on type '*u8'",
1891 );
10941892
1095 cases.add("global variable initializer must be constant expression",
1893 cases.add(
1894 "global variable initializer must be constant expression",
10961895 \\extern fn foo() i32;
10971896 \\const x = foo();
10981897 \\export fn entry() i32 { return x; }
1099 , ".tmp_source.zig:2:11: error: unable to evaluate constant expression");
1898 ,
1899 ".tmp_source.zig:2:11: error: unable to evaluate constant expression",
1900 );
11001901
1101 cases.add("array concatenation with wrong type",
1902 cases.add(
1903 "array concatenation with wrong type",
11021904 \\const src = "aoeu";
11031905 \\const derp = usize(1234);
11041906 \\const a = derp ++ "foo";
11051907 \\
11061908 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
1107 , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'");
1909 ,
1910 ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'",
1911 );
11081912
1109 cases.add("non compile time array concatenation",
1913 cases.add(
1914 "non compile time array concatenation",
11101915 \\fn f() []u8 {
11111916 \\ return s ++ "foo";
11121917 \\}
11131918 \\var s: [10]u8 = undefined;
11141919 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1115 , ".tmp_source.zig:2:12: error: unable to evaluate constant expression");
1920 ,
1921 ".tmp_source.zig:2:12: error: unable to evaluate constant expression",
1922 );
11161923
1117 cases.add("@cImport with bogus include",
1924 cases.add(
1925 "@cImport with bogus include",
11181926 \\const c = @cImport(@cInclude("bogus.h"));
11191927 \\export fn entry() usize { return @sizeOf(@typeOf(c.bogo)); }
1120 , ".tmp_source.zig:1:11: error: C import failed",
1121 ".h:1:10: note: 'bogus.h' file not found");
1928 ,
1929 ".tmp_source.zig:1:11: error: C import failed",
1930 ".h:1:10: note: 'bogus.h' file not found",
1931 );
11221932
1123 cases.add("address of number literal",
1933 cases.add(
1934 "address of number literal",
11241935 \\const x = 3;
11251936 \\const y = &x;
1126 \\fn foo() &const i32 { return y; }
1937 \\fn foo() *const i32 { return y; }
11271938 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1128 , ".tmp_source.zig:3:30: error: expected type '&const i32', found '&const (integer literal)'");
1939 ,
1940 ".tmp_source.zig:3:30: error: expected type '*const i32', found '*const comptime_int'",
1941 );
11291942
1130 cases.add("integer overflow error",
1943 cases.add(
1944 "integer overflow error",
11311945 \\const x : u8 = 300;
11321946 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
1133 , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'");
1947 ,
1948 ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",
1949 );
1950
1951 cases.add(
1952 "invalid shift amount error",
1953 \\const x : u8 = 2;
1954 \\fn f() u16 {
1955 \\ return x << 8;
1956 \\}
1957 \\export fn entry() u16 { return f(); }
1958 ,
1959 ".tmp_source.zig:3:14: error: RHS of shift is too large for LHS type",
1960 ".tmp_source.zig:3:17: note: value 8 cannot fit into type u3",
1961 );
11341962
1135 cases.add("incompatible number literals",
1963 cases.add(
1964 "incompatible number literals",
11361965 \\const x = 2 == 2.0;
11371966 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
1138 , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'");
1967 ,
1968 ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type 'comptime_float'",
1969 );
11391970
1140 cases.add("missing function call param",
1971 cases.add(
1972 "missing function call param",
11411973 \\const Foo = struct {
11421974 \\ a: i32,
11431975 \\ b: i32,
11441976 \\
1145 \\ fn member_a(foo: &const Foo) i32 {
1977 \\ fn member_a(foo: *const Foo) i32 {
11461978 \\ return foo.a;
11471979 \\ }
1148 \\ fn member_b(foo: &const Foo) i32 {
1980 \\ fn member_b(foo: *const Foo) i32 {
11491981 \\ return foo.b;
11501982 \\ }
11511983 \\};
......@@ -1156,158 +1988,606 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
11561988 \\ Foo.member_b,
11571989 \\};
11581990 \\
1159 \\fn f(foo: &const Foo, index: usize) void {
1991 \\fn f(foo: *const Foo, index: usize) void {
11601992 \\ const result = members[index]();
11611993 \\}
1162 \\
1163 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1164 , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0");
1994 \\
1995 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1996 ,
1997 ".tmp_source.zig:20:34: error: expected 1 arguments, found 0",
1998 );
1999
2000 cases.add(
2001 "missing function name and param name",
2002 \\fn () void {}
2003 \\fn f(i32) void {}
2004 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2005 ,
2006 ".tmp_source.zig:1:1: error: missing function name",
2007 ".tmp_source.zig:2:6: error: missing parameter name",
2008 );
2009
2010 cases.add(
2011 "wrong function type",
2012 \\const fns = []fn() void { a, b, c };
2013 \\fn a() i32 {return 0;}
2014 \\fn b() i32 {return 1;}
2015 \\fn c() i32 {return 2;}
2016 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
2017 ,
2018 ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'",
2019 );
2020
2021 cases.add(
2022 "extern function pointer mismatch",
2023 \\const fns = [](fn(i32)i32) { a, b, c };
2024 \\pub fn a(x: i32) i32 {return x + 0;}
2025 \\pub fn b(x: i32) i32 {return x + 1;}
2026 \\export fn c(x: i32) i32 {return x + 2;}
2027 \\
2028 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
2029 ,
2030 ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'",
2031 );
2032
2033 cases.add(
2034 "implicit cast from f64 to f32",
2035 \\const x : f64 = 1.0;
2036 \\const y : f32 = x;
2037 \\
2038 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
2039 ,
2040 ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'",
2041 );
2042
2043 cases.add(
2044 "colliding invalid top level functions",
2045 \\fn func() bogus {}
2046 \\fn func() bogus {}
2047 \\export fn entry() usize { return @sizeOf(@typeOf(func)); }
2048 ,
2049 ".tmp_source.zig:2:1: error: redefinition of 'func'",
2050 ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'",
2051 );
2052
2053 cases.add(
2054 "bogus compile var",
2055 \\const x = @import("builtin").bogus;
2056 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2057 ,
2058 ".tmp_source.zig:1:29: error: no member named 'bogus' in '",
2059 );
2060
2061 cases.add(
2062 "non constant expression in array size outside function",
2063 \\const Foo = struct {
2064 \\ y: [get()]u8,
2065 \\};
2066 \\var global_var: usize = 1;
2067 \\fn get() usize { return global_var; }
2068 \\
2069 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
2070 ,
2071 ".tmp_source.zig:5:25: error: unable to evaluate constant expression",
2072 ".tmp_source.zig:2:12: note: called from here",
2073 ".tmp_source.zig:2:8: note: called from here",
2074 );
2075
2076 cases.add(
2077 "addition with non numbers",
2078 \\const Foo = struct {
2079 \\ field: i32,
2080 \\};
2081 \\const x = Foo {.field = 1} + Foo {.field = 2};
2082 \\
2083 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2084 ,
2085 ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'",
2086 );
2087
2088 cases.add(
2089 "division by zero",
2090 \\const lit_int_x = 1 / 0;
2091 \\const lit_float_x = 1.0 / 0.0;
2092 \\const int_x = u32(1) / u32(0);
2093 \\const float_x = f32(1.0) / f32(0.0);
2094 \\
2095 \\export fn entry1() usize { return @sizeOf(@typeOf(lit_int_x)); }
2096 \\export fn entry2() usize { return @sizeOf(@typeOf(lit_float_x)); }
2097 \\export fn entry3() usize { return @sizeOf(@typeOf(int_x)); }
2098 \\export fn entry4() usize { return @sizeOf(@typeOf(float_x)); }
2099 ,
2100 ".tmp_source.zig:1:21: error: division by zero",
2101 ".tmp_source.zig:2:25: error: division by zero",
2102 ".tmp_source.zig:3:22: error: division by zero",
2103 ".tmp_source.zig:4:26: error: division by zero",
2104 );
2105
2106 cases.add(
2107 "normal string with newline",
2108 \\const foo = "a
2109 \\b";
2110 \\
2111 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2112 ,
2113 ".tmp_source.zig:1:13: error: newline not allowed in string literal",
2114 );
2115
2116 cases.add(
2117 "invalid comparison for function pointers",
2118 \\fn foo() void {}
2119 \\const invalid = foo > foo;
2120 \\
2121 \\export fn entry() usize { return @sizeOf(@typeOf(invalid)); }
2122 ,
2123 ".tmp_source.zig:2:21: error: operator not allowed for type 'fn() void'",
2124 );
2125
2126 cases.add(
2127 "generic function instance with non-constant expression",
2128 \\fn foo(comptime x: i32, y: i32) i32 { return x + y; }
2129 \\fn test1(a: i32, b: i32) i32 {
2130 \\ return foo(a, b);
2131 \\}
2132 \\
2133 \\export fn entry() usize { return @sizeOf(@typeOf(test1)); }
2134 ,
2135 ".tmp_source.zig:3:16: error: unable to evaluate constant expression",
2136 );
2137
2138 cases.add(
2139 "assign null to non-optional pointer",
2140 \\const a: *u8 = null;
2141 \\
2142 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
2143 ,
2144 ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'",
2145 );
2146
2147 cases.add(
2148 "indexing an array of size zero",
2149 \\const array = []u8{};
2150 \\export fn foo() void {
2151 \\ const pointer = &array[0];
2152 \\}
2153 ,
2154 ".tmp_source.zig:3:27: error: index 0 outside array of size 0",
2155 );
2156
2157 cases.add(
2158 "compile time division by zero",
2159 \\const y = foo(0);
2160 \\fn foo(x: u32) u32 {
2161 \\ return 1 / x;
2162 \\}
2163 \\
2164 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
2165 ,
2166 ".tmp_source.zig:3:14: error: division by zero",
2167 ".tmp_source.zig:1:14: note: called from here",
2168 );
2169
2170 cases.add(
2171 "branch on undefined value",
2172 \\const x = if (undefined) true else false;
2173 \\
2174 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2175 ,
2176 ".tmp_source.zig:1:15: error: use of undefined value",
2177 );
2178
2179 cases.add(
2180 "div on undefined value",
2181 \\comptime {
2182 \\ var a: i64 = undefined;
2183 \\ _ = a / a;
2184 \\}
2185 ,
2186 ".tmp_source.zig:3:9: error: use of undefined value",
2187 );
2188
2189 cases.add(
2190 "div assign on undefined value",
2191 \\comptime {
2192 \\ var a: i64 = undefined;
2193 \\ a /= a;
2194 \\}
2195 ,
2196 ".tmp_source.zig:3:5: error: use of undefined value",
2197 );
2198
2199 cases.add(
2200 "mod on undefined value",
2201 \\comptime {
2202 \\ var a: i64 = undefined;
2203 \\ _ = a % a;
2204 \\}
2205 ,
2206 ".tmp_source.zig:3:9: error: use of undefined value",
2207 );
2208
2209 cases.add(
2210 "mod assign on undefined value",
2211 \\comptime {
2212 \\ var a: i64 = undefined;
2213 \\ a %= a;
2214 \\}
2215 ,
2216 ".tmp_source.zig:3:5: error: use of undefined value",
2217 );
2218
2219 cases.add(
2220 "add on undefined value",
2221 \\comptime {
2222 \\ var a: i64 = undefined;
2223 \\ _ = a + a;
2224 \\}
2225 ,
2226 ".tmp_source.zig:3:9: error: use of undefined value",
2227 );
2228
2229 cases.add(
2230 "add assign on undefined value",
2231 \\comptime {
2232 \\ var a: i64 = undefined;
2233 \\ a += a;
2234 \\}
2235 ,
2236 ".tmp_source.zig:3:5: error: use of undefined value",
2237 );
2238
2239 cases.add(
2240 "add wrap on undefined value",
2241 \\comptime {
2242 \\ var a: i64 = undefined;
2243 \\ _ = a +% a;
2244 \\}
2245 ,
2246 ".tmp_source.zig:3:9: error: use of undefined value",
2247 );
2248
2249 cases.add(
2250 "add wrap assign on undefined value",
2251 \\comptime {
2252 \\ var a: i64 = undefined;
2253 \\ a +%= a;
2254 \\}
2255 ,
2256 ".tmp_source.zig:3:5: error: use of undefined value",
2257 );
2258
2259 cases.add(
2260 "sub on undefined value",
2261 \\comptime {
2262 \\ var a: i64 = undefined;
2263 \\ _ = a - a;
2264 \\}
2265 ,
2266 ".tmp_source.zig:3:9: error: use of undefined value",
2267 );
2268
2269 cases.add(
2270 "sub assign on undefined value",
2271 \\comptime {
2272 \\ var a: i64 = undefined;
2273 \\ a -= a;
2274 \\}
2275 ,
2276 ".tmp_source.zig:3:5: error: use of undefined value",
2277 );
2278
2279 cases.add(
2280 "sub wrap on undefined value",
2281 \\comptime {
2282 \\ var a: i64 = undefined;
2283 \\ _ = a -% a;
2284 \\}
2285 ,
2286 ".tmp_source.zig:3:9: error: use of undefined value",
2287 );
2288
2289 cases.add(
2290 "sub wrap assign on undefined value",
2291 \\comptime {
2292 \\ var a: i64 = undefined;
2293 \\ a -%= a;
2294 \\}
2295 ,
2296 ".tmp_source.zig:3:5: error: use of undefined value",
2297 );
2298
2299 cases.add(
2300 "mult on undefined value",
2301 \\comptime {
2302 \\ var a: i64 = undefined;
2303 \\ _ = a * a;
2304 \\}
2305 ,
2306 ".tmp_source.zig:3:9: error: use of undefined value",
2307 );
11652308
1166 cases.add("missing function name and param name",
1167 \\fn () void {}
1168 \\fn f(i32) void {}
1169 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2309 cases.add(
2310 "mult assign on undefined value",
2311 \\comptime {
2312 \\ var a: i64 = undefined;
2313 \\ a *= a;
2314 \\}
11702315 ,
1171 ".tmp_source.zig:1:1: error: missing function name",
1172 ".tmp_source.zig:2:6: error: missing parameter name");
2316 ".tmp_source.zig:3:5: error: use of undefined value",
2317 );
11732318
1174 cases.add("wrong function type",
1175 \\const fns = []fn() void { a, b, c };
1176 \\fn a() i32 {return 0;}
1177 \\fn b() i32 {return 1;}
1178 \\fn c() i32 {return 2;}
1179 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
1180 , ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'");
2319 cases.add(
2320 "mult wrap on undefined value",
2321 \\comptime {
2322 \\ var a: i64 = undefined;
2323 \\ _ = a *% a;
2324 \\}
2325 ,
2326 ".tmp_source.zig:3:9: error: use of undefined value",
2327 );
11812328
1182 cases.add("extern function pointer mismatch",
1183 \\const fns = [](fn(i32)i32) { a, b, c };
1184 \\pub fn a(x: i32) i32 {return x + 0;}
1185 \\pub fn b(x: i32) i32 {return x + 1;}
1186 \\export fn c(x: i32) i32 {return x + 2;}
1187 \\
1188 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
1189 , ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'");
2329 cases.add(
2330 "mult wrap assign on undefined value",
2331 \\comptime {
2332 \\ var a: i64 = undefined;
2333 \\ a *%= a;
2334 \\}
2335 ,
2336 ".tmp_source.zig:3:5: error: use of undefined value",
2337 );
11902338
2339 cases.add(
2340 "shift left on undefined value",
2341 \\comptime {
2342 \\ var a: i64 = undefined;
2343 \\ _ = a << 2;
2344 \\}
2345 ,
2346 ".tmp_source.zig:3:9: error: use of undefined value",
2347 );
11912348
1192 cases.add("implicit cast from f64 to f32",
1193 \\const x : f64 = 1.0;
1194 \\const y : f32 = x;
1195 \\
1196 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
1197 , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'");
2349 cases.add(
2350 "shift left assign on undefined value",
2351 \\comptime {
2352 \\ var a: i64 = undefined;
2353 \\ a <<= 2;
2354 \\}
2355 ,
2356 ".tmp_source.zig:3:5: error: use of undefined value",
2357 );
11982358
2359 cases.add(
2360 "shift right on undefined value",
2361 \\comptime {
2362 \\ var a: i64 = undefined;
2363 \\ _ = a >> 2;
2364 \\}
2365 ,
2366 ".tmp_source.zig:3:9: error: use of undefined value",
2367 );
11992368
1200 cases.add("colliding invalid top level functions",
1201 \\fn func() bogus {}
1202 \\fn func() bogus {}
1203 \\export fn entry() usize { return @sizeOf(@typeOf(func)); }
2369 cases.add(
2370 "shift left assign on undefined value",
2371 \\comptime {
2372 \\ var a: i64 = undefined;
2373 \\ a >>= 2;
2374 \\}
12042375 ,
1205 ".tmp_source.zig:2:1: error: redefinition of 'func'",
1206 ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'");
2376 ".tmp_source.zig:3:5: error: use of undefined value",
2377 );
12072378
2379 cases.add(
2380 "bin and on undefined value",
2381 \\comptime {
2382 \\ var a: i64 = undefined;
2383 \\ _ = a & a;
2384 \\}
2385 ,
2386 ".tmp_source.zig:3:9: error: use of undefined value",
2387 );
12082388
1209 cases.add("bogus compile var",
1210 \\const x = @import("builtin").bogus;
1211 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
1212 , ".tmp_source.zig:1:29: error: no member named 'bogus' in '");
2389 cases.add(
2390 "bin and assign on undefined value",
2391 \\comptime {
2392 \\ var a: i64 = undefined;
2393 \\ a &= a;
2394 \\}
2395 ,
2396 ".tmp_source.zig:3:5: error: use of undefined value",
2397 );
12132398
2399 cases.add(
2400 "bin or on undefined value",
2401 \\comptime {
2402 \\ var a: i64 = undefined;
2403 \\ _ = a | a;
2404 \\}
2405 ,
2406 ".tmp_source.zig:3:9: error: use of undefined value",
2407 );
12142408
1215 cases.add("non constant expression in array size outside function",
1216 \\const Foo = struct {
1217 \\ y: [get()]u8,
1218 \\};
1219 \\var global_var: usize = 1;
1220 \\fn get() usize { return global_var; }
1221 \\
1222 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
2409 cases.add(
2410 "bin or assign on undefined value",
2411 \\comptime {
2412 \\ var a: i64 = undefined;
2413 \\ a |= a;
2414 \\}
12232415 ,
1224 ".tmp_source.zig:5:25: error: unable to evaluate constant expression",
1225 ".tmp_source.zig:2:12: note: called from here",
1226 ".tmp_source.zig:2:8: note: called from here");
2416 ".tmp_source.zig:3:5: error: use of undefined value",
2417 );
12272418
2419 cases.add(
2420 "bin xor on undefined value",
2421 \\comptime {
2422 \\ var a: i64 = undefined;
2423 \\ _ = a ^ a;
2424 \\}
2425 ,
2426 ".tmp_source.zig:3:9: error: use of undefined value",
2427 );
12282428
1229 cases.add("addition with non numbers",
1230 \\const Foo = struct {
1231 \\ field: i32,
1232 \\};
1233 \\const x = Foo {.field = 1} + Foo {.field = 2};
1234 \\
1235 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
1236 , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'");
2429 cases.add(
2430 "bin xor assign on undefined value",
2431 \\comptime {
2432 \\ var a: i64 = undefined;
2433 \\ a ^= a;
2434 \\}
2435 ,
2436 ".tmp_source.zig:3:5: error: use of undefined value",
2437 );
12372438
2439 cases.add(
2440 "equal on undefined value",
2441 \\comptime {
2442 \\ var a: i64 = undefined;
2443 \\ _ = a == a;
2444 \\}
2445 ,
2446 ".tmp_source.zig:3:9: error: use of undefined value",
2447 );
12382448
1239 cases.add("division by zero",
1240 \\const lit_int_x = 1 / 0;
1241 \\const lit_float_x = 1.0 / 0.0;
1242 \\const int_x = u32(1) / u32(0);
1243 \\const float_x = f32(1.0) / f32(0.0);
1244 \\
1245 \\export fn entry1() usize { return @sizeOf(@typeOf(lit_int_x)); }
1246 \\export fn entry2() usize { return @sizeOf(@typeOf(lit_float_x)); }
1247 \\export fn entry3() usize { return @sizeOf(@typeOf(int_x)); }
1248 \\export fn entry4() usize { return @sizeOf(@typeOf(float_x)); }
2449 cases.add(
2450 "not equal on undefined value",
2451 \\comptime {
2452 \\ var a: i64 = undefined;
2453 \\ _ = a != a;
2454 \\}
12492455 ,
1250 ".tmp_source.zig:1:21: error: division by zero",
1251 ".tmp_source.zig:2:25: error: division by zero",
1252 ".tmp_source.zig:3:22: error: division by zero",
1253 ".tmp_source.zig:4:26: error: division by zero");
2456 ".tmp_source.zig:3:9: error: use of undefined value",
2457 );
12542458
2459 cases.add(
2460 "greater than on undefined value",
2461 \\comptime {
2462 \\ var a: i64 = undefined;
2463 \\ _ = a > a;
2464 \\}
2465 ,
2466 ".tmp_source.zig:3:9: error: use of undefined value",
2467 );
12552468
1256 cases.add("normal string with newline",
1257 \\const foo = "a
1258 \\b";
1259 \\
1260 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1261 , ".tmp_source.zig:1:13: error: newline not allowed in string literal");
2469 cases.add(
2470 "greater than equal on undefined value",
2471 \\comptime {
2472 \\ var a: i64 = undefined;
2473 \\ _ = a >= a;
2474 \\}
2475 ,
2476 ".tmp_source.zig:3:9: error: use of undefined value",
2477 );
12622478
1263 cases.add("invalid comparison for function pointers",
1264 \\fn foo() void {}
1265 \\const invalid = foo > foo;
1266 \\
1267 \\export fn entry() usize { return @sizeOf(@typeOf(invalid)); }
1268 , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn() void'");
2479 cases.add(
2480 "less than on undefined value",
2481 \\comptime {
2482 \\ var a: i64 = undefined;
2483 \\ _ = a < a;
2484 \\}
2485 ,
2486 ".tmp_source.zig:3:9: error: use of undefined value",
2487 );
12692488
1270 cases.add("generic function instance with non-constant expression",
1271 \\fn foo(comptime x: i32, y: i32) i32 { return x + y; }
1272 \\fn test1(a: i32, b: i32) i32 {
1273 \\ return foo(a, b);
2489 cases.add(
2490 "less than equal on undefined value",
2491 \\comptime {
2492 \\ var a: i64 = undefined;
2493 \\ _ = a <= a;
12742494 \\}
1275 \\
1276 \\export fn entry() usize { return @sizeOf(@typeOf(test1)); }
1277 , ".tmp_source.zig:3:16: error: unable to evaluate constant expression");
2495 ,
2496 ".tmp_source.zig:3:9: error: use of undefined value",
2497 );
12782498
1279 cases.add("assign null to non-nullable pointer",
1280 \\const a: &u8 = null;
1281 \\
1282 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
1283 , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'");
2499 cases.add(
2500 "and on undefined value",
2501 \\comptime {
2502 \\ var a: bool = undefined;
2503 \\ _ = a and a;
2504 \\}
2505 ,
2506 ".tmp_source.zig:3:9: error: use of undefined value",
2507 );
12842508
1285 cases.add("indexing an array of size zero",
1286 \\const array = []u8{};
1287 \\export fn foo() void {
1288 \\ const pointer = &array[0];
2509 cases.add(
2510 "or on undefined value",
2511 \\comptime {
2512 \\ var a: bool = undefined;
2513 \\ _ = a or a;
12892514 \\}
1290 , ".tmp_source.zig:3:27: error: index 0 outside array of size 0");
2515 ,
2516 ".tmp_source.zig:3:9: error: use of undefined value",
2517 );
12912518
1292 cases.add("compile time division by zero",
1293 \\const y = foo(0);
1294 \\fn foo(x: u32) u32 {
1295 \\ return 1 / x;
2519 cases.add(
2520 "negate on undefined value",
2521 \\comptime {
2522 \\ var a: i64 = undefined;
2523 \\ _ = -a;
12962524 \\}
1297 \\
1298 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
12992525 ,
1300 ".tmp_source.zig:3:14: error: division by zero",
1301 ".tmp_source.zig:1:14: note: called from here");
2526 ".tmp_source.zig:3:10: error: use of undefined value",
2527 );
13022528
1303 cases.add("branch on undefined value",
1304 \\const x = if (undefined) true else false;
1305 \\
1306 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
1307 , ".tmp_source.zig:1:15: error: use of undefined value");
2529 cases.add(
2530 "negate wrap on undefined value",
2531 \\comptime {
2532 \\ var a: i64 = undefined;
2533 \\ _ = -%a;
2534 \\}
2535 ,
2536 ".tmp_source.zig:3:11: error: use of undefined value",
2537 );
2538
2539 cases.add(
2540 "bin not on undefined value",
2541 \\comptime {
2542 \\ var a: i64 = undefined;
2543 \\ _ = ~a;
2544 \\}
2545 ,
2546 ".tmp_source.zig:3:10: error: use of undefined value",
2547 );
2548
2549 cases.add(
2550 "bool not on undefined value",
2551 \\comptime {
2552 \\ var a: bool = undefined;
2553 \\ _ = !a;
2554 \\}
2555 ,
2556 ".tmp_source.zig:3:10: error: use of undefined value",
2557 );
13082558
2559 cases.add(
2560 "orelse on undefined value",
2561 \\comptime {
2562 \\ var a: ?bool = undefined;
2563 \\ _ = a orelse false;
2564 \\}
2565 ,
2566 ".tmp_source.zig:3:11: error: use of undefined value",
2567 );
2568
2569 cases.add(
2570 "catch on undefined value",
2571 \\comptime {
2572 \\ var a: error!bool = undefined;
2573 \\ _ = a catch |err| false;
2574 \\}
2575 ,
2576 ".tmp_source.zig:3:11: error: use of undefined value",
2577 );
2578
2579 cases.add(
2580 "deref on undefined value",
2581 \\comptime {
2582 \\ var a: *u8 = undefined;
2583 \\ _ = a.*;
2584 \\}
2585 ,
2586 ".tmp_source.zig:3:9: error: use of undefined value",
2587 );
13092588
1310 cases.add("endless loop in function evaluation",
2589 cases.add(
2590 "endless loop in function evaluation",
13112591 \\const seventh_fib_number = fibbonaci(7);
13122592 \\fn fibbonaci(x: i32) i32 {
13132593 \\ return fibbonaci(x - 1) + fibbonaci(x - 2);
......@@ -1315,16 +2595,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13152595 \\
13162596 \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); }
13172597 ,
1318 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
1319 ".tmp_source.zig:3:21: note: called from here");
2598 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
2599 ".tmp_source.zig:3:21: note: called from here",
2600 );
13202601
1321 cases.add("@embedFile with bogus file",
1322 \\const resource = @embedFile("bogus.txt");
2602 cases.add(
2603 "@embedFile with bogus file",
2604 \\const resource = @embedFile("bogus.txt",);
13232605 \\
13242606 \\export fn entry() usize { return @sizeOf(@typeOf(resource)); }
1325 , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'");
2607 ,
2608 ".tmp_source.zig:1:29: error: unable to find '",
2609 "bogus.txt'",
2610 );
13262611
1327 cases.add("non-const expression in struct literal outside function",
2612 cases.add(
2613 "non-const expression in struct literal outside function",
13282614 \\const Foo = struct {
13292615 \\ x: i32,
13302616 \\};
......@@ -1332,9 +2618,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13322618 \\extern fn get_it() i32;
13332619 \\
13342620 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
1335 , ".tmp_source.zig:4:21: error: unable to evaluate constant expression");
2621 ,
2622 ".tmp_source.zig:4:21: error: unable to evaluate constant expression",
2623 );
13362624
1337 cases.add("non-const expression function call with struct return value outside function",
2625 cases.add(
2626 "non-const expression function call with struct return value outside function",
13382627 \\const Foo = struct {
13392628 \\ x: i32,
13402629 \\};
......@@ -1347,19 +2636,24 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13472636 \\
13482637 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
13492638 ,
1350 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
1351 ".tmp_source.zig:4:17: note: called from here");
2639 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
2640 ".tmp_source.zig:4:17: note: called from here",
2641 );
13522642
1353 cases.add("undeclared identifier error should mark fn as impure",
2643 cases.add(
2644 "undeclared identifier error should mark fn as impure",
13542645 \\export fn foo() void {
13552646 \\ test_a_thing();
13562647 \\}
13572648 \\fn test_a_thing() void {
13582649 \\ bad_fn_call();
13592650 \\}
1360 , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'");
2651 ,
2652 ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'",
2653 );
13612654
1362 cases.add("illegal comparison of types",
2655 cases.add(
2656 "illegal comparison of types",
13632657 \\fn bad_eql_1(a: []u8, b: []u8) bool {
13642658 \\ return a == b;
13652659 \\}
......@@ -1367,17 +2661,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13672661 \\ One: void,
13682662 \\ Two: i32,
13692663 \\};
1370 \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) bool {
1371 \\ return *a == *b;
2664 \\fn bad_eql_2(a: *const EnumWithData, b: *const EnumWithData) bool {
2665 \\ return a.* == b.*;
13722666 \\}
13732667 \\
13742668 \\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }
13752669 \\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }
13762670 ,
1377 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
1378 ".tmp_source.zig:9:15: error: operator not allowed for type 'EnumWithData'");
2671 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
2672 ".tmp_source.zig:9:16: error: operator not allowed for type 'EnumWithData'",
2673 );
13792674
1380 cases.add("non-const switch number literal",
2675 cases.add(
2676 "non-const switch number literal",
13812677 \\export fn foo() void {
13822678 \\ const x = switch (bar()) {
13832679 \\ 1, 2 => 1,
......@@ -1388,25 +2684,34 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13882684 \\fn bar() i32 {
13892685 \\ return 2;
13902686 \\}
1391 , ".tmp_source.zig:2:15: error: unable to infer expression type");
2687 ,
2688 ".tmp_source.zig:2:15: error: unable to infer expression type",
2689 );
13922690
1393 cases.add("atomic orderings of cmpxchg - failure stricter than success",
2691 cases.add(
2692 "atomic orderings of cmpxchg - failure stricter than success",
13942693 \\const AtomicOrder = @import("builtin").AtomicOrder;
13952694 \\export fn f() void {
13962695 \\ var x: i32 = 1234;
1397 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
2696 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
13982697 \\}
1399 , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success");
2698 ,
2699 ".tmp_source.zig:4:81: error: failure atomic ordering must be no stricter than success",
2700 );
14002701
1401 cases.add("atomic orderings of cmpxchg - success Monotonic or stricter",
2702 cases.add(
2703 "atomic orderings of cmpxchg - success Monotonic or stricter",
14022704 \\const AtomicOrder = @import("builtin").AtomicOrder;
14032705 \\export fn f() void {
14042706 \\ var x: i32 = 1234;
1405 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
2707 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
14062708 \\}
1407 , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter");
2709 ,
2710 ".tmp_source.zig:4:58: error: success atomic ordering must be Monotonic or stricter",
2711 );
14082712
1409 cases.add("negation overflow in function evaluation",
2713 cases.add(
2714 "negation overflow in function evaluation",
14102715 \\const y = neg(-128);
14112716 \\fn neg(x: i8) i8 {
14122717 \\ return -x;
......@@ -1414,10 +2719,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
14142719 \\
14152720 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
14162721 ,
1417 ".tmp_source.zig:3:12: error: negation caused overflow",
1418 ".tmp_source.zig:1:14: note: called from here");
2722 ".tmp_source.zig:3:12: error: negation caused overflow",
2723 ".tmp_source.zig:1:14: note: called from here",
2724 );
14192725
1420 cases.add("add overflow in function evaluation",
2726 cases.add(
2727 "add overflow in function evaluation",
14212728 \\const y = add(65530, 10);
14222729 \\fn add(a: u16, b: u16) u16 {
14232730 \\ return a + b;
......@@ -1425,11 +2732,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
14252732 \\
14262733 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
14272734 ,
1428 ".tmp_source.zig:3:14: error: operation caused overflow",
1429 ".tmp_source.zig:1:14: note: called from here");
1430
2735 ".tmp_source.zig:3:14: error: operation caused overflow",
2736 ".tmp_source.zig:1:14: note: called from here",
2737 );
14312738
1432 cases.add("sub overflow in function evaluation",
2739 cases.add(
2740 "sub overflow in function evaluation",
14332741 \\const y = sub(10, 20);
14342742 \\fn sub(a: u16, b: u16) u16 {
14352743 \\ return a - b;
......@@ -1437,10 +2745,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
14372745 \\
14382746 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
14392747 ,
1440 ".tmp_source.zig:3:14: error: operation caused overflow",
1441 ".tmp_source.zig:1:14: note: called from here");
2748 ".tmp_source.zig:3:14: error: operation caused overflow",
2749 ".tmp_source.zig:1:14: note: called from here",
2750 );
14422751
1443 cases.add("mul overflow in function evaluation",
2752 cases.add(
2753 "mul overflow in function evaluation",
14442754 \\const y = mul(300, 6000);
14452755 \\fn mul(a: u16, b: u16) u16 {
14462756 \\ return a * b;
......@@ -1448,58 +2758,78 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
14482758 \\
14492759 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
14502760 ,
1451 ".tmp_source.zig:3:14: error: operation caused overflow",
1452 ".tmp_source.zig:1:14: note: called from here");
2761 ".tmp_source.zig:3:14: error: operation caused overflow",
2762 ".tmp_source.zig:1:14: note: called from here",
2763 );
14532764
1454 cases.add("truncate sign mismatch",
2765 cases.add(
2766 "truncate sign mismatch",
14552767 \\fn f() i8 {
14562768 \\ const x: u32 = 10;
14572769 \\ return @truncate(i8, x);
14582770 \\}
14592771 \\
14602772 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1461 , ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'");
2773 ,
2774 ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'",
2775 );
14622776
1463 cases.add("try in function with non error return type",
2777 cases.add(
2778 "try in function with non error return type",
14642779 \\export fn f() void {
14652780 \\ try something();
14662781 \\}
14672782 \\fn something() error!void { }
14682783 ,
1469 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
2784 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'",
2785 );
14702786
1471 cases.add("invalid pointer for var type",
2787 cases.add(
2788 "invalid pointer for var type",
14722789 \\extern fn ext() usize;
14732790 \\var bytes: [ext()]u8 = undefined;
14742791 \\export fn f() void {
14752792 \\ for (bytes) |*b, i| {
1476 \\ *b = u8(i);
2793 \\ b.* = u8(i);
14772794 \\ }
14782795 \\}
1479 , ".tmp_source.zig:2:13: error: unable to evaluate constant expression");
2796 ,
2797 ".tmp_source.zig:2:13: error: unable to evaluate constant expression",
2798 );
14802799
1481 cases.add("export function with comptime parameter",
2800 cases.add(
2801 "export function with comptime parameter",
14822802 \\export fn foo(comptime x: i32, y: i32) i32{
14832803 \\ return x + y;
14842804 \\}
1485 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
2805 ,
2806 ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
2807 );
14862808
1487 cases.add("extern function with comptime parameter",
2809 cases.add(
2810 "extern function with comptime parameter",
14882811 \\extern fn foo(comptime x: i32, y: i32) i32;
14892812 \\fn f() i32 {
14902813 \\ return foo(1, 2);
14912814 \\}
14922815 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1493 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
2816 ,
2817 ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
2818 );
14942819
1495 cases.add("convert fixed size array to slice with invalid size",
2820 cases.add(
2821 "convert fixed size array to slice with invalid size",
14962822 \\export fn f() void {
14972823 \\ var array: [5]u8 = undefined;
1498 \\ var foo = ([]const u32)(array)[0];
2824 \\ var foo = @bytesToSlice(u32, array)[0];
14992825 \\}
1500 , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch");
2826 ,
2827 ".tmp_source.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
2828 ".tmp_source.zig:3:29: note: u32 has size 4; remaining bytes: 1",
2829 );
15012830
1502 cases.add("non-pure function returns type",
2831 cases.add(
2832 "non-pure function returns type",
15032833 \\var a: u32 = 0;
15042834 \\pub fn List(comptime T: type) type {
15052835 \\ a += 1;
......@@ -1518,56 +2848,77 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
15182848 \\ var list: List(i32) = undefined;
15192849 \\ list.length = 10;
15202850 \\}
1521 , ".tmp_source.zig:3:7: error: unable to evaluate constant expression",
1522 ".tmp_source.zig:16:19: note: called from here");
2851 ,
2852 ".tmp_source.zig:3:7: error: unable to evaluate constant expression",
2853 ".tmp_source.zig:16:19: note: called from here",
2854 );
15232855
1524 cases.add("bogus method call on slice",
2856 cases.add(
2857 "bogus method call on slice",
15252858 \\var self = "aoeu";
15262859 \\fn f(m: []const u8) void {
15272860 \\ m.copy(u8, self[0..], m);
15282861 \\}
15292862 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1530 , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'");
2863 ,
2864 ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'",
2865 );
15312866
1532 cases.add("wrong number of arguments for method fn call",
2867 cases.add(
2868 "wrong number of arguments for method fn call",
15332869 \\const Foo = struct {
1534 \\ fn method(self: &const Foo, a: i32) void {}
2870 \\ fn method(self: *const Foo, a: i32) void {}
15352871 \\};
1536 \\fn f(foo: &const Foo) void {
2872 \\fn f(foo: *const Foo) void {
15372873 \\
15382874 \\ foo.method(1, 2);
15392875 \\}
15402876 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
1541 , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3");
2877 ,
2878 ".tmp_source.zig:6:15: error: expected 2 arguments, found 3",
2879 );
15422880
1543 cases.add("assign through constant pointer",
2881 cases.add(
2882 "assign through constant pointer",
15442883 \\export fn f() void {
15452884 \\ var cstr = c"Hat";
15462885 \\ cstr[0] = 'W';
15472886 \\}
1548 , ".tmp_source.zig:3:11: error: cannot assign to constant");
2887 ,
2888 ".tmp_source.zig:3:11: error: cannot assign to constant",
2889 );
15492890
1550 cases.add("assign through constant slice",
2891 cases.add(
2892 "assign through constant slice",
15512893 \\export fn f() void {
15522894 \\ var cstr: []const u8 = "Hat";
15532895 \\ cstr[0] = 'W';
15542896 \\}
1555 , ".tmp_source.zig:3:11: error: cannot assign to constant");
2897 ,
2898 ".tmp_source.zig:3:11: error: cannot assign to constant",
2899 );
15562900
1557 cases.add("main function with bogus args type",
2901 cases.add(
2902 "main function with bogus args type",
15582903 \\pub fn main(args: [][]bogus) !void {}
1559 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");
2904 ,
2905 ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'",
2906 );
15602907
1561 cases.add("for loop missing element param",
2908 cases.add(
2909 "for loop missing element param",
15622910 \\fn foo(blah: []u8) void {
15632911 \\ for (blah) { }
15642912 \\}
15652913 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1566 , ".tmp_source.zig:2:5: error: for loop expression missing element parameter");
2914 ,
2915 ".tmp_source.zig:2:5: error: for loop expression missing element parameter",
2916 );
15672917
1568 cases.add("misspelled type with pointer only reference",
2918 cases.add(
2919 "misspelled type with pointer only reference",
15692920 \\const JasonHM = u8;
1570 \\const JasonList = &JsonNode;
2921 \\const JasonList = *JsonNode;
15712922 \\
15722923 \\const JsonOA = union(enum) {
15732924 \\ JSONArray: JsonList,
......@@ -1596,9 +2947,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
15962947 \\}
15972948 \\
15982949 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1599 , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'");
2950 ,
2951 ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'",
2952 );
16002953
1601 cases.add("method call with first arg type primitive",
2954 cases.add(
2955 "method call with first arg type primitive",
16022956 \\const Foo = struct {
16032957 \\ x: i32,
16042958 \\
......@@ -1614,14 +2968,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
16142968 \\
16152969 \\ derp.init();
16162970 \\}
1617 , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'");
2971 ,
2972 ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",
2973 );
16182974
1619 cases.add("method call with first arg type wrong container",
2975 cases.add(
2976 "method call with first arg type wrong container",
16202977 \\pub const List = struct {
16212978 \\ len: usize,
1622 \\ allocator: &Allocator,
2979 \\ allocator: *Allocator,
16232980 \\
1624 \\ pub fn init(allocator: &Allocator) List {
2981 \\ pub fn init(allocator: *Allocator) List {
16252982 \\ return List {
16262983 \\ .len = 0,
16272984 \\ .allocator = allocator,
......@@ -1641,26 +2998,33 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
16412998 \\ var x = List.init(&global_allocator);
16422999 \\ x.init();
16433000 \\}
1644 , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'");
3001 ,
3002 ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'",
3003 );
16453004
1646 cases.add("binary not on number literal",
3005 cases.add(
3006 "binary not on number literal",
16473007 \\const TINY_QUANTUM_SHIFT = 4;
16483008 \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
16493009 \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
16503010 \\
16513011 \\export fn entry() usize { return @sizeOf(@typeOf(block_aligned_stuff)); }
1652 , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'");
3012 ,
3013 ".tmp_source.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'",
3014 );
16533015
16543016 cases.addCase(x: {
1655 const tc = cases.create("multiple files with private function error",
1656 \\const foo = @import("foo.zig");
3017 const tc = cases.create(
3018 "multiple files with private function error",
3019 \\const foo = @import("foo.zig",);
16573020 \\
16583021 \\export fn callPrivFunction() void {
16593022 \\ foo.privateFunction();
16603023 \\}
16613024 ,
16623025 ".tmp_source.zig:4:8: error: 'privateFunction' is private",
1663 "foo.zig:1:1: note: declared here");
3026 "foo.zig:1:1: note: declared here",
3027 );
16643028
16653029 tc.addSourceFile("foo.zig",
16663030 \\fn privateFunction() void { }
......@@ -1669,14 +3033,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
16693033 break :x tc;
16703034 });
16713035
1672 cases.add("container init with non-type",
3036 cases.add(
3037 "container init with non-type",
16733038 \\const zero: i32 = 0;
16743039 \\const a = zero{1};
16753040 \\
16763041 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
1677 , ".tmp_source.zig:2:11: error: expected type, found 'i32'");
3042 ,
3043 ".tmp_source.zig:2:11: error: expected type, found 'i32'",
3044 );
16783045
1679 cases.add("assign to constant field",
3046 cases.add(
3047 "assign to constant field",
16803048 \\const Foo = struct {
16813049 \\ field: i32,
16823050 \\};
......@@ -1684,15 +3052,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
16843052 \\ const f = Foo {.field = 1234,};
16853053 \\ f.field = 0;
16863054 \\}
1687 , ".tmp_source.zig:6:13: error: cannot assign to constant");
3055 ,
3056 ".tmp_source.zig:6:13: error: cannot assign to constant",
3057 );
16883058
1689 cases.add("return from defer expression",
3059 cases.add(
3060 "return from defer expression",
16903061 \\pub fn testTrickyDefer() !void {
16913062 \\ defer canFail() catch {};
16923063 \\
16933064 \\ defer try canFail();
16943065 \\
1695 \\ const a = maybeInt() ?? return;
3066 \\ const a = maybeInt() orelse return;
16963067 \\}
16973068 \\
16983069 \\fn canFail() error!void { }
......@@ -1702,9 +3073,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17023073 \\}
17033074 \\
17043075 \\export fn entry() usize { return @sizeOf(@typeOf(testTrickyDefer)); }
1705 , ".tmp_source.zig:4:11: error: cannot return from defer expression");
3076 ,
3077 ".tmp_source.zig:4:11: error: cannot return from defer expression",
3078 );
17063079
1707 cases.add("attempt to access var args out of bounds",
3080 cases.add(
3081 "attempt to access var args out of bounds",
17083082 \\fn add(args: ...) i32 {
17093083 \\ return args[0] + args[1];
17103084 \\}
......@@ -1715,10 +3089,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17153089 \\
17163090 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
17173091 ,
1718 ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",
1719 ".tmp_source.zig:6:15: note: called from here");
3092 ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",
3093 ".tmp_source.zig:6:15: note: called from here",
3094 );
17203095
1721 cases.add("pass integer literal to var args",
3096 cases.add(
3097 "pass integer literal to var args",
17223098 \\fn add(args: ...) i32 {
17233099 \\ var sum = i32(0);
17243100 \\ {comptime var i: usize = 0; inline while (i < args.len) : (i += 1) {
......@@ -1732,32 +3108,44 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17323108 \\}
17333109 \\
17343110 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
1735 , ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted");
3111 ,
3112 ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted",
3113 );
17363114
1737 cases.add("assign too big number to u16",
3115 cases.add(
3116 "assign too big number to u16",
17383117 \\export fn foo() void {
17393118 \\ var vga_mem: u16 = 0xB8000;
17403119 \\}
1741 , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'");
3120 ,
3121 ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'",
3122 );
17423123
1743 cases.add("global variable alignment non power of 2",
3124 cases.add(
3125 "global variable alignment non power of 2",
17443126 \\const some_data: [100]u8 align(3) = undefined;
17453127 \\export fn entry() usize { return @sizeOf(@typeOf(some_data)); }
1746 , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2");
3128 ,
3129 ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2",
3130 );
17473131
1748 cases.add("function alignment non power of 2",
3132 cases.add(
3133 "function alignment non power of 2",
17493134 \\extern fn foo() align(3) void;
17503135 \\export fn entry() void { return foo(); }
1751 , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2");
3136 ,
3137 ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2",
3138 );
17523139
1753 cases.add("compile log",
3140 cases.add(
3141 "compile log",
17543142 \\export fn foo() void {
1755 \\ comptime bar(12, "hi");
3143 \\ comptime bar(12, "hi",);
17563144 \\}
17573145 \\fn bar(a: i32, b: []const u8) void {
1758 \\ @compileLog("begin");
3146 \\ @compileLog("begin",);
17593147 \\ @compileLog("a", a, "b", b);
1760 \\ @compileLog("end");
3148 \\ @compileLog("end",);
17613149 \\}
17623150 ,
17633151 ".tmp_source.zig:5:5: error: found compile log statement",
......@@ -1765,27 +3153,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17653153 ".tmp_source.zig:6:5: error: found compile log statement",
17663154 ".tmp_source.zig:2:17: note: called from here",
17673155 ".tmp_source.zig:7:5: error: found compile log statement",
1768 ".tmp_source.zig:2:17: note: called from here");
3156 ".tmp_source.zig:2:17: note: called from here",
3157 );
17693158
1770 cases.add("casting bit offset pointer to regular pointer",
3159 cases.add(
3160 "casting bit offset pointer to regular pointer",
17713161 \\const BitField = packed struct {
17723162 \\ a: u3,
17733163 \\ b: u3,
17743164 \\ c: u2,
17753165 \\};
17763166 \\
1777 \\fn foo(bit_field: &const BitField) u3 {
3167 \\fn foo(bit_field: *const BitField) u3 {
17783168 \\ return bar(&bit_field.b);
17793169 \\}
17803170 \\
1781 \\fn bar(x: &const u3) u3 {
1782 \\ return *x;
3171 \\fn bar(x: *const u3) u3 {
3172 \\ return x.*;
17833173 \\}
17843174 \\
17853175 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1786 , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'");
3176 ,
3177 ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(1:3:6) const u3'",
3178 );
17873179
1788 cases.add("referring to a struct that is invalid",
3180 cases.add(
3181 "referring to a struct that is invalid",
17893182 \\const UsbDeviceRequest = struct {
17903183 \\ Type: u8,
17913184 \\};
......@@ -1798,10 +3191,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17983191 \\ if (!ok) unreachable;
17993192 \\}
18003193 ,
1801 ".tmp_source.zig:10:14: error: unable to evaluate constant expression",
1802 ".tmp_source.zig:6:20: note: called from here");
3194 ".tmp_source.zig:10:14: error: unable to evaluate constant expression",
3195 ".tmp_source.zig:6:20: note: called from here",
3196 );
18033197
1804 cases.add("control flow uses comptime var at runtime",
3198 cases.add(
3199 "control flow uses comptime var at runtime",
18053200 \\export fn foo() void {
18063201 \\ comptime var i = 0;
18073202 \\ while (i < 5) : (i += 1) {
......@@ -1811,88 +3206,118 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
18113206 \\
18123207 \\fn bar() void { }
18133208 ,
1814 ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
1815 ".tmp_source.zig:3:24: note: compile-time variable assigned here");
3209 ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
3210 ".tmp_source.zig:3:24: note: compile-time variable assigned here",
3211 );
18163212
1817 cases.add("ignored return value",
3213 cases.add(
3214 "ignored return value",
18183215 \\export fn foo() void {
18193216 \\ bar();
18203217 \\}
18213218 \\fn bar() i32 { return 0; }
1822 , ".tmp_source.zig:2:8: error: expression value is ignored");
3219 ,
3220 ".tmp_source.zig:2:8: error: expression value is ignored",
3221 );
18233222
1824 cases.add("ignored assert-err-ok return value",
3223 cases.add(
3224 "ignored assert-err-ok return value",
18253225 \\export fn foo() void {
18263226 \\ bar() catch unreachable;
18273227 \\}
18283228 \\fn bar() error!i32 { return 0; }
1829 , ".tmp_source.zig:2:11: error: expression value is ignored");
3229 ,
3230 ".tmp_source.zig:2:11: error: expression value is ignored",
3231 );
18303232
1831 cases.add("ignored statement value",
3233 cases.add(
3234 "ignored statement value",
18323235 \\export fn foo() void {
18333236 \\ 1;
18343237 \\}
1835 , ".tmp_source.zig:2:5: error: expression value is ignored");
3238 ,
3239 ".tmp_source.zig:2:5: error: expression value is ignored",
3240 );
18363241
1837 cases.add("ignored comptime statement value",
3242 cases.add(
3243 "ignored comptime statement value",
18383244 \\export fn foo() void {
18393245 \\ comptime {1;}
18403246 \\}
1841 , ".tmp_source.zig:2:15: error: expression value is ignored");
3247 ,
3248 ".tmp_source.zig:2:15: error: expression value is ignored",
3249 );
18423250
1843 cases.add("ignored comptime value",
3251 cases.add(
3252 "ignored comptime value",
18443253 \\export fn foo() void {
18453254 \\ comptime 1;
18463255 \\}
1847 , ".tmp_source.zig:2:5: error: expression value is ignored");
3256 ,
3257 ".tmp_source.zig:2:5: error: expression value is ignored",
3258 );
18483259
1849 cases.add("ignored defered statement value",
3260 cases.add(
3261 "ignored defered statement value",
18503262 \\export fn foo() void {
18513263 \\ defer {1;}
18523264 \\}
1853 , ".tmp_source.zig:2:12: error: expression value is ignored");
3265 ,
3266 ".tmp_source.zig:2:12: error: expression value is ignored",
3267 );
18543268
1855 cases.add("ignored defered function call",
3269 cases.add(
3270 "ignored defered function call",
18563271 \\export fn foo() void {
18573272 \\ defer bar();
18583273 \\}
18593274 \\fn bar() error!i32 { return 0; }
1860 , ".tmp_source.zig:2:14: error: expression value is ignored");
3275 ,
3276 ".tmp_source.zig:2:14: error: expression value is ignored",
3277 );
18613278
1862 cases.add("dereference an array",
3279 cases.add(
3280 "dereference an array",
18633281 \\var s_buffer: [10]u8 = undefined;
18643282 \\pub fn pass(in: []u8) []u8 {
18653283 \\ var out = &s_buffer;
1866 \\ *out[0] = in[0];
1867 \\ return (*out)[0..1];
3284 \\ out.*.* = in[0];
3285 \\ return out.*[0..1];
18683286 \\}
18693287 \\
18703288 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
1871 , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'");
3289 ,
3290 ".tmp_source.zig:4:10: error: attempt to dereference non pointer type '[10]u8'",
3291 );
18723292
1873 cases.add("pass const ptr to mutable ptr fn",
3293 cases.add(
3294 "pass const ptr to mutable ptr fn",
18743295 \\fn foo() bool {
1875 \\ const a = ([]const u8)("a");
3296 \\ const a = ([]const u8)("a",);
18763297 \\ const b = &a;
18773298 \\ return ptrEql(b, b);
18783299 \\}
1879 \\fn ptrEql(a: &[]const u8, b: &[]const u8) bool {
3300 \\fn ptrEql(a: *[]const u8, b: *[]const u8) bool {
18803301 \\ return true;
18813302 \\}
18823303 \\
18833304 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1884 , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'");
3305 ,
3306 ".tmp_source.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'",
3307 );
18853308
18863309 cases.addCase(x: {
1887 const tc = cases.create("export collision",
1888 \\const foo = @import("foo.zig");
3310 const tc = cases.create(
3311 "export collision",
3312 \\const foo = @import("foo.zig",);
18893313 \\
18903314 \\export fn bar() usize {
18913315 \\ return foo.baz;
18923316 \\}
18933317 ,
18943318 "foo.zig:1:8: error: exported symbol collision: 'bar'",
1895 ".tmp_source.zig:3:8: note: other symbol here");
3319 ".tmp_source.zig:3:8: note: other symbol here",
3320 );
18963321
18973322 tc.addSourceFile("foo.zig",
18983323 \\export fn bar() void {}
......@@ -1902,35 +3327,28 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
19023327 break :x tc;
19033328 });
19043329
1905 cases.add("pass non-copyable type by value to function",
1906 \\const Point = struct { x: i32, y: i32, };
1907 \\fn foo(p: Point) void { }
1908 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1909 , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value");
1910
1911 cases.add("implicit cast from array to mutable slice",
3330 cases.add(
3331 "implicit cast from array to mutable slice",
19123332 \\var global_array: [10]i32 = undefined;
19133333 \\fn foo(param: []i32) void {}
19143334 \\export fn entry() void {
19153335 \\ foo(global_array);
19163336 \\}
1917 , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'");
3337 ,
3338 ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'",
3339 );
19183340
1919 cases.add("ptrcast to non-pointer",
1920 \\export fn entry(a: &i32) usize {
3341 cases.add(
3342 "ptrcast to non-pointer",
3343 \\export fn entry(a: *i32) usize {
19213344 \\ return @ptrCast(usize, a);
19223345 \\}
1923 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");
1924
1925 cases.add("too many error values to cast to small integer",
1926 \\const Error = error { A, B, C, D, E, F, G, H };
1927 \\fn foo(e: Error) u2 {
1928 \\ return u2(e);
1929 \\}
1930 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
1931 , ".tmp_source.zig:3:14: error: too many error values to fit in 'u2'");
3346 ,
3347 ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",
3348 );
19323349
1933 cases.add("asm at compile time",
3350 cases.add(
3351 "asm at compile time",
19343352 \\comptime {
19353353 \\ doSomeAsm();
19363354 \\}
......@@ -1942,48 +3360,66 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
19423360 \\ \\.set aoeu, derp;
19433361 \\ );
19443362 \\}
1945 , ".tmp_source.zig:6:5: error: unable to evaluate constant expression");
3363 ,
3364 ".tmp_source.zig:6:5: error: unable to evaluate constant expression",
3365 );
19463366
1947 cases.add("invalid member of builtin enum",
1948 \\const builtin = @import("builtin");
3367 cases.add(
3368 "invalid member of builtin enum",
3369 \\const builtin = @import("builtin",);
19493370 \\export fn entry() void {
19503371 \\ const foo = builtin.Arch.x86;
19513372 \\}
1952 , ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'");
3373 ,
3374 ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'",
3375 );
19533376
1954 cases.add("int to ptr of 0 bits",
3377 cases.add(
3378 "int to ptr of 0 bits",
19553379 \\export fn foo() void {
19563380 \\ var x: usize = 0x1000;
1957 \\ var y: &void = @intToPtr(&void, x);
3381 \\ var y: *void = @intToPtr(*void, x);
19583382 \\}
1959 , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information");
3383 ,
3384 ".tmp_source.zig:3:30: error: type '*void' has 0 bits and cannot store information",
3385 );
19603386
1961 cases.add("@fieldParentPtr - non struct",
3387 cases.add(
3388 "@fieldParentPtr - non struct",
19623389 \\const Foo = i32;
1963 \\export fn foo(a: &i32) &Foo {
3390 \\export fn foo(a: *i32) *Foo {
19643391 \\ return @fieldParentPtr(Foo, "a", a);
19653392 \\}
1966 , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'");
3393 ,
3394 ".tmp_source.zig:3:28: error: expected struct type, found 'i32'",
3395 );
19673396
1968 cases.add("@fieldParentPtr - bad field name",
3397 cases.add(
3398 "@fieldParentPtr - bad field name",
19693399 \\const Foo = extern struct {
19703400 \\ derp: i32,
19713401 \\};
1972 \\export fn foo(a: &i32) &Foo {
3402 \\export fn foo(a: *i32) *Foo {
19733403 \\ return @fieldParentPtr(Foo, "a", a);
19743404 \\}
1975 , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'");
3405 ,
3406 ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'",
3407 );
19763408
1977 cases.add("@fieldParentPtr - field pointer is not pointer",
3409 cases.add(
3410 "@fieldParentPtr - field pointer is not pointer",
19783411 \\const Foo = extern struct {
19793412 \\ a: i32,
19803413 \\};
1981 \\export fn foo(a: i32) &Foo {
3414 \\export fn foo(a: i32) *Foo {
19823415 \\ return @fieldParentPtr(Foo, "a", a);
19833416 \\}
1984 , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'");
3417 ,
3418 ".tmp_source.zig:5:38: error: expected pointer, found 'i32'",
3419 );
19853420
1986 cases.add("@fieldParentPtr - comptime field ptr not based on struct",
3421 cases.add(
3422 "@fieldParentPtr - comptime field ptr not based on struct",
19873423 \\const Foo = struct {
19883424 \\ a: i32,
19893425 \\ b: i32,
......@@ -1991,12 +3427,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
19913427 \\const foo = Foo { .a = 1, .b = 2, };
19923428 \\
19933429 \\comptime {
1994 \\ const field_ptr = @intToPtr(&i32, 0x1234);
3430 \\ const field_ptr = @intToPtr(*i32, 0x1234);
19953431 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
19963432 \\}
1997 , ".tmp_source.zig:9:55: error: pointer value not based on parent struct");
3433 ,
3434 ".tmp_source.zig:9:55: error: pointer value not based on parent struct",
3435 );
19983436
1999 cases.add("@fieldParentPtr - comptime wrong field index",
3437 cases.add(
3438 "@fieldParentPtr - comptime wrong field index",
20003439 \\const Foo = struct {
20013440 \\ a: i32,
20023441 \\ b: i32,
......@@ -2006,76 +3445,100 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
20063445 \\comptime {
20073446 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
20083447 \\}
2009 , ".tmp_source.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'");
3448 ,
3449 ".tmp_source.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'",
3450 );
20103451
2011 cases.add("@offsetOf - non struct",
3452 cases.add(
3453 "@offsetOf - non struct",
20123454 \\const Foo = i32;
20133455 \\export fn foo() usize {
2014 \\ return @offsetOf(Foo, "a");
3456 \\ return @offsetOf(Foo, "a",);
20153457 \\}
2016 , ".tmp_source.zig:3:22: error: expected struct type, found 'i32'");
3458 ,
3459 ".tmp_source.zig:3:22: error: expected struct type, found 'i32'",
3460 );
20173461
2018 cases.add("@offsetOf - bad field name",
3462 cases.add(
3463 "@offsetOf - bad field name",
20193464 \\const Foo = struct {
20203465 \\ derp: i32,
20213466 \\};
20223467 \\export fn foo() usize {
2023 \\ return @offsetOf(Foo, "a");
3468 \\ return @offsetOf(Foo, "a",);
20243469 \\}
2025 , ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'");
3470 ,
3471 ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'",
3472 );
20263473
2027 cases.addExe("missing main fn in executable",
3474 cases.addExe(
3475 "missing main fn in executable",
20283476 \\
2029 , "error: no member named 'main' in '");
3477 ,
3478 "error: no member named 'main' in '",
3479 );
20303480
2031 cases.addExe("private main fn",
3481 cases.addExe(
3482 "private main fn",
20323483 \\fn main() void {}
20333484 ,
20343485 "error: 'main' is private",
2035 ".tmp_source.zig:1:1: note: declared here");
3486 ".tmp_source.zig:1:1: note: declared here",
3487 );
20363488
2037 cases.add("setting a section on an extern variable",
3489 cases.add(
3490 "setting a section on an extern variable",
20383491 \\extern var foo: i32 section(".text2");
20393492 \\export fn entry() i32 {
20403493 \\ return foo;
20413494 \\}
20423495 ,
2043 ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'");
3496 ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'",
3497 );
20443498
2045 cases.add("setting a section on a local variable",
3499 cases.add(
3500 "setting a section on a local variable",
20463501 \\export fn entry() i32 {
20473502 \\ var foo: i32 section(".text2") = 1234;
20483503 \\ return foo;
20493504 \\}
20503505 ,
2051 ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'");
3506 ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'",
3507 );
20523508
2053 cases.add("setting a section on an extern fn",
3509 cases.add(
3510 "setting a section on an extern fn",
20543511 \\extern fn foo() section(".text2") void;
20553512 \\export fn entry() void {
20563513 \\ foo();
20573514 \\}
20583515 ,
2059 ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'");
3516 ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'",
3517 );
20603518
2061 cases.add("returning address of local variable - simple",
2062 \\export fn foo() &i32 {
3519 cases.add(
3520 "returning address of local variable - simple",
3521 \\export fn foo() *i32 {
20633522 \\ var a: i32 = undefined;
20643523 \\ return &a;
20653524 \\}
20663525 ,
2067 ".tmp_source.zig:3:13: error: function returns address of local variable");
3526 ".tmp_source.zig:3:13: error: function returns address of local variable",
3527 );
20683528
2069 cases.add("returning address of local variable - phi",
2070 \\export fn foo(c: bool) &i32 {
3529 cases.add(
3530 "returning address of local variable - phi",
3531 \\export fn foo(c: bool) *i32 {
20713532 \\ var a: i32 = undefined;
20723533 \\ var b: i32 = undefined;
20733534 \\ return if (c) &a else &b;
20743535 \\}
20753536 ,
2076 ".tmp_source.zig:4:12: error: function returns address of local variable");
3537 ".tmp_source.zig:4:12: error: function returns address of local variable",
3538 );
20773539
2078 cases.add("inner struct member shadowing outer struct member",
3540 cases.add(
3541 "inner struct member shadowing outer struct member",
20793542 \\fn A() type {
20803543 \\ return struct {
20813544 \\ b: B(),
......@@ -2097,57 +3560,71 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
20973560 \\}
20983561 ,
20993562 ".tmp_source.zig:9:17: error: redefinition of 'Self'",
2100 ".tmp_source.zig:5:9: note: previous definition is here");
3563 ".tmp_source.zig:5:9: note: previous definition is here",
3564 );
21013565
2102 cases.add("while expected bool, got nullable",
3566 cases.add(
3567 "while expected bool, got optional",
21033568 \\export fn foo() void {
21043569 \\ while (bar()) {}
21053570 \\}
21063571 \\fn bar() ?i32 { return 1; }
21073572 ,
2108 ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'");
3573 ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'",
3574 );
21093575
2110 cases.add("while expected bool, got error union",
3576 cases.add(
3577 "while expected bool, got error union",
21113578 \\export fn foo() void {
21123579 \\ while (bar()) {}
21133580 \\}
21143581 \\fn bar() error!i32 { return 1; }
21153582 ,
2116 ".tmp_source.zig:2:15: error: expected type 'bool', found 'error!i32'");
3583 ".tmp_source.zig:2:15: error: expected type 'bool', found 'error!i32'",
3584 );
21173585
2118 cases.add("while expected nullable, got bool",
3586 cases.add(
3587 "while expected optional, got bool",
21193588 \\export fn foo() void {
21203589 \\ while (bar()) |x| {}
21213590 \\}
21223591 \\fn bar() bool { return true; }
21233592 ,
2124 ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'");
3593 ".tmp_source.zig:2:15: error: expected optional type, found 'bool'",
3594 );
21253595
2126 cases.add("while expected nullable, got error union",
3596 cases.add(
3597 "while expected optional, got error union",
21273598 \\export fn foo() void {
21283599 \\ while (bar()) |x| {}
21293600 \\}
21303601 \\fn bar() error!i32 { return 1; }
21313602 ,
2132 ".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'");
3603 ".tmp_source.zig:2:15: error: expected optional type, found 'error!i32'",
3604 );
21333605
2134 cases.add("while expected error union, got bool",
3606 cases.add(
3607 "while expected error union, got bool",
21353608 \\export fn foo() void {
21363609 \\ while (bar()) |x| {} else |err| {}
21373610 \\}
21383611 \\fn bar() bool { return true; }
21393612 ,
2140 ".tmp_source.zig:2:15: error: expected error union type, found 'bool'");
3613 ".tmp_source.zig:2:15: error: expected error union type, found 'bool'",
3614 );
21413615
2142 cases.add("while expected error union, got nullable",
3616 cases.add(
3617 "while expected error union, got optional",
21433618 \\export fn foo() void {
21443619 \\ while (bar()) |x| {} else |err| {}
21453620 \\}
21463621 \\fn bar() ?i32 { return 1; }
21473622 ,
2148 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'");
3623 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'",
3624 );
21493625
2150 cases.add("inline fn calls itself indirectly",
3626 cases.add(
3627 "inline fn calls itself indirectly",
21513628 \\export fn foo() void {
21523629 \\ bar();
21533630 \\}
......@@ -2161,91 +3638,113 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
21613638 \\}
21623639 \\extern fn quux() void;
21633640 ,
2164 ".tmp_source.zig:4:8: error: unable to inline function");
3641 ".tmp_source.zig:4:8: error: unable to inline function",
3642 );
21653643
2166 cases.add("save reference to inline function",
3644 cases.add(
3645 "save reference to inline function",
21673646 \\export fn foo() void {
21683647 \\ quux(@ptrToInt(bar));
21693648 \\}
21703649 \\inline fn bar() void { }
21713650 \\extern fn quux(usize) void;
21723651 ,
2173 ".tmp_source.zig:4:8: error: unable to inline function");
3652 ".tmp_source.zig:4:8: error: unable to inline function",
3653 );
21743654
2175 cases.add("signed integer division",
3655 cases.add(
3656 "signed integer division",
21763657 \\export fn foo(a: i32, b: i32) i32 {
21773658 \\ return a / b;
21783659 \\}
21793660 ,
2180 ".tmp_source.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact");
3661 ".tmp_source.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact",
3662 );
21813663
2182 cases.add("signed integer remainder division",
3664 cases.add(
3665 "signed integer remainder division",
21833666 \\export fn foo(a: i32, b: i32) i32 {
21843667 \\ return a % b;
21853668 \\}
21863669 ,
2187 ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod");
3670 ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",
3671 );
21883672
2189 cases.add("cast negative value to unsigned integer",
3673 cases.add(
3674 "cast negative value to unsigned integer",
21903675 \\comptime {
21913676 \\ const value: i32 = -1;
2192 \\ const unsigned = u32(value);
3677 \\ const unsigned = @intCast(u32, value);
21933678 \\}
21943679 ,
2195 ".tmp_source.zig:3:25: error: attempt to cast negative value to unsigned integer");
3680 ".tmp_source.zig:3:22: error: attempt to cast negative value to unsigned integer",
3681 );
21963682
2197 cases.add("compile-time division by zero",
3683 cases.add(
3684 "compile-time division by zero",
21983685 \\comptime {
21993686 \\ const a: i32 = 1;
22003687 \\ const b: i32 = 0;
22013688 \\ const c = a / b;
22023689 \\}
22033690 ,
2204 ".tmp_source.zig:4:17: error: division by zero");
3691 ".tmp_source.zig:4:17: error: division by zero",
3692 );
22053693
2206 cases.add("compile-time remainder division by zero",
3694 cases.add(
3695 "compile-time remainder division by zero",
22073696 \\comptime {
22083697 \\ const a: i32 = 1;
22093698 \\ const b: i32 = 0;
22103699 \\ const c = a % b;
22113700 \\}
22123701 ,
2213 ".tmp_source.zig:4:17: error: division by zero");
3702 ".tmp_source.zig:4:17: error: division by zero",
3703 );
22143704
2215 cases.add("compile-time integer cast truncates bits",
3705 cases.add(
3706 "compile-time integer cast truncates bits",
22163707 \\comptime {
22173708 \\ const spartan_count: u16 = 300;
2218 \\ const byte = u8(spartan_count);
3709 \\ const byte = @intCast(u8, spartan_count);
22193710 \\}
22203711 ,
2221 ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits");
3712 ".tmp_source.zig:3:18: error: cast from 'u16' to 'u8' truncates bits",
3713 );
22223714
2223 cases.add("@setRuntimeSafety twice for same scope",
3715 cases.add(
3716 "@setRuntimeSafety twice for same scope",
22243717 \\export fn foo() void {
22253718 \\ @setRuntimeSafety(false);
22263719 \\ @setRuntimeSafety(false);
22273720 \\}
22283721 ,
22293722 ".tmp_source.zig:3:5: error: runtime safety set twice for same scope",
2230 ".tmp_source.zig:2:5: note: first set here");
3723 ".tmp_source.zig:2:5: note: first set here",
3724 );
22313725
2232 cases.add("@setFloatMode twice for same scope",
3726 cases.add(
3727 "@setFloatMode twice for same scope",
22333728 \\export fn foo() void {
22343729 \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized);
22353730 \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized);
22363731 \\}
22373732 ,
22383733 ".tmp_source.zig:3:5: error: float mode set twice for same scope",
2239 ".tmp_source.zig:2:5: note: first set here");
3734 ".tmp_source.zig:2:5: note: first set here",
3735 );
22403736
2241 cases.add("array access of type",
3737 cases.add(
3738 "array access of type",
22423739 \\export fn foo() void {
22433740 \\ var b: u8[40] = undefined;
22443741 \\}
22453742 ,
2246 ".tmp_source.zig:2:14: error: array access of non-array type 'type'");
3743 ".tmp_source.zig:2:14: error: array access of non-array type 'type'",
3744 );
22473745
2248 cases.add("cannot break out of defer expression",
3746 cases.add(
3747 "cannot break out of defer expression",
22493748 \\export fn foo() void {
22503749 \\ while (true) {
22513750 \\ defer {
......@@ -2254,9 +3753,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
22543753 \\ }
22553754 \\}
22563755 ,
2257 ".tmp_source.zig:4:13: error: cannot break out of defer expression");
3756 ".tmp_source.zig:4:13: error: cannot break out of defer expression",
3757 );
22583758
2259 cases.add("cannot continue out of defer expression",
3759 cases.add(
3760 "cannot continue out of defer expression",
22603761 \\export fn foo() void {
22613762 \\ while (true) {
22623763 \\ defer {
......@@ -2265,9 +3766,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
22653766 \\ }
22663767 \\}
22673768 ,
2268 ".tmp_source.zig:4:13: error: cannot continue out of defer expression");
3769 ".tmp_source.zig:4:13: error: cannot continue out of defer expression",
3770 );
22693771
2270 cases.add("calling a var args function only known at runtime",
3772 cases.add(
3773 "calling a var args function only known at runtime",
22713774 \\var foos = []fn(...) void { foo1, foo2 };
22723775 \\
22733776 \\fn foo1(args: ...) void {}
......@@ -2277,9 +3780,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
22773780 \\ foos[0]();
22783781 \\}
22793782 ,
2280 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
3783 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value",
3784 );
22813785
2282 cases.add("calling a generic function only known at runtime",
3786 cases.add(
3787 "calling a generic function only known at runtime",
22833788 \\var foos = []fn(var) void { foo1, foo2 };
22843789 \\
22853790 \\fn foo1(arg: var) void {}
......@@ -2289,10 +3794,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
22893794 \\ foos[0](true);
22903795 \\}
22913796 ,
2292 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
3797 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value",
3798 );
22933799
2294 cases.add("@compileError shows traceback of references that caused it",
2295 \\const foo = @compileError("aoeu");
3800 cases.add(
3801 "@compileError shows traceback of references that caused it",
3802 \\const foo = @compileError("aoeu",);
22963803 \\
22973804 \\const bar = baz + foo;
22983805 \\const baz = 1;
......@@ -2303,9 +3810,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
23033810 ,
23043811 ".tmp_source.zig:1:13: error: aoeu",
23053812 ".tmp_source.zig:3:19: note: referenced here",
2306 ".tmp_source.zig:7:12: note: referenced here");
3813 ".tmp_source.zig:7:12: note: referenced here",
3814 );
23073815
2308 cases.add("instantiating an undefined value for an invalid struct that contains itself",
3816 cases.add(
3817 "instantiating an undefined value for an invalid struct that contains itself",
23093818 \\const Foo = struct {
23103819 \\ x: Foo,
23113820 \\};
......@@ -2316,73 +3825,93 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
23163825 \\ return @sizeOf(@typeOf(foo.x));
23173826 \\}
23183827 ,
2319 ".tmp_source.zig:1:13: error: struct 'Foo' contains itself");
3828 ".tmp_source.zig:1:13: error: struct 'Foo' contains itself",
3829 );
23203830
2321 cases.add("float literal too large error",
3831 cases.add(
3832 "float literal too large error",
23223833 \\comptime {
23233834 \\ const a = 0x1.0p16384;
23243835 \\}
23253836 ,
2326 ".tmp_source.zig:2:15: error: float literal out of range of any type");
3837 ".tmp_source.zig:2:15: error: float literal out of range of any type",
3838 );
23273839
2328 cases.add("float literal too small error (denormal)",
3840 cases.add(
3841 "float literal too small error (denormal)",
23293842 \\comptime {
23303843 \\ const a = 0x1.0p-16384;
23313844 \\}
23323845 ,
2333 ".tmp_source.zig:2:15: error: float literal out of range of any type");
3846 ".tmp_source.zig:2:15: error: float literal out of range of any type",
3847 );
23343848
2335 cases.add("explicit cast float literal to integer when there is a fraction component",
3849 cases.add(
3850 "explicit cast float literal to integer when there is a fraction component",
23363851 \\export fn entry() i32 {
23373852 \\ return i32(12.34);
23383853 \\}
23393854 ,
2340 ".tmp_source.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'");
3855 ".tmp_source.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'",
3856 );
23413857
2342 cases.add("non pointer given to @ptrToInt",
3858 cases.add(
3859 "non pointer given to @ptrToInt",
23433860 \\export fn entry(x: i32) usize {
23443861 \\ return @ptrToInt(x);
23453862 \\}
23463863 ,
2347 ".tmp_source.zig:2:22: error: expected pointer, found 'i32'");
3864 ".tmp_source.zig:2:22: error: expected pointer, found 'i32'",
3865 );
23483866
2349 cases.add("@shlExact shifts out 1 bits",
3867 cases.add(
3868 "@shlExact shifts out 1 bits",
23503869 \\comptime {
23513870 \\ const x = @shlExact(u8(0b01010101), 2);
23523871 \\}
23533872 ,
2354 ".tmp_source.zig:2:15: error: operation caused overflow");
3873 ".tmp_source.zig:2:15: error: operation caused overflow",
3874 );
23553875
2356 cases.add("@shrExact shifts out 1 bits",
3876 cases.add(
3877 "@shrExact shifts out 1 bits",
23573878 \\comptime {
23583879 \\ const x = @shrExact(u8(0b10101010), 2);
23593880 \\}
23603881 ,
2361 ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits");
3882 ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits",
3883 );
23623884
2363 cases.add("shifting without int type or comptime known",
3885 cases.add(
3886 "shifting without int type or comptime known",
23643887 \\export fn entry(x: u8) u8 {
23653888 \\ return 0x11 << x;
23663889 \\}
23673890 ,
2368 ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known");
3891 ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known",
3892 );
23693893
2370 cases.add("shifting RHS is log2 of LHS int bit width",
3894 cases.add(
3895 "shifting RHS is log2 of LHS int bit width",
23713896 \\export fn entry(x: u8, y: u8) u8 {
23723897 \\ return x << y;
23733898 \\}
23743899 ,
2375 ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'");
3900 ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'",
3901 );
23763902
2377 cases.add("globally shadowing a primitive type",
3903 cases.add(
3904 "globally shadowing a primitive type",
23783905 \\const u16 = @intType(false, 8);
23793906 \\export fn entry() void {
23803907 \\ const a: u16 = 300;
23813908 \\}
23823909 ,
2383 ".tmp_source.zig:1:1: error: declaration shadows type 'u16'");
3910 ".tmp_source.zig:1:1: error: declaration shadows type 'u16'",
3911 );
23843912
2385 cases.add("implicitly increasing pointer alignment",
3913 cases.add(
3914 "implicitly increasing pointer alignment",
23863915 \\const Foo = packed struct {
23873916 \\ a: u8,
23883917 \\ b: u32,
......@@ -2393,13 +3922,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
23933922 \\ bar(&foo.b);
23943923 \\}
23953924 \\
2396 \\fn bar(x: &u32) void {
2397 \\ *x += 1;
3925 \\fn bar(x: *u32) void {
3926 \\ x.* += 1;
23983927 \\}
23993928 ,
2400 ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'");
3929 ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'",
3930 );
24013931
2402 cases.add("implicitly increasing slice alignment",
3932 cases.add(
3933 "implicitly increasing slice alignment",
24033934 \\const Foo = packed struct {
24043935 \\ a: u8,
24053936 \\ b: u32,
......@@ -2408,44 +3939,42 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
24083939 \\export fn entry() void {
24093940 \\ var foo = Foo { .a = 1, .b = 10 };
24103941 \\ foo.b += 1;
2411 \\ bar((&foo.b)[0..1]);
3942 \\ bar((*[1]u32)(&foo.b)[0..]);
24123943 \\}
24133944 \\
24143945 \\fn bar(x: []u32) void {
24153946 \\ x[0] += 1;
24163947 \\}
24173948 ,
2418 ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align(1) u32'");
3949 ".tmp_source.zig:9:18: error: cast increases pointer alignment",
3950 ".tmp_source.zig:9:23: note: '*align(1) u32' has alignment 1",
3951 ".tmp_source.zig:9:18: note: '*[1]u32' has alignment 4",
3952 );
24193953
2420 cases.add("increase pointer alignment in @ptrCast",
3954 cases.add(
3955 "increase pointer alignment in @ptrCast",
24213956 \\export fn entry() u32 {
24223957 \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04};
2423 \\ const ptr = @ptrCast(&u32, &bytes[0]);
2424 \\ return *ptr;
3958 \\ const ptr = @ptrCast(*u32, &bytes[0]);
3959 \\ return ptr.*;
24253960 \\}
24263961 ,
24273962 ".tmp_source.zig:3:17: error: cast increases pointer alignment",
2428 ".tmp_source.zig:3:38: note: '&u8' has alignment 1",
2429 ".tmp_source.zig:3:27: note: '&u32' has alignment 4");
3963 ".tmp_source.zig:3:38: note: '*u8' has alignment 1",
3964 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",
3965 );
24303966
2431 cases.add("increase pointer alignment in slice resize",
2432 \\export fn entry() u32 {
2433 \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04};
2434 \\ return ([]u32)(bytes[0..])[0];
2435 \\}
2436 ,
2437 ".tmp_source.zig:3:19: error: cast increases pointer alignment",
2438 ".tmp_source.zig:3:19: note: '[]u8' has alignment 1",
2439 ".tmp_source.zig:3:19: note: '[]u32' has alignment 4");
2440
2441 cases.add("@alignCast expects pointer or slice",
3967 cases.add(
3968 "@alignCast expects pointer or slice",
24423969 \\export fn entry() void {
24433970 \\ @alignCast(4, u32(3));
24443971 \\}
24453972 ,
2446 ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'");
3973 ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'",
3974 );
24473975
2448 cases.add("passing an under-aligned function pointer",
3976 cases.add(
3977 "passing an under-aligned function pointer",
24493978 \\export fn entry() void {
24503979 \\ testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
24513980 \\}
......@@ -2454,26 +3983,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
24543983 \\}
24553984 \\fn alignedSmall() align(4) i32 { return 1234; }
24563985 ,
2457 ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'");
3986 ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'",
3987 );
24583988
2459 cases.add("passing a not-aligned-enough pointer to cmpxchg",
3989 cases.add(
3990 "passing a not-aligned-enough pointer to cmpxchg",
24603991 \\const AtomicOrder = @import("builtin").AtomicOrder;
24613992 \\export fn entry() bool {
24623993 \\ var x: i32 align(1) = 1234;
2463 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
3994 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
24643995 \\ return x == 5678;
24653996 \\}
24663997 ,
2467 ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1");
3998 ".tmp_source.zig:4:32: error: expected type '*i32', found '*align(1) i32'",
3999 );
24684000
2469 cases.add("wrong size to an array literal",
4001 cases.add(
4002 "wrong size to an array literal",
24704003 \\comptime {
24714004 \\ const array = [2]u8{1, 2, 3};
24724005 \\}
24734006 ,
2474 ".tmp_source.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal");
4007 ".tmp_source.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal",
4008 );
24754009
2476 cases.add("@setEvalBranchQuota in non-root comptime execution context",
4010 cases.add(
4011 "@setEvalBranchQuota in non-root comptime execution context",
24774012 \\comptime {
24784013 \\ foo();
24794014 \\}
......@@ -2483,72 +4018,82 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
24834018 ,
24844019 ".tmp_source.zig:5:5: error: @setEvalBranchQuota must be called from the top of the comptime stack",
24854020 ".tmp_source.zig:2:8: note: called from here",
2486 ".tmp_source.zig:1:10: note: called from here");
4021 ".tmp_source.zig:1:10: note: called from here",
4022 );
24874023
2488 cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()",
4024 cases.add(
4025 "wrong pointer implicitly casted to pointer to @OpaqueType()",
24894026 \\const Derp = @OpaqueType();
2490 \\extern fn bar(d: &Derp) void;
4027 \\extern fn bar(d: *Derp) void;
24914028 \\export fn foo() void {
24924029 \\ var x = u8(1);
2493 \\ bar(@ptrCast(&c_void, &x));
4030 \\ bar(@ptrCast(*c_void, &x));
24944031 \\}
24954032 ,
2496 ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'");
4033 ".tmp_source.zig:5:9: error: expected type '*Derp', found '*c_void'",
4034 );
24974035
2498 cases.add("non-const variables of things that require const variables",
4036 cases.add(
4037 "non-const variables of things that require const variables",
24994038 \\const Opaque = @OpaqueType();
25004039 \\
2501 \\export fn entry(opaque: &Opaque) void {
4040 \\export fn entry(opaque: *Opaque) void {
25024041 \\ var m2 = &2;
2503 \\ const y: u32 = *m2;
4042 \\ const y: u32 = m2.*;
25044043 \\
25054044 \\ var a = undefined;
25064045 \\ var b = 1;
25074046 \\ var c = 1.0;
25084047 \\ var d = this;
25094048 \\ var e = null;
2510 \\ var f = *opaque;
4049 \\ var f = opaque.*;
25114050 \\ var g = i32;
2512 \\ var h = @import("std");
4051 \\ var h = @import("std",);
25134052 \\ var i = (Foo {}).bar;
25144053 \\
25154054 \\ var z: noreturn = return;
25164055 \\}
25174056 \\
25184057 \\const Foo = struct {
2519 \\ fn bar(self: &const Foo) void {}
4058 \\ fn bar(self: *const Foo) void {}
25204059 \\};
25214060 ,
2522 ".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime",
4061 ".tmp_source.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",
25234062 ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
2524 ".tmp_source.zig:8:4: error: variable of type '(integer literal)' must be const or comptime",
2525 ".tmp_source.zig:9:4: error: variable of type '(float literal)' must be const or comptime",
4063 ".tmp_source.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
4064 ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
25264065 ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
25274066 ".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",
2528 ".tmp_source.zig:12:4: error: variable of type 'Opaque' must be const or comptime",
4067 ".tmp_source.zig:12:4: error: variable of type 'Opaque' not allowed",
25294068 ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
25304069 ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
2531 ".tmp_source.zig:15:4: error: variable of type '(bound fn(&const Foo) void)' must be const or comptime",
2532 ".tmp_source.zig:17:4: error: unreachable code");
4070 ".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
4071 ".tmp_source.zig:17:4: error: unreachable code",
4072 );
25334073
2534 cases.add("wrong types given to atomic order args in cmpxchg",
4074 cases.add(
4075 "wrong types given to atomic order args in cmpxchg",
25354076 \\export fn entry() void {
25364077 \\ var x: i32 = 1234;
2537 \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {}
4078 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}
25384079 \\}
25394080 ,
2540 ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'");
4081 ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'",
4082 );
25414083
2542 cases.add("wrong types given to @export",
4084 cases.add(
4085 "wrong types given to @export",
25434086 \\extern fn entry() void { }
25444087 \\comptime {
25454088 \\ @export("entry", entry, u32(1234));
25464089 \\}
25474090 ,
2548 ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'");
4091 ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'",
4092 );
25494093
2550 cases.add("struct with invalid field",
2551 \\const std = @import("std");
4094 cases.add(
4095 "struct with invalid field",
4096 \\const std = @import("std",);
25524097 \\const Allocator = std.mem.Allocator;
25534098 \\const ArrayList = std.ArrayList;
25544099 \\
......@@ -2572,23 +4117,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
25724117 \\ };
25734118 \\}
25744119 ,
2575 ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'");
4120 ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
4121 );
25764122
2577 cases.add("@setAlignStack outside function",
4123 cases.add(
4124 "@setAlignStack outside function",
25784125 \\comptime {
25794126 \\ @setAlignStack(16);
25804127 \\}
25814128 ,
2582 ".tmp_source.zig:2:5: error: @setAlignStack outside function");
4129 ".tmp_source.zig:2:5: error: @setAlignStack outside function",
4130 );
25834131
2584 cases.add("@setAlignStack in naked function",
4132 cases.add(
4133 "@setAlignStack in naked function",
25854134 \\export nakedcc fn entry() void {
25864135 \\ @setAlignStack(16);
25874136 \\}
25884137 ,
2589 ".tmp_source.zig:2:5: error: @setAlignStack in naked function");
4138 ".tmp_source.zig:2:5: error: @setAlignStack in naked function",
4139 );
25904140
2591 cases.add("@setAlignStack in inline function",
4141 cases.add(
4142 "@setAlignStack in inline function",
25924143 \\export fn entry() void {
25934144 \\ foo();
25944145 \\}
......@@ -2596,25 +4147,31 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
25964147 \\ @setAlignStack(16);
25974148 \\}
25984149 ,
2599 ".tmp_source.zig:5:5: error: @setAlignStack in inline function");
4150 ".tmp_source.zig:5:5: error: @setAlignStack in inline function",
4151 );
26004152
2601 cases.add("@setAlignStack set twice",
4153 cases.add(
4154 "@setAlignStack set twice",
26024155 \\export fn entry() void {
26034156 \\ @setAlignStack(16);
26044157 \\ @setAlignStack(16);
26054158 \\}
26064159 ,
26074160 ".tmp_source.zig:3:5: error: alignstack set twice",
2608 ".tmp_source.zig:2:5: note: first set here");
4161 ".tmp_source.zig:2:5: note: first set here",
4162 );
26094163
2610 cases.add("@setAlignStack too big",
4164 cases.add(
4165 "@setAlignStack too big",
26114166 \\export fn entry() void {
26124167 \\ @setAlignStack(511 + 1);
26134168 \\}
26144169 ,
2615 ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256");
4170 ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256",
4171 );
26164172
2617 cases.add("storing runtime value in compile time variable then using it",
4173 cases.add(
4174 "storing runtime value in compile time variable then using it",
26184175 \\const Mode = @import("builtin").Mode;
26194176 \\
26204177 \\fn Free(comptime filename: []const u8) TestCase {
......@@ -2657,134 +4214,164 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
26574214 \\ }
26584215 \\}
26594216 ,
2660 ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable");
4217 ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable",
4218 );
26614219
2662 cases.add("field access of opaque type",
4220 cases.add(
4221 "field access of opaque type",
26634222 \\const MyType = @OpaqueType();
26644223 \\
26654224 \\export fn entry() bool {
26664225 \\ var x: i32 = 1;
2667 \\ return bar(@ptrCast(&MyType, &x));
4226 \\ return bar(@ptrCast(*MyType, &x));
26684227 \\}
26694228 \\
2670 \\fn bar(x: &MyType) bool {
4229 \\fn bar(x: *MyType) bool {
26714230 \\ return x.blah;
26724231 \\}
26734232 ,
2674 ".tmp_source.zig:9:13: error: type '&MyType' does not support field access");
4233 ".tmp_source.zig:9:13: error: type '*MyType' does not support field access",
4234 );
26754235
2676 cases.add("carriage return special case",
4236 cases.add(
4237 "carriage return special case",
26774238 "fn test() bool {\r\n" ++
2678 " true\r\n" ++
2679 "}\r\n"
2680 ,
2681 ".tmp_source.zig:1:17: error: invalid carriage return, only '\\n' line endings are supported");
2682
2683 cases.add("non-printable invalid character",
2684 "\xff\xfe" ++
2685 \\fn test() bool {\r
2686 \\ true\r
2687 \\}
2688 ,
2689 ".tmp_source.zig:1:1: error: invalid character: '\\xff'");
4239 " true\r\n" ++
4240 "}\r\n",
4241 ".tmp_source.zig:1:17: error: invalid carriage return, only '\\n' line endings are supported",
4242 );
4243
4244 cases.add(
4245 "non-printable invalid character",
4246 "\xff\xfe" ++
4247 \\fn test() bool {\r
4248 \\ true\r
4249 \\}
4250 ,
4251 ".tmp_source.zig:1:1: error: invalid character: '\\xff'",
4252 );
26904253
2691 cases.add("non-printable invalid character with escape alternative",
4254 cases.add(
4255 "non-printable invalid character with escape alternative",
26924256 "fn test() bool {\n" ++
2693 "\ttrue\n" ++
2694 "}\n"
2695 ,
2696 ".tmp_source.zig:2:1: error: invalid character: '\\t'");
4257 "\ttrue\n" ++
4258 "}\n",
4259 ".tmp_source.zig:2:1: error: invalid character: '\\t'",
4260 );
26974261
2698 cases.add("@ArgType given non function parameter",
4262 cases.add(
4263 "@ArgType given non function parameter",
26994264 \\comptime {
27004265 \\ _ = @ArgType(i32, 3);
27014266 \\}
27024267 ,
2703 ".tmp_source.zig:2:18: error: expected function, found 'i32'");
4268 ".tmp_source.zig:2:18: error: expected function, found 'i32'",
4269 );
27044270
2705 cases.add("@ArgType arg index out of bounds",
4271 cases.add(
4272 "@ArgType arg index out of bounds",
27064273 \\comptime {
27074274 \\ _ = @ArgType(@typeOf(add), 2);
27084275 \\}
27094276 \\fn add(a: i32, b: i32) i32 { return a + b; }
27104277 ,
2711 ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments");
4278 ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments",
4279 );
27124280
2713 cases.add("@memberType on unsupported type",
4281 cases.add(
4282 "@memberType on unsupported type",
27144283 \\comptime {
27154284 \\ _ = @memberType(i32, 0);
27164285 \\}
27174286 ,
2718 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
4287 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType",
4288 );
27194289
2720 cases.add("@memberType on enum",
4290 cases.add(
4291 "@memberType on enum",
27214292 \\comptime {
27224293 \\ _ = @memberType(Foo, 0);
27234294 \\}
27244295 \\const Foo = enum {A,};
27254296 ,
2726 ".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType");
4297 ".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType",
4298 );
27274299
2728 cases.add("@memberType struct out of bounds",
4300 cases.add(
4301 "@memberType struct out of bounds",
27294302 \\comptime {
27304303 \\ _ = @memberType(Foo, 0);
27314304 \\}
27324305 \\const Foo = struct {};
27334306 ,
2734 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
4307 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
4308 );
27354309
2736 cases.add("@memberType union out of bounds",
4310 cases.add(
4311 "@memberType union out of bounds",
27374312 \\comptime {
27384313 \\ _ = @memberType(Foo, 1);
27394314 \\}
27404315 \\const Foo = union {A: void,};
27414316 ,
2742 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
4317 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
4318 );
27434319
2744 cases.add("@memberName on unsupported type",
4320 cases.add(
4321 "@memberName on unsupported type",
27454322 \\comptime {
27464323 \\ _ = @memberName(i32, 0);
27474324 \\}
27484325 ,
2749 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName");
4326 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName",
4327 );
27504328
2751 cases.add("@memberName struct out of bounds",
4329 cases.add(
4330 "@memberName struct out of bounds",
27524331 \\comptime {
27534332 \\ _ = @memberName(Foo, 0);
27544333 \\}
27554334 \\const Foo = struct {};
27564335 ,
2757 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
4336 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
4337 );
27584338
2759 cases.add("@memberName enum out of bounds",
4339 cases.add(
4340 "@memberName enum out of bounds",
27604341 \\comptime {
27614342 \\ _ = @memberName(Foo, 1);
27624343 \\}
27634344 \\const Foo = enum {A,};
27644345 ,
2765 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
4346 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
4347 );
27664348
2767 cases.add("@memberName union out of bounds",
4349 cases.add(
4350 "@memberName union out of bounds",
27684351 \\comptime {
27694352 \\ _ = @memberName(Foo, 1);
27704353 \\}
27714354 \\const Foo = union {A:i32,};
27724355 ,
2773 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
4356 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
4357 );
27744358
2775 cases.add("calling var args extern function, passing array instead of pointer",
4359 cases.add(
4360 "calling var args extern function, passing array instead of pointer",
27764361 \\export fn entry() void {
2777 \\ foo("hello");
4362 \\ foo("hello",);
27784363 \\}
2779 \\pub extern fn foo(format: &const u8, ...) void;
4364 \\pub extern fn foo(format: *const u8, ...) void;
27804365 ,
2781 ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'");
4366 ".tmp_source.zig:2:9: error: expected type '*const u8', found '[5]u8'",
4367 );
27824368
2783 cases.add("constant inside comptime function has compile error",
4369 cases.add(
4370 "constant inside comptime function has compile error",
27844371 \\const ContextAllocator = MemoryPool(usize);
27854372 \\
27864373 \\pub fn MemoryPool(comptime T: type) type {
2787 \\ const free_list_t = @compileError("aoeu");
4374 \\ const free_list_t = @compileError("aoeu",);
27884375 \\
27894376 \\ return struct {
27904377 \\ free_list: free_list_t,
......@@ -2797,9 +4384,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
27974384 ,
27984385 ".tmp_source.zig:4:25: error: aoeu",
27994386 ".tmp_source.zig:1:36: note: called from here",
2800 ".tmp_source.zig:12:20: note: referenced here");
4387 ".tmp_source.zig:12:20: note: referenced here",
4388 );
28014389
2802 cases.add("specify enum tag type that is too small",
4390 cases.add(
4391 "specify enum tag type that is too small",
28034392 \\const Small = enum (u2) {
28044393 \\ One,
28054394 \\ Two,
......@@ -2812,9 +4401,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
28124401 \\ var x = Small.One;
28134402 \\}
28144403 ,
2815 ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'");
4404 ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'",
4405 );
28164406
2817 cases.add("specify non-integer enum tag type",
4407 cases.add(
4408 "specify non-integer enum tag type",
28184409 \\const Small = enum (f32) {
28194410 \\ One,
28204411 \\ Two,
......@@ -2825,9 +4416,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
28254416 \\ var x = Small.One;
28264417 \\}
28274418 ,
2828 ".tmp_source.zig:1:20: error: expected integer, found 'f32'");
4419 ".tmp_source.zig:1:20: error: expected integer, found 'f32'",
4420 );
28294421
2830 cases.add("implicitly casting enum to tag type",
4422 cases.add(
4423 "implicitly casting enum to tag type",
28314424 \\const Small = enum(u2) {
28324425 \\ One,
28334426 \\ Two,
......@@ -2839,23 +4432,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
28394432 \\ var x: u2 = Small.Two;
28404433 \\}
28414434 ,
2842 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'");
2843
2844 cases.add("explicitly casting enum to non tag type",
2845 \\const Small = enum(u2) {
2846 \\ One,
2847 \\ Two,
2848 \\ Three,
2849 \\ Four,
2850 \\};
2851 \\
2852 \\export fn entry() void {
2853 \\ var x = u3(Small.Two);
2854 \\}
2855 ,
2856 ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'");
4435 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",
4436 );
28574437
2858 cases.add("explicitly casting non tag type to enum",
4438 cases.add(
4439 "explicitly casting non tag type to enum",
28594440 \\const Small = enum(u2) {
28604441 \\ One,
28614442 \\ Two,
......@@ -2865,12 +4446,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
28654446 \\
28664447 \\export fn entry() void {
28674448 \\ var y = u3(3);
2868 \\ var x = Small(y);
4449 \\ var x = @intToEnum(Small, y);
28694450 \\}
28704451 ,
2871 ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'");
4452 ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'",
4453 );
28724454
2873 cases.add("non unsigned integer enum tag type",
4455 cases.add(
4456 "non unsigned integer enum tag type",
28744457 \\const Small = enum(i2) {
28754458 \\ One,
28764459 \\ Two,
......@@ -2882,9 +4465,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
28824465 \\ var y = Small.Two;
28834466 \\}
28844467 ,
2885 ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'");
4468 ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'",
4469 );
28864470
2887 cases.add("struct fields with value assignments",
4471 cases.add(
4472 "struct fields with value assignments",
28884473 \\const MultipleChoice = struct {
28894474 \\ A: i32 = 20,
28904475 \\};
......@@ -2892,9 +4477,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
28924477 \\ var x: MultipleChoice = undefined;
28934478 \\}
28944479 ,
2895 ".tmp_source.zig:2:14: error: enums, not structs, support field assignment");
4480 ".tmp_source.zig:2:14: error: enums, not structs, support field assignment",
4481 );
28964482
2897 cases.add("union fields with value assignments",
4483 cases.add(
4484 "union fields with value assignments",
28984485 \\const MultipleChoice = union {
28994486 \\ A: i32 = 20,
29004487 \\};
......@@ -2903,25 +4490,31 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29034490 \\}
29044491 ,
29054492 ".tmp_source.zig:2:14: error: non-enum union field assignment",
2906 ".tmp_source.zig:1:24: note: consider 'union(enum)' here");
4493 ".tmp_source.zig:1:24: note: consider 'union(enum)' here",
4494 );
29074495
2908 cases.add("enum with 0 fields",
4496 cases.add(
4497 "enum with 0 fields",
29094498 \\const Foo = enum {};
29104499 \\export fn entry() usize {
29114500 \\ return @sizeOf(Foo);
29124501 \\}
29134502 ,
2914 ".tmp_source.zig:1:13: error: enums must have 1 or more fields");
4503 ".tmp_source.zig:1:13: error: enums must have 1 or more fields",
4504 );
29154505
2916 cases.add("union with 0 fields",
4506 cases.add(
4507 "union with 0 fields",
29174508 \\const Foo = union {};
29184509 \\export fn entry() usize {
29194510 \\ return @sizeOf(Foo);
29204511 \\}
29214512 ,
2922 ".tmp_source.zig:1:13: error: unions must have 1 or more fields");
4513 ".tmp_source.zig:1:13: error: unions must have 1 or more fields",
4514 );
29234515
2924 cases.add("enum value already taken",
4516 cases.add(
4517 "enum value already taken",
29254518 \\const MultipleChoice = enum(u32) {
29264519 \\ A = 20,
29274520 \\ B = 40,
......@@ -2934,9 +4527,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29344527 \\}
29354528 ,
29364529 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
2937 ".tmp_source.zig:4:9: note: other occurrence here");
4530 ".tmp_source.zig:4:9: note: other occurrence here",
4531 );
29384532
2939 cases.add("union with specified enum omits field",
4533 cases.add(
4534 "union with specified enum omits field",
29404535 \\const Letter = enum {
29414536 \\ A,
29424537 \\ B,
......@@ -2951,9 +4546,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29514546 \\}
29524547 ,
29534548 ".tmp_source.zig:6:17: error: enum field missing: 'C'",
2954 ".tmp_source.zig:4:5: note: declared here");
4549 ".tmp_source.zig:4:5: note: declared here",
4550 );
29554551
2956 cases.add("@TagType when union has no attached enum",
4552 cases.add(
4553 "@TagType when union has no attached enum",
29574554 \\const Foo = union {
29584555 \\ A: i32,
29594556 \\};
......@@ -2962,9 +4559,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29624559 \\}
29634560 ,
29644561 ".tmp_source.zig:5:24: error: union 'Foo' has no tag",
2965 ".tmp_source.zig:1:13: note: consider 'union(enum)' here");
4562 ".tmp_source.zig:1:13: note: consider 'union(enum)' here",
4563 );
29664564
2967 cases.add("non-integer tag type to automatic union enum",
4565 cases.add(
4566 "non-integer tag type to automatic union enum",
29684567 \\const Foo = union(enum(f32)) {
29694568 \\ A: i32,
29704569 \\};
......@@ -2972,9 +4571,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29724571 \\ const x = @TagType(Foo);
29734572 \\}
29744573 ,
2975 ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'");
4574 ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'",
4575 );
29764576
2977 cases.add("non-enum tag type passed to union",
4577 cases.add(
4578 "non-enum tag type passed to union",
29784579 \\const Foo = union(u32) {
29794580 \\ A: i32,
29804581 \\};
......@@ -2982,9 +4583,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29824583 \\ const x = @TagType(Foo);
29834584 \\}
29844585 ,
2985 ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'");
4586 ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'",
4587 );
29864588
2987 cases.add("union auto-enum value already taken",
4589 cases.add(
4590 "union auto-enum value already taken",
29884591 \\const MultipleChoice = union(enum(u32)) {
29894592 \\ A = 20,
29904593 \\ B = 40,
......@@ -2997,9 +4600,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
29974600 \\}
29984601 ,
29994602 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
3000 ".tmp_source.zig:4:9: note: other occurrence here");
4603 ".tmp_source.zig:4:9: note: other occurrence here",
4604 );
30014605
3002 cases.add("union enum field does not match enum",
4606 cases.add(
4607 "union enum field does not match enum",
30034608 \\const Letter = enum {
30044609 \\ A,
30054610 \\ B,
......@@ -3016,9 +4621,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30164621 \\}
30174622 ,
30184623 ".tmp_source.zig:10:5: error: enum field not found: 'D'",
3019 ".tmp_source.zig:1:16: note: enum declared here");
4624 ".tmp_source.zig:1:16: note: enum declared here",
4625 );
30204626
3021 cases.add("field type supplied in an enum",
4627 cases.add(
4628 "field type supplied in an enum",
30224629 \\const Letter = enum {
30234630 \\ A: void,
30244631 \\ B,
......@@ -3029,9 +4636,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30294636 \\}
30304637 ,
30314638 ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types",
3032 ".tmp_source.zig:1:16: note: consider 'union(enum)' here");
4639 ".tmp_source.zig:1:16: note: consider 'union(enum)' here",
4640 );
30334641
3034 cases.add("struct field missing type",
4642 cases.add(
4643 "struct field missing type",
30354644 \\const Letter = struct {
30364645 \\ A,
30374646 \\};
......@@ -3039,9 +4648,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30394648 \\ var a = Letter { .A = {} };
30404649 \\}
30414650 ,
3042 ".tmp_source.zig:2:5: error: struct field missing type");
4651 ".tmp_source.zig:2:5: error: struct field missing type",
4652 );
30434653
3044 cases.add("extern union field missing type",
4654 cases.add(
4655 "extern union field missing type",
30454656 \\const Letter = extern union {
30464657 \\ A,
30474658 \\};
......@@ -3049,9 +4660,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30494660 \\ var a = Letter { .A = {} };
30504661 \\}
30514662 ,
3052 ".tmp_source.zig:2:5: error: union field missing type");
4663 ".tmp_source.zig:2:5: error: union field missing type",
4664 );
30534665
3054 cases.add("extern union given enum tag type",
4666 cases.add(
4667 "extern union given enum tag type",
30554668 \\const Letter = enum {
30564669 \\ A,
30574670 \\ B,
......@@ -3066,9 +4679,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30664679 \\ var a = Payload { .A = 1234 };
30674680 \\}
30684681 ,
3069 ".tmp_source.zig:6:29: error: extern union does not support enum tag type");
4682 ".tmp_source.zig:6:29: error: extern union does not support enum tag type",
4683 );
30704684
3071 cases.add("packed union given enum tag type",
4685 cases.add(
4686 "packed union given enum tag type",
30724687 \\const Letter = enum {
30734688 \\ A,
30744689 \\ B,
......@@ -3083,9 +4698,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30834698 \\ var a = Payload { .A = 1234 };
30844699 \\}
30854700 ,
3086 ".tmp_source.zig:6:29: error: packed union does not support enum tag type");
4701 ".tmp_source.zig:6:29: error: packed union does not support enum tag type",
4702 );
30874703
3088 cases.add("switch on union with no attached enum",
4704 cases.add(
4705 "switch on union with no attached enum",
30894706 \\const Payload = union {
30904707 \\ A: i32,
30914708 \\ B: f64,
......@@ -3095,29 +4712,33 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30954712 \\ const a = Payload { .A = 1234 };
30964713 \\ foo(a);
30974714 \\}
3098 \\fn foo(a: &const Payload) void {
3099 \\ switch (*a) {
4715 \\fn foo(a: *const Payload) void {
4716 \\ switch (a.*) {
31004717 \\ Payload.A => {},
31014718 \\ else => unreachable,
31024719 \\ }
31034720 \\}
31044721 ,
3105 ".tmp_source.zig:11:13: error: switch on union which has no attached enum",
3106 ".tmp_source.zig:1:17: note: consider 'union(enum)' here");
4722 ".tmp_source.zig:11:14: error: switch on union which has no attached enum",
4723 ".tmp_source.zig:1:17: note: consider 'union(enum)' here",
4724 );
31074725
3108 cases.add("enum in field count range but not matching tag",
4726 cases.add(
4727 "enum in field count range but not matching tag",
31094728 \\const Foo = enum(u32) {
31104729 \\ A = 10,
31114730 \\ B = 11,
31124731 \\};
31134732 \\export fn entry() void {
3114 \\ var x = Foo(0);
4733 \\ var x = @intToEnum(Foo, 0);
31154734 \\}
31164735 ,
3117 ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0",
3118 ".tmp_source.zig:1:13: note: 'Foo' declared here");
4736 ".tmp_source.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
4737 ".tmp_source.zig:1:13: note: 'Foo' declared here",
4738 );
31194739
3120 cases.add("comptime cast enum to union but field has payload",
4740 cases.add(
4741 "comptime cast enum to union but field has payload",
31214742 \\const Letter = enum { A, B, C };
31224743 \\const Value = union(Letter) {
31234744 \\ A: i32,
......@@ -3129,9 +4750,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
31294750 \\}
31304751 ,
31314752 ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
3132 ".tmp_source.zig:3:5: note: field 'A' declared here");
4753 ".tmp_source.zig:3:5: note: field 'A' declared here",
4754 );
31334755
3134 cases.add("runtime cast to union which has non-void fields",
4756 cases.add(
4757 "runtime cast to union which has non-void fields",
31354758 \\const Letter = enum { A, B, C };
31364759 \\const Value = union(Letter) {
31374760 \\ A: i32,
......@@ -3146,27 +4769,52 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
31464769 \\}
31474770 ,
31484771 ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
3149 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'");
4772 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
4773 );
4774
4775 cases.add(
4776 "taking offset of void field in struct",
4777 \\const Empty = struct {
4778 \\ val: void,
4779 \\};
4780 \\export fn foo() void {
4781 \\ const fieldOffset = @offsetOf(Empty, "val",);
4782 \\}
4783 ,
4784 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",
4785 );
31504786
3151 cases.add("self-referencing function pointer field",
3152 \\const S = struct {
3153 \\ f: fn(_: S) void,
4787 cases.add(
4788 "invalid union field access in comptime",
4789 \\const Foo = union {
4790 \\ Bar: u8,
4791 \\ Baz: void,
31544792 \\};
3155 \\fn f(_: S) void {
4793 \\comptime {
4794 \\ var foo = Foo {.Baz = {}};
4795 \\ const bar_val = foo.Bar;
31564796 \\}
3157 \\export fn entry() void {
3158 \\ var _ = S { .f = f };
4797 ,
4798 ".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",
4799 );
4800
4801 cases.add(
4802 "getting return type of generic function",
4803 \\fn generic(a: var) void {}
4804 \\comptime {
4805 \\ _ = @typeOf(generic).ReturnType;
31594806 \\}
31604807 ,
3161 ".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value");
4808 ".tmp_source.zig:3:25: error: ReturnType has not been resolved because 'fn(var)var' is generic",
4809 );
31624810
3163 cases.add("taking offset of void field in struct",
3164 \\const Empty = struct {
3165 \\ val: void,
3166 \\};
3167 \\export fn foo() void {
3168 \\ const fieldOffset = @offsetOf(Empty, "val");
4811 cases.add(
4812 "getting @ArgType of generic function",
4813 \\fn generic(a: var) void {}
4814 \\comptime {
4815 \\ _ = @ArgType(@typeOf(generic), 0);
31694816 \\}
31704817 ,
3171 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset");
4818 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
4819 );
31724820}
test/gen_h.zig+49-3
......@@ -1,6 +1,6 @@
11const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.GenHContext) void {
3pub fn addCases(cases: *tests.GenHContext) void {
44 cases.add("declare enum",
55 \\const Foo = extern enum { A, B, C };
66 \\export fn entry(foo: Foo) void { }
......@@ -54,7 +54,7 @@ pub fn addCases(cases: &tests.GenHContext) void {
5454 cases.add("declare opaque type",
5555 \\export const Foo = @OpaqueType();
5656 \\
57 \\export fn entry(foo: ?&Foo) void { }
57 \\export fn entry(foo: ?*Foo) void { }
5858 ,
5959 \\struct Foo;
6060 \\
......@@ -64,7 +64,7 @@ pub fn addCases(cases: &tests.GenHContext) void {
6464 cases.add("array field-type",
6565 \\const Foo = extern struct {
6666 \\ A: [2]i32,
67 \\ B: [4]&u32,
67 \\ B: [4]*u32,
6868 \\};
6969 \\export fn entry(foo: Foo, bar: [3]u8) void { }
7070 ,
......@@ -77,4 +77,50 @@ pub fn addCases(cases: &tests.GenHContext) void {
7777 \\
7878 );
7979
80 cases.add("ptr to zig struct",
81 \\const S = struct {
82 \\ a: u8,
83 \\};
84 \\
85 \\export fn a(s: *S) u8 {
86 \\ return s.a;
87 \\}
88
89 ,
90 \\struct S;
91 \\TEST_EXPORT uint8_t a(struct S * s);
92 \\
93 );
94
95 cases.add("ptr to zig union",
96 \\const U = union(enum) {
97 \\ A: u8,
98 \\ B: u16,
99 \\};
100 \\
101 \\export fn a(s: *U) u8 {
102 \\ return s.A;
103 \\}
104
105 ,
106 \\union U;
107 \\TEST_EXPORT uint8_t a(union U * s);
108 \\
109 );
110
111 cases.add("ptr to zig enum",
112 \\const E = enum(u8) {
113 \\ A,
114 \\ B,
115 \\};
116 \\
117 \\export fn a(s: *E) u8 {
118 \\ return @enumToInt(s.*);
119 \\}
120
121 ,
122 \\enum E;
123 \\TEST_EXPORT uint8_t a(enum E * s);
124 \\
125 );
80126}
test/runtime_safety.zig+90-33
......@@ -1,8 +1,65 @@
11const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompareOutputContext) void {
3pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("@intToEnum - no matching tag value",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\const Foo = enum {
9 \\ A,
10 \\ B,
11 \\ C,
12 \\};
13 \\pub fn main() void {
14 \\ baz(bar(3));
15 \\}
16 \\fn bar(a: u2) Foo {
17 \\ return @intToEnum(Foo, a);
18 \\}
19 \\fn baz(a: Foo) void {}
20 );
21
22 cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned",
23 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
24 \\ @import("std").os.exit(126);
25 \\}
26 \\pub fn main() void {
27 \\ baz(bar(-1.1));
28 \\}
29 \\fn bar(a: f32) u8 {
30 \\ return @floatToInt(u8, a);
31 \\}
32 \\fn baz(a: u8) void { }
33 );
34
35 cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range",
36 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
37 \\ @import("std").os.exit(126);
38 \\}
39 \\pub fn main() void {
40 \\ baz(bar(-129.1));
41 \\}
42 \\fn bar(a: f32) i8 {
43 \\ return @floatToInt(i8, a);
44 \\}
45 \\fn baz(a: i8) void { }
46 );
47
48 cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range",
49 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
50 \\ @import("std").os.exit(126);
51 \\}
52 \\pub fn main() void {
53 \\ baz(bar(256.2));
54 \\}
55 \\fn bar(a: f32) u8 {
56 \\ return @floatToInt(u8, a);
57 \\}
58 \\fn baz(a: u8) void { }
59 );
60
461 cases.addRuntimeSafety("calling panic",
5 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
62 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
663 \\ @import("std").os.exit(126);
764 \\}
865 \\pub fn main() void {
......@@ -11,7 +68,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
1168 );
1269
1370 cases.addRuntimeSafety("out of bounds slice access",
14 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
71 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
1572 \\ @import("std").os.exit(126);
1673 \\}
1774 \\pub fn main() void {
......@@ -25,7 +82,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
2582 );
2683
2784 cases.addRuntimeSafety("integer addition overflow",
28 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
85 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
2986 \\ @import("std").os.exit(126);
3087 \\}
3188 \\pub fn main() !void {
......@@ -38,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
3895 );
3996
4097 cases.addRuntimeSafety("integer subtraction overflow",
41 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
98 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
4299 \\ @import("std").os.exit(126);
43100 \\}
44101 \\pub fn main() !void {
......@@ -51,7 +108,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
51108 );
52109
53110 cases.addRuntimeSafety("integer multiplication overflow",
54 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
111 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
55112 \\ @import("std").os.exit(126);
56113 \\}
57114 \\pub fn main() !void {
......@@ -64,7 +121,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
64121 );
65122
66123 cases.addRuntimeSafety("integer negation overflow",
67 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
124 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
68125 \\ @import("std").os.exit(126);
69126 \\}
70127 \\pub fn main() !void {
......@@ -77,7 +134,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
77134 );
78135
79136 cases.addRuntimeSafety("signed integer division overflow",
80 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
137 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
81138 \\ @import("std").os.exit(126);
82139 \\}
83140 \\pub fn main() !void {
......@@ -90,7 +147,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
90147 );
91148
92149 cases.addRuntimeSafety("signed shift left overflow",
93 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
150 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
94151 \\ @import("std").os.exit(126);
95152 \\}
96153 \\pub fn main() !void {
......@@ -103,7 +160,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
103160 );
104161
105162 cases.addRuntimeSafety("unsigned shift left overflow",
106 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
163 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
107164 \\ @import("std").os.exit(126);
108165 \\}
109166 \\pub fn main() !void {
......@@ -116,7 +173,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
116173 );
117174
118175 cases.addRuntimeSafety("signed shift right overflow",
119 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
176 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
120177 \\ @import("std").os.exit(126);
121178 \\}
122179 \\pub fn main() !void {
......@@ -129,7 +186,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
129186 );
130187
131188 cases.addRuntimeSafety("unsigned shift right overflow",
132 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
189 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
133190 \\ @import("std").os.exit(126);
134191 \\}
135192 \\pub fn main() !void {
......@@ -142,7 +199,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
142199 );
143200
144201 cases.addRuntimeSafety("integer division by zero",
145 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
202 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
146203 \\ @import("std").os.exit(126);
147204 \\}
148205 \\pub fn main() void {
......@@ -154,7 +211,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
154211 );
155212
156213 cases.addRuntimeSafety("exact division failure",
157 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
214 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
158215 \\ @import("std").os.exit(126);
159216 \\}
160217 \\pub fn main() !void {
......@@ -167,7 +224,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
167224 );
168225
169226 cases.addRuntimeSafety("cast []u8 to bigger slice of wrong size",
170 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
227 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
171228 \\ @import("std").os.exit(126);
172229 \\}
173230 \\pub fn main() !void {
......@@ -175,12 +232,12 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
175232 \\ if (x.len == 0) return error.Whatever;
176233 \\}
177234 \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
178 \\ return ([]align(1) const i32)(slice);
235 \\ return @bytesToSlice(i32, slice);
179236 \\}
180237 );
181238
182239 cases.addRuntimeSafety("value does not fit in shortening cast",
183 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
240 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
184241 \\ @import("std").os.exit(126);
185242 \\}
186243 \\pub fn main() !void {
......@@ -188,12 +245,12 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
188245 \\ if (x == 0) return error.Whatever;
189246 \\}
190247 \\fn shorten_cast(x: i32) i8 {
191 \\ return i8(x);
248 \\ return @intCast(i8, x);
192249 \\}
193250 );
194251
195252 cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer",
196 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
253 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
197254 \\ @import("std").os.exit(126);
198255 \\}
199256 \\pub fn main() !void {
......@@ -201,12 +258,12 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
201258 \\ if (x == 0) return error.Whatever;
202259 \\}
203260 \\fn unsigned_cast(x: i32) u32 {
204 \\ return u32(x);
261 \\ return @intCast(u32, x);
205262 \\}
206263 );
207264
208265 cases.addRuntimeSafety("unwrap error",
209 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
266 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
210267 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
211268 \\ @import("std").os.exit(126); // good
212269 \\ }
......@@ -221,19 +278,19 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
221278 );
222279
223280 cases.addRuntimeSafety("cast integer to global error and no code matches",
224 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
281 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
225282 \\ @import("std").os.exit(126);
226283 \\}
227284 \\pub fn main() void {
228285 \\ _ = bar(9999);
229286 \\}
230 \\fn bar(x: u32) error {
231 \\ return error(x);
287 \\fn bar(x: u16) error {
288 \\ return @intToError(x);
232289 \\}
233290 );
234291
235 cases.addRuntimeSafety("cast integer to non-global error set and no match",
236 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
292 cases.addRuntimeSafety("@errSetCast error not present in destination",
293 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
237294 \\ @import("std").os.exit(126);
238295 \\}
239296 \\const Set1 = error{A, B};
......@@ -242,28 +299,28 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
242299 \\ _ = foo(Set1.B);
243300 \\}
244301 \\fn foo(set1: Set1) Set2 {
245 \\ return Set2(set1);
302 \\ return @errSetCast(Set2, set1);
246303 \\}
247304 );
248305
249306 cases.addRuntimeSafety("@alignCast misaligned",
250 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
307 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
251308 \\ @import("std").os.exit(126);
252309 \\}
253310 \\pub fn main() !void {
254311 \\ var array align(4) = []u32{0x11111111, 0x11111111};
255 \\ const bytes = ([]u8)(array[0..]);
312 \\ const bytes = @sliceToBytes(array[0..]);
256313 \\ if (foo(bytes) != 0x11111111) return error.Wrong;
257314 \\}
258315 \\fn foo(bytes: []u8) u32 {
259316 \\ const slice4 = bytes[1..5];
260 \\ const int_slice = ([]u32)(@alignCast(4, slice4));
317 \\ const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
261318 \\ return int_slice[0];
262319 \\}
263320 );
264321
265322 cases.addRuntimeSafety("bad union field access",
266 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
323 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
267324 \\ @import("std").os.exit(126);
268325 \\}
269326 \\
......@@ -277,7 +334,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
277334 \\ bar(&f);
278335 \\}
279336 \\
280 \\fn bar(f: &Foo) void {
337 \\fn bar(f: *Foo) void {
281338 \\ f.float = 12.34;
282339 \\}
283340 );
......@@ -287,7 +344,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
287344 cases.addRuntimeSafety("error return trace across suspend points",
288345 \\const std = @import("std");
289346 \\
290 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn {
347 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
291348 \\ std.os.exit(126);
292349 \\}
293350 \\
test/stage2/compare_output.zig created+25
......@@ -0,0 +1,25 @@
1const std = @import("std");
2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
3
4pub fn addCases(ctx: *TestContext) !void {
5 // hello world
6 try ctx.testCompareOutputLibC(
7 \\extern fn puts([*]const u8) void;
8 \\export fn main() c_int {
9 \\ puts(c"Hello, world!");
10 \\ return 0;
11 \\}
12 , "Hello, world!" ++ std.cstr.line_sep);
13
14 // function calling another function
15 try ctx.testCompareOutputLibC(
16 \\extern fn puts(s: [*]const u8) void;
17 \\export fn main() c_int {
18 \\ return foo(c"OK");
19 \\}
20 \\fn foo(s: [*]const u8) c_int {
21 \\ puts(s);
22 \\ return 0;
23 \\}
24 , "OK" ++ std.cstr.line_sep);
25}
test/stage2/compile_errors.zig created+30
......@@ -0,0 +1,30 @@
1const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
2
3pub fn addCases(ctx: *TestContext) !void {
4 try ctx.testCompileError(
5 \\export fn entry() void {}
6 \\export fn entry() void {}
7 , "1.zig", 2, 8, "exported symbol collision: 'entry'");
8
9 try ctx.testCompileError(
10 \\fn() void {}
11 , "1.zig", 1, 1, "missing function name");
12
13 try ctx.testCompileError(
14 \\comptime {
15 \\ return;
16 \\}
17 , "1.zig", 2, 5, "return expression outside function definition");
18
19 try ctx.testCompileError(
20 \\export fn entry() void {
21 \\ defer return;
22 \\}
23 , "1.zig", 2, 11, "cannot return from defer expression");
24
25 try ctx.testCompileError(
26 \\export fn entry() c_int {
27 \\ return 36893488147419103232;
28 \\}
29 , "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
30}
test/standalone/brace_expansion/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const main = b.addTest("main.zig");
55 main.setBuildMode(b.standardReleaseOptions());
66
test/standalone/brace_expansion/main.zig+18-20
......@@ -14,9 +14,9 @@ const Token = union(enum) {
1414 Eof,
1515};
1616
17var global_allocator: &mem.Allocator = undefined;
17var global_allocator: *mem.Allocator = undefined;
1818
19fn tokenize(input:[] const u8) !ArrayList(Token) {
19fn tokenize(input: []const u8) !ArrayList(Token) {
2020 const State = enum {
2121 Start,
2222 Word,
......@@ -41,7 +41,7 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {
4141 State.Word => switch (b) {
4242 'a'...'z', 'A'...'Z' => {},
4343 '{', '}', ',' => {
44 try token_list.append(Token { .Word = input[tok_begin..i] });
44 try token_list.append(Token{ .Word = input[tok_begin..i] });
4545 switch (b) {
4646 '{' => try token_list.append(Token.OpenBrace),
4747 '}' => try token_list.append(Token.CloseBrace),
......@@ -56,7 +56,7 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {
5656 }
5757 switch (state) {
5858 State.Start => {},
59 State.Word => try token_list.append(Token {.Word = input[tok_begin..] }),
59 State.Word => try token_list.append(Token{ .Word = input[tok_begin..] }),
6060 }
6161 try token_list.append(Token.Eof);
6262 return token_list;
......@@ -68,24 +68,24 @@ const Node = union(enum) {
6868 Combine: []Node,
6969};
7070
71const ParseError = error {
71const ParseError = error{
7272 InvalidInput,
7373 OutOfMemory,
7474};
7575
76fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {
77 const first_token = tokens.items[*token_index];
78 *token_index += 1;
76fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node {
77 const first_token = tokens.items[token_index.*];
78 token_index.* += 1;
7979
8080 const result_node = switch (first_token) {
81 Token.Word => |word| Node { .Scalar = word },
81 Token.Word => |word| Node{ .Scalar = word },
8282 Token.OpenBrace => blk: {
8383 var list = ArrayList(Node).init(global_allocator);
8484 while (true) {
8585 try list.append(try parse(tokens, token_index));
8686
87 const token = tokens.items[*token_index];
88 *token_index += 1;
87 const token = tokens.items[token_index.*];
88 token_index.* += 1;
8989
9090 switch (token) {
9191 Token.CloseBrace => break,
......@@ -93,23 +93,23 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {
9393 else => return error.InvalidInput,
9494 }
9595 }
96 break :blk Node { .List = list };
96 break :blk Node{ .List = list };
9797 },
9898 else => return error.InvalidInput,
9999 };
100100
101 switch (tokens.items[*token_index]) {
101 switch (tokens.items[token_index.*]) {
102102 Token.Word, Token.OpenBrace => {
103103 const pair = try global_allocator.alloc(Node, 2);
104104 pair[0] = result_node;
105105 pair[1] = try parse(tokens, token_index);
106 return Node { .Combine = pair };
106 return Node{ .Combine = pair };
107107 },
108108 else => return result_node,
109109 }
110110}
111111
112fn expandString(input: []const u8, output: &Buffer) !void {
112fn expandString(input: []const u8, output: *Buffer) !void {
113113 const tokens = try tokenize(input);
114114 if (tokens.len == 1) {
115115 return output.resize(0);
......@@ -137,13 +137,11 @@ fn expandString(input: []const u8, output: &Buffer) !void {
137137 }
138138}
139139
140const ExpandNodeError = error {
141 OutOfMemory,
142};
140const ExpandNodeError = error{OutOfMemory};
143141
144fn expandNode(node: &const Node, output: &ArrayList(Buffer)) ExpandNodeError!void {
142fn expandNode(node: *const Node, output: *ArrayList(Buffer)) ExpandNodeError!void {
145143 assert(output.len == 0);
146 switch (*node) {
144 switch (node.*) {
147145 Node.Scalar => |scalar| {
148146 try output.append(try Buffer.init(global_allocator, scalar));
149147 },
test/standalone/issue_339/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const obj = b.addObject("test", "test.zig");
55
66 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+4-1
......@@ -1,5 +1,8 @@
11const StackTrace = @import("builtin").StackTrace;
2pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) noreturn { @breakpoint(); while (true) {} }
2pub fn panic(msg: []const u8, stack_trace: ?*StackTrace) noreturn {
3 @breakpoint();
4 while (true) {}
5}
36
47fn bar() error!void {}
58
test/standalone/issue_794/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const test_artifact = b.addTest("main.zig");
55 test_artifact.addIncludeDir("a_directory");
66
test/standalone/load_dynamic_library/add.zig created+3
......@@ -0,0 +1,3 @@
1export fn add(a: i32, b: i32) i32 {
2 return a + b;
3}
test/standalone/load_dynamic_library/build.zig created+21
......@@ -0,0 +1,21 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const opts = b.standardReleaseOptions();
5
6 const lib = b.addSharedLibrary("add", "add.zig", b.version(1, 0, 0));
7 lib.setBuildMode(opts);
8
9 const main = b.addExecutable("main", "main.zig");
10 main.setBuildMode(opts);
11
12 const run = b.addCommand(".", b.env_map, [][]const u8{
13 main.getOutputPath(),
14 lib.getOutputPath(),
15 });
16 run.step.dependOn(&lib.step);
17 run.step.dependOn(&main.step);
18
19 const test_step = b.step("test", "Test the program");
20 test_step.dependOn(&run.step);
21}
test/standalone/load_dynamic_library/main.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("std");
2
3pub fn main() !void {
4 const args = try std.os.argsAlloc(std.debug.global_allocator);
5 defer std.os.argsFree(std.debug.global_allocator, args);
6
7 const dynlib_name = args[1];
8
9 var lib = try std.DynLib.open(std.debug.global_allocator, dynlib_name);
10 defer lib.close();
11
12 const addr = lib.lookup("add") orelse return error.SymbolNotFound;
13 const addFn = @intToPtr(extern fn (i32, i32) i32, addr);
14
15 const result = addFn(12, 34);
16 std.debug.assert(result == 46);
17}
test/standalone/pkg_import/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 const exe = b.addExecutable("test", "test.zig");
55 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/pkg_import/pkg.zig+3-1
......@@ -1 +1,3 @@
1pub fn add(a: i32, b: i32) i32 { return a + b; }
1pub fn add(a: i32, b: i32) i32 {
2 return a + b;
3}
test/standalone/use_alias/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) void {
3pub fn build(b: *Builder) void {
44 b.addCIncludePath(".");
55
66 const main = b.addTest("main.zig");
test/standalone/use_alias/main.zig+1-1
......@@ -2,7 +2,7 @@ const c = @import("c.zig");
22const assert = @import("std").debug.assert;
33
44test "symbol exists" {
5 var foo = c.Foo {
5 var foo = c.Foo{
66 .a = 1,
77 .b = 1,
88 };
test/tests.zig+159-198
......@@ -27,18 +27,18 @@ const TestTarget = struct {
2727 environ: builtin.Environ,
2828};
2929
30const test_targets = []TestTarget {
31 TestTarget {
30const test_targets = []TestTarget{
31 TestTarget{
3232 .os = builtin.Os.linux,
3333 .arch = builtin.Arch.x86_64,
3434 .environ = builtin.Environ.gnu,
3535 },
36 TestTarget {
36 TestTarget{
3737 .os = builtin.Os.macosx,
3838 .arch = builtin.Arch.x86_64,
3939 .environ = builtin.Environ.unknown,
4040 },
41 TestTarget {
41 TestTarget{
4242 .os = builtin.Os.windows,
4343 .arch = builtin.Arch.x86_64,
4444 .environ = builtin.Environ.msvc,
......@@ -47,120 +47,117 @@ const test_targets = []TestTarget {
4747
4848const max_stdout_size = 1 * 1024 * 1024; // 1 MB
4949
50pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
51 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
52 *cases = CompareOutputContext {
50pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
51 const cases = b.allocator.create(CompareOutputContext{
5352 .b = b,
5453 .step = b.step("test-compare-output", "Run the compare output tests"),
5554 .test_index = 0,
5655 .test_filter = test_filter,
57 };
56 .modes = modes,
57 }) catch unreachable;
5858
5959 compare_output.addCases(cases);
6060
6161 return cases.step;
6262}
6363
64pub fn addRuntimeSafetyTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
65 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
66 *cases = CompareOutputContext {
64pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
65 const cases = b.allocator.create(CompareOutputContext{
6766 .b = b,
6867 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),
6968 .test_index = 0,
7069 .test_filter = test_filter,
71 };
70 .modes = modes,
71 }) catch unreachable;
7272
7373 runtime_safety.addCases(cases);
7474
7575 return cases.step;
7676}
7777
78pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
79 const cases = b.allocator.create(CompileErrorContext) catch unreachable;
80 *cases = CompileErrorContext {
78pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
79 const cases = b.allocator.create(CompileErrorContext{
8180 .b = b,
8281 .step = b.step("test-compile-errors", "Run the compile error tests"),
8382 .test_index = 0,
8483 .test_filter = test_filter,
85 };
84 .modes = modes,
85 }) catch unreachable;
8686
8787 compile_errors.addCases(cases);
8888
8989 return cases.step;
9090}
9191
92pub fn addBuildExampleTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
93 const cases = b.allocator.create(BuildExamplesContext) catch unreachable;
94 *cases = BuildExamplesContext {
92pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
93 const cases = b.allocator.create(BuildExamplesContext{
9594 .b = b,
9695 .step = b.step("test-build-examples", "Build the examples"),
9796 .test_index = 0,
9897 .test_filter = test_filter,
99 };
98 .modes = modes,
99 }) catch unreachable;
100100
101101 build_examples.addCases(cases);
102102
103103 return cases.step;
104104}
105105
106pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
107 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
108 *cases = CompareOutputContext {
106pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
107 const cases = b.allocator.create(CompareOutputContext{
109108 .b = b,
110109 .step = b.step("test-asm-link", "Run the assemble and link tests"),
111110 .test_index = 0,
112111 .test_filter = test_filter,
113 };
112 .modes = modes,
113 }) catch unreachable;
114114
115115 assemble_and_link.addCases(cases);
116116
117117 return cases.step;
118118}
119119
120pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
121 const cases = b.allocator.create(TranslateCContext) catch unreachable;
122 *cases = TranslateCContext {
120pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
121 const cases = b.allocator.create(TranslateCContext{
123122 .b = b,
124123 .step = b.step("test-translate-c", "Run the C transation tests"),
125124 .test_index = 0,
126125 .test_filter = test_filter,
127 };
126 }) catch unreachable;
128127
129128 translate_c.addCases(cases);
130129
131130 return cases.step;
132131}
133132
134pub fn addGenHTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
135 const cases = b.allocator.create(GenHContext) catch unreachable;
136 *cases = GenHContext {
133pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
134 const cases = b.allocator.create(GenHContext{
137135 .b = b,
138136 .step = b.step("test-gen-h", "Run the C header file generation tests"),
139137 .test_index = 0,
140138 .test_filter = test_filter,
141 };
139 }) catch unreachable;
142140
143141 gen_h.addCases(cases);
144142
145143 return cases.step;
146144}
147145
148
149pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8,
150 name:[] const u8, desc: []const u8, with_lldb: bool) &build.Step
151{
146pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []const u8, name: []const u8, desc: []const u8, modes: []const Mode) *build.Step {
152147 const step = b.step(b.fmt("test-{}", name), desc);
153148 for (test_targets) |test_target| {
154149 const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);
155 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
156 for ([]bool{false, true}) |link_libc| {
150 for (modes) |mode| {
151 for ([]bool{
152 false,
153 true,
154 }) |link_libc| {
157155 if (link_libc and !is_native) {
158156 // don't assume we have a cross-compiling libc set up
159157 continue;
160158 }
161159 const these_tests = b.addTest(root_src);
162 these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os),
163 @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
160 these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
164161 these_tests.setFilter(test_filter);
165162 these_tests.setBuildMode(mode);
166163 if (!is_native) {
......@@ -169,10 +166,6 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
169166 if (link_libc) {
170167 these_tests.linkSystemLibrary("c");
171168 }
172 if (with_lldb) {
173 these_tests.setExecCmd([]?[]const u8{
174 "lldb", null, "-o", "run", "-o", "bt", "-o", "exit"});
175 }
176169 step.dependOn(&these_tests.step);
177170 }
178171 }
......@@ -181,10 +174,11 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
181174}
182175
183176pub const CompareOutputContext = struct {
184 b: &build.Builder,
185 step: &build.Step,
177 b: *build.Builder,
178 step: *build.Step,
186179 test_index: usize,
187180 test_filter: ?[]const u8,
181 modes: []const Mode,
188182
189183 const Special = enum {
190184 None,
......@@ -205,34 +199,30 @@ pub const CompareOutputContext = struct {
205199 source: []const u8,
206200 };
207201
208 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
209 self.sources.append(SourceFile {
202 pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void {
203 self.sources.append(SourceFile{
210204 .filename = filename,
211205 .source = source,
212206 }) catch unreachable;
213207 }
214208
215 pub fn setCommandLineArgs(self: &TestCase, args: []const []const u8) void {
209 pub fn setCommandLineArgs(self: *TestCase, args: []const []const u8) void {
216210 self.cli_args = args;
217211 }
218212 };
219213
220214 const RunCompareOutputStep = struct {
221215 step: build.Step,
222 context: &CompareOutputContext,
216 context: *CompareOutputContext,
223217 exe_path: []const u8,
224218 name: []const u8,
225219 expected_output: []const u8,
226220 test_index: usize,
227221 cli_args: []const []const u8,
228222
229 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
230 name: []const u8, expected_output: []const u8,
231 cli_args: []const []const u8) &RunCompareOutputStep
232 {
223 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep {
233224 const allocator = context.b.allocator;
234 const ptr = allocator.create(RunCompareOutputStep) catch unreachable;
235 *ptr = RunCompareOutputStep {
225 const ptr = allocator.create(RunCompareOutputStep{
236226 .context = context,
237227 .exe_path = exe_path,
238228 .name = name,
......@@ -240,12 +230,12 @@ pub const CompareOutputContext = struct {
240230 .test_index = context.test_index,
241231 .step = build.Step.init("RunCompareOutput", allocator, make),
242232 .cli_args = cli_args,
243 };
233 }) catch unreachable;
244234 context.test_index += 1;
245235 return ptr;
246236 }
247237
248 fn make(step: &build.Step) !void {
238 fn make(step: *build.Step) !void {
249239 const self = @fieldParentPtr(RunCompareOutputStep, "step", step);
250240 const b = self.context.b;
251241
......@@ -258,7 +248,7 @@ pub const CompareOutputContext = struct {
258248 args.append(arg) catch unreachable;
259249 }
260250
261 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
251 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
262252
263253 const child = os.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable;
264254 defer child.deinit();
......@@ -273,8 +263,8 @@ pub const CompareOutputContext = struct {
273263 var stdout = Buffer.initNull(b.allocator);
274264 var stderr = Buffer.initNull(b.allocator);
275265
276 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
277 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
266 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
267 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
278268
279269 stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
280270 stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
......@@ -295,7 +285,6 @@ pub const CompareOutputContext = struct {
295285 },
296286 }
297287
298
299288 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {
300289 warn(
301290 \\
......@@ -313,34 +302,32 @@ pub const CompareOutputContext = struct {
313302
314303 const RuntimeSafetyRunStep = struct {
315304 step: build.Step,
316 context: &CompareOutputContext,
305 context: *CompareOutputContext,
317306 exe_path: []const u8,
318307 name: []const u8,
319308 test_index: usize,
320309
321 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
322 name: []const u8) &RuntimeSafetyRunStep
323 {
310 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep {
324311 const allocator = context.b.allocator;
325 const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable;
326 *ptr = RuntimeSafetyRunStep {
312 const ptr = allocator.create(RuntimeSafetyRunStep{
327313 .context = context,
328314 .exe_path = exe_path,
329315 .name = name,
330316 .test_index = context.test_index,
331317 .step = build.Step.init("RuntimeSafetyRun", allocator, make),
332 };
318 }) catch unreachable;
319
333320 context.test_index += 1;
334321 return ptr;
335322 }
336323
337 fn make(step: &build.Step) !void {
324 fn make(step: *build.Step) !void {
338325 const self = @fieldParentPtr(RuntimeSafetyRunStep, "step", step);
339326 const b = self.context.b;
340327
341328 const full_exe_path = b.pathFromRoot(self.exe_path);
342329
343 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
330 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
344331
345332 const child = os.ChildProcess.init([][]u8{full_exe_path}, b.allocator) catch unreachable;
346333 defer child.deinit();
......@@ -358,19 +345,16 @@ pub const CompareOutputContext = struct {
358345 switch (term) {
359346 Term.Exited => |code| {
360347 if (code != expected_exit_code) {
361 warn("\nProgram expected to exit with code {} " ++
362 "but exited with code {}\n", expected_exit_code, code);
348 warn("\nProgram expected to exit with code {} " ++ "but exited with code {}\n", expected_exit_code, code);
363349 return error.TestFailed;
364350 }
365351 },
366352 Term.Signal => |sig| {
367 warn("\nProgram expected to exit with code {} " ++
368 "but instead signaled {}\n", expected_exit_code, sig);
353 warn("\nProgram expected to exit with code {} " ++ "but instead signaled {}\n", expected_exit_code, sig);
369354 return error.TestFailed;
370355 },
371356 else => {
372 warn("\nProgram expected to exit with code {}" ++
373 " but exited in an unexpected way\n", expected_exit_code);
357 warn("\nProgram expected to exit with code {}" ++ " but exited in an unexpected way\n", expected_exit_code);
374358 return error.TestFailed;
375359 },
376360 }
......@@ -379,10 +363,8 @@ pub const CompareOutputContext = struct {
379363 }
380364 };
381365
382 pub fn createExtra(self: &CompareOutputContext, name: []const u8, source: []const u8,
383 expected_output: []const u8, special: Special) TestCase
384 {
385 var tc = TestCase {
366 pub fn createExtra(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8, special: Special) TestCase {
367 var tc = TestCase{
386368 .name = name,
387369 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
388370 .expected_output = expected_output,
......@@ -395,34 +377,32 @@ pub const CompareOutputContext = struct {
395377 return tc;
396378 }
397379
398 pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8,
399 expected_output: []const u8) TestCase
400 {
380 pub fn create(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) TestCase {
401381 return createExtra(self, name, source, expected_output, Special.None);
402382 }
403383
404 pub fn addC(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void {
384 pub fn addC(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void {
405385 var tc = self.create(name, source, expected_output);
406386 tc.link_libc = true;
407387 self.addCase(tc);
408388 }
409389
410 pub fn add(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void {
390 pub fn add(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void {
411391 const tc = self.create(name, source, expected_output);
412392 self.addCase(tc);
413393 }
414394
415 pub fn addAsm(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void {
395 pub fn addAsm(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void {
416396 const tc = self.createExtra(name, source, expected_output, Special.Asm);
417397 self.addCase(tc);
418398 }
419399
420 pub fn addRuntimeSafety(self: &CompareOutputContext, name: []const u8, source: []const u8) void {
400 pub fn addRuntimeSafety(self: *CompareOutputContext, name: []const u8, source: []const u8) void {
421401 const tc = self.createExtra(name, source, undefined, Special.RuntimeSafety);
422402 self.addCase(tc);
423403 }
424404
425 pub fn addCase(self: &CompareOutputContext, case: &const TestCase) void {
405 pub fn addCase(self: *CompareOutputContext, case: *const TestCase) void {
426406 const b = self.b;
427407
428408 const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable;
......@@ -431,8 +411,7 @@ pub const CompareOutputContext = struct {
431411 Special.Asm => {
432412 const annotated_case_name = fmt.allocPrint(self.b.allocator, "assemble-and-link {}", case.name) catch unreachable;
433413 if (self.test_filter) |filter| {
434 if (mem.indexOf(u8, annotated_case_name, filter) == null)
435 return;
414 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
436415 }
437416
438417 const exe = b.addExecutable("test", null);
......@@ -444,19 +423,16 @@ pub const CompareOutputContext = struct {
444423 exe.step.dependOn(&write_src.step);
445424 }
446425
447 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name,
448 case.expected_output, case.cli_args);
426 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name, case.expected_output, case.cli_args);
449427 run_and_cmp_output.step.dependOn(&exe.step);
450428
451429 self.step.dependOn(&run_and_cmp_output.step);
452430 },
453431 Special.None => {
454 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
455 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})",
456 "compare-output", case.name, @tagName(mode)) catch unreachable;
432 for (self.modes) |mode| {
433 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "compare-output", case.name, @tagName(mode)) catch unreachable;
457434 if (self.test_filter) |filter| {
458 if (mem.indexOf(u8, annotated_case_name, filter) == null)
459 continue;
435 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
460436 }
461437
462438 const exe = b.addExecutable("test", root_src);
......@@ -471,8 +447,7 @@ pub const CompareOutputContext = struct {
471447 exe.step.dependOn(&write_src.step);
472448 }
473449
474 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(),
475 annotated_case_name, case.expected_output, case.cli_args);
450 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name, case.expected_output, case.cli_args);
476451 run_and_cmp_output.step.dependOn(&exe.step);
477452
478453 self.step.dependOn(&run_and_cmp_output.step);
......@@ -481,8 +456,7 @@ pub const CompareOutputContext = struct {
481456 Special.RuntimeSafety => {
482457 const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {}", case.name) catch unreachable;
483458 if (self.test_filter) |filter| {
484 if (mem.indexOf(u8, annotated_case_name, filter) == null)
485 return;
459 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
486460 }
487461
488462 const exe = b.addExecutable("test", root_src);
......@@ -506,10 +480,11 @@ pub const CompareOutputContext = struct {
506480};
507481
508482pub const CompileErrorContext = struct {
509 b: &build.Builder,
510 step: &build.Step,
483 b: *build.Builder,
484 step: *build.Step,
511485 test_index: usize,
512486 test_filter: ?[]const u8,
487 modes: []const Mode,
513488
514489 const TestCase = struct {
515490 name: []const u8,
......@@ -523,44 +498,42 @@ pub const CompileErrorContext = struct {
523498 source: []const u8,
524499 };
525500
526 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
527 self.sources.append(SourceFile {
501 pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void {
502 self.sources.append(SourceFile{
528503 .filename = filename,
529504 .source = source,
530505 }) catch unreachable;
531506 }
532507
533 pub fn addExpectedError(self: &TestCase, text: []const u8) void {
508 pub fn addExpectedError(self: *TestCase, text: []const u8) void {
534509 self.expected_errors.append(text) catch unreachable;
535510 }
536511 };
537512
538513 const CompileCmpOutputStep = struct {
539514 step: build.Step,
540 context: &CompileErrorContext,
515 context: *CompileErrorContext,
541516 name: []const u8,
542517 test_index: usize,
543 case: &const TestCase,
518 case: *const TestCase,
544519 build_mode: Mode,
545520
546 pub fn create(context: &CompileErrorContext, name: []const u8,
547 case: &const TestCase, build_mode: Mode) &CompileCmpOutputStep
548 {
521 pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep {
549522 const allocator = context.b.allocator;
550 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
551 *ptr = CompileCmpOutputStep {
523 const ptr = allocator.create(CompileCmpOutputStep{
552524 .step = build.Step.init("CompileCmpOutput", allocator, make),
553525 .context = context,
554526 .name = name,
555527 .test_index = context.test_index,
556528 .case = case,
557529 .build_mode = build_mode,
558 };
530 }) catch unreachable;
531
559532 context.test_index += 1;
560533 return ptr;
561534 }
562535
563 fn make(step: &build.Step) !void {
536 fn make(step: *build.Step) !void {
564537 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
565538 const b = self.context.b;
566539
......@@ -583,9 +556,10 @@ pub const CompileErrorContext = struct {
583556 Mode.Debug => {},
584557 Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
585558 Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
559 Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
586560 }
587561
588 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
562 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
589563
590564 if (b.verbose) {
591565 printInvocation(zig_args.toSliceConst());
......@@ -604,8 +578,8 @@ pub const CompileErrorContext = struct {
604578 var stdout_buf = Buffer.initNull(b.allocator);
605579 var stderr_buf = Buffer.initNull(b.allocator);
606580
607 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
608 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
581 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
582 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
609583
610584 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
611585 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
......@@ -625,7 +599,6 @@ pub const CompileErrorContext = struct {
625599 },
626600 }
627601
628
629602 const stdout = stdout_buf.toSliceConst();
630603 const stderr = stderr_buf.toSliceConst();
631604
......@@ -665,17 +638,15 @@ pub const CompileErrorContext = struct {
665638 warn("\n");
666639 }
667640
668 pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8,
669 expected_lines: ...) &TestCase
670 {
671 const tc = self.b.allocator.create(TestCase) catch unreachable;
672 *tc = TestCase {
641 pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
642 const tc = self.b.allocator.create(TestCase{
673643 .name = name,
674644 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
675645 .expected_errors = ArrayList([]const u8).init(self.b.allocator),
676646 .link_libc = false,
677647 .is_exe = false,
678 };
648 }) catch unreachable;
649
679650 tc.addSourceFile(".tmp_source.zig", source);
680651 comptime var arg_i = 0;
681652 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
......@@ -684,32 +655,30 @@ pub const CompileErrorContext = struct {
684655 return tc;
685656 }
686657
687 pub fn addC(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void {
658 pub fn addC(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void {
688659 var tc = self.create(name, source, expected_lines);
689660 tc.link_libc = true;
690661 self.addCase(tc);
691662 }
692663
693 pub fn addExe(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void {
664 pub fn addExe(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void {
694665 var tc = self.create(name, source, expected_lines);
695666 tc.is_exe = true;
696667 self.addCase(tc);
697668 }
698669
699 pub fn add(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void {
670 pub fn add(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void {
700671 const tc = self.create(name, source, expected_lines);
701672 self.addCase(tc);
702673 }
703674
704 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {
675 pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void {
705676 const b = self.b;
706677
707 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
708 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
709 case.name, @tagName(mode)) catch unreachable;
678 for (self.modes) |mode| {
679 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})", case.name, @tagName(mode)) catch unreachable;
710680 if (self.test_filter) |filter| {
711 if (mem.indexOf(u8, annotated_case_name, filter) == null)
712 continue;
681 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
713682 }
714683
715684 const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, mode);
......@@ -725,26 +694,26 @@ pub const CompileErrorContext = struct {
725694};
726695
727696pub const BuildExamplesContext = struct {
728 b: &build.Builder,
729 step: &build.Step,
697 b: *build.Builder,
698 step: *build.Step,
730699 test_index: usize,
731700 test_filter: ?[]const u8,
701 modes: []const Mode,
732702
733 pub fn addC(self: &BuildExamplesContext, root_src: []const u8) void {
703 pub fn addC(self: *BuildExamplesContext, root_src: []const u8) void {
734704 self.addAllArgs(root_src, true);
735705 }
736706
737 pub fn add(self: &BuildExamplesContext, root_src: []const u8) void {
707 pub fn add(self: *BuildExamplesContext, root_src: []const u8) void {
738708 self.addAllArgs(root_src, false);
739709 }
740710
741 pub fn addBuildFile(self: &BuildExamplesContext, build_file: []const u8) void {
711 pub fn addBuildFile(self: *BuildExamplesContext, build_file: []const u8) void {
742712 const b = self.b;
743713
744714 const annotated_case_name = b.fmt("build {} (Debug)", build_file);
745715 if (self.test_filter) |filter| {
746 if (mem.indexOf(u8, annotated_case_name, filter) == null)
747 return;
716 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
748717 }
749718
750719 var zig_args = ArrayList([]const u8).init(b.allocator);
......@@ -769,15 +738,13 @@ pub const BuildExamplesContext = struct {
769738 self.step.dependOn(&log_step.step);
770739 }
771740
772 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {
741 pub fn addAllArgs(self: *BuildExamplesContext, root_src: []const u8, link_libc: bool) void {
773742 const b = self.b;
774743
775 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
776 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})",
777 root_src, @tagName(mode)) catch unreachable;
744 for (self.modes) |mode| {
745 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})", root_src, @tagName(mode)) catch unreachable;
778746 if (self.test_filter) |filter| {
779 if (mem.indexOf(u8, annotated_case_name, filter) == null)
780 continue;
747 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
781748 }
782749
783750 const exe = b.addExecutable("test", root_src);
......@@ -795,8 +762,8 @@ pub const BuildExamplesContext = struct {
795762};
796763
797764pub const TranslateCContext = struct {
798 b: &build.Builder,
799 step: &build.Step,
765 b: *build.Builder,
766 step: *build.Step,
800767 test_index: usize,
801768 test_filter: ?[]const u8,
802769
......@@ -811,40 +778,40 @@ pub const TranslateCContext = struct {
811778 source: []const u8,
812779 };
813780
814 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
815 self.sources.append(SourceFile {
781 pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void {
782 self.sources.append(SourceFile{
816783 .filename = filename,
817784 .source = source,
818785 }) catch unreachable;
819786 }
820787
821 pub fn addExpectedLine(self: &TestCase, text: []const u8) void {
788 pub fn addExpectedLine(self: *TestCase, text: []const u8) void {
822789 self.expected_lines.append(text) catch unreachable;
823790 }
824791 };
825792
826793 const TranslateCCmpOutputStep = struct {
827794 step: build.Step,
828 context: &TranslateCContext,
795 context: *TranslateCContext,
829796 name: []const u8,
830797 test_index: usize,
831 case: &const TestCase,
798 case: *const TestCase,
832799
833 pub fn create(context: &TranslateCContext, name: []const u8, case: &const TestCase) &TranslateCCmpOutputStep {
800 pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep {
834801 const allocator = context.b.allocator;
835 const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable;
836 *ptr = TranslateCCmpOutputStep {
802 const ptr = allocator.create(TranslateCCmpOutputStep{
837803 .step = build.Step.init("ParseCCmpOutput", allocator, make),
838804 .context = context,
839805 .name = name,
840806 .test_index = context.test_index,
841807 .case = case,
842 };
808 }) catch unreachable;
809
843810 context.test_index += 1;
844811 return ptr;
845812 }
846813
847 fn make(step: &build.Step) !void {
814 fn make(step: *build.Step) !void {
848815 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
849816 const b = self.context.b;
850817
......@@ -856,7 +823,7 @@ pub const TranslateCContext = struct {
856823 zig_args.append("translate-c") catch unreachable;
857824 zig_args.append(b.pathFromRoot(root_src)) catch unreachable;
858825
859 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
826 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
860827
861828 if (b.verbose) {
862829 printInvocation(zig_args.toSliceConst());
......@@ -875,8 +842,8 @@ pub const TranslateCContext = struct {
875842 var stdout_buf = Buffer.initNull(b.allocator);
876843 var stderr_buf = Buffer.initNull(b.allocator);
877844
878 var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
879 var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
845 var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
846 var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
880847
881848 stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
882849 stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
......@@ -938,16 +905,14 @@ pub const TranslateCContext = struct {
938905 warn("\n");
939906 }
940907
941 pub fn create(self: &TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8,
942 source: []const u8, expected_lines: ...) &TestCase
943 {
944 const tc = self.b.allocator.create(TestCase) catch unreachable;
945 *tc = TestCase {
908 pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
909 const tc = self.b.allocator.create(TestCase{
946910 .name = name,
947911 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
948912 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
949913 .allow_warnings = allow_warnings,
950 };
914 }) catch unreachable;
915
951916 tc.addSourceFile(filename, source);
952917 comptime var arg_i = 0;
953918 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
......@@ -956,28 +921,27 @@ pub const TranslateCContext = struct {
956921 return tc;
957922 }
958923
959 pub fn add(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
924 pub fn add(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
960925 const tc = self.create(false, "source.h", name, source, expected_lines);
961926 self.addCase(tc);
962927 }
963928
964 pub fn addC(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
929 pub fn addC(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
965930 const tc = self.create(false, "source.c", name, source, expected_lines);
966931 self.addCase(tc);
967932 }
968933
969 pub fn addAllowWarnings(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
934 pub fn addAllowWarnings(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
970935 const tc = self.create(true, "source.h", name, source, expected_lines);
971936 self.addCase(tc);
972937 }
973938
974 pub fn addCase(self: &TranslateCContext, case: &const TestCase) void {
939 pub fn addCase(self: *TranslateCContext, case: *const TestCase) void {
975940 const b = self.b;
976941
977942 const annotated_case_name = fmt.allocPrint(self.b.allocator, "translate-c {}", case.name) catch unreachable;
978943 if (self.test_filter) |filter| {
979 if (mem.indexOf(u8, annotated_case_name, filter) == null)
980 return;
944 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
981945 }
982946
983947 const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case);
......@@ -992,8 +956,8 @@ pub const TranslateCContext = struct {
992956};
993957
994958pub const GenHContext = struct {
995 b: &build.Builder,
996 step: &build.Step,
959 b: *build.Builder,
960 step: *build.Step,
997961 test_index: usize,
998962 test_filter: ?[]const u8,
999963
......@@ -1007,46 +971,46 @@ pub const GenHContext = struct {
1007971 source: []const u8,
1008972 };
1009973
1010 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
1011 self.sources.append(SourceFile {
974 pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void {
975 self.sources.append(SourceFile{
1012976 .filename = filename,
1013977 .source = source,
1014978 }) catch unreachable;
1015979 }
1016980
1017 pub fn addExpectedLine(self: &TestCase, text: []const u8) void {
981 pub fn addExpectedLine(self: *TestCase, text: []const u8) void {
1018982 self.expected_lines.append(text) catch unreachable;
1019983 }
1020984 };
1021985
1022986 const GenHCmpOutputStep = struct {
1023987 step: build.Step,
1024 context: &GenHContext,
988 context: *GenHContext,
1025989 h_path: []const u8,
1026990 name: []const u8,
1027991 test_index: usize,
1028 case: &const TestCase,
992 case: *const TestCase,
1029993
1030 pub fn create(context: &GenHContext, h_path: []const u8, name: []const u8, case: &const TestCase) &GenHCmpOutputStep {
994 pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep {
1031995 const allocator = context.b.allocator;
1032 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
1033 *ptr = GenHCmpOutputStep {
996 const ptr = allocator.create(GenHCmpOutputStep{
1034997 .step = build.Step.init("ParseCCmpOutput", allocator, make),
1035998 .context = context,
1036999 .h_path = h_path,
10371000 .name = name,
10381001 .test_index = context.test_index,
10391002 .case = case,
1040 };
1003 }) catch unreachable;
1004
10411005 context.test_index += 1;
10421006 return ptr;
10431007 }
10441008
1045 fn make(step: &build.Step) !void {
1009 fn make(step: *build.Step) !void {
10461010 const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);
10471011 const b = self.context.b;
10481012
1049 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
1013 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
10501014
10511015 const full_h_path = b.pathFromRoot(self.h_path);
10521016 const actual_h = try io.readFileAlloc(b.allocator, full_h_path);
......@@ -1075,15 +1039,13 @@ pub const GenHContext = struct {
10751039 warn("\n");
10761040 }
10771041
1078 pub fn create(self: &GenHContext, filename: []const u8, name: []const u8,
1079 source: []const u8, expected_lines: ...) &TestCase
1080 {
1081 const tc = self.b.allocator.create(TestCase) catch unreachable;
1082 *tc = TestCase {
1042 pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
1043 const tc = self.b.allocator.create(TestCase{
10831044 .name = name,
10841045 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
10851046 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
1086 };
1047 }) catch unreachable;
1048
10871049 tc.addSourceFile(filename, source);
10881050 comptime var arg_i = 0;
10891051 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
......@@ -1092,20 +1054,19 @@ pub const GenHContext = struct {
10921054 return tc;
10931055 }
10941056
1095 pub fn add(self: &GenHContext, name: []const u8, source: []const u8, expected_lines: ...) void {
1057 pub fn add(self: *GenHContext, name: []const u8, source: []const u8, expected_lines: ...) void {
10961058 const tc = self.create("test.zig", name, source, expected_lines);
10971059 self.addCase(tc);
10981060 }
10991061
1100 pub fn addCase(self: &GenHContext, case: &const TestCase) void {
1062 pub fn addCase(self: *GenHContext, case: *const TestCase) void {
11011063 const b = self.b;
11021064 const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable;
11031065
11041066 const mode = builtin.Mode.Debug;
11051067 const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;
11061068 if (self.test_filter) |filter| {
1107 if (mem.indexOf(u8, annotated_case_name, filter) == null)
1108 return;
1069 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
11091070 }
11101071
11111072 const obj = b.addObject("test", root_src);
test/translate_c.zig+197-110
......@@ -1,6 +1,72 @@
11const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.TranslateCContext) void {
3pub fn addCases(cases: *tests.TranslateCContext) void {
4 cases.add("for loop with var init but empty body",
5 \\void foo(void) {
6 \\ for (int x = 0; x < 10; x++);
7 \\}
8 ,
9 \\pub fn foo() void {
10 \\ {
11 \\ var x: c_int = 0;
12 \\ while (x < 10) : (x += 1) {}
13 \\ }
14 \\}
15 );
16
17 cases.add("do while with empty body",
18 \\void foo(void) {
19 \\ do ; while (1);
20 \\}
21 , // TODO this should be if (1 != 0) break
22 \\pub fn foo() void {
23 \\ while (true) {
24 \\ if (!1) break;
25 \\ }
26 \\}
27 );
28
29 cases.add("for with empty body",
30 \\void foo(void) {
31 \\ for (;;);
32 \\}
33 ,
34 \\pub fn foo() void {
35 \\ while (true) {}
36 \\}
37 );
38
39 cases.add("while with empty body",
40 \\void foo(void) {
41 \\ while (1);
42 \\}
43 ,
44 \\pub fn foo() void {
45 \\ while (1 != 0) {}
46 \\}
47 );
48
49 cases.add("double define struct",
50 \\typedef struct Bar Bar;
51 \\typedef struct Foo Foo;
52 \\
53 \\struct Foo {
54 \\ Foo *a;
55 \\};
56 \\
57 \\struct Bar {
58 \\ Foo *a;
59 \\};
60 ,
61 \\pub const struct_Foo = extern struct {
62 \\ a: ?[*]Foo,
63 \\};
64 \\pub const Foo = struct_Foo;
65 \\pub const struct_Bar = extern struct {
66 \\ a: ?[*]Foo,
67 \\};
68 );
69
470 cases.addAllowWarnings("simple data types",
571 \\#include <stdint.h>
672 \\int foo(char a, unsigned char b, signed char c);
......@@ -53,10 +119,32 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
53119 \\pub const Foo = enum_Foo;
54120 );
55121
122 cases.add("enums",
123 \\enum Foo {
124 \\ FooA = 2,
125 \\ FooB = 5,
126 \\ Foo1,
127 \\};
128 ,
129 \\pub const enum_Foo = extern enum {
130 \\ A = 2,
131 \\ B = 5,
132 \\ @"1" = 6,
133 \\};
134 ,
135 \\pub const FooA = enum_Foo.A;
136 ,
137 \\pub const FooB = enum_Foo.B;
138 ,
139 \\pub const Foo1 = enum_Foo.@"1";
140 ,
141 \\pub const Foo = enum_Foo;
142 );
143
56144 cases.add("restrict -> noalias",
57145 \\void foo(void *restrict bar, void *restrict);
58146 ,
59 \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void) void;
147 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
60148 );
61149
62150 cases.add("simple struct",
......@@ -67,7 +155,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
67155 ,
68156 \\const struct_Foo = extern struct {
69157 \\ x: c_int,
70 \\ y: ?&u8,
158 \\ y: ?[*]u8,
71159 \\};
72160 ,
73161 \\pub const Foo = struct_Foo;
......@@ -98,7 +186,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
98186 ,
99187 \\pub const BarB = enum_Bar.B;
100188 ,
101 \\pub extern fn func(a: ?&struct_Foo, b: ?&(?&enum_Bar)) void;
189 \\pub extern fn func(a: ?[*]struct_Foo, b: ?[*](?[*]enum_Bar)) void;
102190 ,
103191 \\pub const Foo = struct_Foo;
104192 ,
......@@ -108,7 +196,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
108196 cases.add("constant size array",
109197 \\void func(int array[20]);
110198 ,
111 \\pub extern fn func(array: ?&c_int) void;
199 \\pub extern fn func(array: ?[*]c_int) void;
112200 );
113201
114202 cases.add("self referential struct with function pointer",
......@@ -117,7 +205,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
117205 \\};
118206 ,
119207 \\pub const struct_Foo = extern struct {
120 \\ derp: ?extern fn(?&struct_Foo) void,
208 \\ derp: ?extern fn(?[*]struct_Foo) void,
121209 \\};
122210 ,
123211 \\pub const Foo = struct_Foo;
......@@ -129,7 +217,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
129217 ,
130218 \\pub const struct_Foo = @OpaqueType();
131219 ,
132 \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) ?&struct_Foo;
220 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
133221 ,
134222 \\pub const Foo = struct_Foo;
135223 );
......@@ -176,11 +264,11 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
176264 \\};
177265 ,
178266 \\pub const struct_Bar = extern struct {
179 \\ next: ?&struct_Foo,
267 \\ next: ?[*]struct_Foo,
180268 \\};
181269 ,
182270 \\pub const struct_Foo = extern struct {
183 \\ next: ?&struct_Bar,
271 \\ next: ?[*]struct_Bar,
184272 \\};
185273 );
186274
......@@ -190,7 +278,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
190278 ,
191279 \\pub const Foo = c_void;
192280 ,
193 \\pub extern fn fun(a: ?&Foo) Foo;
281 \\pub extern fn fun(a: ?*Foo) Foo;
194282 );
195283
196284 cases.add("generate inline func for #define global extern fn",
......@@ -203,13 +291,13 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
203291 \\pub extern var fn_ptr: ?extern fn() void;
204292 ,
205293 \\pub inline fn foo() void {
206 \\ return (??fn_ptr)();
294 \\ return fn_ptr.?();
207295 \\}
208296 ,
209297 \\pub extern var fn_ptr2: ?extern fn(c_int, f32) u8;
210298 ,
211299 \\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
212 \\ return (??fn_ptr2)(arg0, arg1);
300 \\ return fn_ptr2.?(arg0, arg1);
213301 \\}
214302 );
215303
......@@ -462,7 +550,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
462550 \\ return 6;
463551 \\}
464552 ,
465 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
553 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
466554 \\ if ((a != 0) and (b != 0)) return 0;
467555 \\ if ((b != 0) and (c != null)) return 1;
468556 \\ if ((a != 0) and (c != null)) return 2;
......@@ -564,8 +652,8 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
564652 \\pub const struct_Foo = extern struct {
565653 \\ field: c_int,
566654 \\};
567 \\pub export fn read_field(foo: ?&struct_Foo) c_int {
568 \\ return (??foo).field;
655 \\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
656 \\ return foo.?.field;
569657 \\}
570658 );
571659
......@@ -595,7 +683,6 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
595683 \\}
596684 );
597685
598
599686 cases.addC("c style cast",
600687 \\int float_to_int(float a) {
601688 \\ return (int)a;
......@@ -611,8 +698,8 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
611698 \\ return x;
612699 \\}
613700 ,
614 \\pub export fn foo(x: ?&c_ushort) ?&c_void {
615 \\ return @ptrCast(?&c_void, x);
701 \\pub export fn foo(x: ?[*]c_ushort) ?*c_void {
702 \\ return @ptrCast(?*c_void, x);
616703 \\}
617704 );
618705
......@@ -632,7 +719,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
632719 \\ return 0;
633720 \\}
634721 ,
635 \\pub export fn foo() ?&c_int {
722 \\pub export fn foo() ?[*]c_int {
636723 \\ return null;
637724 \\}
638725 );
......@@ -677,43 +764,43 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
677764 \\ var a: c_int = 0;
678765 \\ a += x: {
679766 \\ const _ref = &a;
680 \\ (*_ref) = ((*_ref) + 1);
681 \\ break :x *_ref;
767 \\ _ref.* = (_ref.* + 1);
768 \\ break :x _ref.*;
682769 \\ };
683770 \\ a -= x: {
684771 \\ const _ref = &a;
685 \\ (*_ref) = ((*_ref) - 1);
686 \\ break :x *_ref;
772 \\ _ref.* = (_ref.* - 1);
773 \\ break :x _ref.*;
687774 \\ };
688775 \\ a *= x: {
689776 \\ const _ref = &a;
690 \\ (*_ref) = ((*_ref) * 1);
691 \\ break :x *_ref;
777 \\ _ref.* = (_ref.* * 1);
778 \\ break :x _ref.*;
692779 \\ };
693780 \\ a &= x: {
694781 \\ const _ref = &a;
695 \\ (*_ref) = ((*_ref) & 1);
696 \\ break :x *_ref;
782 \\ _ref.* = (_ref.* & 1);
783 \\ break :x _ref.*;
697784 \\ };
698785 \\ a |= x: {
699786 \\ const _ref = &a;
700 \\ (*_ref) = ((*_ref) | 1);
701 \\ break :x *_ref;
787 \\ _ref.* = (_ref.* | 1);
788 \\ break :x _ref.*;
702789 \\ };
703790 \\ a ^= x: {
704791 \\ const _ref = &a;
705 \\ (*_ref) = ((*_ref) ^ 1);
706 \\ break :x *_ref;
792 \\ _ref.* = (_ref.* ^ 1);
793 \\ break :x _ref.*;
707794 \\ };
708795 \\ a >>= @import("std").math.Log2Int(c_int)(x: {
709796 \\ const _ref = &a;
710 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1));
711 \\ break :x *_ref;
797 \\ _ref.* = (_ref.* >> @import("std").math.Log2Int(c_int)(1));
798 \\ break :x _ref.*;
712799 \\ });
713800 \\ a <<= @import("std").math.Log2Int(c_int)(x: {
714801 \\ const _ref = &a;
715 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1));
716 \\ break :x *_ref;
802 \\ _ref.* = (_ref.* << @import("std").math.Log2Int(c_int)(1));
803 \\ break :x _ref.*;
717804 \\ });
718805 \\}
719806 );
......@@ -735,43 +822,43 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
735822 \\ var a: c_uint = c_uint(0);
736823 \\ a +%= x: {
737824 \\ const _ref = &a;
738 \\ (*_ref) = ((*_ref) +% c_uint(1));
739 \\ break :x *_ref;
825 \\ _ref.* = (_ref.* +% c_uint(1));
826 \\ break :x _ref.*;
740827 \\ };
741828 \\ a -%= x: {
742829 \\ const _ref = &a;
743 \\ (*_ref) = ((*_ref) -% c_uint(1));
744 \\ break :x *_ref;
830 \\ _ref.* = (_ref.* -% c_uint(1));
831 \\ break :x _ref.*;
745832 \\ };
746833 \\ a *%= x: {
747834 \\ const _ref = &a;
748 \\ (*_ref) = ((*_ref) *% c_uint(1));
749 \\ break :x *_ref;
835 \\ _ref.* = (_ref.* *% c_uint(1));
836 \\ break :x _ref.*;
750837 \\ };
751838 \\ a &= x: {
752839 \\ const _ref = &a;
753 \\ (*_ref) = ((*_ref) & c_uint(1));
754 \\ break :x *_ref;
840 \\ _ref.* = (_ref.* & c_uint(1));
841 \\ break :x _ref.*;
755842 \\ };
756843 \\ a |= x: {
757844 \\ const _ref = &a;
758 \\ (*_ref) = ((*_ref) | c_uint(1));
759 \\ break :x *_ref;
845 \\ _ref.* = (_ref.* | c_uint(1));
846 \\ break :x _ref.*;
760847 \\ };
761848 \\ a ^= x: {
762849 \\ const _ref = &a;
763 \\ (*_ref) = ((*_ref) ^ c_uint(1));
764 \\ break :x *_ref;
850 \\ _ref.* = (_ref.* ^ c_uint(1));
851 \\ break :x _ref.*;
765852 \\ };
766853 \\ a >>= @import("std").math.Log2Int(c_uint)(x: {
767854 \\ const _ref = &a;
768 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1));
769 \\ break :x *_ref;
855 \\ _ref.* = (_ref.* >> @import("std").math.Log2Int(c_uint)(1));
856 \\ break :x _ref.*;
770857 \\ });
771858 \\ a <<= @import("std").math.Log2Int(c_uint)(x: {
772859 \\ const _ref = &a;
773 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1));
774 \\ break :x *_ref;
860 \\ _ref.* = (_ref.* << @import("std").math.Log2Int(c_uint)(1));
861 \\ break :x _ref.*;
775862 \\ });
776863 \\}
777864 );
......@@ -810,26 +897,26 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
810897 \\ u -%= 1;
811898 \\ i = x: {
812899 \\ const _ref = &i;
813 \\ const _tmp = *_ref;
814 \\ (*_ref) += 1;
900 \\ const _tmp = _ref.*;
901 \\ _ref.* += 1;
815902 \\ break :x _tmp;
816903 \\ };
817904 \\ i = x: {
818905 \\ const _ref = &i;
819 \\ const _tmp = *_ref;
820 \\ (*_ref) -= 1;
906 \\ const _tmp = _ref.*;
907 \\ _ref.* -= 1;
821908 \\ break :x _tmp;
822909 \\ };
823910 \\ u = x: {
824911 \\ const _ref = &u;
825 \\ const _tmp = *_ref;
826 \\ (*_ref) +%= 1;
912 \\ const _tmp = _ref.*;
913 \\ _ref.* +%= 1;
827914 \\ break :x _tmp;
828915 \\ };
829916 \\ u = x: {
830917 \\ const _ref = &u;
831 \\ const _tmp = *_ref;
832 \\ (*_ref) -%= 1;
918 \\ const _tmp = _ref.*;
919 \\ _ref.* -%= 1;
833920 \\ break :x _tmp;
834921 \\ };
835922 \\}
......@@ -858,23 +945,23 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
858945 \\ u -%= 1;
859946 \\ i = x: {
860947 \\ const _ref = &i;
861 \\ (*_ref) += 1;
862 \\ break :x *_ref;
948 \\ _ref.* += 1;
949 \\ break :x _ref.*;
863950 \\ };
864951 \\ i = x: {
865952 \\ const _ref = &i;
866 \\ (*_ref) -= 1;
867 \\ break :x *_ref;
953 \\ _ref.* -= 1;
954 \\ break :x _ref.*;
868955 \\ };
869956 \\ u = x: {
870957 \\ const _ref = &u;
871 \\ (*_ref) +%= 1;
872 \\ break :x *_ref;
958 \\ _ref.* +%= 1;
959 \\ break :x _ref.*;
873960 \\ };
874961 \\ u = x: {
875962 \\ const _ref = &u;
876 \\ (*_ref) -%= 1;
877 \\ break :x *_ref;
963 \\ _ref.* -%= 1;
964 \\ break :x _ref.*;
878965 \\ };
879966 \\}
880967 );
......@@ -927,11 +1014,11 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
9271014 \\pub export fn bar() void {
9281015 \\ var f: ?extern fn() void = foo;
9291016 \\ var b: ?extern fn() c_int = baz;
930 \\ (??f)();
931 \\ (??f)();
1017 \\ f.?();
1018 \\ f.?();
9321019 \\ foo();
933 \\ _ = (??b)();
934 \\ _ = (??b)();
1020 \\ _ = b.?();
1021 \\ _ = b.?();
9351022 \\ _ = baz();
9361023 \\}
9371024 );
......@@ -941,8 +1028,8 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
9411028 \\ *x = 1;
9421029 \\}
9431030 ,
944 \\pub export fn foo(x: ?&c_int) void {
945 \\ (*??x) = 1;
1031 \\pub export fn foo(x: ?[*]c_int) void {
1032 \\ x.?.* = 1;
9461033 \\}
9471034 );
9481035
......@@ -969,8 +1056,8 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
9691056 ,
9701057 \\pub fn foo() c_int {
9711058 \\ var x: c_int = 1234;
972 \\ var ptr: ?&c_int = &x;
973 \\ return *??ptr;
1059 \\ var ptr: ?[*]c_int = &x;
1060 \\ return ptr.?.*;
9741061 \\}
9751062 );
9761063
......@@ -979,7 +1066,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
9791066 \\ return "bar";
9801067 \\}
9811068 ,
982 \\pub fn foo() ?&const u8 {
1069 \\pub fn foo() ?[*]const u8 {
9831070 \\ return c"bar";
9841071 \\}
9851072 );
......@@ -1077,7 +1164,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
10771164 \\pub const glClearPFN = PFNGLCLEARPROC;
10781165 ,
10791166 \\pub inline fn glClearUnion(arg0: GLbitfield) void {
1080 \\ return (??glProcs.gl.Clear)(arg0);
1167 \\ return glProcs.gl.Clear.?(arg0);
10811168 \\}
10821169 ,
10831170 \\pub const OpenGLProcs = union_OpenGLProcs;
......@@ -1108,8 +1195,8 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
11081195 \\ return (float *)a;
11091196 \\}
11101197 ,
1111 \\fn ptrcast(a: ?&c_int) ?&f32 {
1112 \\ return @ptrCast(?&f32, a);
1198 \\fn ptrcast(a: ?[*]c_int) ?[*]f32 {
1199 \\ return @ptrCast(?[*]f32, a);
11131200 \\}
11141201 );
11151202
......@@ -1131,7 +1218,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
11311218 \\ return !c;
11321219 \\}
11331220 ,
1134 \\pub fn foo(a: c_int, b: f32, c: ?&c_void) c_int {
1221 \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
11351222 \\ return !(a == 0);
11361223 \\ return !(a != 0);
11371224 \\ return !(b != 0);
......@@ -1152,7 +1239,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
11521239 cases.add("const ptr initializer",
11531240 \\static const char *v0 = "0.0.0";
11541241 ,
1155 \\pub var v0: ?&const u8 = c"0.0.0";
1242 \\pub var v0: ?[*]const u8 = c"0.0.0";
11561243 );
11571244
11581245 cases.add("static incomplete array inside function",
......@@ -1161,14 +1248,14 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
11611248 \\}
11621249 ,
11631250 \\pub fn foo() void {
1164 \\ const v2: &const u8 = c"2.2.2";
1251 \\ const v2: [*]const u8 = c"2.2.2";
11651252 \\}
11661253 );
11671254
11681255 cases.add("macro pointer cast",
11691256 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
11701257 ,
1171 \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE);
1258 \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*]NRF_GPIO_Type)(NRF_GPIO_BASE);
11721259 );
11731260
11741261 cases.add("if on none bool",
......@@ -1189,7 +1276,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
11891276 \\ B,
11901277 \\ C,
11911278 \\};
1192 \\pub fn if_none_bool(a: c_int, b: f32, c: ?&c_void, d: enum_SomeEnum) c_int {
1279 \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
11931280 \\ if (a != 0) return 0;
11941281 \\ if (b != 0) return 1;
11951282 \\ if (c != null) return 2;
......@@ -1206,7 +1293,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
12061293 \\ return 3;
12071294 \\}
12081295 ,
1209 \\pub fn while_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
1296 \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
12101297 \\ while (a != 0) return 0;
12111298 \\ while (b != 0) return 1;
12121299 \\ while (c != null) return 2;
......@@ -1222,7 +1309,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
12221309 \\ return 3;
12231310 \\}
12241311 ,
1225 \\pub fn for_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
1312 \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
12261313 \\ while (a != 0) return 0;
12271314 \\ while (b != 0) return 1;
12281315 \\ while (c != null) return 2;
......@@ -1246,29 +1333,29 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
12461333 \\ }
12471334 \\}
12481335 ,
1249 \\pub fn switch_fn(i: c_int) c_int {
1250 \\ var res: c_int = 0;
1251 \\ __switch: {
1252 \\ __case_2: {
1253 \\ __default: {
1254 \\ __case_1: {
1255 \\ __case_0: {
1256 \\ switch (i) {
1257 \\ 0 => break :__case_0,
1258 \\ 1 => break :__case_1,
1259 \\ else => break :__default,
1260 \\ 2 => break :__case_2,
1261 \\ }
1262 \\ }
1263 \\ res = 1;
1264 \\ }
1265 \\ res = 2;
1266 \\ }
1267 \\ res = (3 * i);
1268 \\ break :__switch;
1269 \\ }
1270 \\ res = 5;
1271 \\ }
1272 \\}
1336 \\pub fn switch_fn(i: c_int) c_int {
1337 \\ var res: c_int = 0;
1338 \\ __switch: {
1339 \\ __case_2: {
1340 \\ __default: {
1341 \\ __case_1: {
1342 \\ __case_0: {
1343 \\ switch (i) {
1344 \\ 0 => break :__case_0,
1345 \\ 1 => break :__case_1,
1346 \\ else => break :__default,
1347 \\ 2 => break :__case_2,
1348 \\ }
1349 \\ }
1350 \\ res = 1;
1351 \\ }
1352 \\ res = 2;
1353 \\ }
1354 \\ res = (3 * i);
1355 \\ break :__switch;
1356 \\ }
1357 \\ res = 5;
1358 \\ }
1359 \\}
12731360 );
12741361}