commit
6daa041932
|
@ -0,0 +1,43 @@
|
|||
image: freebsd/latest
|
||||
packages:
|
||||
- cmake
|
||||
- ninja
|
||||
- llvm70
|
||||
sources:
|
||||
- https://github.com/ziglang/zig
|
||||
tasks:
|
||||
- build: |
|
||||
cd zig && mkdir build && cd build
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
|
||||
ninja install
|
||||
- test: |
|
||||
cd zig/build
|
||||
bin/zig test ../test/stage1/behavior.zig
|
||||
bin/zig test ../std/special/compiler_rt/index.zig
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --library c
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --library c
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --release-fast
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --release-fast
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --release-fast --library c
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --release-small --library c
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --release-small
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --release-small
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --release-safe
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --release-safe
|
||||
|
||||
bin/zig test ../test/stage1/behavior.zig --release-safe --library c
|
||||
bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c
|
||||
# TODO enable all tests
|
||||
#bin/zig build --build-file ../build.zig test
|
||||
# TODO integrate with the download page updater and make a
|
||||
# static build available to download for FreeBSD.
|
||||
# This will require setting up a cache of LLVM/Clang built
|
||||
# statically.
|
|
@ -429,6 +429,7 @@ set(BLAKE_SOURCES
|
|||
)
|
||||
set(ZIG_CPP_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_clang.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
|
||||
)
|
||||
|
||||
|
@ -454,10 +455,10 @@ set(ZIG_STD_FILES
|
|||
"crypto/hmac.zig"
|
||||
"crypto/index.zig"
|
||||
"crypto/md5.zig"
|
||||
"crypto/poly1305.zig"
|
||||
"crypto/sha1.zig"
|
||||
"crypto/sha2.zig"
|
||||
"crypto/sha3.zig"
|
||||
"crypto/poly1305.zig"
|
||||
"crypto/x25519.zig"
|
||||
"cstr.zig"
|
||||
"debug/failing_allocator.zig"
|
||||
|
@ -482,6 +483,7 @@ set(ZIG_STD_FILES
|
|||
"fmt/errol/index.zig"
|
||||
"fmt/errol/lookup.zig"
|
||||
"fmt/index.zig"
|
||||
"fmt/parse_float.zig"
|
||||
"hash/adler.zig"
|
||||
"hash/crc.zig"
|
||||
"hash/fnv.zig"
|
||||
|
@ -566,9 +568,9 @@ set(ZIG_STD_FILES
|
|||
"math/tan.zig"
|
||||
"math/tanh.zig"
|
||||
"math/trunc.zig"
|
||||
"mem.zig"
|
||||
"meta/index.zig"
|
||||
"meta/trait.zig"
|
||||
"mem.zig"
|
||||
"mutex.zig"
|
||||
"net.zig"
|
||||
"os/child_process.zig"
|
||||
|
@ -576,20 +578,19 @@ set(ZIG_STD_FILES
|
|||
"os/darwin/errno.zig"
|
||||
"os/epoch.zig"
|
||||
"os/file.zig"
|
||||
"os/freebsd/errno.zig"
|
||||
"os/freebsd/index.zig"
|
||||
"os/get_app_data_dir.zig"
|
||||
"os/get_user_id.zig"
|
||||
"os/index.zig"
|
||||
"os/linux/arm64.zig"
|
||||
"os/linux/errno.zig"
|
||||
"os/linux/index.zig"
|
||||
"os/linux/vdso.zig"
|
||||
"os/linux/x86_64.zig"
|
||||
"os/linux/arm64.zig"
|
||||
"os/freebsd/errno.zig"
|
||||
"os/freebsd/index.zig"
|
||||
"os/freebsd/syscall.zig"
|
||||
"os/freebsd/x86_64.zig"
|
||||
"os/path.zig"
|
||||
"os/time.zig"
|
||||
"os/uefi.zig"
|
||||
"os/windows/advapi32.zig"
|
||||
"os/windows/error.zig"
|
||||
"os/windows/index.zig"
|
||||
|
@ -597,6 +598,7 @@ set(ZIG_STD_FILES
|
|||
"os/windows/ntdll.zig"
|
||||
"os/windows/ole32.zig"
|
||||
"os/windows/shell32.zig"
|
||||
"os/windows/tls.zig"
|
||||
"os/windows/util.zig"
|
||||
"os/zen.zig"
|
||||
"pdb.zig"
|
||||
|
@ -608,11 +610,22 @@ set(ZIG_STD_FILES
|
|||
"special/bootstrap_lib.zig"
|
||||
"special/build_runner.zig"
|
||||
"special/builtin.zig"
|
||||
"special/compiler_rt/addXf3.zig"
|
||||
"special/compiler_rt/aulldiv.zig"
|
||||
"special/compiler_rt/aullrem.zig"
|
||||
"special/compiler_rt/comparetf2.zig"
|
||||
"special/compiler_rt/divti3.zig"
|
||||
"special/compiler_rt/extendXfYf2.zig"
|
||||
"special/compiler_rt/fixdfdi.zig"
|
||||
"special/compiler_rt/fixdfsi.zig"
|
||||
"special/compiler_rt/fixdfti.zig"
|
||||
"special/compiler_rt/fixint.zig"
|
||||
"special/compiler_rt/fixsfdi.zig"
|
||||
"special/compiler_rt/fixsfsi.zig"
|
||||
"special/compiler_rt/fixsfti.zig"
|
||||
"special/compiler_rt/fixtfdi.zig"
|
||||
"special/compiler_rt/fixtfsi.zig"
|
||||
"special/compiler_rt/fixtfti.zig"
|
||||
"special/compiler_rt/fixuint.zig"
|
||||
"special/compiler_rt/fixunsdfdi.zig"
|
||||
"special/compiler_rt/fixunsdfsi.zig"
|
||||
|
@ -640,6 +653,7 @@ set(ZIG_STD_FILES
|
|||
"special/compiler_rt/udivmodti4.zig"
|
||||
"special/compiler_rt/udivti3.zig"
|
||||
"special/compiler_rt/umodti3.zig"
|
||||
"special/fmt_runner.zig"
|
||||
"special/init-exe/build.zig"
|
||||
"special/init-exe/src/main.zig"
|
||||
"special/init-lib/build.zig"
|
||||
|
@ -647,6 +661,8 @@ set(ZIG_STD_FILES
|
|||
"special/panic.zig"
|
||||
"special/test_runner.zig"
|
||||
"spinlock.zig"
|
||||
"statically_initialized_mutex.zig"
|
||||
"testing.zig"
|
||||
"unicode.zig"
|
||||
"zig/ast.zig"
|
||||
"zig/index.zig"
|
||||
|
@ -891,3 +907,7 @@ foreach(file ${ZIG_STD_FILES})
|
|||
get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}")
|
||||
endforeach()
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
|
||||
|
|
54
README.md
54
README.md
|
@ -3,7 +3,7 @@
|
|||
A programming language designed for robustness, optimality, and
|
||||
clarity.
|
||||
|
||||
[ziglang.org](https://ziglang.org)
|
||||
[Download & Documentation](https://ziglang.org/download/)
|
||||
|
||||
## Feature Highlights
|
||||
|
||||
|
@ -84,29 +84,32 @@ clarity.
|
|||
* LLVM may have the target as an experimental target, which means that you
|
||||
need to use Zig-provided binaries for the target to be available, or
|
||||
build LLVM from source with special configure flags.
|
||||
* This target may be considered deprecated by an official party,
|
||||
[such as macosx/i386](https://support.apple.com/en-us/HT208436) in which
|
||||
case this target will remain forever stuck in Tier 4.
|
||||
|
||||
#### Support Table
|
||||
|
||||
| | freestanding | linux | macosx | windows | freebsd | other |
|
||||
|--------|--------------|--------|--------|---------|---------|--------|
|
||||
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 3 |
|
||||
|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 |
|
||||
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|
||||
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A |
|
||||
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A |
|
||||
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 |
|
||||
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 |
|
||||
| | freestanding | linux | macosx | windows | freebsd | UEFI | other |
|
||||
|--------|--------------|--------|--------|---------|---------|--------|--------|
|
||||
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 3 |
|
||||
|i386 | Tier 2 | Tier 2 | Tier 4 | Tier 2 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|
||||
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 |
|
||||
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 |
|
||||
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 |
|
||||
|
||||
## Community
|
||||
|
||||
|
@ -171,7 +174,8 @@ See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
|
|||
*Note: Stage 2 compiler is not complete. Beta users of Zig should use the
|
||||
Stage 1 compiler for now.*
|
||||
|
||||
Dependencies are the same as Stage 1, except now you have a working zig compiler.
|
||||
Dependencies are the same as Stage 1, except now you can use stage 1 to compile
|
||||
Zig code.
|
||||
|
||||
```
|
||||
bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install
|
||||
|
@ -183,11 +187,13 @@ binary.
|
|||
|
||||
### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler
|
||||
|
||||
This is the actual compiler binary that we will install to the system.
|
||||
|
||||
*Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is
|
||||
not yet supported.*
|
||||
|
||||
Once the self-hosted compiler can build itself, this will be the actual
|
||||
compiler binary that we will install to the system. Until then, users should
|
||||
use stage 1.
|
||||
|
||||
#### Debug / Development Build
|
||||
|
||||
```
|
||||
|
|
59
build.zig
59
build.zig
|
@ -16,7 +16,10 @@ pub fn build(b: *Builder) !void {
|
|||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||
|
||||
const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||
const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable;
|
||||
const langref_out_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ b.cache_root, "langref.html" },
|
||||
) catch unreachable;
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
|
||||
docgen_exe.getOutputPath(),
|
||||
rel_zig_exe,
|
||||
|
@ -104,7 +107,7 @@ pub fn build(b: *Builder) !void {
|
|||
}
|
||||
const modes = chosen_modes[0..chosen_mode_index];
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes));
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
|
||||
|
||||
|
@ -125,13 +128,19 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
|
|||
for (dep.libdirs.toSliceConst()) |lib_dir| {
|
||||
lib_exe_obj.addLibPath(lib_dir);
|
||||
}
|
||||
const lib_dir = os.path.join(b.allocator, dep.prefix, "lib") catch unreachable;
|
||||
const lib_dir = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ dep.prefix, "lib" },
|
||||
) catch unreachable;
|
||||
for (dep.system_libs.toSliceConst()) |lib| {
|
||||
const static_bare_name = if (mem.eql(u8, lib, "curses"))
|
||||
([]const u8)("libncurses.a")
|
||||
else
|
||||
b.fmt("lib{}.a", lib);
|
||||
const static_lib_name = os.path.join(b.allocator, lib_dir, static_bare_name) catch unreachable;
|
||||
const static_lib_name = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ lib_dir, static_bare_name },
|
||||
) catch unreachable;
|
||||
const have_static = fileExists(static_lib_name) catch unreachable;
|
||||
if (have_static) {
|
||||
lib_exe_obj.addObjectFile(static_lib_name);
|
||||
|
@ -159,7 +168,11 @@ fn fileExists(filename: []const u8) !bool {
|
|||
|
||||
fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
|
||||
const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
|
||||
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);
|
||||
lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{
|
||||
cmake_binary_dir,
|
||||
"zig_cpp",
|
||||
b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()),
|
||||
}) catch unreachable);
|
||||
}
|
||||
|
||||
const LibraryDep = struct {
|
||||
|
@ -189,14 +202,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
|
|||
const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" });
|
||||
|
||||
var result = LibraryDep{
|
||||
.prefix = mem.split(prefix_output, " \r\n").next().?,
|
||||
.prefix = mem.tokenize(prefix_output, " \r\n").next().?,
|
||||
.libs = ArrayList([]const u8).init(b.allocator),
|
||||
.system_libs = ArrayList([]const u8).init(b.allocator),
|
||||
.includes = ArrayList([]const u8).init(b.allocator),
|
||||
.libdirs = ArrayList([]const u8).init(b.allocator),
|
||||
};
|
||||
{
|
||||
var it = mem.split(libs_output, " \r\n");
|
||||
var it = mem.tokenize(libs_output, " \r\n");
|
||||
while (it.next()) |lib_arg| {
|
||||
if (mem.startsWith(u8, lib_arg, "-l")) {
|
||||
try result.system_libs.append(lib_arg[2..]);
|
||||
|
@ -210,7 +223,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
|
|||
}
|
||||
}
|
||||
{
|
||||
var it = mem.split(includes_output, " \r\n");
|
||||
var it = mem.tokenize(includes_output, " \r\n");
|
||||
while (it.next()) |include_arg| {
|
||||
if (mem.startsWith(u8, include_arg, "-I")) {
|
||||
try result.includes.append(include_arg[2..]);
|
||||
|
@ -220,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
|
|||
}
|
||||
}
|
||||
{
|
||||
var it = mem.split(libdir_output, " \r\n");
|
||||
var it = mem.tokenize(libdir_output, " \r\n");
|
||||
while (it.next()) |libdir| {
|
||||
if (mem.startsWith(u8, libdir, "-L")) {
|
||||
try result.libdirs.append(libdir[2..]);
|
||||
|
@ -233,19 +246,25 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
|
|||
}
|
||||
|
||||
pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
|
||||
var it = mem.split(stdlib_files, ";");
|
||||
var it = mem.tokenize(stdlib_files, ";");
|
||||
while (it.next()) |stdlib_file| {
|
||||
const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;
|
||||
const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable;
|
||||
const src_path = os.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable;
|
||||
const dest_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ "lib", "zig", "std", stdlib_file },
|
||||
) catch unreachable;
|
||||
b.installFile(src_path, dest_path);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
|
||||
var it = mem.split(c_header_files, ";");
|
||||
var it = mem.tokenize(c_header_files, ";");
|
||||
while (it.next()) |c_header_file| {
|
||||
const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;
|
||||
const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable;
|
||||
const src_path = os.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable;
|
||||
const dest_path = os.path.join(
|
||||
b.allocator,
|
||||
[][]const u8{ "lib", "zig", "include", c_header_file },
|
||||
) catch unreachable;
|
||||
b.installFile(src_path, dest_path);
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +296,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
|
|||
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
|
||||
if (ctx.lld_include_dir.len != 0) {
|
||||
exe.addIncludeDir(ctx.lld_include_dir);
|
||||
var it = mem.split(ctx.lld_libraries, ";");
|
||||
var it = mem.tokenize(ctx.lld_libraries, ";");
|
||||
while (it.next()) |lib| {
|
||||
exe.addObjectFile(lib);
|
||||
}
|
||||
|
@ -293,11 +312,13 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
|
|||
try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
|
||||
\\Unable to determine path to libstdc++.a
|
||||
\\On Fedora, install libstdc++-static and try again.
|
||||
\\
|
||||
);
|
||||
|
||||
exe.linkSystemLibrary("pthread");
|
||||
} else if (exe.target.isDarwin() or exe.target.isFreeBSD()) {
|
||||
} else if (exe.target.isFreeBSD()) {
|
||||
try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
|
||||
exe.linkSystemLibrary("pthread");
|
||||
} else if (exe.target.isDarwin()) {
|
||||
if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
|
||||
// Compiler is GCC.
|
||||
try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
|
||||
|
@ -332,7 +353,7 @@ fn addCxxKnownPath(
|
|||
ctx.cxx_compiler,
|
||||
b.fmt("-print-file-name={}", objname),
|
||||
});
|
||||
const path_unpadded = mem.split(path_padded, "\r\n").next().?;
|
||||
const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?;
|
||||
if (mem.eql(u8, path_unpadded, objname)) {
|
||||
if (errtxt) |msg| {
|
||||
warn("{}", msg);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
set -x
|
||||
set -e
|
||||
|
||||
pacman -Su --needed --noconfirm
|
||||
pacman -S --needed --noconfirm wget p7zip python3-pip
|
||||
pip install s3cmd
|
||||
wget -nv "https://ziglang.org/deps/llvm%2bclang-7.0.0-win64-msvc-release.tar.xz"
|
||||
|
|
|
@ -15,6 +15,51 @@ find_program(LLVM_CONFIG_EXE
|
|||
"c:/msys64/mingw64/bin"
|
||||
"C:/Libraries/llvm-7.0.0/bin")
|
||||
|
||||
if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")
|
||||
message(FATAL_ERROR "unable to find llvm-config")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_EXE} --version
|
||||
OUTPUT_VARIABLE LLVM_CONFIG_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if("${LLVM_CONFIG_VERSION}" VERSION_LESS 7)
|
||||
message(FATAL_ERROR "expected LLVM 7.x but found ${LLVM_CONFIG_VERSION}")
|
||||
endif()
|
||||
if("${LLVM_CONFIG_VERSION}" VERSION_EQUAL 8)
|
||||
message(FATAL_ERROR "expected LLVM 7.x but found ${LLVM_CONFIG_VERSION}")
|
||||
endif()
|
||||
if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 8)
|
||||
message(FATAL_ERROR "expected LLVM 7.x but found ${LLVM_CONFIG_VERSION}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_EXE} --targets-built
|
||||
OUTPUT_VARIABLE LLVM_TARGETS_BUILT_SPACES
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REPLACE " " ";" LLVM_TARGETS_BUILT "${LLVM_TARGETS_BUILT_SPACES}")
|
||||
function(NEED_TARGET TARGET_NAME)
|
||||
list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index)
|
||||
if (${_index} EQUAL -1)
|
||||
message(FATAL_ERROR "LLVM is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.")
|
||||
endif()
|
||||
endfunction(NEED_TARGET)
|
||||
NEED_TARGET("AArch64")
|
||||
NEED_TARGET("AMDGPU")
|
||||
NEED_TARGET("ARM")
|
||||
NEED_TARGET("BPF")
|
||||
NEED_TARGET("Hexagon")
|
||||
NEED_TARGET("Lanai")
|
||||
NEED_TARGET("Mips")
|
||||
NEED_TARGET("MSP430")
|
||||
NEED_TARGET("NVPTX")
|
||||
NEED_TARGET("PowerPC")
|
||||
NEED_TARGET("Sparc")
|
||||
NEED_TARGET("SystemZ")
|
||||
NEED_TARGET("X86")
|
||||
NEED_TARGET("XCore")
|
||||
|
||||
if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug") OR ZIG_STATIC)
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static
|
||||
|
|
|
@ -4,7 +4,7 @@ const io = std.io;
|
|||
const os = std.os;
|
||||
const warn = std.debug.warn;
|
||||
const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
|
||||
const max_doc_file_size = 10 * 1024 * 1024;
|
||||
|
||||
|
@ -620,7 +620,7 @@ const TermState = enum {
|
|||
test "term color" {
|
||||
const input_bytes = "A\x1b[32;1mgreen\x1b[0mB";
|
||||
const result = try termColor(std.debug.global_allocator, input_bytes);
|
||||
assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B"));
|
||||
testing.expectEqualSlices(u8, "A<span class=\"t32\">green</span>B", result);
|
||||
}
|
||||
|
||||
fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
|
||||
|
@ -770,6 +770,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
|||
std.zig.Token.Id.Keyword_suspend,
|
||||
std.zig.Token.Id.Keyword_switch,
|
||||
std.zig.Token.Id.Keyword_test,
|
||||
std.zig.Token.Id.Keyword_threadlocal,
|
||||
std.zig.Token.Id.Keyword_try,
|
||||
std.zig.Token.Id.Keyword_union,
|
||||
std.zig.Token.Id.Keyword_unreachable,
|
||||
|
@ -915,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
|||
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
|
||||
std.zig.Token.Id.Tilde,
|
||||
std.zig.Token.Id.BracketStarBracket,
|
||||
std.zig.Token.Id.BracketStarCBracket,
|
||||
=> try writeEscaped(out, src[token.start..token.end]),
|
||||
|
||||
std.zig.Token.Id.Invalid => return parseError(
|
||||
|
@ -990,13 +992,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
try tokenizeAndPrint(tokenizer, out, code.source_token);
|
||||
try out.write("</pre>");
|
||||
const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
|
||||
const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
|
||||
const tmp_source_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_ext },
|
||||
);
|
||||
try io.writeFile(tmp_source_file_name, trimmed_raw_source);
|
||||
|
||||
switch (code.id) {
|
||||
Code.Id.Exe => |expected_outcome| {
|
||||
const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
|
||||
const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
|
||||
const tmp_bin_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_bin_ext },
|
||||
);
|
||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer build_args.deinit();
|
||||
try build_args.appendSlice([][]const u8{
|
||||
|
@ -1024,7 +1032,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
}
|
||||
for (code.link_objects) |link_object| {
|
||||
const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
|
||||
const full_path_object = try os.path.join(allocator, tmp_dir_name, name_with_ext);
|
||||
const full_path_object = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_with_ext },
|
||||
);
|
||||
try build_args.append("--object");
|
||||
try build_args.append(full_path_object);
|
||||
try out.print(" --object {}", name_with_ext);
|
||||
|
@ -1216,12 +1227,18 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||
},
|
||||
Code.Id.Obj => |maybe_error_match| {
|
||||
const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);
|
||||
const tmp_obj_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_obj_ext);
|
||||
const tmp_obj_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_obj_ext },
|
||||
);
|
||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer build_args.deinit();
|
||||
|
||||
const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
|
||||
const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext);
|
||||
const output_h_file_name = try os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ tmp_dir_name, name_plus_h_ext },
|
||||
);
|
||||
|
||||
try build_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
|
|
|
@ -165,7 +165,7 @@ const std = @import("std");
|
|||
|
||||
pub fn main() !void {
|
||||
// If this program is run without stdout attached, exit with an error.
|
||||
var stdout_file = try std.io.getStdOut();
|
||||
const stdout_file = try std.io.getStdOut();
|
||||
// If this program encounters pipe failure when printing to stdout, exit
|
||||
// with an error.
|
||||
try stdout_file.write("Hello, world!\n");
|
||||
|
@ -1531,6 +1531,29 @@ test "array initialization with function calls" {
|
|||
{#code_end#}
|
||||
{#see_also|for|Slices#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Vectors#}
|
||||
<p>
|
||||
A vector is a group of {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on
|
||||
in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin
|
||||
function {#link|@Vector#}.
|
||||
</p>
|
||||
<p>
|
||||
TODO talk about C ABI interop
|
||||
</p>
|
||||
{#header_open|SIMD#}
|
||||
<p>
|
||||
TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the
|
||||
docs with:
|
||||
* What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector?
|
||||
* How to convert to/from vectors/arrays
|
||||
* How to access individual elements from vectors, how to loop over the elements
|
||||
* "shuffle"
|
||||
* Advice on writing high perf software, how to abstract the best way
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Pointers#}
|
||||
<p>
|
||||
Zig has two kinds of pointers:
|
||||
|
@ -1671,7 +1694,7 @@ test "comptime @intToPtr" {
|
|||
}
|
||||
}
|
||||
{#code_end#}
|
||||
{#see_also|Optional Pointers#}
|
||||
{#see_also|Optional Pointers|@intToPtr|@ptrToInt#}
|
||||
{#header_open|volatile#}
|
||||
<p>Loads and stores are assumed to not have side effects. If a given load or store
|
||||
should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}.
|
||||
|
@ -1800,7 +1823,9 @@ fn foo(bytes: []u8) u32 {
|
|||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
{#see_also|C Pointers#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Slices#}
|
||||
{#code_begin|test_safety|index out of bounds#}
|
||||
const assert = @import("std").debug.assert;
|
||||
|
@ -3169,7 +3194,16 @@ fn foo() void { }
|
|||
{#code_end#}
|
||||
{#header_open|Pass-by-value Parameters#}
|
||||
<p>
|
||||
In Zig, structs, unions, and enums with payloads can be passed directly to a function:
|
||||
Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters
|
||||
are copied, and then the copy is available in the function body. This is called "passing by value".
|
||||
Copying a primitive type is essentially free and typically involves nothing more than
|
||||
setting a register.
|
||||
</p>
|
||||
<p>
|
||||
Structs, unions, and arrays can sometimes be more efficiently passed as a reference, since a copy
|
||||
could be arbitrarily expensive depending on the size. When these types are passed
|
||||
as parameters, Zig may choose to copy and pass by value, or pass by reference, whichever way
|
||||
Zig decides will be faster. This is made possible, in part, by the fact that parameters are immutable.
|
||||
</p>
|
||||
{#code_begin|test#}
|
||||
const Point = struct {
|
||||
|
@ -3178,20 +3212,20 @@ const Point = struct {
|
|||
};
|
||||
|
||||
fn foo(point: Point) i32 {
|
||||
// Here, `point` could be a reference, or a copy. The function body
|
||||
// can ignore the difference and treat it as a value. Be very careful
|
||||
// taking the address of the parameter - it should be treated as if
|
||||
// the address will become invalid when the function returns.
|
||||
return point.x + point.y;
|
||||
}
|
||||
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
test "pass aggregate type by non-copy value to function" {
|
||||
test "pass struct to function" {
|
||||
assert(foo(Point{ .x = 1, .y = 2 }) == 3);
|
||||
}
|
||||
{#code_end#}
|
||||
<p>
|
||||
In this case, the value may be passed by reference, or by value, whichever way
|
||||
Zig decides will be faster.
|
||||
</p>
|
||||
<p>
|
||||
For extern functions, Zig follows the C ABI for passing structs and unions by value.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
@ -3949,7 +3983,7 @@ test "implicit cast - invoke a type as a function" {
|
|||
{#code_end#}
|
||||
<p>
|
||||
Implicit casts are only allowed when it is completely unambiguous how to get from one type to another,
|
||||
and the transformation is guaranteed to be safe.
|
||||
and the transformation is guaranteed to be safe. There is one exception, which is {#link|C Pointers#}.
|
||||
</p>
|
||||
{#header_open|Implicit Cast: Stricter Qualification#}
|
||||
<p>
|
||||
|
@ -4327,7 +4361,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
|
|||
<p>
|
||||
For example, if we were to introduce another function to the above snippet:
|
||||
</p>
|
||||
{#code_begin|test_err|unable to evaluate constant expression#}
|
||||
{#code_begin|test_err|values of type 'type' must be comptime known#}
|
||||
fn max(comptime T: type, a: T, b: T) T {
|
||||
return if (a > b) a else b;
|
||||
}
|
||||
|
@ -4595,7 +4629,7 @@ test "fibonacci" {
|
|||
<p>
|
||||
What if we fix the base case, but put the wrong value in the {#syntax#}assert{#endsyntax#} line?
|
||||
</p>
|
||||
{#code_begin|test_err|encountered @panic at compile-time#}
|
||||
{#code_begin|test_err|unable to evaluate constant expression#}
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
fn fibonacci(index: i32) i32 {
|
||||
|
@ -5169,6 +5203,34 @@ fn seq(c: u8) void {
|
|||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@alignCast#}
|
||||
<pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>
|
||||
<p>
|
||||
{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#},
|
||||
{#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#}
|
||||
except with the alignment adjusted to the new value.
|
||||
</p>
|
||||
<p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added
|
||||
to the generated code to make sure the pointer is aligned as promised.</p>
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|@alignOf#}
|
||||
<pre>{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns the number of bytes that this type should be aligned to
|
||||
for the current target to match the C ABI. When the child type of a pointer has
|
||||
this alignment, the alignment can be omitted from the type.
|
||||
</p>
|
||||
<pre>{#syntax#}const assert = @import("std").debug.assert;
|
||||
comptime {
|
||||
assert(*u32 == *align(@alignOf(u32)) u32);
|
||||
}{#endsyntax#}</pre>
|
||||
<p>
|
||||
The result is a target-specific compile time constant. It is guaranteed to be
|
||||
less than or equal to {#link|@sizeOf(T)|@sizeOf#}.
|
||||
</p>
|
||||
{#see_also|Alignment#}
|
||||
{#header_close#}
|
||||
{#header_open|@ArgType#}
|
||||
<pre>{#syntax#}@ArgType(comptime T: type, comptime n: usize) type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5241,6 +5303,7 @@ fn seq(c: u8) void {
|
|||
Works at compile-time if {#syntax#}value{#endsyntax#} is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@bitOffsetOf#}
|
||||
<pre>{#syntax#}@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5253,52 +5316,6 @@ fn seq(c: u8) void {
|
|||
</p>
|
||||
{#see_also|@byteOffsetOf#}
|
||||
{#header_close#}
|
||||
{#header_open|@breakpoint#}
|
||||
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
|
||||
<p>
|
||||
This function inserts a platform-specific debug trap instruction which causes
|
||||
debuggers to break there.
|
||||
</p>
|
||||
<p>
|
||||
This function is only valid within function scope.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|@byteOffsetOf#}
|
||||
<pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the byte offset of a field relative to its containing struct.
|
||||
</p>
|
||||
{#see_also|@bitOffsetOf#}
|
||||
{#header_close#}
|
||||
{#header_open|@alignCast#}
|
||||
<pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>
|
||||
<p>
|
||||
{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#},
|
||||
{#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#}
|
||||
except with the alignment adjusted to the new value.
|
||||
</p>
|
||||
<p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added
|
||||
to the generated code to make sure the pointer is aligned as promised.</p>
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|@alignOf#}
|
||||
<pre>{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns the number of bytes that this type should be aligned to
|
||||
for the current target to match the C ABI. When the child type of a pointer has
|
||||
this alignment, the alignment can be omitted from the type.
|
||||
</p>
|
||||
<pre>{#syntax#}const assert = @import("std").debug.assert;
|
||||
comptime {
|
||||
assert(*u32 == *align(@alignOf(u32)) u32);
|
||||
}{#endsyntax#}</pre>
|
||||
<p>
|
||||
The result is a target-specific compile time constant. It is guaranteed to be
|
||||
less than or equal to {#link|@sizeOf(T)|@sizeOf#}.
|
||||
</p>
|
||||
{#see_also|Alignment#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@boolToInt#}
|
||||
<pre>{#syntax#}@boolToInt(value: bool) u1{#endsyntax#}</pre>
|
||||
|
@ -5312,6 +5329,47 @@ comptime {
|
|||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@breakpoint#}
|
||||
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
|
||||
<p>
|
||||
This function inserts a platform-specific debug trap instruction which causes
|
||||
debuggers to break there.
|
||||
</p>
|
||||
<p>
|
||||
This function is only valid within function scope.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@bswap#}
|
||||
<pre>{#syntax#}@bswap(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p>
|
||||
<p>
|
||||
Swaps the byte order of the integer. This converts a big endian integer to a little endian integer,
|
||||
and converts a little endian integer to a big endian integer.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@bitreverse#}
|
||||
<pre>{#syntax#}@bitreverse(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>{#syntax#}T{#endsyntax#} accepts any integer type.</p>
|
||||
<p>
|
||||
Reverses the bitpattern of an integer value, including the sign bit if applicable.
|
||||
</p>
|
||||
<p>
|
||||
For example 0b10110110 ({#syntax#}u8 = 182{#endsyntax#}, {#syntax#}i8 = -74{#endsyntax#})
|
||||
becomes 0b01101101 ({#syntax#}u8 = 109{#endsyntax#}, {#syntax#}i8 = 109{#endsyntax#}).
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@byteOffsetOf#}
|
||||
<pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the byte offset of a field relative to its containing struct.
|
||||
</p>
|
||||
{#see_also|@bitOffsetOf#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@bytesToSlice#}
|
||||
<pre>{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5378,17 +5436,7 @@ comptime {
|
|||
</p>
|
||||
{#see_also|Import from C Header File|@cImport|@cDefine|@cUndef#}
|
||||
{#header_close#}
|
||||
{#header_open|@cUndef#}
|
||||
<pre>{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}</pre>
|
||||
<p>
|
||||
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
|
||||
</p>
|
||||
<p>
|
||||
This appends <code>#undef $name</code> to the {#syntax#}@cImport{#endsyntax#}
|
||||
temporary buffer.
|
||||
</p>
|
||||
{#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@clz#}
|
||||
<pre>{#syntax#}@clz(x: T) U{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5404,6 +5452,7 @@ comptime {
|
|||
</p>
|
||||
{#see_also|@ctz|@popCount#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@cmpxchgStrong#}
|
||||
<pre>{#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5459,6 +5508,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
<p>{#syntax#}@typeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
|
||||
{#see_also|Compile Variables|cmpxchgStrong#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@compileError#}
|
||||
<pre>{#syntax#}@compileError(comptime msg: []u8){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5471,6 +5521,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
and {#syntax#}comptime{#endsyntax#} functions.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@compileLog#}
|
||||
<pre>{#syntax#}@compileLog(args: ...){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5525,6 +5576,7 @@ test "main" {
|
|||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@ctz#}
|
||||
<pre>{#syntax#}@ctz(x: T) U{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5540,6 +5592,19 @@ test "main" {
|
|||
</p>
|
||||
{#see_also|@clz|@popCount#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@cUndef#}
|
||||
<pre>{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}</pre>
|
||||
<p>
|
||||
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
|
||||
</p>
|
||||
<p>
|
||||
This appends <code>#undef $name</code> to the {#syntax#}@cImport{#endsyntax#}
|
||||
temporary buffer.
|
||||
</p>
|
||||
{#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@divExact#}
|
||||
<pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5606,14 +5671,6 @@ test "main" {
|
|||
{#see_also|@intToEnum#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@errSetCast#}
|
||||
<pre>{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}</pre>
|
||||
<p>
|
||||
Converts an error value from one error set to another error set. Attempting to convert an error
|
||||
which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@errorName#}
|
||||
<pre>{#syntax#}@errorName(err: anyerror) []const u8{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5656,6 +5713,14 @@ test "main" {
|
|||
{#see_also|@intToError#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@errSetCast#}
|
||||
<pre>{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}</pre>
|
||||
<p>
|
||||
Converts an error value from one error set to another error set. Attempting to convert an error
|
||||
which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@export#}
|
||||
<pre>{#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5724,6 +5789,7 @@ test "main" {
|
|||
This function is only valid within function scope.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@handle#}
|
||||
<pre>{#syntax#}@handle(){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5734,6 +5800,7 @@ test "main" {
|
|||
This function is only valid within an async function scope.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@import#}
|
||||
<pre>{#syntax#}@import(comptime path: []u8) (namespace){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5754,6 +5821,7 @@ test "main" {
|
|||
</ul>
|
||||
{#see_also|Compile Variables|@embedFile#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@inlineCall#}
|
||||
<pre>{#syntax#}@inlineCall(function: X, args: ...) Y{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5833,6 +5901,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
|
|||
bit count for an integer type is {#syntax#}65535{#endsyntax#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@memberCount#}
|
||||
<pre>{#syntax#}@memberCount(comptime T: type) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5859,6 +5928,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
|
|||
<pre>{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}</pre>
|
||||
<p>Returns the field type of a struct or union.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@memcpy#}
|
||||
<pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5869,14 +5939,15 @@ fn add(a: i32, b: i32) i32 { return a + b; }
|
|||
This function is a low level intrinsic with no safety mechanisms. Most code
|
||||
should not use this function, instead using something like this:
|
||||
</p>
|
||||
<pre>{#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre>
|
||||
<pre>{#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre>
|
||||
<p>
|
||||
The optimizer is intelligent enough to turn the above snippet into a memcpy.
|
||||
</p>
|
||||
<p>There is also a standard library function for this:</p>
|
||||
<pre>{#syntax#}const mem = @import("std").mem;
|
||||
mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
|
||||
mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@memset#}
|
||||
<pre>{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5886,7 +5957,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
|
|||
This function is a low level intrinsic with no safety mechanisms. Most
|
||||
code should not use this function, instead using something like this:
|
||||
</p>
|
||||
<pre>{#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}</pre>
|
||||
<pre>{#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}</pre>
|
||||
<p>
|
||||
The optimizer is intelligent enough to turn the above snippet into a memset.
|
||||
</p>
|
||||
|
@ -5894,6 +5965,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
|
|||
<pre>{#syntax#}const mem = @import("std").mem;
|
||||
mem.set(u8, dest, c);{#endsyntax#}</pre>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@mod#}
|
||||
<pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5907,6 +5979,7 @@ mem.set(u8, dest, c);{#endsyntax#}</pre>
|
|||
<p>For a function that returns an error code, see {#syntax#}@import("std").math.mod{#endsyntax#}.</p>
|
||||
{#see_also|@rem#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@mulWithOverflow#}
|
||||
<pre>{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5915,6 +5988,7 @@ mem.set(u8, dest, c);{#endsyntax#}</pre>
|
|||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@newStackCall#}
|
||||
<pre>{#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5951,6 +6025,7 @@ fn targetFunction(x: i32) usize {
|
|||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@noInlineCall#}
|
||||
<pre>{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5973,6 +6048,7 @@ fn add(a: i32, b: i32) i32 {
|
|||
</p>
|
||||
{#see_also|@inlineCall#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@OpaqueType#}
|
||||
<pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -5996,6 +6072,7 @@ test "call foo" {
|
|||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@panic#}
|
||||
<pre>{#syntax#}@panic(message: []const u8) noreturn{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6012,6 +6089,7 @@ test "call foo" {
|
|||
</ul>
|
||||
{#see_also|Root Source File#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@popCount#}
|
||||
<pre>{#syntax#}@popCount(integer: var) var{#endsyntax#}</pre>
|
||||
<p>Counts the number of bits set in an integer.</p>
|
||||
|
@ -6022,12 +6100,18 @@ test "call foo" {
|
|||
</p>
|
||||
{#see_also|@ctz|@clz#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@ptrCast#}
|
||||
<pre>{#syntax#}@ptrCast(comptime DestType: type, value: var) DestType{#endsyntax#}</pre>
|
||||
<p>
|
||||
Converts a pointer of one type to a pointer of another type.
|
||||
</p>
|
||||
<p>
|
||||
{#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}
|
||||
to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@ptrToInt#}
|
||||
<pre>{#syntax#}@ptrToInt(value: var) usize{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6042,6 +6126,7 @@ test "call foo" {
|
|||
<p>To convert the other way, use {#link|@intToPtr#}</p>
|
||||
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@rem#}
|
||||
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6055,6 +6140,7 @@ test "call foo" {
|
|||
<p>For a function that returns an error code, see {#syntax#}@import("std").math.rem{#endsyntax#}.</p>
|
||||
{#see_also|@mod#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@returnAddress#}
|
||||
<pre>{#syntax#}@returnAddress(){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6075,19 +6161,14 @@ test "call foo" {
|
|||
Ensures that a function will have a stack alignment of at least {#syntax#}alignment{#endsyntax#} bytes.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@setCold#}
|
||||
<pre>{#syntax#}@setCold(is_cold: bool){#endsyntax#}</pre>
|
||||
<p>
|
||||
Tells the optimizer that a function is rarely called.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@setRuntimeSafety#}
|
||||
<pre>{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}</pre>
|
||||
<p>
|
||||
Sets whether runtime safety checks are on for the scope that contains the function call.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|@setEvalBranchQuota#}
|
||||
<pre>{#syntax#}@setEvalBranchQuota(new_quota: usize){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6122,6 +6203,7 @@ test "foo" {
|
|||
|
||||
{#see_also|comptime#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@setFloatMode#}
|
||||
<pre>{#syntax#}@setFloatMode(mode: @import("builtin").FloatMode){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6156,6 +6238,7 @@ pub const FloatMode = enum {
|
|||
</p>
|
||||
{#see_also|Floating Point Operations#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@setGlobalLinkage#}
|
||||
<pre>{#syntax#}@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage){#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6163,6 +6246,15 @@ pub const FloatMode = enum {
|
|||
</p>
|
||||
{#see_also|Compile Variables#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@setRuntimeSafety#}
|
||||
<pre>{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}</pre>
|
||||
<p>
|
||||
Sets whether runtime safety checks are on for the scope that contains the function call.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@shlExact#}
|
||||
<pre>{#syntax#}@shlExact(value: T, shift_amt: Log2T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6175,6 +6267,7 @@ pub const FloatMode = enum {
|
|||
</p>
|
||||
{#see_also|@shrExact|@shlWithOverflow#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@shlWithOverflow#}
|
||||
<pre>{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6188,6 +6281,7 @@ pub const FloatMode = enum {
|
|||
</p>
|
||||
{#see_also|@shlExact|@shrExact#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@shrExact#}
|
||||
<pre>{#syntax#}@shrExact(value: T, shift_amt: Log2T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6205,10 +6299,15 @@ pub const FloatMode = enum {
|
|||
<pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory.
|
||||
</p>
|
||||
<p>
|
||||
The result is a target-specific compile time constant.
|
||||
</p>
|
||||
<p>
|
||||
This size may contain padding bytes. If there were two consecutive T in memory, this would be the offset
|
||||
in bytes between element at index 0 and the element at index 1. For {#link|integer|Integers#},
|
||||
consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or
|
||||
{#syntax#}@typeInfo(T).Int.bits{#endsyntax#}.
|
||||
</p>
|
||||
{#see_also|@typeInfo#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@sliceToBytes#}
|
||||
|
@ -6229,6 +6328,7 @@ pub const FloatMode = enum {
|
|||
This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@subWithOverflow#}
|
||||
<pre>{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6237,12 +6337,14 @@ pub const FloatMode = enum {
|
|||
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@tagName#}
|
||||
<pre>{#syntax#}@tagName(value: var) []const u8{#endsyntax#}</pre>
|
||||
<p>
|
||||
Converts an enum value or union value to a slice of bytes representing the name.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@TagType#}
|
||||
<pre>{#syntax#}@TagType(T: type) type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6252,6 +6354,7 @@ pub const FloatMode = enum {
|
|||
For a union, returns the enum type that is used to store the tag value.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@This#}
|
||||
<pre>{#syntax#}@This() type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6287,15 +6390,16 @@ fn List(comptime T: type) type {
|
|||
<a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@truncate#}
|
||||
<pre>{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}</pre>
|
||||
<pre>{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function truncates bits from an integer type, resulting in a smaller
|
||||
integer type.
|
||||
</p>
|
||||
<p>
|
||||
The following produces a crash in debug mode and undefined behavior in
|
||||
release mode:
|
||||
The following produces a crash in {#link|Debug#} mode and {#link|Undefined Behavior#} in
|
||||
{#link|ReleaseFast#} mode:
|
||||
</p>
|
||||
<pre>{#syntax#}const a: u16 = 0xabcd;
|
||||
const b: u8 = u8(a);{#endsyntax#}</pre>
|
||||
|
@ -6309,8 +6413,12 @@ const b: u8 = @truncate(u8, a);
|
|||
This function always truncates the significant bits of the integer, regardless
|
||||
of endianness on the target platform.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#},
|
||||
then this is semantically equivalent to an {#link|implicit cast|Implicit Casts#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@typeId#}
|
||||
<pre>{#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6345,6 +6453,7 @@ pub const TypeId = enum {
|
|||
};
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@typeInfo#}
|
||||
<pre>{#syntax#}@typeInfo(comptime T: type) @import("builtin").TypeInfo{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6527,13 +6636,16 @@ pub const TypeInfo = union(TypeId) {
|
|||
};
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@typeName#}
|
||||
<pre>{#syntax#}@typeName(T: type) []u8{#endsyntax#}</pre>
|
||||
<pre>{#syntax#}@typeName(T: type) [N]u8{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns the string representation of a type.
|
||||
This function returns the string representation of a type, as
|
||||
an array. It is equivalent to a string literal of the type name.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@typeOf#}
|
||||
<pre>{#syntax#}@typeOf(expression) type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
@ -6542,7 +6654,19 @@ pub const TypeInfo = union(TypeId) {
|
|||
</p>
|
||||
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Vector#}
|
||||
<pre>{#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns a vector type for {#link|SIMD#}.
|
||||
</p>
|
||||
<p>
|
||||
{#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a
|
||||
{#link|pointer|Pointers#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Build Mode#}
|
||||
<p>
|
||||
Zig has four build modes:
|
||||
|
@ -6613,6 +6737,25 @@ pub fn build(b: *Builder) void {
|
|||
{#header_close#}
|
||||
{#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Single Threaded Builds#}
|
||||
<p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
|
||||
<ul>
|
||||
<li>{#link|@atomicLoad#} is emitted as a normal load.</li>
|
||||
<li>{#link|@atomicRmw#} is emitted as a normal memory load, modify, store.</li>
|
||||
<li>{#link|@fence#} becomes a no-op.</li>
|
||||
<li>Variables which have Thread Local Storage instead become globals. TODO thread local variables
|
||||
are not implemented yet.</li>
|
||||
<li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead.
|
||||
TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li>
|
||||
<li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
|
||||
and therefore various userland APIs which read this variable become more efficient.
|
||||
For example {#syntax#}std.Mutex{#endsyntax#} becomes
|
||||
an empty data structure and all of its functions become no-ops.</li>
|
||||
</ul>
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Undefined Behavior#}
|
||||
<p>
|
||||
Zig has many instances of undefined behavior. If undefined behavior is
|
||||
|
@ -7213,10 +7356,27 @@ fn bar(f: *Foo) void {
|
|||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Out of Bounds Float To Integer Cast#}
|
||||
{#header_open|Out of Bounds Float to Integer Cast#}
|
||||
<p>TODO</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Pointer Cast Invalid Null#}
|
||||
<p>At compile-time:</p>
|
||||
{#code_begin|test_err|null pointer casted to type#}
|
||||
comptime {
|
||||
const opt_ptr: ?*i32 = null;
|
||||
const ptr = @ptrCast(*i32, opt_ptr);
|
||||
}
|
||||
{#code_end#}
|
||||
<p>At runtime:</p>
|
||||
{#code_begin|exe_err#}
|
||||
pub fn main() void {
|
||||
var opt_ptr: ?*i32 = null;
|
||||
var ptr = @ptrCast(*i32, opt_ptr);
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|Memory#}
|
||||
<p>TODO: explain no default allocator in zig</p>
|
||||
|
@ -7307,6 +7467,7 @@ pub fn main() void {
|
|||
{#code_end#}
|
||||
{#see_also|String Literals#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Import from C Header File#}
|
||||
<p>
|
||||
The {#syntax#}@cImport{#endsyntax#} builtin function can be used
|
||||
|
@ -7345,6 +7506,36 @@ const c = @cImport({
|
|||
{#code_end#}
|
||||
{#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|C Pointers#}
|
||||
<p>
|
||||
This type is to be avoided whenever possible. The only valid reason for using a C pointer is in
|
||||
auto-generated code from translating C code.
|
||||
</p>
|
||||
<p>
|
||||
When importing C header files, it is ambiguous whether pointers should be translated as
|
||||
single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}).
|
||||
C pointers are a compromise so that Zig code can utilize translated header files directly.
|
||||
</p>
|
||||
<p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p>
|
||||
<ul>
|
||||
<li>Supports all the syntax of the other two pointer types.</li>
|
||||
<li>Implicitly casts to other pointer types, as well as {#link|Optional Pointers#}.
|
||||
When a C pointer is implicitly casted to a non-optional pointer, safety-checked
|
||||
{#link|Undefined Behavior#} occurs if the address is 0.
|
||||
</li>
|
||||
<li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
|
||||
{#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
|
||||
null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
|
||||
is unnecessary as one can use normal {#link|Optional Pointers#}.
|
||||
</li>
|
||||
<li>Supports {#link|implicit casting|Implicit Casts#} to and from integers.</li>
|
||||
<li>Supports comparison with integers.</li>
|
||||
<li>Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#}
|
||||
please!</li>
|
||||
</ul>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Exporting a C Library#}
|
||||
<p>
|
||||
One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
|
||||
|
@ -7741,7 +7932,7 @@ TopLevelComptime <- KEYWORD_comptime BlockExpr
|
|||
|
||||
TopLevelDecl
|
||||
<- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block)
|
||||
/ (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? VarDecl
|
||||
/ (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl
|
||||
/ KEYWORD_use Expr SEMICOLON
|
||||
|
||||
FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
|
@ -8032,7 +8223,8 @@ ArrayTypeStart <- LBRACKET Expr? RBRACKET
|
|||
PtrTypeStart
|
||||
<- ASTERISK
|
||||
/ ASTERISK2
|
||||
/ LBRACKET ASTERISK RBRACKET
|
||||
/ PTRUNKNOWN
|
||||
/ PTRC
|
||||
|
||||
# ContainerDecl specific
|
||||
ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
|
||||
|
@ -8130,7 +8322,7 @@ LARROW2 <- '<<' ![=] skip
|
|||
LARROW2EQUAL <- '<<=' skip
|
||||
LARROWEQUAL <- '<=' skip
|
||||
LBRACE <- '{' skip
|
||||
LBRACKET <- '[' skip
|
||||
LBRACKET <- '[' ![*] skip
|
||||
LPAREN <- '(' skip
|
||||
MINUS <- '-' ![%=>] skip
|
||||
MINUSEQUAL <- '-=' skip
|
||||
|
@ -8147,6 +8339,8 @@ PLUS2 <- '++' skip
|
|||
PLUSEQUAL <- '+=' skip
|
||||
PLUSPERCENT <- '+%' ![=] skip
|
||||
PLUSPERCENTEQUAL <- '+%=' skip
|
||||
PTRC <- '[*c]' skip
|
||||
PTRUNKNOWN <- '[*]' skip
|
||||
QUESTIONMARK <- '?' skip
|
||||
RARROW <- '>' ![>=] skip
|
||||
RARROW2 <- '>>' ![=] skip
|
||||
|
@ -8201,6 +8395,7 @@ KEYWORD_struct <- 'struct' end_of_word
|
|||
KEYWORD_suspend <- 'suspend' end_of_word
|
||||
KEYWORD_switch <- 'switch' end_of_word
|
||||
KEYWORD_test <- 'test' end_of_word
|
||||
KEYWORD_threadlocal <- 'threadlocal' end_of_word
|
||||
KEYWORD_true <- 'true' end_of_word
|
||||
KEYWORD_try <- 'try' end_of_word
|
||||
KEYWORD_undefined <- 'undefined' end_of_word
|
||||
|
@ -8221,7 +8416,7 @@ keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm
|
|||
/ KEYWORD_orelse / KEYWORD_packed / KEYWORD_promise / KEYWORD_pub
|
||||
/ KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
|
||||
/ KEYWORD_stdcallcc / KEYWORD_struct / KEYWORD_suspend
|
||||
/ KEYWORD_switch / KEYWORD_test / KEYWORD_true / KEYWORD_try
|
||||
/ KEYWORD_switch / KEYWORD_test / KEYWORD_threadlocal / KEYWORD_true / KEYWORD_try
|
||||
/ KEYWORD_undefined / KEYWORD_union / KEYWORD_unreachable
|
||||
/ KEYWORD_use / KEYWORD_var / KEYWORD_volatile / KEYWORD_while</code></pre>
|
||||
{#header_close#}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# How to Add Support For More Targets
|
||||
|
||||
Create bootstrap code in std/bootstrap.zig and add conditional compilation
|
||||
logic. This code is responsible for the real executable entry point, calling
|
||||
main() and making the exit syscall when main returns.
|
||||
|
||||
How to pass a byvalue struct parameter in the C calling convention is
|
||||
target-specific. Add logic for how to do function prototypes and function calls
|
||||
for the target when an exported or external function has a byvalue struct.
|
||||
|
||||
Write the target-specific code in the standard library.
|
||||
|
||||
Update the C integer types to be the correct size for the target.
|
||||
|
||||
Make sure that `c_longdouble` codegens the correct floating point value.
|
|
@ -15,7 +15,7 @@ pub fn main() !void {
|
|||
std.debug.warn("unable to seed random number generator: {}", err);
|
||||
return err;
|
||||
};
|
||||
const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
|
||||
const seed = std.mem.readIntNative(u64, &seed_bytes);
|
||||
var prng = std.rand.DefaultPrng.init(seed);
|
||||
|
||||
const answer = prng.random.range(u8, 0, 100) + 1;
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
|
||||
pub fn main() !void {
|
||||
// If this program is run without stdout attached, exit with an error.
|
||||
var stdout_file = try std.io.getStdOut();
|
||||
const stdout_file = try std.io.getStdOut();
|
||||
// If this program encounters pipe failure when printing to stdout, exit
|
||||
// with an error.
|
||||
try stdout_file.write("Hello, world!\n");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("std");
|
||||
const debug = std.debug;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
|
@ -272,21 +273,21 @@ test "parse arguments" {
|
|||
|
||||
var args = try Args.parse(std.debug.global_allocator, spec1, cliargs);
|
||||
|
||||
debug.assert(args.present("help"));
|
||||
debug.assert(!args.present("help2"));
|
||||
debug.assert(!args.present("init"));
|
||||
testing.expect(args.present("help"));
|
||||
testing.expect(!args.present("help2"));
|
||||
testing.expect(!args.present("init"));
|
||||
|
||||
debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig"));
|
||||
debug.assert(mem.eql(u8, args.single("color").?, "on"));
|
||||
testing.expect(mem.eql(u8, args.single("build-file").?, "build.zig"));
|
||||
testing.expect(mem.eql(u8, args.single("color").?, "on"));
|
||||
|
||||
const objects = args.many("object").?;
|
||||
debug.assert(mem.eql(u8, objects[0], "obj1"));
|
||||
debug.assert(mem.eql(u8, objects[1], "obj2"));
|
||||
testing.expect(mem.eql(u8, objects[0], "obj1"));
|
||||
testing.expect(mem.eql(u8, objects[1], "obj2"));
|
||||
|
||||
debug.assert(mem.eql(u8, args.single("library").?, "lib2"));
|
||||
testing.expect(mem.eql(u8, args.single("library").?, "lib2"));
|
||||
|
||||
const pos = args.positionals.toSliceConst();
|
||||
debug.assert(mem.eql(u8, pos[0], "build"));
|
||||
debug.assert(mem.eql(u8, pos[1], "pos1"));
|
||||
debug.assert(mem.eql(u8, pos[2], "pos2"));
|
||||
testing.expect(mem.eql(u8, pos[0], "build"));
|
||||
testing.expect(mem.eql(u8, pos[1], "pos1"));
|
||||
testing.expect(mem.eql(u8, pos[2], "pos2"));
|
||||
}
|
||||
|
|
|
@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
|
|||
|
||||
pub const ObjectFile = struct {
|
||||
comp: *Compilation,
|
||||
module: llvm.ModuleRef,
|
||||
builder: llvm.BuilderRef,
|
||||
module: *llvm.Module,
|
||||
builder: *llvm.Builder,
|
||||
dibuilder: *llvm.DIBuilder,
|
||||
context: llvm.ContextRef,
|
||||
context: *llvm.Context,
|
||||
lock: event.Lock,
|
||||
arena: *std.mem.Allocator,
|
||||
|
||||
|
@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
|
|||
|
||||
fn addLLVMAttr(
|
||||
ofile: *ObjectFile,
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
) !void {
|
||||
|
@ -335,7 +335,7 @@ fn addLLVMAttr(
|
|||
|
||||
fn addLLVMAttrStr(
|
||||
ofile: *ObjectFile,
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
attr_val: []const u8,
|
||||
|
@ -351,7 +351,7 @@ fn addLLVMAttrStr(
|
|||
}
|
||||
|
||||
fn addLLVMAttrInt(
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
attr_val: u64,
|
||||
|
@ -362,25 +362,25 @@ fn addLLVMAttrInt(
|
|||
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void {
|
||||
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void {
|
||||
return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void {
|
||||
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void {
|
||||
return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
|
||||
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void {
|
||||
return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
|
||||
}
|
||||
|
||||
fn renderLoadUntyped(
|
||||
ofile: *ObjectFile,
|
||||
ptr: llvm.ValueRef,
|
||||
ptr: *llvm.Value,
|
||||
alignment: Type.Pointer.Align,
|
||||
vol: Type.Pointer.Vol,
|
||||
name: [*]const u8,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
|
||||
switch (vol) {
|
||||
Type.Pointer.Vol.Non => {},
|
||||
|
@ -390,11 +390,11 @@ fn renderLoadUntyped(
|
|||
return result;
|
||||
}
|
||||
|
||||
fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
|
||||
fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value {
|
||||
return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
|
||||
}
|
||||
|
||||
pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
|
||||
pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value {
|
||||
const child_type = ptr_type.key.child_type;
|
||||
if (!child_type.hasBits()) {
|
||||
return null;
|
||||
|
@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po
|
|||
|
||||
pub fn renderStoreUntyped(
|
||||
ofile: *ObjectFile,
|
||||
value: llvm.ValueRef,
|
||||
ptr: llvm.ValueRef,
|
||||
value: *llvm.Value,
|
||||
ptr: *llvm.Value,
|
||||
alignment: Type.Pointer.Align,
|
||||
vol: Type.Pointer.Vol,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
|
||||
switch (vol) {
|
||||
Type.Pointer.Vol.Non => {},
|
||||
|
@ -423,10 +423,10 @@ pub fn renderStoreUntyped(
|
|||
|
||||
pub fn renderStore(
|
||||
ofile: *ObjectFile,
|
||||
value: llvm.ValueRef,
|
||||
ptr: llvm.ValueRef,
|
||||
value: *llvm.Value,
|
||||
ptr: *llvm.Value,
|
||||
ptr_type: *Type.Pointer,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ pub fn renderAlloca(
|
|||
var_type: *Type,
|
||||
name: []const u8,
|
||||
alignment: Type.Pointer.Align,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
|
||||
const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
|
||||
const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
|
||||
|
@ -443,7 +443,7 @@ pub fn renderAlloca(
|
|||
return result;
|
||||
}
|
||||
|
||||
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
|
||||
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 {
|
||||
return switch (alignment) {
|
||||
Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
|
||||
Type.Pointer.Align.Override => |a| a,
|
||||
|
|
|
@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
|||
/// Data that is local to the event loop.
|
||||
pub const ZigCompiler = struct {
|
||||
loop: *event.Loop,
|
||||
llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
|
||||
llvm_handle_pool: std.atomic.Stack(*llvm.Context),
|
||||
lld_lock: event.Lock,
|
||||
|
||||
/// TODO pool these so that it doesn't have to lock
|
||||
|
@ -55,12 +55,12 @@ pub const ZigCompiler = struct {
|
|||
|
||||
var seed_bytes: [@sizeOf(u64)]u8 = undefined;
|
||||
try std.os.getRandomBytes(seed_bytes[0..]);
|
||||
const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
|
||||
const seed = mem.readIntNative(u64, &seed_bytes);
|
||||
|
||||
return ZigCompiler{
|
||||
.loop = loop,
|
||||
.lld_lock = event.Lock.init(loop),
|
||||
.llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
|
||||
.llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(),
|
||||
.prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
|
||||
.native_libc = event.Future(LibCInstallation).init(loop),
|
||||
};
|
||||
|
@ -70,7 +70,7 @@ pub const ZigCompiler = struct {
|
|||
fn deinit(self: *ZigCompiler) void {
|
||||
self.lld_lock.deinit();
|
||||
while (self.llvm_handle_pool.pop()) |node| {
|
||||
c.LLVMContextDispose(node.data);
|
||||
llvm.ContextDispose(node.data);
|
||||
self.loop.allocator.destroy(node);
|
||||
}
|
||||
}
|
||||
|
@ -80,13 +80,14 @@ pub const ZigCompiler = struct {
|
|||
pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle {
|
||||
if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
|
||||
|
||||
const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
|
||||
errdefer c.LLVMContextDispose(context_ref);
|
||||
const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory;
|
||||
errdefer llvm.ContextDispose(context_ref);
|
||||
|
||||
const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{
|
||||
const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node);
|
||||
node.* = std.atomic.Stack(*llvm.Context).Node{
|
||||
.next = undefined,
|
||||
.data = context_ref,
|
||||
});
|
||||
};
|
||||
errdefer self.loop.allocator.destroy(node);
|
||||
|
||||
return LlvmHandle{ .node = node };
|
||||
|
@ -113,7 +114,7 @@ pub const ZigCompiler = struct {
|
|||
};
|
||||
|
||||
pub const LlvmHandle = struct {
|
||||
node: *std.atomic.Stack(llvm.ContextRef).Node,
|
||||
node: *std.atomic.Stack(*llvm.Context).Node,
|
||||
|
||||
pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void {
|
||||
zig_compiler.llvm_handle_pool.push(self.node);
|
||||
|
@ -127,7 +128,7 @@ pub const Compilation = struct {
|
|||
llvm_triple: Buffer,
|
||||
root_src_path: ?[]const u8,
|
||||
target: Target,
|
||||
llvm_target: llvm.TargetRef,
|
||||
llvm_target: *llvm.Target,
|
||||
build_mode: builtin.Mode,
|
||||
zig_lib_dir: []const u8,
|
||||
zig_std_dir: []const u8,
|
||||
|
@ -211,8 +212,8 @@ pub const Compilation = struct {
|
|||
false_value: *Value.Bool,
|
||||
noreturn_value: *Value.NoReturn,
|
||||
|
||||
target_machine: llvm.TargetMachineRef,
|
||||
target_data_ref: llvm.TargetDataRef,
|
||||
target_machine: *llvm.TargetMachine,
|
||||
target_data_ref: *llvm.TargetData,
|
||||
target_layout_str: [*]u8,
|
||||
target_ptr_bits: u32,
|
||||
|
||||
|
@ -300,6 +301,7 @@ pub const Compilation = struct {
|
|||
UserResourceLimitReached,
|
||||
InvalidUtf8,
|
||||
BadPathName,
|
||||
DeviceBusy,
|
||||
};
|
||||
|
||||
pub const Event = union(enum) {
|
||||
|
@ -485,7 +487,7 @@ pub const Compilation = struct {
|
|||
comp.name = try Buffer.init(comp.arena(), name);
|
||||
comp.llvm_triple = try target.getTriple(comp.arena());
|
||||
comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);
|
||||
comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");
|
||||
comp.zig_std_dir = try std.os.path.join(comp.arena(), [][]const u8{ zig_lib_dir, "std" });
|
||||
|
||||
const opt_level = switch (build_mode) {
|
||||
builtin.Mode.Debug => llvm.CodeGenLevelNone,
|
||||
|
@ -595,7 +597,8 @@ pub const Compilation = struct {
|
|||
}
|
||||
|
||||
fn initTypes(comp: *Compilation) !void {
|
||||
comp.meta_type = try comp.arena().create(Type.MetaType{
|
||||
comp.meta_type = try comp.arena().create(Type.MetaType);
|
||||
comp.meta_type.* = Type.MetaType{
|
||||
.base = Type{
|
||||
.name = "type",
|
||||
.base = Value{
|
||||
|
@ -607,12 +610,13 @@ pub const Compilation = struct {
|
|||
.abi_alignment = Type.AbiAlignment.init(comp.loop),
|
||||
},
|
||||
.value = undefined,
|
||||
});
|
||||
};
|
||||
comp.meta_type.value = &comp.meta_type.base;
|
||||
comp.meta_type.base.base.typ = &comp.meta_type.base;
|
||||
assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
|
||||
|
||||
comp.void_type = try comp.arena().create(Type.Void{
|
||||
comp.void_type = try comp.arena().create(Type.Void);
|
||||
comp.void_type.* = Type.Void{
|
||||
.base = Type{
|
||||
.name = "void",
|
||||
.base = Value{
|
||||
|
@ -623,10 +627,11 @@ pub const Compilation = struct {
|
|||
.id = builtin.TypeId.Void,
|
||||
.abi_alignment = Type.AbiAlignment.init(comp.loop),
|
||||
},
|
||||
});
|
||||
};
|
||||
assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);
|
||||
|
||||
comp.noreturn_type = try comp.arena().create(Type.NoReturn{
|
||||
comp.noreturn_type = try comp.arena().create(Type.NoReturn);
|
||||
comp.noreturn_type.* = Type.NoReturn{
|
||||
.base = Type{
|
||||
.name = "noreturn",
|
||||
.base = Value{
|
||||
|
@ -637,10 +642,11 @@ pub const Compilation = struct {
|
|||
.id = builtin.TypeId.NoReturn,
|
||||
.abi_alignment = Type.AbiAlignment.init(comp.loop),
|
||||
},
|
||||
});
|
||||
};
|
||||
assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);
|
||||
|
||||
comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{
|
||||
comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt);
|
||||
comp.comptime_int_type.* = Type.ComptimeInt{
|
||||
.base = Type{
|
||||
.name = "comptime_int",
|
||||
.base = Value{
|
||||
|
@ -651,10 +657,11 @@ pub const Compilation = struct {
|
|||
.id = builtin.TypeId.ComptimeInt,
|
||||
.abi_alignment = Type.AbiAlignment.init(comp.loop),
|
||||
},
|
||||
});
|
||||
};
|
||||
assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);
|
||||
|
||||
comp.bool_type = try comp.arena().create(Type.Bool{
|
||||
comp.bool_type = try comp.arena().create(Type.Bool);
|
||||
comp.bool_type.* = Type.Bool{
|
||||
.base = Type{
|
||||
.name = "bool",
|
||||
.base = Value{
|
||||
|
@ -665,45 +672,50 @@ pub const Compilation = struct {
|
|||
.id = builtin.TypeId.Bool,
|
||||
.abi_alignment = Type.AbiAlignment.init(comp.loop),
|
||||
},
|
||||
});
|
||||
};
|
||||
assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);
|
||||
|
||||
comp.void_value = try comp.arena().create(Value.Void{
|
||||
comp.void_value = try comp.arena().create(Value.Void);
|
||||
comp.void_value.* = Value.Void{
|
||||
.base = Value{
|
||||
.id = Value.Id.Void,
|
||||
.typ = &Type.Void.get(comp).base,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
comp.true_value = try comp.arena().create(Value.Bool{
|
||||
comp.true_value = try comp.arena().create(Value.Bool);
|
||||
comp.true_value.* = Value.Bool{
|
||||
.base = Value{
|
||||
.id = Value.Id.Bool,
|
||||
.typ = &Type.Bool.get(comp).base,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
.x = true,
|
||||
});
|
||||
};
|
||||
|
||||
comp.false_value = try comp.arena().create(Value.Bool{
|
||||
comp.false_value = try comp.arena().create(Value.Bool);
|
||||
comp.false_value.* = Value.Bool{
|
||||
.base = Value{
|
||||
.id = Value.Id.Bool,
|
||||
.typ = &Type.Bool.get(comp).base,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
.x = false,
|
||||
});
|
||||
};
|
||||
|
||||
comp.noreturn_value = try comp.arena().create(Value.NoReturn{
|
||||
comp.noreturn_value = try comp.arena().create(Value.NoReturn);
|
||||
comp.noreturn_value.* = Value.NoReturn{
|
||||
.base = Value{
|
||||
.id = Value.Id.NoReturn,
|
||||
.typ = &Type.NoReturn.get(comp).base,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
for (CInt.list) |cint, i| {
|
||||
const c_int_type = try comp.arena().create(Type.Int{
|
||||
const c_int_type = try comp.arena().create(Type.Int);
|
||||
c_int_type.* = Type.Int{
|
||||
.base = Type{
|
||||
.name = cint.zig_name,
|
||||
.base = Value{
|
||||
|
@ -719,11 +731,12 @@ pub const Compilation = struct {
|
|||
.bit_count = comp.target.cIntTypeSizeInBits(cint.id),
|
||||
},
|
||||
.garbage_node = undefined,
|
||||
});
|
||||
};
|
||||
comp.c_int_types[i] = c_int_type;
|
||||
assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
|
||||
}
|
||||
comp.u8_type = try comp.arena().create(Type.Int{
|
||||
comp.u8_type = try comp.arena().create(Type.Int);
|
||||
comp.u8_type.* = Type.Int{
|
||||
.base = Type{
|
||||
.name = "u8",
|
||||
.base = Value{
|
||||
|
@ -739,7 +752,7 @@ pub const Compilation = struct {
|
|||
.bit_count = 8,
|
||||
},
|
||||
.garbage_node = undefined,
|
||||
});
|
||||
};
|
||||
assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null);
|
||||
}
|
||||
|
||||
|
@ -828,7 +841,7 @@ pub const Compilation = struct {
|
|||
};
|
||||
errdefer self.gpa().free(source_code);
|
||||
|
||||
const tree = try self.gpa().createOne(ast.Tree);
|
||||
const tree = try self.gpa().create(ast.Tree);
|
||||
tree.* = try std.zig.parse(self.gpa(), source_code);
|
||||
errdefer {
|
||||
tree.deinit();
|
||||
|
@ -924,7 +937,8 @@ pub const Compilation = struct {
|
|||
}
|
||||
} else {
|
||||
// add new decl
|
||||
const fn_decl = try self.gpa().create(Decl.Fn{
|
||||
const fn_decl = try self.gpa().create(Decl.Fn);
|
||||
fn_decl.* = Decl.Fn{
|
||||
.base = Decl{
|
||||
.id = Decl.Id.Fn,
|
||||
.name = name,
|
||||
|
@ -935,7 +949,7 @@ pub const Compilation = struct {
|
|||
},
|
||||
.value = Decl.Fn.Val{ .Unresolved = {} },
|
||||
.fn_proto = fn_proto,
|
||||
});
|
||||
};
|
||||
tree_scope.base.ref();
|
||||
errdefer self.gpa().destroy(fn_decl);
|
||||
|
||||
|
@ -1139,12 +1153,13 @@ pub const Compilation = struct {
|
|||
}
|
||||
}
|
||||
|
||||
const link_lib = try self.gpa().create(LinkLib{
|
||||
const link_lib = try self.gpa().create(LinkLib);
|
||||
link_lib.* = LinkLib{
|
||||
.name = name,
|
||||
.path = null,
|
||||
.provided_explicitly = provided_explicitly,
|
||||
.symbols = ArrayList([]u8).init(self.gpa()),
|
||||
});
|
||||
};
|
||||
try self.link_libs_list.append(link_lib);
|
||||
if (is_libc) {
|
||||
self.libc_link_lib = link_lib;
|
||||
|
@ -1183,7 +1198,7 @@ pub const Compilation = struct {
|
|||
const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix);
|
||||
defer self.gpa().free(file_name);
|
||||
|
||||
const full_path = try os.path.join(self.gpa(), tmp_dir, file_name[0..]);
|
||||
const full_path = try os.path.join(self.gpa(), [][]const u8{ tmp_dir, file_name[0..] });
|
||||
errdefer self.gpa().free(full_path);
|
||||
|
||||
return Buffer.fromOwnedSlice(self.gpa(), full_path);
|
||||
|
@ -1204,7 +1219,7 @@ pub const Compilation = struct {
|
|||
const zig_dir_path = try getZigDir(self.gpa());
|
||||
defer self.gpa().free(zig_dir_path);
|
||||
|
||||
const tmp_dir = try os.path.join(self.arena(), zig_dir_path, comp_dir_name[0..]);
|
||||
const tmp_dir = try os.path.join(self.arena(), [][]const u8{ zig_dir_path, comp_dir_name[0..] });
|
||||
try os.makePath(self.gpa(), tmp_dir);
|
||||
return tmp_dir;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,8 @@ pub const Msg = struct {
|
|||
const realpath = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath);
|
||||
errdefer comp.gpa().free(realpath);
|
||||
|
||||
const msg = try comp.gpa().create(Msg{
|
||||
const msg = try comp.gpa().create(Msg);
|
||||
msg.* = Msg{
|
||||
.text = text,
|
||||
.realpath = realpath,
|
||||
.data = Data{
|
||||
|
@ -128,7 +129,7 @@ pub const Msg = struct {
|
|||
.span = span,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
tree_scope.base.ref();
|
||||
return msg;
|
||||
}
|
||||
|
@ -139,13 +140,14 @@ pub const Msg = struct {
|
|||
const realpath_copy = try mem.dupe(comp.gpa(), u8, realpath);
|
||||
errdefer comp.gpa().free(realpath_copy);
|
||||
|
||||
const msg = try comp.gpa().create(Msg{
|
||||
const msg = try comp.gpa().create(Msg);
|
||||
msg.* = Msg{
|
||||
.text = text,
|
||||
.realpath = realpath_copy,
|
||||
.data = Data{
|
||||
.Cli = Cli{ .allocator = comp.gpa() },
|
||||
},
|
||||
});
|
||||
};
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -164,7 +166,8 @@ pub const Msg = struct {
|
|||
var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
|
||||
try parse_error.render(&tree_scope.tree.tokens, out_stream);
|
||||
|
||||
const msg = try comp.gpa().create(Msg{
|
||||
const msg = try comp.gpa().create(Msg);
|
||||
msg.* = Msg{
|
||||
.text = undefined,
|
||||
.realpath = realpath_copy,
|
||||
.data = Data{
|
||||
|
@ -177,7 +180,7 @@ pub const Msg = struct {
|
|||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
tree_scope.base.ref();
|
||||
msg.text = text_buf.toOwnedSlice();
|
||||
return msg;
|
||||
|
@ -203,7 +206,8 @@ pub const Msg = struct {
|
|||
var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
|
||||
try parse_error.render(&tree.tokens, out_stream);
|
||||
|
||||
const msg = try allocator.create(Msg{
|
||||
const msg = try allocator.create(Msg);
|
||||
msg.* = Msg{
|
||||
.text = undefined,
|
||||
.realpath = realpath_copy,
|
||||
.data = Data{
|
||||
|
@ -216,7 +220,7 @@ pub const Msg = struct {
|
|||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
msg.text = text_buf.toOwnedSlice();
|
||||
errdefer allocator.destroy(msg);
|
||||
|
||||
|
|
|
@ -8,10 +8,10 @@ const warn = std.debug.warn;
|
|||
|
||||
/// Caller must free result
|
||||
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
|
||||
const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
|
||||
const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });
|
||||
errdefer allocator.free(test_zig_dir);
|
||||
|
||||
const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
|
||||
const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "index.zig" });
|
||||
defer allocator.free(test_index_file);
|
||||
|
||||
var file = try os.File.openRead(test_index_file);
|
||||
|
|
|
@ -67,7 +67,7 @@ pub const Inst = struct {
|
|||
parent: ?*Inst,
|
||||
|
||||
/// populated durign codegen
|
||||
llvm_value: ?llvm.ValueRef,
|
||||
llvm_value: ?*llvm.Value,
|
||||
|
||||
pub fn cast(base: *Inst, comptime T: type) ?*T {
|
||||
if (base.id == comptime typeToId(T)) {
|
||||
|
@ -129,7 +129,7 @@ pub const Inst = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
|
||||
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) {
|
||||
switch (base.id) {
|
||||
Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
|
||||
Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
|
||||
|
@ -313,10 +313,10 @@ pub const Inst = struct {
|
|||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const fn_ref = self.params.fn_ref.llvm_value.?;
|
||||
|
||||
const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
|
||||
const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len);
|
||||
for (self.params.args) |arg, i| {
|
||||
args[i] = arg.llvm_value.?;
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ pub const Inst = struct {
|
|||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
return self.base.val.KnownValue.getLlvmConst(ofile);
|
||||
}
|
||||
};
|
||||
|
@ -392,7 +392,7 @@ pub const Inst = struct {
|
|||
return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
|
||||
}
|
||||
|
||||
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const value = self.params.return_value.llvm_value;
|
||||
const return_type = self.params.return_value.getKnownType();
|
||||
|
||||
|
@ -540,7 +540,7 @@ pub const Inst = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef {
|
||||
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value {
|
||||
switch (self.params.var_scope.data) {
|
||||
Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
|
||||
Scope.Var.Data.Param => |param| return param.llvm_value,
|
||||
|
@ -596,7 +596,7 @@ pub const Inst = struct {
|
|||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const child_type = self.base.getKnownType();
|
||||
if (!child_type.hasBits()) {
|
||||
return null;
|
||||
|
@ -935,8 +935,8 @@ pub const BasicBlock = struct {
|
|||
ref_instruction: ?*Inst,
|
||||
|
||||
/// for codegen
|
||||
llvm_block: llvm.BasicBlockRef,
|
||||
llvm_exit_block: llvm.BasicBlockRef,
|
||||
llvm_block: *llvm.BasicBlock,
|
||||
llvm_exit_block: *llvm.BasicBlock,
|
||||
|
||||
/// the basic block that is derived from this one in analysis
|
||||
child: ?*BasicBlock,
|
||||
|
@ -1021,12 +1021,13 @@ pub const Builder = struct {
|
|||
pub const Error = Analyze.Error;
|
||||
|
||||
pub fn init(comp: *Compilation, tree_scope: *Scope.AstTree, begin_scope: ?*Scope) !Builder {
|
||||
const code = try comp.gpa().create(Code{
|
||||
const code = try comp.gpa().create(Code);
|
||||
code.* = Code{
|
||||
.basic_block_list = undefined,
|
||||
.arena = std.heap.ArenaAllocator.init(comp.gpa()),
|
||||
.return_type = null,
|
||||
.tree_scope = tree_scope,
|
||||
});
|
||||
};
|
||||
code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator);
|
||||
errdefer code.destroy(comp.gpa());
|
||||
|
||||
|
@ -1052,7 +1053,8 @@ pub const Builder = struct {
|
|||
|
||||
/// No need to clean up resources thanks to the arena allocator.
|
||||
pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock {
|
||||
const basic_block = try self.arena().create(BasicBlock{
|
||||
const basic_block = try self.arena().create(BasicBlock);
|
||||
basic_block.* = BasicBlock{
|
||||
.ref_count = 0,
|
||||
.name_hint = name_hint,
|
||||
.debug_id = self.next_debug_id,
|
||||
|
@ -1063,7 +1065,7 @@ pub const Builder = struct {
|
|||
.ref_instruction = null,
|
||||
.llvm_block = undefined,
|
||||
.llvm_exit_block = undefined,
|
||||
});
|
||||
};
|
||||
self.next_debug_id += 1;
|
||||
return basic_block;
|
||||
}
|
||||
|
@ -1774,7 +1776,8 @@ pub const Builder = struct {
|
|||
params: I.Params,
|
||||
is_generated: bool,
|
||||
) !*Inst {
|
||||
const inst = try self.arena().create(I{
|
||||
const inst = try self.arena().create(I);
|
||||
inst.* = I{
|
||||
.base = Inst{
|
||||
.id = Inst.typeToId(I),
|
||||
.is_generated = is_generated,
|
||||
|
@ -1793,7 +1796,7 @@ pub const Builder = struct {
|
|||
.owner_bb = self.current_basic_block,
|
||||
},
|
||||
.params = params,
|
||||
});
|
||||
};
|
||||
|
||||
// Look at the params and ref() other instructions
|
||||
comptime var i = 0;
|
||||
|
|
|
@ -57,10 +57,10 @@ pub const LibCInstallation = struct {
|
|||
const contents = try std.io.readFileAlloc(allocator, libc_file);
|
||||
defer allocator.free(contents);
|
||||
|
||||
var it = std.mem.split(contents, "\n");
|
||||
var it = std.mem.tokenize(contents, "\n");
|
||||
while (it.next()) |line| {
|
||||
if (line.len == 0 or line[0] == '#') continue;
|
||||
var line_it = std.mem.split(line, "=");
|
||||
var line_it = std.mem.separate(line, "=");
|
||||
const name = line_it.next() orelse {
|
||||
try stderr.print("missing equal sign after field name\n");
|
||||
return error.ParseError;
|
||||
|
@ -154,8 +154,8 @@ pub const LibCInstallation = struct {
|
|||
c.ZigFindWindowsSdkError.None => {
|
||||
windows_sdk = sdk;
|
||||
|
||||
if (sdk.msvc_lib_dir_ptr) |ptr| {
|
||||
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]);
|
||||
if (sdk.msvc_lib_dir_ptr != 0) {
|
||||
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]);
|
||||
}
|
||||
try group.call(findNativeKernel32LibDir, self, loop, sdk);
|
||||
try group.call(findNativeIncludeDirWindows, self, loop, sdk);
|
||||
|
@ -213,7 +213,7 @@ pub const LibCInstallation = struct {
|
|||
},
|
||||
}
|
||||
|
||||
var it = std.mem.split(exec_result.stderr, "\n\r");
|
||||
var it = std.mem.tokenize(exec_result.stderr, "\n\r");
|
||||
var search_paths = std.ArrayList([]const u8).init(loop.allocator);
|
||||
defer search_paths.deinit();
|
||||
while (it.next()) |line| {
|
||||
|
@ -230,7 +230,7 @@ pub const LibCInstallation = struct {
|
|||
while (path_i < search_paths.len) : (path_i += 1) {
|
||||
const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
|
||||
const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
|
||||
const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h");
|
||||
const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ search_path, "stdlib.h" });
|
||||
defer loop.allocator.free(stdlib_path);
|
||||
|
||||
if (try fileExists(stdlib_path)) {
|
||||
|
@ -254,7 +254,10 @@ pub const LibCInstallation = struct {
|
|||
const stream = &std.io.BufferOutStream.init(&result_buf).stream;
|
||||
try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);
|
||||
|
||||
const stdlib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "stdlib.h");
|
||||
const stdlib_path = try std.os.path.join(
|
||||
loop.allocator,
|
||||
[][]const u8{ result_buf.toSliceConst(), "stdlib.h" },
|
||||
);
|
||||
defer loop.allocator.free(stdlib_path);
|
||||
|
||||
if (try fileExists(stdlib_path)) {
|
||||
|
@ -283,7 +286,10 @@ pub const LibCInstallation = struct {
|
|||
builtin.Arch.aarch64v8 => try stream.write("arm"),
|
||||
else => return error.UnsupportedArchitecture,
|
||||
}
|
||||
const ucrt_lib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "ucrt.lib");
|
||||
const ucrt_lib_path = try std.os.path.join(
|
||||
loop.allocator,
|
||||
[][]const u8{ result_buf.toSliceConst(), "ucrt.lib" },
|
||||
);
|
||||
defer loop.allocator.free(ucrt_lib_path);
|
||||
if (try fileExists(ucrt_lib_path)) {
|
||||
self.lib_dir = result_buf.toOwnedSlice();
|
||||
|
@ -358,7 +364,10 @@ pub const LibCInstallation = struct {
|
|||
builtin.Arch.aarch64v8 => try stream.write("arm\\"),
|
||||
else => return error.UnsupportedArchitecture,
|
||||
}
|
||||
const kernel32_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "kernel32.lib");
|
||||
const kernel32_path = try std.os.path.join(
|
||||
loop.allocator,
|
||||
[][]const u8{ result_buf.toSliceConst(), "kernel32.lib" },
|
||||
);
|
||||
defer loop.allocator.free(kernel32_path);
|
||||
if (try fileExists(kernel32_path)) {
|
||||
self.kernel32_lib_dir = result_buf.toOwnedSlice();
|
||||
|
@ -410,7 +419,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo
|
|||
return error.CCompilerCrashed;
|
||||
},
|
||||
}
|
||||
var it = std.mem.split(exec_result.stdout, "\n\r");
|
||||
var it = std.mem.tokenize(exec_result.stdout, "\n\r");
|
||||
const line = it.next() orelse return error.LibCRuntimeNotFound;
|
||||
const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;
|
||||
|
||||
|
@ -428,20 +437,20 @@ const Search = struct {
|
|||
|
||||
fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
|
||||
var search_end: usize = 0;
|
||||
if (sdk.path10_ptr) |path10_ptr| {
|
||||
if (sdk.version10_ptr) |ver10_ptr| {
|
||||
if (sdk.path10_ptr != 0) {
|
||||
if (sdk.version10_ptr != 0) {
|
||||
search_buf[search_end] = Search{
|
||||
.path = path10_ptr[0..sdk.path10_len],
|
||||
.version = ver10_ptr[0..sdk.version10_len],
|
||||
.path = sdk.path10_ptr[0..sdk.path10_len],
|
||||
.version = sdk.version10_ptr[0..sdk.version10_len],
|
||||
};
|
||||
search_end += 1;
|
||||
}
|
||||
}
|
||||
if (sdk.path81_ptr) |path81_ptr| {
|
||||
if (sdk.version81_ptr) |ver81_ptr| {
|
||||
if (sdk.path81_ptr != 0) {
|
||||
if (sdk.version81_ptr != 0) {
|
||||
search_buf[search_end] = Search{
|
||||
.path = path81_ptr[0..sdk.path81_len],
|
||||
.version = ver81_ptr[0..sdk.version81_len],
|
||||
.path = sdk.path81_ptr[0..sdk.path81_len],
|
||||
.version = sdk.version81_ptr[0..sdk.version81_len],
|
||||
};
|
||||
search_end += 1;
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
|
|||
}
|
||||
|
||||
fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
|
||||
const full_path = try std.os.path.join(&ctx.arena.allocator, dirname, basename);
|
||||
const full_path = try std.os.path.join(&ctx.arena.allocator, [][]const u8{ dirname, basename });
|
||||
const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
|
||||
try ctx.args.append(full_path_with_null.ptr);
|
||||
}
|
||||
|
|
|
@ -11,45 +11,31 @@ const assert = @import("std").debug.assert;
|
|||
pub const AttributeIndex = c_uint;
|
||||
pub const Bool = c_int;
|
||||
|
||||
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
|
||||
pub const ContextRef = removeNullability(c.LLVMContextRef);
|
||||
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
|
||||
pub const ValueRef = removeNullability(c.LLVMValueRef);
|
||||
pub const TypeRef = removeNullability(c.LLVMTypeRef);
|
||||
pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
|
||||
pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
|
||||
pub const TargetRef = removeNullability(c.LLVMTargetRef);
|
||||
pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
|
||||
pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
|
||||
pub const Builder = c.LLVMBuilderRef.Child.Child;
|
||||
pub const Context = c.LLVMContextRef.Child.Child;
|
||||
pub const Module = c.LLVMModuleRef.Child.Child;
|
||||
pub const Value = c.LLVMValueRef.Child.Child;
|
||||
pub const Type = c.LLVMTypeRef.Child.Child;
|
||||
pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child;
|
||||
pub const Attribute = c.LLVMAttributeRef.Child.Child;
|
||||
pub const Target = c.LLVMTargetRef.Child.Child;
|
||||
pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child;
|
||||
pub const TargetData = c.LLVMTargetDataRef.Child.Child;
|
||||
pub const DIBuilder = c.ZigLLVMDIBuilder;
|
||||
pub const DIFile = c.ZigLLVMDIFile;
|
||||
pub const DICompileUnit = c.ZigLLVMDICompileUnit;
|
||||
|
||||
pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
|
||||
pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
|
||||
pub const AddFunction = c.LLVMAddFunction;
|
||||
pub const AddGlobal = c.LLVMAddGlobal;
|
||||
pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
|
||||
pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
|
||||
pub const ArrayType = c.LLVMArrayType;
|
||||
pub const BuildLoad = c.LLVMBuildLoad;
|
||||
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
|
||||
pub const ConstAllOnes = c.LLVMConstAllOnes;
|
||||
pub const ConstArray = c.LLVMConstArray;
|
||||
pub const ConstBitCast = c.LLVMConstBitCast;
|
||||
pub const ConstInt = c.LLVMConstInt;
|
||||
pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
|
||||
pub const ConstNeg = c.LLVMConstNeg;
|
||||
pub const ConstNull = c.LLVMConstNull;
|
||||
pub const ConstStringInContext = c.LLVMConstStringInContext;
|
||||
pub const ConstStructInContext = c.LLVMConstStructInContext;
|
||||
pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
|
||||
pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
|
||||
pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
|
||||
pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
|
||||
pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
|
||||
pub const CreateFile = c.ZigLLVMCreateFile;
|
||||
pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
|
||||
pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
|
||||
pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
|
||||
pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
|
||||
pub const DisposeBuilder = c.LLVMDisposeBuilder;
|
||||
pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
|
||||
|
@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule;
|
|||
pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
|
||||
pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
|
||||
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
|
||||
pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
|
||||
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
|
||||
pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
|
||||
pub const GetUndef = c.LLVMGetUndef;
|
||||
pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
|
||||
pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
|
||||
|
@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
|
|||
pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
|
||||
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
|
||||
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
|
||||
pub const IntTypeInContext = c.LLVMIntTypeInContext;
|
||||
pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
|
||||
pub const MDNodeInContext = c.LLVMMDNodeInContext;
|
||||
pub const MDStringInContext = c.LLVMMDStringInContext;
|
||||
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
|
||||
pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
|
||||
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
|
||||
pub const PointerType = c.LLVMPointerType;
|
||||
pub const SetAlignment = c.LLVMSetAlignment;
|
||||
pub const SetDataLayout = c.LLVMSetDataLayout;
|
||||
pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
|
||||
|
@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
|
|||
pub const SetVolatile = c.LLVMSetVolatile;
|
||||
pub const StructTypeInContext = c.LLVMStructTypeInContext;
|
||||
pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
|
||||
pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
|
||||
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
|
||||
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
|
||||
|
||||
pub const AddGlobal = LLVMAddGlobal;
|
||||
extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const ConstStringInContext = LLVMConstStringInContext;
|
||||
extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
|
||||
|
||||
pub const ConstInt = LLVMConstInt;
|
||||
extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
|
||||
|
||||
pub const BuildLoad = LLVMBuildLoad;
|
||||
extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const ConstNull = LLVMConstNull;
|
||||
extern fn LLVMConstNull(Ty: *Type) ?*Value;
|
||||
|
||||
pub const CreateStringAttribute = LLVMCreateStringAttribute;
|
||||
extern fn LLVMCreateStringAttribute(
|
||||
C: *Context,
|
||||
K: [*]const u8,
|
||||
KLength: c_uint,
|
||||
V: [*]const u8,
|
||||
VLength: c_uint,
|
||||
) ?*Attribute;
|
||||
|
||||
pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
|
||||
extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
|
||||
|
||||
pub const AddFunction = LLVMAddFunction;
|
||||
extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value;
|
||||
|
||||
pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
|
||||
extern fn ZigLLVMCreateCompileUnit(
|
||||
dibuilder: *DIBuilder,
|
||||
lang: c_uint,
|
||||
difile: *DIFile,
|
||||
producer: [*]const u8,
|
||||
is_optimized: bool,
|
||||
flags: [*]const u8,
|
||||
runtime_version: c_uint,
|
||||
split_name: [*]const u8,
|
||||
dwo_id: u64,
|
||||
emit_debug_info: bool,
|
||||
) ?*DICompileUnit;
|
||||
|
||||
pub const CreateFile = ZigLLVMCreateFile;
|
||||
extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile;
|
||||
|
||||
pub const ArrayType = LLVMArrayType;
|
||||
extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
|
||||
|
||||
pub const CreateDIBuilder = ZigLLVMCreateDIBuilder;
|
||||
extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder;
|
||||
|
||||
pub const PointerType = LLVMPointerType;
|
||||
extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type;
|
||||
|
||||
pub const CreateBuilderInContext = LLVMCreateBuilderInContext;
|
||||
extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder;
|
||||
|
||||
pub const IntTypeInContext = LLVMIntTypeInContext;
|
||||
extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
|
||||
|
||||
pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
|
||||
extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module;
|
||||
|
||||
pub const VoidTypeInContext = LLVMVoidTypeInContext;
|
||||
extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
|
||||
|
||||
pub const ContextCreate = LLVMContextCreate;
|
||||
extern fn LLVMContextCreate() ?*Context;
|
||||
|
||||
pub const ContextDispose = LLVMContextDispose;
|
||||
extern fn LLVMContextDispose(C: *Context) void;
|
||||
|
||||
pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
|
||||
extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8;
|
||||
|
||||
pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
|
||||
extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
|
||||
|
||||
pub const CreateTargetMachine = LLVMCreateTargetMachine;
|
||||
extern fn LLVMCreateTargetMachine(
|
||||
T: *Target,
|
||||
Triple: [*]const u8,
|
||||
CPU: [*]const u8,
|
||||
Features: [*]const u8,
|
||||
Level: CodeGenOptLevel,
|
||||
Reloc: RelocMode,
|
||||
CodeModel: CodeModel,
|
||||
) ?*TargetMachine;
|
||||
|
||||
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||
extern fn LLVMGetHostCPUName() ?[*]u8;
|
||||
|
||||
pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
|
||||
extern fn ZigLLVMGetNativeFeatures() ?[*]u8;
|
||||
|
||||
pub const GetElementType = LLVMGetElementType;
|
||||
extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
|
||||
extern fn LLVMGetElementType(Ty: *Type) *Type;
|
||||
|
||||
pub const TypeOf = LLVMTypeOf;
|
||||
extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
|
||||
extern fn LLVMTypeOf(Val: *Value) *Type;
|
||||
|
||||
pub const BuildStore = LLVMBuildStore;
|
||||
extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef;
|
||||
extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
|
||||
|
||||
pub const BuildAlloca = LLVMBuildAlloca;
|
||||
extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef;
|
||||
extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value;
|
||||
|
||||
pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
|
||||
|
||||
pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool;
|
||||
|
||||
pub const VerifyModule = LLVMVerifyModule;
|
||||
extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
|
||||
extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
|
||||
|
||||
pub const GetInsertBlock = LLVMGetInsertBlock;
|
||||
extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
|
||||
extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
|
||||
|
||||
pub const FunctionType = LLVMFunctionType;
|
||||
extern fn LLVMFunctionType(
|
||||
ReturnType: TypeRef,
|
||||
ParamTypes: [*]TypeRef,
|
||||
ReturnType: *Type,
|
||||
ParamTypes: [*]*Type,
|
||||
ParamCount: c_uint,
|
||||
IsVarArg: Bool,
|
||||
) ?TypeRef;
|
||||
) ?*Type;
|
||||
|
||||
pub const GetParam = LLVMGetParam;
|
||||
extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef;
|
||||
extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
|
||||
|
||||
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock;
|
||||
|
||||
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
|
||||
|
||||
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
|
||||
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
|
||||
|
@ -190,17 +267,17 @@ pub const FnInline = extern enum {
|
|||
};
|
||||
|
||||
fn removeNullability(comptime T: type) type {
|
||||
comptime assert(@typeId(T) == builtin.TypeId.Optional);
|
||||
return T.Child;
|
||||
comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C);
|
||||
return *T.Child;
|
||||
}
|
||||
|
||||
pub const BuildRet = LLVMBuildRet;
|
||||
extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
|
||||
extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
|
||||
|
||||
pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
|
||||
extern fn ZigLLVMTargetMachineEmitToFile(
|
||||
targ_machine_ref: TargetMachineRef,
|
||||
module_ref: ModuleRef,
|
||||
targ_machine_ref: *TargetMachine,
|
||||
module_ref: *Module,
|
||||
filename: [*]const u8,
|
||||
output_type: EmitOutputType,
|
||||
error_message: *[*]u8,
|
||||
|
@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
|
|||
) bool;
|
||||
|
||||
pub const BuildCall = ZigLLVMBuildCall;
|
||||
extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
|
||||
extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
|
||||
|
|
|
@ -24,7 +24,7 @@ var stderr_file: os.File = undefined;
|
|||
var stderr: *io.OutStream(os.File.WriteError) = undefined;
|
||||
var stdout: *io.OutStream(os.File.WriteError) = undefined;
|
||||
|
||||
const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
||||
pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
||||
|
||||
const usage =
|
||||
\\usage: zig [command] [options]
|
||||
|
@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
|
|||
const root_name = if (provided_name) |n| n else blk: {
|
||||
if (root_source_file) |file| {
|
||||
const basename = os.path.basename(file);
|
||||
var it = mem.split(basename, ".");
|
||||
var it = mem.separate(basename, ".");
|
||||
break :blk it.next() orelse basename;
|
||||
} else {
|
||||
try stderr.write("--name [name] not provided and unable to infer\n");
|
||||
|
@ -510,7 +510,7 @@ fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
|
|||
return buildOutputType(allocator, args, Compilation.Kind.Obj);
|
||||
}
|
||||
|
||||
const usage_fmt =
|
||||
pub const usage_fmt =
|
||||
\\usage: zig fmt [file]...
|
||||
\\
|
||||
\\ Formats the input files and modifies them in-place.
|
||||
|
@ -527,7 +527,7 @@ const usage_fmt =
|
|||
\\
|
||||
;
|
||||
|
||||
const args_fmt_spec = []Flag{
|
||||
pub const args_fmt_spec = []Flag{
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--check"),
|
||||
Flag.Option("--color", []const []const u8{
|
||||
|
@ -757,7 +757,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
|
|||
var group = event.Group(FmtError!void).init(fmt.loop);
|
||||
while (try dir.next()) |entry| {
|
||||
if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
|
||||
const full_path = try os.path.join(fmt.loop.allocator, file_path, entry.name);
|
||||
const full_path = try os.path.join(fmt.loop.allocator, [][]const u8{ file_path, entry.name });
|
||||
try group.call(fmtPath, fmt, full_path, check_mode);
|
||||
}
|
||||
}
|
||||
|
@ -944,12 +944,13 @@ const CliPkg = struct {
|
|||
parent: ?*CliPkg,
|
||||
|
||||
pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg {
|
||||
var pkg = try allocator.create(CliPkg{
|
||||
var pkg = try allocator.create(CliPkg);
|
||||
pkg.* = CliPkg{
|
||||
.name = name,
|
||||
.path = path,
|
||||
.children = ArrayList(*CliPkg).init(allocator),
|
||||
.parent = parent,
|
||||
});
|
||||
};
|
||||
return pkg;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,13 @@ pub const Package = struct {
|
|||
/// makes internal copies of root_src_dir and root_src_path
|
||||
/// allocator should be an arena allocator because Package never frees anything
|
||||
pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package {
|
||||
return allocator.create(Package{
|
||||
const ptr = try allocator.create(Package);
|
||||
ptr.* = Package{
|
||||
.root_src_dir = try Buffer.init(allocator, root_src_dir),
|
||||
.root_src_path = try Buffer.init(allocator, root_src_path),
|
||||
.table = Table.init(allocator),
|
||||
});
|
||||
};
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub fn add(self: *Package, name: []const u8, package: *Package) !void {
|
||||
|
|
|
@ -120,7 +120,7 @@ pub const Scope = struct {
|
|||
/// Creates a Root scope with 1 reference
|
||||
/// Takes ownership of realpath
|
||||
pub fn create(comp: *Compilation, realpath: []u8) !*Root {
|
||||
const self = try comp.gpa().createOne(Root);
|
||||
const self = try comp.gpa().create(Root);
|
||||
self.* = Root{
|
||||
.base = Scope{
|
||||
.id = Id.Root,
|
||||
|
@ -150,7 +150,7 @@ pub const Scope = struct {
|
|||
/// Creates a scope with 1 reference
|
||||
/// Takes ownership of tree, will deinit and destroy when done.
|
||||
pub fn create(comp: *Compilation, tree: *ast.Tree, root_scope: *Root) !*AstTree {
|
||||
const self = try comp.gpa().createOne(AstTree);
|
||||
const self = try comp.gpa().create(AstTree);
|
||||
self.* = AstTree{
|
||||
.base = undefined,
|
||||
.tree = tree,
|
||||
|
@ -182,7 +182,7 @@ pub const Scope = struct {
|
|||
|
||||
/// Creates a Decls scope with 1 reference
|
||||
pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
|
||||
const self = try comp.gpa().createOne(Decls);
|
||||
const self = try comp.gpa().create(Decls);
|
||||
self.* = Decls{
|
||||
.base = undefined,
|
||||
.table = event.RwLocked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),
|
||||
|
@ -235,7 +235,7 @@ pub const Scope = struct {
|
|||
|
||||
/// Creates a Block scope with 1 reference
|
||||
pub fn create(comp: *Compilation, parent: *Scope) !*Block {
|
||||
const self = try comp.gpa().createOne(Block);
|
||||
const self = try comp.gpa().create(Block);
|
||||
self.* = Block{
|
||||
.base = undefined,
|
||||
.incoming_values = undefined,
|
||||
|
@ -262,7 +262,7 @@ pub const Scope = struct {
|
|||
/// Creates a FnDef scope with 1 reference
|
||||
/// Must set the fn_val later
|
||||
pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
|
||||
const self = try comp.gpa().createOne(FnDef);
|
||||
const self = try comp.gpa().create(FnDef);
|
||||
self.* = FnDef{
|
||||
.base = undefined,
|
||||
.fn_val = null,
|
||||
|
@ -281,7 +281,7 @@ pub const Scope = struct {
|
|||
|
||||
/// Creates a CompTime scope with 1 reference
|
||||
pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {
|
||||
const self = try comp.gpa().createOne(CompTime);
|
||||
const self = try comp.gpa().create(CompTime);
|
||||
self.* = CompTime{ .base = undefined };
|
||||
self.base.init(Id.CompTime, parent);
|
||||
return self;
|
||||
|
@ -309,7 +309,7 @@ pub const Scope = struct {
|
|||
kind: Kind,
|
||||
defer_expr_scope: *DeferExpr,
|
||||
) !*Defer {
|
||||
const self = try comp.gpa().createOne(Defer);
|
||||
const self = try comp.gpa().create(Defer);
|
||||
self.* = Defer{
|
||||
.base = undefined,
|
||||
.defer_expr_scope = defer_expr_scope,
|
||||
|
@ -333,7 +333,7 @@ pub const Scope = struct {
|
|||
|
||||
/// Creates a DeferExpr scope with 1 reference
|
||||
pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {
|
||||
const self = try comp.gpa().createOne(DeferExpr);
|
||||
const self = try comp.gpa().create(DeferExpr);
|
||||
self.* = DeferExpr{
|
||||
.base = undefined,
|
||||
.expr_node = expr_node,
|
||||
|
@ -362,7 +362,7 @@ pub const Scope = struct {
|
|||
pub const Param = struct {
|
||||
index: usize,
|
||||
typ: *Type,
|
||||
llvm_value: llvm.ValueRef,
|
||||
llvm_value: *llvm.Value,
|
||||
};
|
||||
|
||||
pub fn createParam(
|
||||
|
@ -398,7 +398,7 @@ pub const Scope = struct {
|
|||
}
|
||||
|
||||
fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var {
|
||||
const self = try comp.gpa().createOne(Var);
|
||||
const self = try comp.gpa().create(Var);
|
||||
self.* = Var{
|
||||
.base = undefined,
|
||||
.name = name,
|
||||
|
|
|
@ -457,8 +457,8 @@ pub const Target = union(enum) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
|
||||
var result: llvm.TargetRef = undefined;
|
||||
pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
|
||||
var result: *llvm.Target = undefined;
|
||||
var err_msg: [*]u8 = undefined;
|
||||
if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
|
||||
std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
|
||||
|
@ -520,7 +520,7 @@ pub const Target = union(enum) {
|
|||
=> return 64,
|
||||
},
|
||||
|
||||
builtin.Os.windows => switch (id) {
|
||||
builtin.Os.windows, builtin.Os.uefi => switch (id) {
|
||||
CInt.Id.Short,
|
||||
CInt.Id.UShort,
|
||||
=> return 16,
|
||||
|
|
|
@ -4,7 +4,7 @@ const builtin = @import("builtin");
|
|||
const Target = @import("target.zig").Target;
|
||||
const Compilation = @import("compilation.zig").Compilation;
|
||||
const introspect = @import("introspect.zig");
|
||||
const assertOrPanic = std.debug.assertOrPanic;
|
||||
const testing = std.testing;
|
||||
const errmsg = @import("errmsg.zig");
|
||||
const ZigCompiler = @import("compilation.zig").ZigCompiler;
|
||||
|
||||
|
@ -87,7 +87,7 @@ pub const TestContext = struct {
|
|||
) !void {
|
||||
var file_index_buf: [20]u8 = undefined;
|
||||
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
|
||||
const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
|
||||
const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });
|
||||
|
||||
if (std.os.path.dirname(file1_path)) |dirname| {
|
||||
try std.os.makePath(allocator, dirname);
|
||||
|
@ -120,7 +120,7 @@ pub const TestContext = struct {
|
|||
) !void {
|
||||
var file_index_buf: [20]u8 = undefined;
|
||||
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
|
||||
const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
|
||||
const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });
|
||||
|
||||
const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt());
|
||||
if (std.os.path.dirname(file1_path)) |dirname| {
|
||||
|
@ -210,7 +210,7 @@ pub const TestContext = struct {
|
|||
@panic("build incorrectly failed");
|
||||
},
|
||||
Compilation.Event.Fail => |msgs| {
|
||||
assertOrPanic(msgs.len != 0);
|
||||
testing.expect(msgs.len != 0);
|
||||
for (msgs) |msg| {
|
||||
if (mem.endsWith(u8, msg.realpath, path) and mem.eql(u8, msg.text, text)) {
|
||||
const span = msg.getSpan();
|
||||
|
|
|
@ -44,14 +44,15 @@ pub const Type = struct {
|
|||
Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
|
||||
Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
|
||||
Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp),
|
||||
Id.Vector => @fieldParentPtr(Vector, "base", base).destroy(comp),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getLlvmType(
|
||||
base: *Type,
|
||||
allocator: *Allocator,
|
||||
llvm_context: llvm.ContextRef,
|
||||
) (error{OutOfMemory}!llvm.TypeRef) {
|
||||
llvm_context: *llvm.Context,
|
||||
) (error{OutOfMemory}!*llvm.Type) {
|
||||
switch (base.id) {
|
||||
Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
|
||||
|
@ -77,6 +78,7 @@ pub const Type = struct {
|
|||
Id.ArgTuple => unreachable,
|
||||
Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,6 +105,7 @@ pub const Type = struct {
|
|||
Id.Enum,
|
||||
Id.Fn,
|
||||
Id.Promise,
|
||||
Id.Vector,
|
||||
=> return false,
|
||||
|
||||
Id.Struct => @panic("TODO"),
|
||||
|
@ -135,6 +138,7 @@ pub const Type = struct {
|
|||
Id.Float,
|
||||
Id.Fn,
|
||||
Id.Promise,
|
||||
Id.Vector,
|
||||
=> return true,
|
||||
|
||||
Id.Pointer => {
|
||||
|
@ -192,7 +196,7 @@ pub const Type = struct {
|
|||
}
|
||||
|
||||
/// If you have an llvm conext handy, you can use it here.
|
||||
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
|
||||
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
|
||||
if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
|
||||
|
||||
base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
|
||||
|
@ -201,7 +205,7 @@ pub const Type = struct {
|
|||
}
|
||||
|
||||
/// Lower level function that does the work. See getAbiAlignment.
|
||||
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
|
||||
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
|
||||
const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
|
||||
return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
|
||||
}
|
||||
|
@ -214,7 +218,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -409,7 +413,7 @@ pub const Type = struct {
|
|||
key.ref();
|
||||
errdefer key.deref(comp);
|
||||
|
||||
const self = try comp.gpa().createOne(Fn);
|
||||
const self = try comp.gpa().create(Fn);
|
||||
self.* = Fn{
|
||||
.base = undefined,
|
||||
.key = key,
|
||||
|
@ -492,13 +496,13 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const normal = &self.key.data.Normal;
|
||||
const llvm_return_type = switch (normal.return_type.id) {
|
||||
Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
|
||||
else => try normal.return_type.getLlvmType(allocator, llvm_context),
|
||||
};
|
||||
const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len);
|
||||
const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len);
|
||||
defer allocator.free(llvm_param_types);
|
||||
for (llvm_param_types) |*llvm_param_type, i| {
|
||||
llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
|
||||
|
@ -555,7 +559,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -611,11 +615,12 @@ pub const Type = struct {
|
|||
}
|
||||
}
|
||||
|
||||
const self = try comp.gpa().create(Int{
|
||||
const self = try comp.gpa().create(Int);
|
||||
self.* = Int{
|
||||
.base = undefined,
|
||||
.key = key,
|
||||
.garbage_node = undefined,
|
||||
});
|
||||
};
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
const u_or_i = "ui"[@boolToInt(key.is_signed)];
|
||||
|
@ -653,7 +658,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
|
||||
}
|
||||
};
|
||||
|
@ -665,7 +670,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -777,17 +782,19 @@ pub const Type = struct {
|
|||
}
|
||||
}
|
||||
|
||||
const self = try comp.gpa().create(Pointer{
|
||||
const self = try comp.gpa().create(Pointer);
|
||||
self.* = Pointer{
|
||||
.base = undefined,
|
||||
.key = normal_key,
|
||||
.garbage_node = undefined,
|
||||
});
|
||||
};
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
const size_str = switch (self.key.size) {
|
||||
Size.One => "*",
|
||||
Size.Many => "[*]",
|
||||
Size.Slice => "[]",
|
||||
Size.C => "[*c]",
|
||||
};
|
||||
const mut_str = switch (self.key.mut) {
|
||||
Mut.Const => "const ",
|
||||
|
@ -829,7 +836,7 @@ pub const Type = struct {
|
|||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
|
||||
return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
|
||||
}
|
||||
|
@ -875,11 +882,12 @@ pub const Type = struct {
|
|||
}
|
||||
}
|
||||
|
||||
const self = try comp.gpa().create(Array{
|
||||
const self = try comp.gpa().create(Array);
|
||||
self.* = Array{
|
||||
.base = undefined,
|
||||
.key = key,
|
||||
.garbage_node = undefined,
|
||||
});
|
||||
};
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name);
|
||||
|
@ -896,12 +904,24 @@ pub const Type = struct {
|
|||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
|
||||
return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Vector = struct {
|
||||
base: Type,
|
||||
|
||||
pub fn destroy(self: *Vector, comp: *Compilation) void {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
||||
pub const ComptimeFloat = struct {
|
||||
base: Type,
|
||||
|
||||
|
@ -947,7 +967,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -959,7 +979,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -971,7 +991,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -983,7 +1003,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -995,7 +1015,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -1015,7 +1035,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -1035,7 +1055,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -1047,7 +1067,7 @@ pub const Type = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
@ -1069,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 {
|
|||
builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.C => unreachable,
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed),
|
||||
|
|
|
@ -57,7 +57,7 @@ pub const Value = struct {
|
|||
std.debug.warn("{}", @tagName(base.id));
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
|
||||
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) {
|
||||
switch (base.id) {
|
||||
Id.Type => unreachable,
|
||||
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
|
||||
|
@ -135,14 +135,15 @@ pub const Value = struct {
|
|||
symbol_name: Buffer,
|
||||
|
||||
pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto {
|
||||
const self = try comp.gpa().create(FnProto{
|
||||
const self = try comp.gpa().create(FnProto);
|
||||
self.* = FnProto{
|
||||
.base = Value{
|
||||
.id = Value.Id.FnProto,
|
||||
.typ = &fn_type.base,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
.symbol_name = symbol_name,
|
||||
});
|
||||
};
|
||||
fn_type.base.base.ref();
|
||||
return self;
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ pub const Value = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
const llvm_fn = llvm.AddFunction(
|
||||
ofile.module,
|
||||
|
@ -190,14 +191,16 @@ pub const Value = struct {
|
|||
/// Creates a Fn value with 1 ref
|
||||
/// Takes ownership of symbol_name
|
||||
pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn {
|
||||
const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node{
|
||||
const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node);
|
||||
link_set_node.* = Compilation.FnLinkSet.Node{
|
||||
.data = null,
|
||||
.next = undefined,
|
||||
.prev = undefined,
|
||||
});
|
||||
};
|
||||
errdefer comp.gpa().destroy(link_set_node);
|
||||
|
||||
const self = try comp.gpa().create(Fn{
|
||||
const self = try comp.gpa().create(Fn);
|
||||
self.* = Fn{
|
||||
.base = Value{
|
||||
.id = Value.Id.Fn,
|
||||
.typ = &fn_type.base,
|
||||
|
@ -209,7 +212,7 @@ pub const Value = struct {
|
|||
.symbol_name = symbol_name,
|
||||
.containing_object = Buffer.initNull(comp.gpa()),
|
||||
.link_set_node = link_set_node,
|
||||
});
|
||||
};
|
||||
fn_type.base.base.ref();
|
||||
fndef_scope.fn_val = self;
|
||||
fndef_scope.base.ref();
|
||||
|
@ -235,7 +238,7 @@ pub const Value = struct {
|
|||
/// We know that the function definition will end up in an .o file somewhere.
|
||||
/// Here, all we have to do is generate a global prototype.
|
||||
/// TODO cache the prototype per ObjectFile
|
||||
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
const llvm_fn = llvm.AddFunction(
|
||||
ofile.module,
|
||||
|
@ -280,8 +283,8 @@ pub const Value = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
|
||||
const llvm_type = llvm.Int1TypeInContext(ofile.context);
|
||||
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_type = llvm.Int1TypeInContext(ofile.context) orelse return error.OutOfMemory;
|
||||
if (self.x) {
|
||||
return llvm.ConstAllOnes(llvm_type);
|
||||
} else {
|
||||
|
@ -353,7 +356,8 @@ pub const Value = struct {
|
|||
var ptr_type_consumed = false;
|
||||
errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
|
||||
|
||||
const self = try comp.gpa().create(Value.Ptr{
|
||||
const self = try comp.gpa().create(Value.Ptr);
|
||||
self.* = Value.Ptr{
|
||||
.base = Value{
|
||||
.id = Value.Id.Ptr,
|
||||
.typ = &ptr_type.base,
|
||||
|
@ -366,7 +370,7 @@ pub const Value = struct {
|
|||
},
|
||||
},
|
||||
.mut = Mut.CompTimeConst,
|
||||
});
|
||||
};
|
||||
ptr_type_consumed = true;
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
|
@ -377,7 +381,7 @@ pub const Value = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
// TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
|
||||
switch (self.special) {
|
||||
|
@ -387,7 +391,7 @@ pub const Value = struct {
|
|||
const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
|
||||
const ptr_bit_count = ofile.comp.target_ptr_bits;
|
||||
const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
|
||||
const indices = []llvm.ValueRef{
|
||||
const indices = []*llvm.Value{
|
||||
llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
|
||||
llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
|
||||
};
|
||||
|
@ -430,14 +434,15 @@ pub const Value = struct {
|
|||
}) catch unreachable);
|
||||
errdefer array_type.base.base.deref(comp);
|
||||
|
||||
const self = try comp.gpa().create(Value.Array{
|
||||
const self = try comp.gpa().create(Value.Array);
|
||||
self.* = Value.Array{
|
||||
.base = Value{
|
||||
.id = Value.Id.Array,
|
||||
.typ = &array_type.base,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
.special = Special{ .OwnedBuffer = buffer },
|
||||
});
|
||||
};
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
return self;
|
||||
|
@ -454,7 +459,7 @@ pub const Value = struct {
|
|||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value {
|
||||
switch (self.special) {
|
||||
Special.Undefined => {
|
||||
const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
|
@ -509,14 +514,15 @@ pub const Value = struct {
|
|||
big_int: std.math.big.Int,
|
||||
|
||||
pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int {
|
||||
const self = try comp.gpa().create(Value.Int{
|
||||
const self = try comp.gpa().create(Value.Int);
|
||||
self.* = Value.Int{
|
||||
.base = Value{
|
||||
.id = Value.Id.Int,
|
||||
.typ = typ,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
.big_int = undefined,
|
||||
});
|
||||
};
|
||||
typ.base.ref();
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
|
@ -528,7 +534,7 @@ pub const Value = struct {
|
|||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value {
|
||||
switch (self.base.typ.id) {
|
||||
Type.Id.Int => {
|
||||
const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
|
@ -557,14 +563,15 @@ pub const Value = struct {
|
|||
old.base.typ.base.ref();
|
||||
errdefer old.base.typ.base.deref(comp);
|
||||
|
||||
const new = try comp.gpa().create(Value.Int{
|
||||
const new = try comp.gpa().create(Value.Int);
|
||||
new.* = Value.Int{
|
||||
.base = Value{
|
||||
.id = Value.Id.Int,
|
||||
.typ = old.base.typ,
|
||||
.ref_count = std.atomic.Int(usize).init(1),
|
||||
},
|
||||
.big_int = undefined,
|
||||
});
|
||||
};
|
||||
errdefer comp.gpa().destroy(new);
|
||||
|
||||
new.big_int = try old.big_int.clone();
|
||||
|
|
|
@ -56,9 +56,6 @@ struct IrExecutable {
|
|||
size_t next_debug_id;
|
||||
size_t *backward_branch_count;
|
||||
size_t backward_branch_quota;
|
||||
bool invalid;
|
||||
bool is_inline;
|
||||
bool is_generic_instantiation;
|
||||
ZigFn *fn_entry;
|
||||
Buf *c_import_buf;
|
||||
AstNode *source_node;
|
||||
|
@ -78,6 +75,10 @@ struct IrExecutable {
|
|||
IrBasicBlock *coro_suspend_block;
|
||||
IrBasicBlock *coro_final_cleanup_block;
|
||||
ZigVar *coro_allocator_var;
|
||||
|
||||
bool invalid;
|
||||
bool is_inline;
|
||||
bool is_generic_instantiation;
|
||||
};
|
||||
|
||||
enum OutType {
|
||||
|
@ -90,6 +91,9 @@ enum OutType {
|
|||
enum ConstParentId {
|
||||
ConstParentIdNone,
|
||||
ConstParentIdStruct,
|
||||
ConstParentIdErrUnionCode,
|
||||
ConstParentIdErrUnionPayload,
|
||||
ConstParentIdOptionalPayload,
|
||||
ConstParentIdArray,
|
||||
ConstParentIdUnion,
|
||||
ConstParentIdScalar,
|
||||
|
@ -107,6 +111,15 @@ struct ConstParent {
|
|||
ConstExprValue *struct_val;
|
||||
size_t field_index;
|
||||
} p_struct;
|
||||
struct {
|
||||
ConstExprValue *err_union_val;
|
||||
} p_err_union_code;
|
||||
struct {
|
||||
ConstExprValue *err_union_val;
|
||||
} p_err_union_payload;
|
||||
struct {
|
||||
ConstExprValue *optional_val;
|
||||
} p_optional_payload;
|
||||
struct {
|
||||
ConstExprValue *union_val;
|
||||
} p_union;
|
||||
|
@ -118,13 +131,11 @@ struct ConstParent {
|
|||
|
||||
struct ConstStructValue {
|
||||
ConstExprValue *fields;
|
||||
ConstParent parent;
|
||||
};
|
||||
|
||||
struct ConstUnionValue {
|
||||
BigInt tag;
|
||||
ConstExprValue *payload;
|
||||
ConstParent parent;
|
||||
};
|
||||
|
||||
enum ConstArraySpecial {
|
||||
|
@ -138,7 +149,6 @@ struct ConstArrayValue {
|
|||
union {
|
||||
struct {
|
||||
ConstExprValue *elements;
|
||||
ConstParent parent;
|
||||
} s_none;
|
||||
Buf *s_buf;
|
||||
} data;
|
||||
|
@ -153,19 +163,29 @@ enum ConstPtrSpecial {
|
|||
ConstPtrSpecialBaseArray,
|
||||
// The pointer points to a field in an underlying struct.
|
||||
ConstPtrSpecialBaseStruct,
|
||||
// The pointer points to the error set field of an error union
|
||||
ConstPtrSpecialBaseErrorUnionCode,
|
||||
// The pointer points to the payload field of an error union
|
||||
ConstPtrSpecialBaseErrorUnionPayload,
|
||||
// The pointer points to the payload field of an optional
|
||||
ConstPtrSpecialBaseOptionalPayload,
|
||||
// This means that we did a compile-time pointer reinterpret and we cannot
|
||||
// understand the value of pointee at compile time. However, we will still
|
||||
// emit a binary with a compile time known address.
|
||||
// In this case index is the numeric address value.
|
||||
// We also use this for null pointer. We need the data layout for ConstCastOnly == true
|
||||
// types to be the same, so all optionals of pointer types use x_ptr
|
||||
// instead of x_optional
|
||||
ConstPtrSpecialHardCodedAddr,
|
||||
// This means that the pointer represents memory of assigning to _.
|
||||
// That is, storing discards the data, and loading is invalid.
|
||||
ConstPtrSpecialDiscard,
|
||||
// This is actually a function.
|
||||
ConstPtrSpecialFunction,
|
||||
// This means the pointer is null. This is only allowed when the type is ?*T.
|
||||
// We use this instead of ConstPtrSpecialHardCodedAddr because often we check
|
||||
// for that value to avoid doing comptime work.
|
||||
// We need the data layout for ConstCastOnly == true
|
||||
// types to be the same, so all optionals of pointer types use x_ptr
|
||||
// instead of x_optional.
|
||||
ConstPtrSpecialNull,
|
||||
};
|
||||
|
||||
enum ConstPtrMut {
|
||||
|
@ -199,6 +219,15 @@ struct ConstPtrValue {
|
|||
ConstExprValue *struct_val;
|
||||
size_t field_index;
|
||||
} base_struct;
|
||||
struct {
|
||||
ConstExprValue *err_union_val;
|
||||
} base_err_union_code;
|
||||
struct {
|
||||
ConstExprValue *err_union_val;
|
||||
} base_err_union_payload;
|
||||
struct {
|
||||
ConstExprValue *optional_val;
|
||||
} base_optional_payload;
|
||||
struct {
|
||||
uint64_t addr;
|
||||
} hard_coded_addr;
|
||||
|
@ -209,7 +238,7 @@ struct ConstPtrValue {
|
|||
};
|
||||
|
||||
struct ConstErrValue {
|
||||
ErrorTableEntry *err;
|
||||
ConstExprValue *error_set;
|
||||
ConstExprValue *payload;
|
||||
};
|
||||
|
||||
|
@ -265,6 +294,7 @@ struct ConstGlobalRefs {
|
|||
struct ConstExprValue {
|
||||
ZigType *type;
|
||||
ConstValSpecial special;
|
||||
ConstParent parent;
|
||||
ConstGlobalRefs *global_refs;
|
||||
|
||||
union {
|
||||
|
@ -433,7 +463,7 @@ enum NodeType {
|
|||
NodeTypeArrayType,
|
||||
NodeTypeErrorType,
|
||||
NodeTypeIfErrorExpr,
|
||||
NodeTypeTestExpr,
|
||||
NodeTypeIfOptional,
|
||||
NodeTypeErrorSetDecl,
|
||||
NodeTypeCancel,
|
||||
NodeTypeResume,
|
||||
|
@ -514,12 +544,7 @@ struct AstNodeDefer {
|
|||
};
|
||||
|
||||
struct AstNodeVariableDeclaration {
|
||||
VisibMod visib_mod;
|
||||
Buf *symbol;
|
||||
bool is_const;
|
||||
bool is_comptime;
|
||||
bool is_export;
|
||||
bool is_extern;
|
||||
// one or both of type and expr will be non null
|
||||
AstNode *type;
|
||||
AstNode *expr;
|
||||
|
@ -529,6 +554,13 @@ struct AstNodeVariableDeclaration {
|
|||
AstNode *align_expr;
|
||||
// populated if the "section(S)" is present
|
||||
AstNode *section_expr;
|
||||
Token *threadlocal_tok;
|
||||
|
||||
VisibMod visib_mod;
|
||||
bool is_const;
|
||||
bool is_comptime;
|
||||
bool is_export;
|
||||
bool is_extern;
|
||||
};
|
||||
|
||||
struct AstNodeTestDecl {
|
||||
|
@ -605,7 +637,6 @@ enum CastOp {
|
|||
CastOpFloatToInt,
|
||||
CastOpBoolToInt,
|
||||
CastOpResizeSlice,
|
||||
CastOpBytesToSlice,
|
||||
CastOpNumLitToConcrete,
|
||||
CastOpErrSet,
|
||||
CastOpBitCast,
|
||||
|
@ -660,15 +691,17 @@ struct AstNodePointerType {
|
|||
AstNode *align_expr;
|
||||
BigInt *bit_offset_start;
|
||||
BigInt *host_int_bytes;
|
||||
AstNode *op_expr;
|
||||
Token *allow_zero_token;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
AstNode *op_expr;
|
||||
};
|
||||
|
||||
struct AstNodeArrayType {
|
||||
AstNode *size;
|
||||
AstNode *child_type;
|
||||
AstNode *align_expr;
|
||||
Token *allow_zero_token;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
|
@ -678,7 +711,7 @@ struct AstNodeUse {
|
|||
AstNode *expr;
|
||||
|
||||
TldResolution resolution;
|
||||
IrInstruction *value;
|
||||
ConstExprValue *value;
|
||||
};
|
||||
|
||||
struct AstNodeIfBoolExpr {
|
||||
|
@ -1007,6 +1040,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
|
|||
enum PtrLen {
|
||||
PtrLenUnknown,
|
||||
PtrLenSingle,
|
||||
PtrLenC,
|
||||
};
|
||||
|
||||
struct ZigTypePointer {
|
||||
|
@ -1018,6 +1052,7 @@ struct ZigTypePointer {
|
|||
uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct ZigTypeInt {
|
||||
|
@ -1167,6 +1202,7 @@ struct ZigTypeFn {
|
|||
FnGenParamInfo *gen_param_info;
|
||||
|
||||
LLVMTypeRef raw_type_ref;
|
||||
ZigLLVMDIType *raw_di_type;
|
||||
|
||||
ZigType *bound_fn_parent;
|
||||
};
|
||||
|
@ -1180,6 +1216,12 @@ struct ZigTypePromise {
|
|||
ZigType *result_type;
|
||||
};
|
||||
|
||||
struct ZigTypeVector {
|
||||
// The type must be a pointer, integer, or float
|
||||
ZigType *elem_type;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
enum ZigTypeId {
|
||||
ZigTypeIdInvalid,
|
||||
ZigTypeIdMetaType,
|
||||
|
@ -1206,6 +1248,7 @@ enum ZigTypeId {
|
|||
ZigTypeIdArgTuple,
|
||||
ZigTypeIdOpaque,
|
||||
ZigTypeIdPromise,
|
||||
ZigTypeIdVector,
|
||||
};
|
||||
|
||||
struct ZigType {
|
||||
|
@ -1232,6 +1275,7 @@ struct ZigType {
|
|||
ZigTypeFn fn;
|
||||
ZigTypeBoundFn bound_fn;
|
||||
ZigTypePromise promise;
|
||||
ZigTypeVector vector;
|
||||
} data;
|
||||
|
||||
// use these fields to make sure we don't duplicate type table entries for the same type
|
||||
|
@ -1385,6 +1429,7 @@ enum BuiltinFnId {
|
|||
BuiltinFnIdEnumToInt,
|
||||
BuiltinFnIdIntToEnum,
|
||||
BuiltinFnIdIntType,
|
||||
BuiltinFnIdVectorType,
|
||||
BuiltinFnIdSetCold,
|
||||
BuiltinFnIdSetRuntimeSafety,
|
||||
BuiltinFnIdSetFloatMode,
|
||||
|
@ -1415,6 +1460,8 @@ enum BuiltinFnId {
|
|||
BuiltinFnIdErrorReturnTrace,
|
||||
BuiltinFnIdAtomicRmw,
|
||||
BuiltinFnIdAtomicLoad,
|
||||
BuiltinFnIdBswap,
|
||||
BuiltinFnIdBitReverse,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
|
@ -1441,6 +1488,7 @@ enum PanicMsgId {
|
|||
PanicMsgIdBadUnionField,
|
||||
PanicMsgIdBadEnumValue,
|
||||
PanicMsgIdFloatToInt,
|
||||
PanicMsgIdPtrCastNull,
|
||||
|
||||
PanicMsgIdCount,
|
||||
};
|
||||
|
@ -1455,11 +1503,12 @@ struct TypeId {
|
|||
struct {
|
||||
ZigType *child_type;
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
uint32_t alignment;
|
||||
uint32_t bit_offset_in_host;
|
||||
uint32_t host_int_bytes;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
} pointer;
|
||||
struct {
|
||||
ZigType *child_type;
|
||||
|
@ -1473,6 +1522,10 @@ struct TypeId {
|
|||
ZigType *err_set_type;
|
||||
ZigType *payload_type;
|
||||
} error_union;
|
||||
struct {
|
||||
ZigType *elem_type;
|
||||
uint32_t len;
|
||||
} vector;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
@ -1487,8 +1540,12 @@ enum ZigLLVMFnId {
|
|||
ZigLLVMFnIdFloor,
|
||||
ZigLLVMFnIdCeil,
|
||||
ZigLLVMFnIdSqrt,
|
||||
ZigLLVMFnIdBswap,
|
||||
ZigLLVMFnIdBitReverse,
|
||||
};
|
||||
|
||||
// There are a bunch of places in code that rely on these values being in
|
||||
// exactly this order.
|
||||
enum AddSubMul {
|
||||
AddSubMulAdd = 0,
|
||||
AddSubMulSub = 1,
|
||||
|
@ -1514,8 +1571,15 @@ struct ZigLLVMFnKey {
|
|||
struct {
|
||||
AddSubMul add_sub_mul;
|
||||
uint32_t bit_count;
|
||||
uint32_t vector_len; // 0 means not a vector
|
||||
bool is_signed;
|
||||
} overflow_arithmetic;
|
||||
struct {
|
||||
uint32_t bit_count;
|
||||
} bswap;
|
||||
struct {
|
||||
uint32_t bit_count;
|
||||
} bit_reverse;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
@ -1600,7 +1664,7 @@ struct CodeGen {
|
|||
HashMap<FnTypeId *, ZigType *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
|
||||
HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
|
||||
HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
|
||||
HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
|
||||
HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
|
||||
HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
|
||||
|
@ -1694,6 +1758,7 @@ struct CodeGen {
|
|||
ZigFn *cur_fn;
|
||||
ZigFn *main_fn;
|
||||
ZigFn *panic_fn;
|
||||
TldFn *panic_tld_fn;
|
||||
AstNode *root_export_decl;
|
||||
|
||||
CacheHash cache_hash;
|
||||
|
@ -1746,12 +1811,12 @@ struct CodeGen {
|
|||
BuildMode build_mode;
|
||||
OutType out_type;
|
||||
ZigTarget zig_target;
|
||||
TargetSubsystem subsystem;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool is_test_build;
|
||||
bool is_single_threaded;
|
||||
bool is_native_target;
|
||||
bool windows_subsystem_windows;
|
||||
bool windows_subsystem_console;
|
||||
bool linker_rdynamic;
|
||||
bool no_rosegment_workaround;
|
||||
bool each_lib_rpath;
|
||||
|
@ -1793,10 +1858,9 @@ enum VarLinkage {
|
|||
|
||||
struct ZigVar {
|
||||
Buf name;
|
||||
ConstExprValue *value;
|
||||
ConstExprValue *const_value;
|
||||
ZigType *var_type;
|
||||
LLVMValueRef value_ref;
|
||||
bool src_is_const;
|
||||
bool gen_is_const;
|
||||
IrInstruction *is_comptime;
|
||||
// which node is the declaration of the variable
|
||||
AstNode *decl_node;
|
||||
|
@ -1806,17 +1870,22 @@ struct ZigVar {
|
|||
Scope *parent_scope;
|
||||
Scope *child_scope;
|
||||
LLVMValueRef param_value_ref;
|
||||
bool shadowable;
|
||||
size_t mem_slot_index;
|
||||
IrExecutable *owner_exec;
|
||||
size_t ref_count;
|
||||
VarLinkage linkage;
|
||||
uint32_t align_bytes;
|
||||
|
||||
// In an inline loop, multiple variables may be created,
|
||||
// In this case, a reference to a variable should follow
|
||||
// this pointer to the redefined variable.
|
||||
ZigVar *next_var;
|
||||
|
||||
uint32_t align_bytes;
|
||||
VarLinkage linkage;
|
||||
|
||||
bool shadowable;
|
||||
bool src_is_const;
|
||||
bool gen_is_const;
|
||||
bool is_thread_local;
|
||||
};
|
||||
|
||||
struct ErrorTableEntry {
|
||||
|
@ -1882,10 +1951,11 @@ struct ScopeBlock {
|
|||
ZigList<IrInstruction *> *incoming_values;
|
||||
ZigList<IrBasicBlock *> *incoming_blocks;
|
||||
|
||||
bool safety_off;
|
||||
AstNode *safety_set_node;
|
||||
bool fast_math_on;
|
||||
AstNode *fast_math_set_node;
|
||||
|
||||
bool safety_off;
|
||||
bool fast_math_on;
|
||||
};
|
||||
|
||||
// This scope is created from every defer expression.
|
||||
|
@ -2021,8 +2091,19 @@ struct IrBasicBlock {
|
|||
IrInstruction *must_be_comptime_source_instr;
|
||||
};
|
||||
|
||||
// These instructions are in transition to having "pass 1" instructions
|
||||
// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
|
||||
// and pass 2 are suffixed with Gen.
|
||||
// Once all instructions are separated in this way, they'll have different
|
||||
// base types for better type safety.
|
||||
// Src instructions are generated by ir_gen_* functions in ir.cpp from AST.
|
||||
// ir_analyze_* functions consume Src instructions and produce Gen instructions.
|
||||
// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
|
||||
// Src instructions do not have type information; Gen instructions do.
|
||||
enum IrInstructionId {
|
||||
IrInstructionIdInvalid,
|
||||
IrInstructionIdDeclVarSrc,
|
||||
IrInstructionIdDeclVarGen,
|
||||
IrInstructionIdBr,
|
||||
IrInstructionIdCondBr,
|
||||
IrInstructionIdSwitchBr,
|
||||
|
@ -2031,7 +2112,6 @@ enum IrInstructionId {
|
|||
IrInstructionIdPhi,
|
||||
IrInstructionIdUnOp,
|
||||
IrInstructionIdBinOp,
|
||||
IrInstructionIdDeclVar,
|
||||
IrInstructionIdLoadPtr,
|
||||
IrInstructionIdStorePtr,
|
||||
IrInstructionIdFieldPtr,
|
||||
|
@ -2060,7 +2140,7 @@ enum IrInstructionId {
|
|||
IrInstructionIdAsm,
|
||||
IrInstructionIdSizeOf,
|
||||
IrInstructionIdTestNonNull,
|
||||
IrInstructionIdUnwrapOptional,
|
||||
IrInstructionIdOptionalUnwrapPtr,
|
||||
IrInstructionIdOptionalWrap,
|
||||
IrInstructionIdUnionTag,
|
||||
IrInstructionIdClz,
|
||||
|
@ -2076,7 +2156,8 @@ enum IrInstructionId {
|
|||
IrInstructionIdCompileLog,
|
||||
IrInstructionIdErrName,
|
||||
IrInstructionIdEmbedFile,
|
||||
IrInstructionIdCmpxchg,
|
||||
IrInstructionIdCmpxchgSrc,
|
||||
IrInstructionIdCmpxchgGen,
|
||||
IrInstructionIdFence,
|
||||
IrInstructionIdTruncate,
|
||||
IrInstructionIdIntCast,
|
||||
|
@ -2085,6 +2166,7 @@ enum IrInstructionId {
|
|||
IrInstructionIdFloatToInt,
|
||||
IrInstructionIdBoolToInt,
|
||||
IrInstructionIdIntType,
|
||||
IrInstructionIdVectorType,
|
||||
IrInstructionIdBoolNot,
|
||||
IrInstructionIdMemset,
|
||||
IrInstructionIdMemcpy,
|
||||
|
@ -2105,7 +2187,8 @@ enum IrInstructionId {
|
|||
IrInstructionIdErrWrapPayload,
|
||||
IrInstructionIdFnProto,
|
||||
IrInstructionIdTestComptime,
|
||||
IrInstructionIdPtrCast,
|
||||
IrInstructionIdPtrCastSrc,
|
||||
IrInstructionIdPtrCastGen,
|
||||
IrInstructionIdBitCast,
|
||||
IrInstructionIdWidenOrShorten,
|
||||
IrInstructionIdIntToPtr,
|
||||
|
@ -2158,10 +2241,15 @@ enum IrInstructionId {
|
|||
IrInstructionIdMergeErrRetTraces,
|
||||
IrInstructionIdMarkErrRetTracePtr,
|
||||
IrInstructionIdSqrt,
|
||||
IrInstructionIdBswap,
|
||||
IrInstructionIdBitReverse,
|
||||
IrInstructionIdErrSetCast,
|
||||
IrInstructionIdToBytes,
|
||||
IrInstructionIdFromBytes,
|
||||
IrInstructionIdCheckRuntimeScope,
|
||||
IrInstructionIdVectorToArray,
|
||||
IrInstructionIdArrayToVector,
|
||||
IrInstructionIdAssertZero,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
|
@ -2183,6 +2271,22 @@ struct IrInstruction {
|
|||
bool is_gen;
|
||||
};
|
||||
|
||||
struct IrInstructionDeclVarSrc {
|
||||
IrInstruction base;
|
||||
|
||||
ZigVar *var;
|
||||
IrInstruction *var_type;
|
||||
IrInstruction *align_value;
|
||||
IrInstruction *init_value;
|
||||
};
|
||||
|
||||
struct IrInstructionDeclVarGen {
|
||||
IrInstruction base;
|
||||
|
||||
ZigVar *var;
|
||||
IrInstruction *init_value;
|
||||
};
|
||||
|
||||
struct IrInstructionCondBr {
|
||||
IrInstruction base;
|
||||
|
||||
|
@ -2291,20 +2395,11 @@ struct IrInstructionBinOp {
|
|||
IrInstruction base;
|
||||
|
||||
IrInstruction *op1;
|
||||
IrBinOp op_id;
|
||||
IrInstruction *op2;
|
||||
IrBinOp op_id;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionDeclVar {
|
||||
IrInstruction base;
|
||||
|
||||
ZigVar *var;
|
||||
IrInstruction *var_type;
|
||||
IrInstruction *align_value;
|
||||
IrInstruction *init_value;
|
||||
};
|
||||
|
||||
struct IrInstructionLoadPtr {
|
||||
IrInstruction base;
|
||||
|
||||
|
@ -2324,7 +2419,6 @@ struct IrInstructionFieldPtr {
|
|||
IrInstruction *container_ptr;
|
||||
Buf *field_name_buffer;
|
||||
IrInstruction *field_name_expr;
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct IrInstructionStructFieldPtr {
|
||||
|
@ -2367,13 +2461,13 @@ struct IrInstructionCall {
|
|||
ZigFn *fn_entry;
|
||||
size_t arg_count;
|
||||
IrInstruction **args;
|
||||
bool is_comptime;
|
||||
LLVMValueRef tmp_ptr;
|
||||
FnInline fn_inline;
|
||||
bool is_async;
|
||||
|
||||
IrInstruction *async_allocator;
|
||||
IrInstruction *new_stack;
|
||||
FnInline fn_inline;
|
||||
bool is_async;
|
||||
bool is_comptime;
|
||||
};
|
||||
|
||||
struct IrInstructionConst {
|
||||
|
@ -2504,6 +2598,7 @@ struct IrInstructionPtrType {
|
|||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionPromiseType {
|
||||
|
@ -2516,9 +2611,10 @@ struct IrInstructionSliceType {
|
|||
IrInstruction base;
|
||||
|
||||
IrInstruction *align_value;
|
||||
IrInstruction *child_type;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
IrInstruction *child_type;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionAsm {
|
||||
|
@ -2546,10 +2642,12 @@ struct IrInstructionTestNonNull {
|
|||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionUnwrapOptional {
|
||||
// Takes a pointer to an optional value, returns a pointer
|
||||
// to the payload.
|
||||
struct IrInstructionOptionalUnwrapPtr {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
IrInstruction *base_ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
|
@ -2640,7 +2738,7 @@ struct IrInstructionEmbedFile {
|
|||
IrInstruction *name;
|
||||
};
|
||||
|
||||
struct IrInstructionCmpxchg {
|
||||
struct IrInstructionCmpxchgSrc {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *type_value;
|
||||
|
@ -2650,14 +2748,19 @@ struct IrInstructionCmpxchg {
|
|||
IrInstruction *success_order_value;
|
||||
IrInstruction *failure_order_value;
|
||||
|
||||
// if this instruction gets to runtime then we know these values:
|
||||
ZigType *type;
|
||||
bool is_weak;
|
||||
};
|
||||
|
||||
struct IrInstructionCmpxchgGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *cmp_value;
|
||||
IrInstruction *new_value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
AtomicOrder success_order;
|
||||
AtomicOrder failure_order;
|
||||
|
||||
bool is_weak;
|
||||
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionFence {
|
||||
|
@ -2737,6 +2840,13 @@ struct IrInstructionIntType {
|
|||
IrInstruction *bit_count;
|
||||
};
|
||||
|
||||
struct IrInstructionVectorType {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *len;
|
||||
IrInstruction *elem_type;
|
||||
};
|
||||
|
||||
struct IrInstructionBoolNot {
|
||||
IrInstruction base;
|
||||
|
||||
|
@ -2840,7 +2950,7 @@ struct IrInstructionTestErr {
|
|||
struct IrInstructionUnwrapErrCode {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
IrInstruction *err_union;
|
||||
};
|
||||
|
||||
struct IrInstructionUnwrapErrPayload {
|
||||
|
@ -2888,11 +2998,19 @@ struct IrInstructionTestComptime {
|
|||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrCast {
|
||||
struct IrInstructionPtrCastSrc {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *dest_type;
|
||||
IrInstruction *ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrCastGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCast {
|
||||
|
@ -3251,6 +3369,39 @@ struct IrInstructionCheckRuntimeScope {
|
|||
IrInstruction *is_comptime;
|
||||
};
|
||||
|
||||
struct IrInstructionBswap {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *type;
|
||||
IrInstruction *op;
|
||||
};
|
||||
|
||||
struct IrInstructionBitReverse {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *type;
|
||||
IrInstruction *op;
|
||||
};
|
||||
|
||||
struct IrInstructionArrayToVector {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *array;
|
||||
};
|
||||
|
||||
struct IrInstructionVectorToArray {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *vector;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionAssertZero {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *target;
|
||||
};
|
||||
|
||||
static const size_t slice_ptr_index = 0;
|
||||
static const size_t slice_len_index = 1;
|
||||
|
||||
|
|
919
src/analyze.cpp
919
src/analyze.cpp
File diff suppressed because it is too large
Load Diff
|
@ -12,14 +12,17 @@
|
|||
|
||||
void semantic_analyze(CodeGen *g);
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg);
|
||||
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
|
||||
ZigType *new_type_table_entry(ZigTypeId id);
|
||||
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
|
||||
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
|
||||
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count);
|
||||
uint64_t type_size(CodeGen *g, ZigType *type_entry);
|
||||
uint64_t type_size_store(CodeGen *g, ZigType *type_entry);
|
||||
uint64_t type_size_bits(CodeGen *g, ZigType *type_entry);
|
||||
ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
|
||||
ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type);
|
||||
ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
|
||||
ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type);
|
||||
ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
|
||||
|
@ -42,7 +45,9 @@ void find_libc_include_path(CodeGen *g);
|
|||
void find_libc_lib_path(CodeGen *g);
|
||||
|
||||
bool type_has_bits(ZigType *type_entry);
|
||||
|
||||
bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
|
||||
bool ptr_allows_addr_zero(ZigType *ptr_type);
|
||||
bool type_is_nonnull_ptr(ZigType *type);
|
||||
|
||||
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
|
||||
|
||||
|
@ -73,6 +78,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag);
|
|||
bool is_ref(ZigType *type_entry);
|
||||
bool is_array_ref(ZigType *type_entry);
|
||||
bool is_container_ref(ZigType *type_entry);
|
||||
bool is_valid_vector_elem_type(ZigType *elem_type);
|
||||
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
||||
void scan_import(CodeGen *g, ImportTableEntry *import);
|
||||
void preview_use_decl(CodeGen *g, AstNode *node);
|
||||
|
@ -81,7 +87,7 @@ ZigFn *scope_fn_entry(Scope *scope);
|
|||
ImportTableEntry *get_scope_import(Scope *scope);
|
||||
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
|
||||
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
|
||||
bool is_const, ConstExprValue *init_value, Tld *src_tld);
|
||||
bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);
|
||||
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
|
||||
ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
|
||||
ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
|
||||
|
@ -212,6 +218,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
|
|||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
|
||||
bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
|
||||
bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
|
||||
const char *container_string(ContainerKind kind);
|
||||
|
||||
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
|
||||
|
||||
|
@ -222,4 +229,15 @@ enum ReqCompTime {
|
|||
};
|
||||
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
|
||||
|
||||
enum OnePossibleValue {
|
||||
OnePossibleValueInvalid,
|
||||
OnePossibleValueNo,
|
||||
OnePossibleValueYes,
|
||||
};
|
||||
OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry);
|
||||
|
||||
Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
|
||||
ConstExprValue *const_val, ZigType *wanted_type);
|
||||
|
||||
void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
|
||||
#endif
|
||||
|
|
|
@ -132,13 +132,23 @@ static const char *const_or_var_string(bool is_const) {
|
|||
return is_const ? "const" : "var";
|
||||
}
|
||||
|
||||
const char *container_string(ContainerKind kind) {
|
||||
switch (kind) {
|
||||
case ContainerKindEnum: return "enum";
|
||||
case ContainerKindStruct: return "struct";
|
||||
case ContainerKindUnion: return "union";
|
||||
static const char *thread_local_string(Token *tok) {
|
||||
return (tok == nullptr) ? "" : "threadlocal ";
|
||||
}
|
||||
|
||||
static const char *token_to_ptr_len_str(Token *tok) {
|
||||
assert(tok != nullptr);
|
||||
switch (tok->id) {
|
||||
case TokenIdStar:
|
||||
case TokenIdStarStar:
|
||||
return "*";
|
||||
case TokenIdBracketStarBracket:
|
||||
return "[*]";
|
||||
case TokenIdBracketStarCBracket:
|
||||
return "[*c]";
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static const char *node_type_str(NodeType node_type) {
|
||||
|
@ -233,8 +243,8 @@ static const char *node_type_str(NodeType node_type) {
|
|||
return "ErrorType";
|
||||
case NodeTypeIfErrorExpr:
|
||||
return "IfErrorExpr";
|
||||
case NodeTypeTestExpr:
|
||||
return "TestExpr";
|
||||
case NodeTypeIfOptional:
|
||||
return "IfOptional";
|
||||
case NodeTypeErrorSetDecl:
|
||||
return "ErrorSetDecl";
|
||||
case NodeTypeCancel:
|
||||
|
@ -387,7 +397,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
|
|||
if (node->data.if_err_expr.else_node)
|
||||
return statement_terminates_without_semicolon(node->data.if_err_expr.else_node);
|
||||
return node->data.if_err_expr.then_node->type == NodeTypeBlock;
|
||||
case NodeTypeTestExpr:
|
||||
case NodeTypeIfOptional:
|
||||
if (node->data.test_expr.else_node)
|
||||
return statement_terminates_without_semicolon(node->data.test_expr.else_node);
|
||||
return node->data.test_expr.then_node->type == NodeTypeBlock;
|
||||
|
@ -554,8 +564,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||
{
|
||||
const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod);
|
||||
const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
|
||||
const char *thread_local_str = thread_local_string(node->data.variable_declaration.threadlocal_tok);
|
||||
const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
|
||||
fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var);
|
||||
fprintf(ar->f, "%s%s%s%s ", pub_str, extern_str, thread_local_str, const_or_var);
|
||||
print_symbol(ar, node->data.variable_declaration.symbol);
|
||||
|
||||
if (node->data.variable_declaration.type) {
|
||||
|
@ -639,13 +650,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||
case NodeTypePointerType:
|
||||
{
|
||||
if (!grouped) fprintf(ar->f, "(");
|
||||
const char *star = "[*]";
|
||||
if (node->data.pointer_type.star_token != nullptr &&
|
||||
(node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
|
||||
{
|
||||
star = "*";
|
||||
}
|
||||
fprintf(ar->f, "%s", star);
|
||||
const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
|
||||
fprintf(ar->f, "%s", ptr_len_str);
|
||||
if (node->data.pointer_type.align_expr != nullptr) {
|
||||
fprintf(ar->f, "align(");
|
||||
render_node_grouped(ar, node->data.pointer_type.align_expr);
|
||||
|
@ -974,7 +980,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NodeTypeTestExpr:
|
||||
case NodeTypeIfOptional:
|
||||
{
|
||||
fprintf(ar->f, "if (");
|
||||
render_node_grouped(ar, node->data.test_expr.target_node);
|
||||
|
|
|
@ -17,7 +17,4 @@ void ast_print(FILE *f, AstNode *node, int indent);
|
|||
|
||||
void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size);
|
||||
|
||||
const char *container_string(ContainerKind kind);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) {
|
|||
|
||||
bigint_add(x, ©, &one);
|
||||
}
|
||||
|
||||
|
|
|
@ -222,14 +222,9 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents
|
|||
assert(chf->path != nullptr);
|
||||
|
||||
OsFile this_file;
|
||||
if ((err = os_file_open_r(chf->path, &this_file)))
|
||||
if ((err = os_file_open_r(chf->path, &this_file, &chf->mtime)))
|
||||
return err;
|
||||
|
||||
if ((err = os_file_mtime(this_file, &chf->mtime))) {
|
||||
os_file_close(this_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = hash_file(chf->bin_digest, this_file, contents))) {
|
||||
os_file_close(this_file);
|
||||
return err;
|
||||
|
@ -351,17 +346,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
|
|||
|
||||
// if the mtime matches we can trust the digest
|
||||
OsFile this_file;
|
||||
if ((err = os_file_open_r(chf->path, &this_file))) {
|
||||
OsTimeStamp actual_mtime;
|
||||
if ((err = os_file_open_r(chf->path, &this_file, &actual_mtime))) {
|
||||
fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err));
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorCacheUnavailable;
|
||||
}
|
||||
OsTimeStamp actual_mtime;
|
||||
if ((err = os_file_mtime(this_file, &actual_mtime))) {
|
||||
os_file_close(this_file);
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) {
|
||||
os_file_close(this_file);
|
||||
} else {
|
||||
|
|
982
src/codegen.cpp
982
src/codegen.cpp
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
|
||||
Buf *zig_lib_dir);
|
||||
Buf *zig_lib_dir, Buf *override_std_dir);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
|
@ -33,7 +33,6 @@ void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir);
|
|||
void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir);
|
||||
void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
|
||||
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
|
||||
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
|
||||
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
|
||||
void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
|
||||
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
|
||||
|
|
3200
src/ir.cpp
3200
src/ir.cpp
File diff suppressed because it is too large
Load Diff
|
@ -13,15 +13,18 @@
|
|||
bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable);
|
||||
bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
|
||||
|
||||
IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
|
||||
ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
|
||||
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
|
||||
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
|
||||
IrExecutable *parent_exec);
|
||||
IrExecutable *parent_exec, AstNode *expected_type_source_node);
|
||||
|
||||
ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
|
||||
ZigType *expected_type, AstNode *expected_type_source_node);
|
||||
|
||||
bool ir_has_side_effects(IrInstruction *instruction);
|
||||
ConstExprValue *const_ptr_pointee(CodeGen *codegen, ConstExprValue *const_val);
|
||||
|
||||
struct IrAnalyze;
|
||||
ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val,
|
||||
AstNode *source_node);
|
||||
|
||||
#endif
|
||||
|
|
151
src/ir_print.cpp
151
src/ir_print.cpp
|
@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction
|
|||
}
|
||||
}
|
||||
|
||||
static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) {
|
||||
static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) {
|
||||
const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
|
||||
const char *name = buf_ptr(&decl_var_instruction->var->name);
|
||||
if (decl_var_instruction->var_type) {
|
||||
|
@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
|
|||
}
|
||||
|
||||
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
|
||||
fprintf(irp->f, "*");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ".*");
|
||||
}
|
||||
|
||||
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
|
||||
|
@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
|
||||
fprintf(irp->f, "*");
|
||||
static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, " != null");
|
||||
}
|
||||
|
||||
static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
|
||||
fprintf(irp->f, "&??*");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) {
|
||||
fprintf(irp->f, "&");
|
||||
ir_print_other_instruction(irp, instruction->base_ptr);
|
||||
fprintf(irp->f, ".*.?");
|
||||
if (!instruction->safety_check_on) {
|
||||
fprintf(irp->f, " // no safety");
|
||||
}
|
||||
|
@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
|
||||
static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) {
|
||||
fprintf(irp->f, "@cmpxchg(");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ", ");
|
||||
|
@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
|
||||
fprintf(irp->f, "@cmpxchg(");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->cmp_value);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->new_value);
|
||||
fprintf(irp->f, ", TODO print atomic orders)");
|
||||
}
|
||||
|
||||
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
|
||||
fprintf(irp->f, "@fence(");
|
||||
ir_print_other_instruction(irp, instruction->order_value);
|
||||
|
@ -709,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruction) {
|
||||
fprintf(irp->f, "@Vector(");
|
||||
ir_print_other_instruction(irp, instruction->len);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->elem_type);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
|
||||
fprintf(irp->f, "! ");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
|
@ -820,13 +838,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
|
|||
}
|
||||
|
||||
static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
|
||||
fprintf(irp->f, "@unwrapErrorCode(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, "UnwrapErrorCode(");
|
||||
ir_print_other_instruction(irp, instruction->err_union);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
|
||||
fprintf(irp->f, "@unwrapErrorPayload(");
|
||||
fprintf(irp->f, "ErrorUnionFieldPayload(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
if (!instruction->safety_check_on) {
|
||||
|
@ -879,7 +897,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
|
||||
static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) {
|
||||
fprintf(irp->f, "@ptrCast(");
|
||||
if (instruction->dest_type) {
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
|
@ -889,6 +907,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) {
|
||||
fprintf(irp->f, "@ptrCast(");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
|
||||
fprintf(irp->f, "@bitCast(");
|
||||
if (instruction->dest_type) {
|
||||
|
@ -900,7 +924,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
|
|||
}
|
||||
|
||||
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
|
||||
fprintf(irp->f, "@widenOrShorten(");
|
||||
fprintf(irp->f, "WidenOrShorten(");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
@ -948,6 +972,24 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *instruction) {
|
||||
fprintf(irp->f, "ArrayToVector(");
|
||||
ir_print_other_instruction(irp, instruction->array);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) {
|
||||
fprintf(irp->f, "VectorToArray(");
|
||||
ir_print_other_instruction(irp, instruction->vector);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) {
|
||||
fprintf(irp->f, "AssertZero(");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
|
||||
fprintf(irp->f, "inttoerr ");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
|
@ -1323,6 +1365,44 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) {
|
||||
ZigVar *var = decl_var_instruction->var;
|
||||
const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
|
||||
const char *name = buf_ptr(&decl_var_instruction->var->name);
|
||||
fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name),
|
||||
var->align_bytes);
|
||||
|
||||
ir_print_other_instruction(irp, decl_var_instruction->init_value);
|
||||
if (decl_var_instruction->var->is_comptime != nullptr) {
|
||||
fprintf(irp->f, " // comptime = ");
|
||||
ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
|
||||
fprintf(irp->f, "@bswap(");
|
||||
if (instruction->type != nullptr) {
|
||||
ir_print_other_instruction(irp, instruction->type);
|
||||
} else {
|
||||
fprintf(irp->f, "null");
|
||||
}
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->op);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bit_reverse(IrPrint *irp, IrInstructionBitReverse *instruction) {
|
||||
fprintf(irp->f, "@bitreverse(");
|
||||
if (instruction->type != nullptr) {
|
||||
ir_print_other_instruction(irp, instruction->type);
|
||||
} else {
|
||||
fprintf(irp->f, "null");
|
||||
}
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->op);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
|
@ -1337,8 +1417,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdBinOp:
|
||||
ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
|
||||
break;
|
||||
case IrInstructionIdDeclVar:
|
||||
ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction);
|
||||
case IrInstructionIdDeclVarSrc:
|
||||
ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCast:
|
||||
ir_print_cast(irp, (IrInstructionCast *)instruction);
|
||||
|
@ -1428,10 +1508,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
|
||||
break;
|
||||
case IrInstructionIdTestNonNull:
|
||||
ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
|
||||
ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnwrapOptional:
|
||||
ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
|
||||
case IrInstructionIdOptionalUnwrapPtr:
|
||||
ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCtz:
|
||||
ir_print_ctz(irp, (IrInstructionCtz *)instruction);
|
||||
|
@ -1484,8 +1564,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdEmbedFile:
|
||||
ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCmpxchg:
|
||||
ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
|
||||
case IrInstructionIdCmpxchgSrc:
|
||||
ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCmpxchgGen:
|
||||
ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdFence:
|
||||
ir_print_fence(irp, (IrInstructionFence *)instruction);
|
||||
|
@ -1520,6 +1603,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdIntType:
|
||||
ir_print_int_type(irp, (IrInstructionIntType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdVectorType:
|
||||
ir_print_vector_type(irp, (IrInstructionVectorType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBoolNot:
|
||||
ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
|
||||
break;
|
||||
|
@ -1583,8 +1669,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdTestComptime:
|
||||
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
|
||||
break;
|
||||
case IrInstructionIdPtrCast:
|
||||
ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
|
||||
case IrInstructionIdPtrCastSrc:
|
||||
ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdPtrCastGen:
|
||||
ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitCast:
|
||||
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
|
||||
|
@ -1736,6 +1825,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdSqrt:
|
||||
ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBswap:
|
||||
ir_print_bswap(irp, (IrInstructionBswap *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitReverse:
|
||||
ir_print_bit_reverse(irp, (IrInstructionBitReverse *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAtomicLoad:
|
||||
ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
|
||||
break;
|
||||
|
@ -1745,6 +1840,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdCheckRuntimeScope:
|
||||
ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction);
|
||||
break;
|
||||
case IrInstructionIdDeclVarGen:
|
||||
ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdArrayToVector:
|
||||
ir_print_array_to_vector(irp, (IrInstructionArrayToVector *)instruction);
|
||||
break;
|
||||
case IrInstructionIdVectorToArray:
|
||||
ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAssertZero:
|
||||
ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
|
306
src/link.cpp
306
src/link.cpp
|
@ -42,7 +42,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
|
|||
}
|
||||
|
||||
CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir);
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir);
|
||||
|
||||
child_gen->out_h_path = nullptr;
|
||||
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
|
||||
|
@ -444,73 +444,20 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si
|
|||
return ZigLLDLink(oformat, args, arg_count, link_diag_callback, diag);
|
||||
}
|
||||
|
||||
static void construct_linker_job_coff(LinkJob *lj) {
|
||||
static void add_uefi_link_args(LinkJob *lj) {
|
||||
lj->args.append("/BASE:0");
|
||||
lj->args.append("/ENTRY:EfiMain");
|
||||
lj->args.append("/OPT:REF");
|
||||
lj->args.append("/SAFESEH:NO");
|
||||
lj->args.append("/MERGE:.rdata=.data");
|
||||
lj->args.append("/ALIGN:32");
|
||||
lj->args.append("/NODEFAULTLIB");
|
||||
lj->args.append("/SECTION:.xdata,D");
|
||||
}
|
||||
|
||||
static void add_nt_link_args(LinkJob *lj, bool is_library) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
lj->args.append("/ERRORLIMIT:0");
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
find_libc_lib_path(g);
|
||||
}
|
||||
|
||||
lj->args.append("-NOLOGO");
|
||||
|
||||
if (!g->strip_debug_symbols) {
|
||||
lj->args.append("-DEBUG");
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeExe) {
|
||||
// TODO compile time stack upper bound detection
|
||||
lj->args.append("/STACK:16777216");
|
||||
}
|
||||
|
||||
coff_append_machine_arg(g, &lj->args);
|
||||
|
||||
if (g->windows_subsystem_windows) {
|
||||
lj->args.append("/SUBSYSTEM:windows");
|
||||
} else if (g->windows_subsystem_console) {
|
||||
lj->args.append("/SUBSYSTEM:console");
|
||||
}
|
||||
// The commented out stuff is from when we linked with MinGW
|
||||
// Now that we're linking with LLD it remains to be determined
|
||||
// how to handle --target-environ gnu
|
||||
// These comments are a clue
|
||||
|
||||
bool is_library = g->out_type == OutTypeLib;
|
||||
//bool dll = g->out_type == OutTypeLib;
|
||||
//bool shared = !g->is_static && dll;
|
||||
//if (g->is_static) {
|
||||
// lj->args.append("-Bstatic");
|
||||
//} else {
|
||||
// if (dll) {
|
||||
// lj->args.append("--dll");
|
||||
// } else if (shared) {
|
||||
// lj->args.append("--shared");
|
||||
// }
|
||||
// lj->args.append("-Bdynamic");
|
||||
// if (dll || shared) {
|
||||
// lj->args.append("-e");
|
||||
// if (g->zig_target.arch.arch == ZigLLVM_x86) {
|
||||
// lj->args.append("_DllMainCRTStartup@12");
|
||||
// } else {
|
||||
// lj->args.append("DllMainCRTStartup");
|
||||
// }
|
||||
// lj->args.append("--enable-auto-image-base");
|
||||
// }
|
||||
//}
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
|
||||
if (g->libc_static_lib_dir != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
|
||||
}
|
||||
}
|
||||
|
||||
if (lj->link_in_crt) {
|
||||
const char *lib_str = g->is_static ? "lib" : "";
|
||||
const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : "";
|
||||
|
@ -533,29 +480,180 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
|||
//https://msdn.microsoft.com/en-us/library/bb531344.aspx
|
||||
lj->args.append("legacy_stdio_definitions.lib");
|
||||
|
||||
//if (shared || dll) {
|
||||
// lj->args.append(get_libc_file(g, "dllcrt2.o"));
|
||||
//} else {
|
||||
// if (g->windows_linker_unicode) {
|
||||
// lj->args.append(get_libc_file(g, "crt2u.o"));
|
||||
// } else {
|
||||
// lj->args.append(get_libc_file(g, "crt2.o"));
|
||||
// }
|
||||
//}
|
||||
//lj->args.append(get_libc_static_file(g, "crtbegin.o"));
|
||||
|
||||
// msvcrt depends on kernel32
|
||||
lj->args.append("kernel32.lib");
|
||||
} else {
|
||||
lj->args.append("-NODEFAULTLIB");
|
||||
lj->args.append("/NODEFAULTLIB");
|
||||
if (!is_library) {
|
||||
if (g->have_winmain) {
|
||||
lj->args.append("-ENTRY:WinMain");
|
||||
lj->args.append("/ENTRY:WinMain");
|
||||
} else {
|
||||
lj->args.append("-ENTRY:WinMainCRTStartup");
|
||||
lj->args.append("/ENTRY:WinMainCRTStartup");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These are n actual command lines from LINK.EXE UEFI builds (app & driver) to be used as guidance cleaning
|
||||
// up a bit for building the COFF linker args:
|
||||
// /OUT:"J:\coding\nebulae\k\x64\Release\k.efi" /LTCG:incremental /Driver /PDB:"J:\coding\nebulae\k\x64\Release\k.pdb" "UefiApplicationEntryPoint.lib" "UefiRuntimeLib.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\nebulae\k\x64\Release\k.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_APPLICATION /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D"
|
||||
// /OUT:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.efi" /LTCG:incremental /Driver /PDB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.pdb" "UefiDriverEntryPoint.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D"
|
||||
// This commented out stuff is from when we linked with MinGW
|
||||
// Now that we're linking with LLD it remains to be determined
|
||||
// how to handle --target-environ gnu
|
||||
// These comments are a clue
|
||||
//bool dll = g->out_type == OutTypeLib;
|
||||
//bool shared = !g->is_static && dll;
|
||||
//if (g->is_static) {
|
||||
// lj->args.append("-Bstatic");
|
||||
//} else {
|
||||
// if (dll) {
|
||||
// lj->args.append("--dll");
|
||||
// } else if (shared) {
|
||||
// lj->args.append("--shared");
|
||||
// }
|
||||
// lj->args.append("-Bdynamic");
|
||||
// if (dll || shared) {
|
||||
// lj->args.append("-e");
|
||||
// if (g->zig_target.arch.arch == ZigLLVM_x86) {
|
||||
// lj->args.append("_DllMainCRTStartup@12");
|
||||
// } else {
|
||||
// lj->args.append("DllMainCRTStartup");
|
||||
// }
|
||||
// lj->args.append("--enable-auto-image-base");
|
||||
// }
|
||||
//}
|
||||
//if (shared || dll) {
|
||||
// lj->args.append(get_libc_file(g, "dllcrt2.o"));
|
||||
//} else {
|
||||
// if (g->windows_linker_unicode) {
|
||||
// lj->args.append(get_libc_file(g, "crt2u.o"));
|
||||
// } else {
|
||||
// lj->args.append(get_libc_file(g, "crt2.o"));
|
||||
// }
|
||||
//}
|
||||
//lj->args.append(get_libc_static_file(g, "crtbegin.o"));
|
||||
//if (g->libc_link_lib != nullptr) {
|
||||
//if (g->is_static) {
|
||||
// lj->args.append("--start-group");
|
||||
//}
|
||||
|
||||
//lj->args.append("-lmingw32");
|
||||
|
||||
//lj->args.append("-lgcc");
|
||||
//bool is_android = (g->zig_target.env_type == ZigLLVM_Android);
|
||||
//bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target);
|
||||
//if (!g->is_static && !is_android) {
|
||||
// if (!is_cyg_ming) {
|
||||
// lj->args.append("--as-needed");
|
||||
// }
|
||||
// //lj->args.append("-lgcc_s");
|
||||
// if (!is_cyg_ming) {
|
||||
// lj->args.append("--no-as-needed");
|
||||
// }
|
||||
//}
|
||||
//if (g->is_static && !is_android) {
|
||||
// //lj->args.append("-lgcc_eh");
|
||||
//}
|
||||
//if (is_android && !g->is_static) {
|
||||
// lj->args.append("-ldl");
|
||||
//}
|
||||
|
||||
//lj->args.append("-lmoldname");
|
||||
//lj->args.append("-lmingwex");
|
||||
//lj->args.append("-lmsvcrt");
|
||||
|
||||
|
||||
//if (g->windows_subsystem_windows) {
|
||||
// lj->args.append("-lgdi32");
|
||||
// lj->args.append("-lcomdlg32");
|
||||
//}
|
||||
//lj->args.append("-ladvapi32");
|
||||
//lj->args.append("-lshell32");
|
||||
//lj->args.append("-luser32");
|
||||
//lj->args.append("-lkernel32");
|
||||
|
||||
//if (g->is_static) {
|
||||
// lj->args.append("--end-group");
|
||||
//}
|
||||
|
||||
//if (lj->link_in_crt) {
|
||||
// lj->args.append(get_libc_static_file(g, "crtend.o"));
|
||||
//}
|
||||
//}
|
||||
|
||||
|
||||
static void construct_linker_job_coff(LinkJob *lj) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
lj->args.append("/ERRORLIMIT:0");
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
find_libc_lib_path(g);
|
||||
}
|
||||
|
||||
lj->args.append("/NOLOGO");
|
||||
|
||||
if (!g->strip_debug_symbols) {
|
||||
lj->args.append("/DEBUG");
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeExe) {
|
||||
// TODO compile time stack upper bound detection
|
||||
lj->args.append("/STACK:16777216");
|
||||
}
|
||||
|
||||
coff_append_machine_arg(g, &lj->args);
|
||||
|
||||
bool is_library = g->out_type == OutTypeLib;
|
||||
switch (g->subsystem) {
|
||||
case TargetSubsystemAuto:
|
||||
break;
|
||||
case TargetSubsystemConsole:
|
||||
lj->args.append("/SUBSYSTEM:console");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemEfiApplication:
|
||||
lj->args.append("/SUBSYSTEM:efi_application");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiBootServiceDriver:
|
||||
lj->args.append("/SUBSYSTEM:efi_boot_service_driver");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiRom:
|
||||
lj->args.append("/SUBSYSTEM:efi_rom");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemEfiRuntimeDriver:
|
||||
lj->args.append("/SUBSYSTEM:efi_runtime_driver");
|
||||
add_uefi_link_args(lj);
|
||||
break;
|
||||
case TargetSubsystemNative:
|
||||
lj->args.append("/SUBSYSTEM:native");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemPosix:
|
||||
lj->args.append("/SUBSYSTEM:posix");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
case TargetSubsystemWindows:
|
||||
lj->args.append("/SUBSYSTEM:windows");
|
||||
add_nt_link_args(lj, is_library);
|
||||
break;
|
||||
}
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
|
||||
if (g->libc_static_lib_dir != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_library && !g->is_static) {
|
||||
lj->args.append("-DLL");
|
||||
|
@ -627,54 +725,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
|||
}
|
||||
}
|
||||
|
||||
//if (g->libc_link_lib != nullptr) {
|
||||
//if (g->is_static) {
|
||||
// lj->args.append("--start-group");
|
||||
//}
|
||||
|
||||
//lj->args.append("-lmingw32");
|
||||
|
||||
//lj->args.append("-lgcc");
|
||||
//bool is_android = (g->zig_target.env_type == ZigLLVM_Android);
|
||||
//bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target);
|
||||
//if (!g->is_static && !is_android) {
|
||||
// if (!is_cyg_ming) {
|
||||
// lj->args.append("--as-needed");
|
||||
// }
|
||||
// //lj->args.append("-lgcc_s");
|
||||
// if (!is_cyg_ming) {
|
||||
// lj->args.append("--no-as-needed");
|
||||
// }
|
||||
//}
|
||||
//if (g->is_static && !is_android) {
|
||||
// //lj->args.append("-lgcc_eh");
|
||||
//}
|
||||
//if (is_android && !g->is_static) {
|
||||
// lj->args.append("-ldl");
|
||||
//}
|
||||
|
||||
//lj->args.append("-lmoldname");
|
||||
//lj->args.append("-lmingwex");
|
||||
//lj->args.append("-lmsvcrt");
|
||||
|
||||
|
||||
//if (g->windows_subsystem_windows) {
|
||||
// lj->args.append("-lgdi32");
|
||||
// lj->args.append("-lcomdlg32");
|
||||
//}
|
||||
//lj->args.append("-ladvapi32");
|
||||
//lj->args.append("-lshell32");
|
||||
//lj->args.append("-luser32");
|
||||
//lj->args.append("-lkernel32");
|
||||
|
||||
//if (g->is_static) {
|
||||
// lj->args.append("--end-group");
|
||||
//}
|
||||
|
||||
//if (lj->link_in_crt) {
|
||||
// lj->args.append(get_libc_static_file(g, "crtend.o"));
|
||||
//}
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
|
98
src/main.cpp
98
src/main.cpp
|
@ -21,8 +21,8 @@ static int print_error_usage(const char *arg0) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int print_full_usage(const char *arg0) {
|
||||
fprintf(stdout,
|
||||
static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
||||
fprintf(file,
|
||||
"Usage: %s [command] [options]\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
|
@ -31,6 +31,7 @@ static int print_full_usage(const char *arg0) {
|
|||
" build-lib [source] create library from source or object files\n"
|
||||
" build-obj [source] create object from source or assembly\n"
|
||||
" builtin show the source code of that @import(\"builtin\")\n"
|
||||
" fmt parse files and render in canonical zig format\n"
|
||||
" help show this usage information\n"
|
||||
" id print the base64-encoded compiler id\n"
|
||||
" init-exe initialize a `zig build` application in the cwd\n"
|
||||
|
@ -59,6 +60,7 @@ static int print_full_usage(const char *arg0) {
|
|||
" --release-fast build with optimizations on and safety off\n"
|
||||
" --release-safe build with optimizations on and safety on\n"
|
||||
" --release-small build with size optimizations on and safety off\n"
|
||||
" --single-threaded source may assume it is only used single-threaded\n"
|
||||
" --static output will be statically linked\n"
|
||||
" --strip exclude debug symbols\n"
|
||||
" --target-arch [name] specify target architecture\n"
|
||||
|
@ -73,6 +75,7 @@ static int print_full_usage(const char *arg0) {
|
|||
" -dirafter [dir] same as -isystem but do it last\n"
|
||||
" -isystem [dir] add additional search path for other .h files\n"
|
||||
" -mllvm [arg] forward an arg to LLVM's option processing\n"
|
||||
" --override-std-dir [arg] use an alternate Zig standard library\n"
|
||||
"\n"
|
||||
"Link Options:\n"
|
||||
" --dynamic-linker [path] set the path to ld.so\n"
|
||||
|
@ -90,8 +93,7 @@ static int print_full_usage(const char *arg0) {
|
|||
" -rdynamic add all symbols to the dynamic symbol table\n"
|
||||
" -rpath [path] add directory to the runtime library search path\n"
|
||||
" --no-rosegment compromise security to workaround valgrind bug\n"
|
||||
" -mconsole (windows) --subsystem console to the linker\n"
|
||||
" -mwindows (windows) --subsystem windows to the linker\n"
|
||||
" --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
|
||||
" -framework [name] (darwin) link against framework\n"
|
||||
" -mios-version-min [ver] (darwin) set iOS deployment target\n"
|
||||
" -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n"
|
||||
|
@ -105,7 +107,7 @@ static int print_full_usage(const char *arg0) {
|
|||
" --test-cmd [arg] specify test execution command one arg at a time\n"
|
||||
" --test-cmd-bin appends test binary path to test cmd args\n"
|
||||
, arg0);
|
||||
return EXIT_SUCCESS;
|
||||
return return_code;
|
||||
}
|
||||
|
||||
static const char *ZIG_ZEN = "\n"
|
||||
|
@ -371,8 +373,6 @@ int main(int argc, char **argv) {
|
|||
const char *target_arch = nullptr;
|
||||
const char *target_os = nullptr;
|
||||
const char *target_environ = nullptr;
|
||||
bool mwindows = false;
|
||||
bool mconsole = false;
|
||||
bool rdynamic = false;
|
||||
const char *mmacosx_version_min = nullptr;
|
||||
const char *mios_version_min = nullptr;
|
||||
|
@ -395,6 +395,9 @@ int main(int argc, char **argv) {
|
|||
int runtime_args_start = -1;
|
||||
bool no_rosegment_workaround = false;
|
||||
bool system_linker_hack = false;
|
||||
TargetSubsystem subsystem = TargetSubsystemAuto;
|
||||
bool is_single_threaded = false;
|
||||
Buf *override_std_dir = nullptr;
|
||||
|
||||
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
|
||||
Buf zig_exe_path_buf = BUF_INIT;
|
||||
|
@ -430,7 +433,8 @@ int main(int argc, char **argv) {
|
|||
Buf *build_runner_path = buf_alloc();
|
||||
os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path);
|
||||
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir());
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
|
||||
override_std_dir);
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_create_from_str("build"));
|
||||
|
@ -512,6 +516,31 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "\n");
|
||||
}
|
||||
return (term.how == TerminationIdClean) ? term.code : -1;
|
||||
} else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
|
||||
init_all_targets();
|
||||
Buf *fmt_runner_path = buf_alloc();
|
||||
os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
|
||||
CodeGen *g = codegen_create(fmt_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
|
||||
nullptr);
|
||||
g->is_single_threaded = true;
|
||||
codegen_set_out_name(g, buf_create_from_str("fmt"));
|
||||
g->enable_cache = true;
|
||||
|
||||
codegen_build_and_link(g);
|
||||
|
||||
ZigList<const char*> args = {0};
|
||||
for (int i = 2; i < argc; i += 1) {
|
||||
args.append(argv[i]);
|
||||
}
|
||||
args.append(nullptr);
|
||||
const char *exec_path = buf_ptr(&g->output_file_path);
|
||||
|
||||
os_execv(exec_path, args.items);
|
||||
|
||||
args.pop();
|
||||
Termination term;
|
||||
os_spawn_process(exec_path, args, &term);
|
||||
return term.code;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
|
@ -524,6 +553,8 @@ int main(int argc, char **argv) {
|
|||
build_mode = BuildModeSafeRelease;
|
||||
} else if (strcmp(arg, "--release-small") == 0) {
|
||||
build_mode = BuildModeSmallRelease;
|
||||
} else if (strcmp(arg, "--help") == 0) {
|
||||
return print_full_usage(arg0, stderr, EXIT_FAILURE);
|
||||
} else if (strcmp(arg, "--strip") == 0) {
|
||||
strip = true;
|
||||
} else if (strcmp(arg, "--static") == 0) {
|
||||
|
@ -540,10 +571,6 @@ int main(int argc, char **argv) {
|
|||
verbose_llvm_ir = true;
|
||||
} else if (strcmp(arg, "--verbose-cimport") == 0) {
|
||||
verbose_cimport = true;
|
||||
} else if (strcmp(arg, "-mwindows") == 0) {
|
||||
mwindows = true;
|
||||
} else if (strcmp(arg, "-mconsole") == 0) {
|
||||
mconsole = true;
|
||||
} else if (strcmp(arg, "-rdynamic") == 0) {
|
||||
rdynamic = true;
|
||||
} else if (strcmp(arg, "--no-rosegment") == 0) {
|
||||
|
@ -556,6 +583,8 @@ int main(int argc, char **argv) {
|
|||
disable_pic = true;
|
||||
} else if (strcmp(arg, "--system-linker-hack") == 0) {
|
||||
system_linker_hack = true;
|
||||
} else if (strcmp(arg, "--single-threaded") == 0) {
|
||||
is_single_threaded = true;
|
||||
} else if (strcmp(arg, "--test-cmd-bin") == 0) {
|
||||
test_exec_args.append(nullptr);
|
||||
} else if (arg[1] == 'L' && arg[2] != 0) {
|
||||
|
@ -647,6 +676,8 @@ int main(int argc, char **argv) {
|
|||
clang_argv.append(argv[i]);
|
||||
|
||||
llvm_argv.append(argv[i]);
|
||||
} else if (strcmp(arg, "--override-std-dir") == 0) {
|
||||
override_std_dir = buf_create_from_str(argv[i]);
|
||||
} else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
|
||||
lib_dirs.append(argv[i]);
|
||||
} else if (strcmp(arg, "--library") == 0) {
|
||||
|
@ -687,6 +718,37 @@ int main(int argc, char **argv) {
|
|||
ver_patch = atoi(argv[i]);
|
||||
} else if (strcmp(arg, "--test-cmd") == 0) {
|
||||
test_exec_args.append(argv[i]);
|
||||
} else if (strcmp(arg, "--subsystem") == 0) {
|
||||
if (strcmp(argv[i], "console") == 0) {
|
||||
subsystem = TargetSubsystemConsole;
|
||||
} else if (strcmp(argv[i], "windows") == 0) {
|
||||
subsystem = TargetSubsystemWindows;
|
||||
} else if (strcmp(argv[i], "posix") == 0) {
|
||||
subsystem = TargetSubsystemPosix;
|
||||
} else if (strcmp(argv[i], "native") == 0) {
|
||||
subsystem = TargetSubsystemNative;
|
||||
} else if (strcmp(argv[i], "efi_application") == 0) {
|
||||
subsystem = TargetSubsystemEfiApplication;
|
||||
} else if (strcmp(argv[i], "efi_boot_service_driver") == 0) {
|
||||
subsystem = TargetSubsystemEfiBootServiceDriver;
|
||||
} else if (strcmp(argv[i], "efi_rom") == 0) {
|
||||
subsystem = TargetSubsystemEfiRom;
|
||||
} else if (strcmp(argv[i], "efi_runtime_driver") == 0) {
|
||||
subsystem = TargetSubsystemEfiRuntimeDriver;
|
||||
} else {
|
||||
fprintf(stderr, "invalid: --subsystem %s\n"
|
||||
"Options are:\n"
|
||||
" console\n"
|
||||
" windows\n"
|
||||
" posix\n"
|
||||
" native\n"
|
||||
" efi_application\n"
|
||||
" efi_boot_service_driver\n"
|
||||
" efi_rom\n"
|
||||
" efi_runtime_driver\n"
|
||||
, argv[i]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Invalid argument: %s\n", arg);
|
||||
return print_error_usage(arg0);
|
||||
|
@ -790,7 +852,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
switch (cmd) {
|
||||
case CmdBuiltin: {
|
||||
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir());
|
||||
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir);
|
||||
g->is_single_threaded = is_single_threaded;
|
||||
Buf *builtin_source = codegen_generate_builtin_source(g);
|
||||
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
|
||||
fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
|
||||
|
@ -848,7 +911,10 @@ int main(int argc, char **argv) {
|
|||
if (cmd == CmdRun && buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir());
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(),
|
||||
override_std_dir);
|
||||
g->subsystem = subsystem;
|
||||
|
||||
if (disable_pic) {
|
||||
if (out_type != OutTypeLib || !is_static) {
|
||||
fprintf(stderr, "--disable-pic only applies to static libraries");
|
||||
|
@ -862,6 +928,7 @@ int main(int argc, char **argv) {
|
|||
codegen_set_out_name(g, buf_out_name);
|
||||
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
|
||||
codegen_set_is_test(g, cmd == CmdTest);
|
||||
g->is_single_threaded = is_single_threaded;
|
||||
codegen_set_linker_script(g, linker_script);
|
||||
if (each_lib_rpath)
|
||||
codegen_set_each_lib_rpath(g, each_lib_rpath);
|
||||
|
@ -909,7 +976,6 @@ int main(int argc, char **argv) {
|
|||
codegen_add_rpath(g, rpath_list.at(i));
|
||||
}
|
||||
|
||||
codegen_set_windows_subsystem(g, mwindows, mconsole);
|
||||
codegen_set_rdynamic(g, rdynamic);
|
||||
g->no_rosegment_workaround = no_rosegment_workaround;
|
||||
if (mmacosx_version_min && mios_version_min) {
|
||||
|
@ -1042,7 +1108,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
case CmdHelp:
|
||||
return print_full_usage(arg0);
|
||||
return print_full_usage(arg0, stdout, EXIT_SUCCESS);
|
||||
case CmdVersion:
|
||||
printf("%s\n", ZIG_VERSION_STRING);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
64
src/os.cpp
64
src/os.cpp
|
@ -1456,7 +1456,7 @@ Error os_self_exe_path(Buf *out_path) {
|
|||
if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
buf_resize(out_path, cb);
|
||||
buf_resize(out_path, cb - 1);
|
||||
return ErrorNone;
|
||||
#endif
|
||||
return ErrorFileNotFound;
|
||||
|
@ -1808,7 +1808,7 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
|
|||
#endif
|
||||
}
|
||||
|
||||
Error os_file_open_r(Buf *full_path, OsFile *out_file) {
|
||||
Error os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
// TODO use CreateFileW
|
||||
HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
@ -1834,8 +1834,18 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) {
|
|||
return ErrorUnexpected;
|
||||
}
|
||||
}
|
||||
|
||||
*out_file = result;
|
||||
|
||||
if (mtime != nullptr) {
|
||||
FILETIME last_write_time;
|
||||
if (!GetFileTime(result, nullptr, nullptr, &last_write_time)) {
|
||||
CloseHandle(result);
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime;
|
||||
mtime->nsec = 0;
|
||||
}
|
||||
|
||||
return ErrorNone;
|
||||
#else
|
||||
for (;;) {
|
||||
|
@ -1858,7 +1868,26 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) {
|
|||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
struct stat statbuf;
|
||||
if (fstat(fd, &statbuf) == -1) {
|
||||
close(fd);
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
close(fd);
|
||||
return ErrorIsDir;
|
||||
}
|
||||
*out_file = fd;
|
||||
|
||||
if (mtime != nullptr) {
|
||||
#if defined(ZIG_OS_DARWIN)
|
||||
mtime->sec = statbuf.st_mtimespec.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtimespec.tv_nsec;
|
||||
#else
|
||||
mtime->sec = statbuf.st_mtim.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtim.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
|
@ -1948,35 +1977,6 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
|
|||
#endif
|
||||
}
|
||||
|
||||
Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
FILETIME last_write_time;
|
||||
if (!GetFileTime(file, nullptr, nullptr, &last_write_time))
|
||||
return ErrorUnexpected;
|
||||
mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime;
|
||||
mtime->nsec = 0;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
|
||||
struct stat statbuf;
|
||||
if (fstat(file, &statbuf) == -1)
|
||||
return ErrorFileSystem;
|
||||
|
||||
mtime->sec = statbuf.st_mtim.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtim.tv_nsec;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
struct stat statbuf;
|
||||
if (fstat(file, &statbuf) == -1)
|
||||
return ErrorFileSystem;
|
||||
|
||||
mtime->sec = statbuf.st_mtimespec.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtimespec.tv_nsec;
|
||||
return ErrorNone;
|
||||
#else
|
||||
#error unimplemented
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_read(OsFile file, void *ptr, size_t *len) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
DWORD amt_read;
|
||||
|
|
|
@ -101,9 +101,8 @@ bool os_path_is_absolute(Buf *path);
|
|||
Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
|
||||
Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file);
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime);
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
|
||||
Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime);
|
||||
Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
|
||||
Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
|
||||
Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents);
|
||||
|
|
|
@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse
|
|||
else_body = ast_expect(pc, body_parser);
|
||||
}
|
||||
|
||||
assert(res->type == NodeTypeTestExpr);
|
||||
assert(res->type == NodeTypeIfOptional);
|
||||
if (err_payload != nullptr) {
|
||||
AstNodeTestExpr old = res->data.test_expr;
|
||||
res->type = NodeTypeIfErrorExpr;
|
||||
|
@ -844,12 +844,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
|
|||
|
||||
// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
||||
static AstNode *ast_parse_var_decl(ParseContext *pc) {
|
||||
Token *first = eat_token_if(pc, TokenIdKeywordConst);
|
||||
if (first == nullptr)
|
||||
first = eat_token_if(pc, TokenIdKeywordVar);
|
||||
if (first == nullptr)
|
||||
return nullptr;
|
||||
|
||||
Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);
|
||||
Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst);
|
||||
if (mut_kw == nullptr)
|
||||
mut_kw = eat_token_if(pc, TokenIdKeywordVar);
|
||||
if (mut_kw == nullptr) {
|
||||
if (thread_local_kw == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
ast_invalid_token_error(pc, peek_token(pc));
|
||||
}
|
||||
}
|
||||
Token *identifier = expect_token(pc, TokenIdSymbol);
|
||||
AstNode *type_expr = nullptr;
|
||||
if (eat_token_if(pc, TokenIdColon) != nullptr)
|
||||
|
@ -863,8 +868,9 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) {
|
|||
|
||||
expect_token(pc, TokenIdSemicolon);
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, first);
|
||||
res->data.variable_declaration.is_const = first->id == TokenIdKeywordConst;
|
||||
AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw);
|
||||
res->data.variable_declaration.threadlocal_tok = thread_local_kw;
|
||||
res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst;
|
||||
res->data.variable_declaration.symbol = token_buf(identifier);
|
||||
res->data.variable_declaration.type = type_expr;
|
||||
res->data.variable_declaration.align_expr = align_expr;
|
||||
|
@ -990,7 +996,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {
|
|||
if (requires_semi && else_body == nullptr)
|
||||
expect_token(pc, TokenIdSemicolon);
|
||||
|
||||
assert(res->type == NodeTypeTestExpr);
|
||||
assert(res->type == NodeTypeIfOptional);
|
||||
if (err_payload != nullptr) {
|
||||
AstNodeTestExpr old = res->data.test_expr;
|
||||
res->type = NodeTypeIfErrorExpr;
|
||||
|
@ -2204,7 +2210,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) {
|
|||
Optional<PtrPayload> opt_payload = ast_parse_ptr_payload(pc);
|
||||
|
||||
PtrPayload payload;
|
||||
AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first);
|
||||
res->data.test_expr.target_node = condition;
|
||||
if (opt_payload.unwrap(&payload)) {
|
||||
res->data.test_expr.var_symbol = token_buf(payload.payload);
|
||||
|
@ -2772,7 +2778,8 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
|
|||
// PtrTypeStart
|
||||
// <- ASTERISK
|
||||
// / ASTERISK2
|
||||
// / LBRACKET ASTERISK RBRACKET
|
||||
// / PTRUNKNOWN
|
||||
// / PTRC
|
||||
static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
|
||||
Token *asterisk = eat_token_if(pc, TokenIdStar);
|
||||
if (asterisk != nullptr) {
|
||||
|
@ -2798,6 +2805,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
|
|||
return res;
|
||||
}
|
||||
|
||||
Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket);
|
||||
if (cptr != nullptr) {
|
||||
AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr);
|
||||
res->data.pointer_type.star_token = cptr;
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2999,7 +3013,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
|||
visit_field(&node->data.if_err_expr.then_node, visit, context);
|
||||
visit_field(&node->data.if_err_expr.else_node, visit, context);
|
||||
break;
|
||||
case NodeTypeTestExpr:
|
||||
case NodeTypeIfOptional:
|
||||
visit_field(&node->data.test_expr.target_node, visit, context);
|
||||
visit_field(&node->data.test_expr.then_node, visit, context);
|
||||
visit_field(&node->data.test_expr.else_node, visit, context);
|
||||
|
|
|
@ -174,6 +174,7 @@ static const Os os_list[] = {
|
|||
OsContiki,
|
||||
OsAMDPAL,
|
||||
OsZen,
|
||||
OsUefi,
|
||||
};
|
||||
|
||||
// Coordinate with zig_llvm.h
|
||||
|
@ -282,6 +283,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) {
|
|||
case OsSolaris:
|
||||
return ZigLLVM_Solaris;
|
||||
case OsWindows:
|
||||
case OsUefi:
|
||||
return ZigLLVM_Win32;
|
||||
case OsHaiku:
|
||||
return ZigLLVM_Haiku;
|
||||
|
@ -394,6 +396,8 @@ const char *get_target_os_name(Os os_type) {
|
|||
return "freestanding";
|
||||
case OsZen:
|
||||
return "zen";
|
||||
case OsUefi:
|
||||
return "uefi";
|
||||
case OsAnanas:
|
||||
case OsCloudABI:
|
||||
case OsDragonFly:
|
||||
|
@ -756,6 +760,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
|||
case CIntTypeCount:
|
||||
zig_unreachable();
|
||||
}
|
||||
case OsUefi:
|
||||
case OsWindows:
|
||||
switch (id) {
|
||||
case CIntTypeShort:
|
||||
|
@ -802,8 +807,12 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool target_allows_addr_zero(const ZigTarget *target) {
|
||||
return target->os == OsFreestanding;
|
||||
}
|
||||
|
||||
const char *target_o_file_ext(ZigTarget *target) {
|
||||
if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows) {
|
||||
if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) {
|
||||
return ".obj";
|
||||
} else {
|
||||
return ".o";
|
||||
|
@ -821,13 +830,15 @@ const char *target_llvm_ir_file_ext(ZigTarget *target) {
|
|||
const char *target_exe_file_ext(ZigTarget *target) {
|
||||
if (target->os == OsWindows) {
|
||||
return ".exe";
|
||||
} else if (target->os == OsUefi) {
|
||||
return ".efi";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) {
|
||||
if (target->os == OsWindows) {
|
||||
if (target->os == OsWindows || target->os == OsUefi) {
|
||||
if (is_static) {
|
||||
return ".lib";
|
||||
} else {
|
||||
|
|
|
@ -51,6 +51,19 @@ enum Os {
|
|||
OsContiki,
|
||||
OsAMDPAL,
|
||||
OsZen,
|
||||
OsUefi,
|
||||
};
|
||||
|
||||
enum TargetSubsystem {
|
||||
TargetSubsystemAuto, // Zig should infer the subsystem
|
||||
TargetSubsystemConsole,
|
||||
TargetSubsystemWindows,
|
||||
TargetSubsystemPosix,
|
||||
TargetSubsystemNative,
|
||||
TargetSubsystemEfiApplication,
|
||||
TargetSubsystemEfiBootServiceDriver,
|
||||
TargetSubsystemEfiRom,
|
||||
TargetSubsystemEfiRuntimeDriver,
|
||||
};
|
||||
|
||||
struct ZigTarget {
|
||||
|
@ -122,5 +135,6 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
|
|||
ZigLLVM_OSType get_llvm_os_type(Os os_type);
|
||||
|
||||
bool target_is_arm(const ZigTarget *target);
|
||||
bool target_allows_addr_zero(const ZigTarget *target);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -146,6 +146,7 @@ static const struct ZigKeyword zig_keywords[] = {
|
|||
{"suspend", TokenIdKeywordSuspend},
|
||||
{"switch", TokenIdKeywordSwitch},
|
||||
{"test", TokenIdKeywordTest},
|
||||
{"threadlocal", TokenIdKeywordThreadLocal},
|
||||
{"true", TokenIdKeywordTrue},
|
||||
{"try", TokenIdKeywordTry},
|
||||
{"undefined", TokenIdKeywordUndefined},
|
||||
|
@ -220,6 +221,7 @@ enum TokenizeState {
|
|||
TokenizeStateError,
|
||||
TokenizeStateLBracket,
|
||||
TokenizeStateLBracketStar,
|
||||
TokenizeStateLBracketStarC,
|
||||
};
|
||||
|
||||
|
||||
|
@ -248,13 +250,8 @@ ATTRIBUTE_PRINTF(2, 3)
|
|||
static void tokenize_error(Tokenize *t, const char *format, ...) {
|
||||
t->state = TokenizeStateError;
|
||||
|
||||
if (t->cur_tok) {
|
||||
t->out->err_line = t->cur_tok->start_line;
|
||||
t->out->err_column = t->cur_tok->start_column;
|
||||
} else {
|
||||
t->out->err_line = t->line;
|
||||
t->out->err_column = t->column;
|
||||
}
|
||||
t->out->err_line = t->line;
|
||||
t->out->err_column = t->column;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
@ -850,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||
switch (c) {
|
||||
case '*':
|
||||
t.state = TokenizeStateLBracketStar;
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
|
||||
break;
|
||||
default:
|
||||
// reinterpret as just an lbracket
|
||||
|
@ -861,6 +857,21 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||
}
|
||||
break;
|
||||
case TokenizeStateLBracketStar:
|
||||
switch (c) {
|
||||
case 'c':
|
||||
t.state = TokenizeStateLBracketStarC;
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket);
|
||||
break;
|
||||
case ']':
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
invalid_char_error(&t, c);
|
||||
}
|
||||
break;
|
||||
case TokenizeStateLBracketStarC:
|
||||
switch (c) {
|
||||
case ']':
|
||||
end_token(&t);
|
||||
|
@ -886,6 +897,9 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||
break;
|
||||
case TokenizeStateSawAmpersand:
|
||||
switch (c) {
|
||||
case '&':
|
||||
tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND.");
|
||||
break;
|
||||
case '=':
|
||||
set_token_id(&t, t.cur_tok, TokenIdBitAndEq);
|
||||
end_token(&t);
|
||||
|
@ -1492,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||
case TokenizeStateLineStringContinue:
|
||||
case TokenizeStateLineStringContinueC:
|
||||
case TokenizeStateLBracketStar:
|
||||
case TokenizeStateLBracketStarC:
|
||||
tokenize_error(&t, "unexpected EOF");
|
||||
break;
|
||||
case TokenizeStateLineComment:
|
||||
|
@ -1529,6 +1544,7 @@ const char * token_name(TokenId id) {
|
|||
case TokenIdBitShiftRightEq: return ">>=";
|
||||
case TokenIdBitXorEq: return "^=";
|
||||
case TokenIdBracketStarBracket: return "[*]";
|
||||
case TokenIdBracketStarCBracket: return "[*c]";
|
||||
case TokenIdCharLiteral: return "CharLiteral";
|
||||
case TokenIdCmpEq: return "==";
|
||||
case TokenIdCmpGreaterOrEq: return ">=";
|
||||
|
@ -1588,6 +1604,7 @@ const char * token_name(TokenId id) {
|
|||
case TokenIdKeywordStruct: return "struct";
|
||||
case TokenIdKeywordSwitch: return "switch";
|
||||
case TokenIdKeywordTest: return "test";
|
||||
case TokenIdKeywordThreadLocal: return "threadlocal";
|
||||
case TokenIdKeywordTrue: return "true";
|
||||
case TokenIdKeywordTry: return "try";
|
||||
case TokenIdKeywordUndefined: return "undefined";
|
||||
|
|
|
@ -29,6 +29,7 @@ enum TokenId {
|
|||
TokenIdBitShiftRightEq,
|
||||
TokenIdBitXorEq,
|
||||
TokenIdBracketStarBracket,
|
||||
TokenIdBracketStarCBracket,
|
||||
TokenIdCharLiteral,
|
||||
TokenIdCmpEq,
|
||||
TokenIdCmpGreaterOrEq,
|
||||
|
@ -88,6 +89,7 @@ enum TokenId {
|
|||
TokenIdKeywordSuspend,
|
||||
TokenIdKeywordSwitch,
|
||||
TokenIdKeywordTest,
|
||||
TokenIdKeywordThreadLocal,
|
||||
TokenIdKeywordTrue,
|
||||
TokenIdKeywordTry,
|
||||
TokenIdKeywordUndefined,
|
||||
|
|
2395
src/translate_c.cpp
2395
src/translate_c.cpp
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The point of this file is to contain all the Clang C++ API interaction so that:
|
||||
* 1. The compile time of other files is kept under control.
|
||||
* 2. Provide a C interface to the Clang functions we need for self-hosting purposes.
|
||||
* 3. Prevent C++ from infecting the rest of the project.
|
||||
*/
|
||||
#include "zig_clang.h"
|
||||
|
||||
#if __GNUC__ >= 8
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
|
||||
#include <clang/Frontend/ASTUnit.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/AST/Expr.h>
|
||||
|
||||
#if __GNUC__ >= 8
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// Detect additions to the enum
|
||||
void zig2clang_BO(ZigClangBO op) {
|
||||
switch (op) {
|
||||
case ZigClangBO_PtrMemD:
|
||||
case ZigClangBO_PtrMemI:
|
||||
case ZigClangBO_Cmp:
|
||||
case ZigClangBO_Mul:
|
||||
case ZigClangBO_Div:
|
||||
case ZigClangBO_Rem:
|
||||
case ZigClangBO_Add:
|
||||
case ZigClangBO_Sub:
|
||||
case ZigClangBO_Shl:
|
||||
case ZigClangBO_Shr:
|
||||
case ZigClangBO_LT:
|
||||
case ZigClangBO_GT:
|
||||
case ZigClangBO_LE:
|
||||
case ZigClangBO_GE:
|
||||
case ZigClangBO_EQ:
|
||||
case ZigClangBO_NE:
|
||||
case ZigClangBO_And:
|
||||
case ZigClangBO_Xor:
|
||||
case ZigClangBO_Or:
|
||||
case ZigClangBO_LAnd:
|
||||
case ZigClangBO_LOr:
|
||||
case ZigClangBO_Assign:
|
||||
case ZigClangBO_Comma:
|
||||
case ZigClangBO_MulAssign:
|
||||
case ZigClangBO_DivAssign:
|
||||
case ZigClangBO_RemAssign:
|
||||
case ZigClangBO_AddAssign:
|
||||
case ZigClangBO_SubAssign:
|
||||
case ZigClangBO_ShlAssign:
|
||||
case ZigClangBO_ShrAssign:
|
||||
case ZigClangBO_AndAssign:
|
||||
case ZigClangBO_XorAssign:
|
||||
case ZigClangBO_OrAssign:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Add == clang::BO_Add, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_AddAssign == clang::BO_AddAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_And == clang::BO_And, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_AndAssign == clang::BO_AndAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Assign == clang::BO_Assign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Cmp == clang::BO_Cmp, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Comma == clang::BO_Comma, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Div == clang::BO_Div, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_DivAssign == clang::BO_DivAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_EQ == clang::BO_EQ, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_GE == clang::BO_GE, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_GT == clang::BO_GT, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LAnd == clang::BO_LAnd, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LE == clang::BO_LE, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LOr == clang::BO_LOr, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_LT == clang::BO_LT, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Mul == clang::BO_Mul, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_MulAssign == clang::BO_MulAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_NE == clang::BO_NE, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Or == clang::BO_Or, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_OrAssign == clang::BO_OrAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemD == clang::BO_PtrMemD, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemI == clang::BO_PtrMemI, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Rem == clang::BO_Rem, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_RemAssign == clang::BO_RemAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Shl == clang::BO_Shl, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_ShlAssign == clang::BO_ShlAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Shr == clang::BO_Shr, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_ShrAssign == clang::BO_ShrAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Sub == clang::BO_Sub, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_SubAssign == clang::BO_SubAssign, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_Xor == clang::BO_Xor, "");
|
||||
static_assert((clang::BinaryOperatorKind)ZigClangBO_XorAssign == clang::BO_XorAssign, "");
|
||||
|
||||
// This function detects additions to the enum
|
||||
void zig2clang_UO(ZigClangUO op) {
|
||||
switch (op) {
|
||||
case ZigClangUO_AddrOf:
|
||||
case ZigClangUO_Coawait:
|
||||
case ZigClangUO_Deref:
|
||||
case ZigClangUO_Extension:
|
||||
case ZigClangUO_Imag:
|
||||
case ZigClangUO_LNot:
|
||||
case ZigClangUO_Minus:
|
||||
case ZigClangUO_Not:
|
||||
case ZigClangUO_Plus:
|
||||
case ZigClangUO_PostDec:
|
||||
case ZigClangUO_PostInc:
|
||||
case ZigClangUO_PreDec:
|
||||
case ZigClangUO_PreInc:
|
||||
case ZigClangUO_Real:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_AddrOf == clang::UO_AddrOf, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Coawait == clang::UO_Coawait, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Deref == clang::UO_Deref, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Extension == clang::UO_Extension, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Imag == clang::UO_Imag, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_LNot == clang::UO_LNot, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Minus == clang::UO_Minus, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Not == clang::UO_Not, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Plus == clang::UO_Plus, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PostDec == clang::UO_PostDec, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PostInc == clang::UO_PostInc, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PreDec == clang::UO_PreDec, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, "");
|
||||
static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, "");
|
||||
|
||||
static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), "");
|
||||
static ZigClangSourceLocation bitcast(clang::SourceLocation src) {
|
||||
ZigClangSourceLocation dest;
|
||||
memcpy(&dest, &src, sizeof(ZigClangSourceLocation));
|
||||
return dest;
|
||||
}
|
||||
static clang::SourceLocation bitcast(ZigClangSourceLocation src) {
|
||||
clang::SourceLocation dest;
|
||||
memcpy(&dest, &src, sizeof(ZigClangSourceLocation));
|
||||
return dest;
|
||||
}
|
||||
|
||||
static_assert(sizeof(ZigClangQualType) == sizeof(clang::QualType), "");
|
||||
static ZigClangQualType bitcast(clang::QualType src) {
|
||||
ZigClangQualType dest;
|
||||
memcpy(&dest, &src, sizeof(ZigClangQualType));
|
||||
return dest;
|
||||
}
|
||||
static clang::QualType bitcast(ZigClangQualType src) {
|
||||
clang::QualType dest;
|
||||
memcpy(&dest, &src, sizeof(ZigClangQualType));
|
||||
return dest;
|
||||
}
|
||||
|
||||
ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation Loc)
|
||||
{
|
||||
return bitcast(reinterpret_cast<const clang::SourceManager *>(self)->getSpellingLoc(bitcast(Loc)));
|
||||
}
|
||||
|
||||
const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation SpellingLoc)
|
||||
{
|
||||
StringRef s = reinterpret_cast<const clang::SourceManager *>(self)->getFilename(bitcast(SpellingLoc));
|
||||
return (const char *)s.bytes_begin();
|
||||
}
|
||||
|
||||
unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation Loc)
|
||||
{
|
||||
return reinterpret_cast<const clang::SourceManager *>(self)->getSpellingLineNumber(bitcast(Loc));
|
||||
}
|
||||
|
||||
unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation Loc)
|
||||
{
|
||||
return reinterpret_cast<const clang::SourceManager *>(self)->getSpellingColumnNumber(bitcast(Loc));
|
||||
}
|
||||
|
||||
const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *self,
|
||||
ZigClangSourceLocation SL)
|
||||
{
|
||||
return reinterpret_cast<const clang::SourceManager *>(self)->getCharacterData(bitcast(SL));
|
||||
}
|
||||
|
||||
ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* self, ZigClangQualType T) {
|
||||
return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T)));
|
||||
}
|
||||
|
||||
ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) {
|
||||
clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext();
|
||||
return reinterpret_cast<ZigClangASTContext *>(result);
|
||||
}
|
||||
|
||||
ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *self) {
|
||||
clang::SourceManager *result = &reinterpret_cast<clang::ASTUnit *>(self)->getSourceManager();
|
||||
return reinterpret_cast<ZigClangSourceManager *>(result);
|
||||
}
|
||||
|
||||
bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context,
|
||||
bool (*Fn)(void *context, const ZigClangDecl *decl))
|
||||
{
|
||||
return reinterpret_cast<clang::ASTUnit *>(self)->visitLocalTopLevelDecls(context,
|
||||
reinterpret_cast<bool (*)(void *, const clang::Decl *)>(Fn));
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_ZIG_CLANG_H
|
||||
#define ZIG_ZIG_CLANG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ZIG_EXTERN_C extern "C"
|
||||
#else
|
||||
#define ZIG_EXTERN_C
|
||||
#endif
|
||||
|
||||
// ATTENTION: If you modify this file, be sure to update the corresponding
|
||||
// extern function declarations in the self-hosted compiler.
|
||||
|
||||
struct ZigClangSourceLocation {
|
||||
unsigned ID;
|
||||
};
|
||||
|
||||
struct ZigClangQualType {
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
struct ZigClangAPValue;
|
||||
struct ZigClangASTContext;
|
||||
struct ZigClangASTUnit;
|
||||
struct ZigClangArraySubscriptExpr;
|
||||
struct ZigClangArrayType;
|
||||
struct ZigClangAttributedType;
|
||||
struct ZigClangBinaryOperator;
|
||||
struct ZigClangBreakStmt;
|
||||
struct ZigClangBuiltinType;
|
||||
struct ZigClangCStyleCastExpr;
|
||||
struct ZigClangCallExpr;
|
||||
struct ZigClangCaseStmt;
|
||||
struct ZigClangCompoundAssignOperator;
|
||||
struct ZigClangCompoundStmt;
|
||||
struct ZigClangConditionalOperator;
|
||||
struct ZigClangConstantArrayType;
|
||||
struct ZigClangContinueStmt;
|
||||
struct ZigClangDecayedType;
|
||||
struct ZigClangDecl;
|
||||
struct ZigClangDeclRefExpr;
|
||||
struct ZigClangDeclStmt;
|
||||
struct ZigClangDefaultStmt;
|
||||
struct ZigClangDiagnosticOptions;
|
||||
struct ZigClangDiagnosticsEngine;
|
||||
struct ZigClangDoStmt;
|
||||
struct ZigClangElaboratedType;
|
||||
struct ZigClangEnumConstantDecl;
|
||||
struct ZigClangEnumDecl;
|
||||
struct ZigClangEnumType;
|
||||
struct ZigClangExpr;
|
||||
struct ZigClangFieldDecl;
|
||||
struct ZigClangFileID;
|
||||
struct ZigClangForStmt;
|
||||
struct ZigClangFullSourceLoc;
|
||||
struct ZigClangFunctionDecl;
|
||||
struct ZigClangFunctionProtoType;
|
||||
struct ZigClangIfStmt;
|
||||
struct ZigClangImplicitCastExpr;
|
||||
struct ZigClangIncompleteArrayType;
|
||||
struct ZigClangIntegerLiteral;
|
||||
struct ZigClangMacroDefinitionRecord;
|
||||
struct ZigClangMemberExpr;
|
||||
struct ZigClangNamedDecl;
|
||||
struct ZigClangNone;
|
||||
struct ZigClangPCHContainerOperations;
|
||||
struct ZigClangParenExpr;
|
||||
struct ZigClangParenType;
|
||||
struct ZigClangParmVarDecl;
|
||||
struct ZigClangPointerType;
|
||||
struct ZigClangPreprocessedEntity;
|
||||
struct ZigClangRecordDecl;
|
||||
struct ZigClangRecordType;
|
||||
struct ZigClangReturnStmt;
|
||||
struct ZigClangSkipFunctionBodiesScope;
|
||||
struct ZigClangSourceManager;
|
||||
struct ZigClangSourceRange;
|
||||
struct ZigClangStmt;
|
||||
struct ZigClangStorageClass;
|
||||
struct ZigClangStringLiteral;
|
||||
struct ZigClangStringRef;
|
||||
struct ZigClangSwitchStmt;
|
||||
struct ZigClangType;
|
||||
struct ZigClangTypedefNameDecl;
|
||||
struct ZigClangTypedefType;
|
||||
struct ZigClangUnaryExprOrTypeTraitExpr;
|
||||
struct ZigClangUnaryOperator;
|
||||
struct ZigClangValueDecl;
|
||||
struct ZigClangVarDecl;
|
||||
struct ZigClangWhileStmt;
|
||||
|
||||
enum ZigClangBO {
|
||||
ZigClangBO_PtrMemD,
|
||||
ZigClangBO_PtrMemI,
|
||||
ZigClangBO_Mul,
|
||||
ZigClangBO_Div,
|
||||
ZigClangBO_Rem,
|
||||
ZigClangBO_Add,
|
||||
ZigClangBO_Sub,
|
||||
ZigClangBO_Shl,
|
||||
ZigClangBO_Shr,
|
||||
ZigClangBO_Cmp,
|
||||
ZigClangBO_LT,
|
||||
ZigClangBO_GT,
|
||||
ZigClangBO_LE,
|
||||
ZigClangBO_GE,
|
||||
ZigClangBO_EQ,
|
||||
ZigClangBO_NE,
|
||||
ZigClangBO_And,
|
||||
ZigClangBO_Xor,
|
||||
ZigClangBO_Or,
|
||||
ZigClangBO_LAnd,
|
||||
ZigClangBO_LOr,
|
||||
ZigClangBO_Assign,
|
||||
ZigClangBO_MulAssign,
|
||||
ZigClangBO_DivAssign,
|
||||
ZigClangBO_RemAssign,
|
||||
ZigClangBO_AddAssign,
|
||||
ZigClangBO_SubAssign,
|
||||
ZigClangBO_ShlAssign,
|
||||
ZigClangBO_ShrAssign,
|
||||
ZigClangBO_AndAssign,
|
||||
ZigClangBO_XorAssign,
|
||||
ZigClangBO_OrAssign,
|
||||
ZigClangBO_Comma,
|
||||
};
|
||||
|
||||
enum ZigClangUO {
|
||||
ZigClangUO_PostInc,
|
||||
ZigClangUO_PostDec,
|
||||
ZigClangUO_PreInc,
|
||||
ZigClangUO_PreDec,
|
||||
ZigClangUO_AddrOf,
|
||||
ZigClangUO_Deref,
|
||||
ZigClangUO_Plus,
|
||||
ZigClangUO_Minus,
|
||||
ZigClangUO_Not,
|
||||
ZigClangUO_LNot,
|
||||
ZigClangUO_Real,
|
||||
ZigClangUO_Imag,
|
||||
ZigClangUO_Extension,
|
||||
ZigClangUO_Coawait,
|
||||
};
|
||||
|
||||
//struct ZigClangCC_AAPCS;
|
||||
//struct ZigClangCC_AAPCS_VFP;
|
||||
//struct ZigClangCC_C;
|
||||
//struct ZigClangCC_IntelOclBicc;
|
||||
//struct ZigClangCC_OpenCLKernel;
|
||||
//struct ZigClangCC_PreserveAll;
|
||||
//struct ZigClangCC_PreserveMost;
|
||||
//struct ZigClangCC_SpirFunction;
|
||||
//struct ZigClangCC_Swift;
|
||||
//struct ZigClangCC_Win64;
|
||||
//struct ZigClangCC_X86FastCall;
|
||||
//struct ZigClangCC_X86Pascal;
|
||||
//struct ZigClangCC_X86RegCall;
|
||||
//struct ZigClangCC_X86StdCall;
|
||||
//struct ZigClangCC_X86ThisCall;
|
||||
//struct ZigClangCC_X86VectorCall;
|
||||
//struct ZigClangCC_X86_64SysV;
|
||||
|
||||
//struct ZigClangCK_ARCConsumeObject;
|
||||
//struct ZigClangCK_ARCExtendBlockObject;
|
||||
//struct ZigClangCK_ARCProduceObject;
|
||||
//struct ZigClangCK_ARCReclaimReturnedObject;
|
||||
//struct ZigClangCK_AddressSpaceConversion;
|
||||
//struct ZigClangCK_AnyPointerToBlockPointerCast;
|
||||
//struct ZigClangCK_ArrayToPointerDecay;
|
||||
//struct ZigClangCK_AtomicToNonAtomic;
|
||||
//struct ZigClangCK_BaseToDerived;
|
||||
//struct ZigClangCK_BaseToDerivedMemberPointer;
|
||||
//struct ZigClangCK_BitCast;
|
||||
//struct ZigClangCK_BlockPointerToObjCPointerCast;
|
||||
//struct ZigClangCK_BooleanToSignedIntegral;
|
||||
//struct ZigClangCK_BuiltinFnToFnPtr;
|
||||
//struct ZigClangCK_CPointerToObjCPointerCast;
|
||||
//struct ZigClangCK_ConstructorConversion;
|
||||
//struct ZigClangCK_CopyAndAutoreleaseBlockObject;
|
||||
//struct ZigClangCK_Dependent;
|
||||
//struct ZigClangCK_DerivedToBase;
|
||||
//struct ZigClangCK_DerivedToBaseMemberPointer;
|
||||
//struct ZigClangCK_Dynamic;
|
||||
//struct ZigClangCK_FloatingCast;
|
||||
//struct ZigClangCK_FloatingComplexCast;
|
||||
//struct ZigClangCK_FloatingComplexToBoolean;
|
||||
//struct ZigClangCK_FloatingComplexToIntegralComplex;
|
||||
//struct ZigClangCK_FloatingComplexToReal;
|
||||
//struct ZigClangCK_FloatingRealToComplex;
|
||||
//struct ZigClangCK_FloatingToBoolean;
|
||||
//struct ZigClangCK_FloatingToIntegral;
|
||||
//struct ZigClangCK_FunctionToPointerDecay;
|
||||
//struct ZigClangCK_IntToOCLSampler;
|
||||
//struct ZigClangCK_IntegralCast;
|
||||
//struct ZigClangCK_IntegralComplexCast;
|
||||
//struct ZigClangCK_IntegralComplexToBoolean;
|
||||
//struct ZigClangCK_IntegralComplexToFloatingComplex;
|
||||
//struct ZigClangCK_IntegralComplexToReal;
|
||||
//struct ZigClangCK_IntegralRealToComplex;
|
||||
//struct ZigClangCK_IntegralToBoolean;
|
||||
//struct ZigClangCK_IntegralToFloating;
|
||||
//struct ZigClangCK_IntegralToPointer;
|
||||
//struct ZigClangCK_LValueBitCast;
|
||||
//struct ZigClangCK_LValueToRValue;
|
||||
//struct ZigClangCK_MemberPointerToBoolean;
|
||||
//struct ZigClangCK_NoOp;
|
||||
//struct ZigClangCK_NonAtomicToAtomic;
|
||||
//struct ZigClangCK_NullToMemberPointer;
|
||||
//struct ZigClangCK_NullToPointer;
|
||||
//struct ZigClangCK_ObjCObjectLValueCast;
|
||||
//struct ZigClangCK_PointerToBoolean;
|
||||
//struct ZigClangCK_PointerToIntegral;
|
||||
//struct ZigClangCK_ReinterpretMemberPointer;
|
||||
//struct ZigClangCK_ToUnion;
|
||||
//struct ZigClangCK_ToVoid;
|
||||
//struct ZigClangCK_UncheckedDerivedToBase;
|
||||
//struct ZigClangCK_UserDefinedConversion;
|
||||
//struct ZigClangCK_VectorSplat;
|
||||
//struct ZigClangCK_ZeroToOCLEvent;
|
||||
//struct ZigClangCK_ZeroToOCLQueue;
|
||||
|
||||
//struct ZigClangETK_Class;
|
||||
//struct ZigClangETK_Enum;
|
||||
//struct ZigClangETK_Interface;
|
||||
//struct ZigClangETK_None;
|
||||
//struct ZigClangETK_Struct;
|
||||
//struct ZigClangETK_Typename;
|
||||
//struct ZigClangETK_Union;
|
||||
|
||||
//struct ZigClangSC_None;
|
||||
//struct ZigClangSC_PrivateExtern;
|
||||
//struct ZigClangSC_Static;
|
||||
|
||||
//struct ZigClangTU_Complete;
|
||||
|
||||
ZIG_EXTERN_C ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation SpellingLoc);
|
||||
ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *,
|
||||
ZigClangSourceLocation SL);
|
||||
|
||||
ZIG_EXTERN_C ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext*, ZigClangQualType T);
|
||||
|
||||
ZIG_EXTERN_C ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *);
|
||||
ZIG_EXTERN_C ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *);
|
||||
ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *, void *context,
|
||||
bool (*Fn)(void *context, const ZigClangDecl *decl));
|
||||
#endif
|
|
@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch
|
|||
return reinterpret_cast<ZigLLVMDIType*>(di_type);
|
||||
}
|
||||
|
||||
struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, struct ZigLLVMDIType *Ty, uint32_t elem_count)
|
||||
{
|
||||
SmallVector<Metadata *, 1> subrange;
|
||||
subrange.push_back(reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateSubrange(0, elem_count));
|
||||
DIType *di_type = reinterpret_cast<DIBuilder*>(dibuilder)->createVectorType(
|
||||
SizeInBits,
|
||||
AlignInBits,
|
||||
reinterpret_cast<DIType*>(Ty),
|
||||
reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(subrange));
|
||||
return reinterpret_cast<ZigLLVMDIType*>(di_type);
|
||||
}
|
||||
|
||||
ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits,
|
||||
uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count)
|
||||
{
|
||||
|
@ -605,7 +618,7 @@ ZigLLVMDISubprogram *ZigLLVMCreateFunction(ZigLLVMDIBuilder *dibuilder, ZigLLVMD
|
|||
reinterpret_cast<DIFile*>(file),
|
||||
lineno,
|
||||
di_sub_type,
|
||||
is_local_to_unit, is_definition, scope_line, DINode::FlagZero, is_optimized,
|
||||
is_local_to_unit, is_definition, scope_line, DINode::FlagStaticMember, is_optimized,
|
||||
nullptr,
|
||||
reinterpret_cast<DISubprogram *>(decl_subprogram));
|
||||
return reinterpret_cast<ZigLLVMDISubprogram*>(result);
|
||||
|
|
|
@ -191,6 +191,9 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB
|
|||
unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition,
|
||||
unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram);
|
||||
|
||||
ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, struct ZigLLVMDIType *Ty, uint32_t elem_count);
|
||||
|
||||
ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram);
|
||||
|
||||
ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("index.zig");
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const assertError = debug.assertError;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
|
@ -212,8 +212,8 @@ test "std.ArrayList.init" {
|
|||
var list = ArrayList(i32).init(allocator);
|
||||
defer list.deinit();
|
||||
|
||||
assert(list.count() == 0);
|
||||
assert(list.capacity() == 0);
|
||||
testing.expect(list.count() == 0);
|
||||
testing.expect(list.capacity() == 0);
|
||||
}
|
||||
|
||||
test "std.ArrayList.basic" {
|
||||
|
@ -224,7 +224,7 @@ test "std.ArrayList.basic" {
|
|||
defer list.deinit();
|
||||
|
||||
// setting on empty list is out of bounds
|
||||
assertError(list.setOrError(0, 1), error.OutOfBounds);
|
||||
testing.expectError(error.OutOfBounds, list.setOrError(0, 1));
|
||||
|
||||
{
|
||||
var i: usize = 0;
|
||||
|
@ -236,44 +236,44 @@ test "std.ArrayList.basic" {
|
|||
{
|
||||
var i: usize = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
assert(list.items[i] == @intCast(i32, i + 1));
|
||||
testing.expect(list.items[i] == @intCast(i32, i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
for (list.toSlice()) |v, i| {
|
||||
assert(v == @intCast(i32, i + 1));
|
||||
testing.expect(v == @intCast(i32, i + 1));
|
||||
}
|
||||
|
||||
for (list.toSliceConst()) |v, i| {
|
||||
assert(v == @intCast(i32, i + 1));
|
||||
testing.expect(v == @intCast(i32, i + 1));
|
||||
}
|
||||
|
||||
assert(list.pop() == 10);
|
||||
assert(list.len == 9);
|
||||
testing.expect(list.pop() == 10);
|
||||
testing.expect(list.len == 9);
|
||||
|
||||
list.appendSlice([]const i32{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
}) catch unreachable;
|
||||
assert(list.len == 12);
|
||||
assert(list.pop() == 3);
|
||||
assert(list.pop() == 2);
|
||||
assert(list.pop() == 1);
|
||||
assert(list.len == 9);
|
||||
testing.expect(list.len == 12);
|
||||
testing.expect(list.pop() == 3);
|
||||
testing.expect(list.pop() == 2);
|
||||
testing.expect(list.pop() == 1);
|
||||
testing.expect(list.len == 9);
|
||||
|
||||
list.appendSlice([]const i32{}) catch unreachable;
|
||||
assert(list.len == 9);
|
||||
testing.expect(list.len == 9);
|
||||
|
||||
// can only set on indices < self.len
|
||||
list.set(7, 33);
|
||||
list.set(8, 42);
|
||||
|
||||
assertError(list.setOrError(9, 99), error.OutOfBounds);
|
||||
assertError(list.setOrError(10, 123), error.OutOfBounds);
|
||||
testing.expectError(error.OutOfBounds, list.setOrError(9, 99));
|
||||
testing.expectError(error.OutOfBounds, list.setOrError(10, 123));
|
||||
|
||||
assert(list.pop() == 42);
|
||||
assert(list.pop() == 33);
|
||||
testing.expect(list.pop() == 42);
|
||||
testing.expect(list.pop() == 33);
|
||||
}
|
||||
|
||||
test "std.ArrayList.swapRemove" {
|
||||
|
@ -289,18 +289,18 @@ test "std.ArrayList.swapRemove" {
|
|||
try list.append(7);
|
||||
|
||||
//remove from middle
|
||||
assert(list.swapRemove(3) == 4);
|
||||
assert(list.at(3) == 7);
|
||||
assert(list.len == 6);
|
||||
testing.expect(list.swapRemove(3) == 4);
|
||||
testing.expect(list.at(3) == 7);
|
||||
testing.expect(list.len == 6);
|
||||
|
||||
//remove from end
|
||||
assert(list.swapRemove(5) == 6);
|
||||
assert(list.len == 5);
|
||||
testing.expect(list.swapRemove(5) == 6);
|
||||
testing.expect(list.len == 5);
|
||||
|
||||
//remove from front
|
||||
assert(list.swapRemove(0) == 1);
|
||||
assert(list.at(0) == 5);
|
||||
assert(list.len == 4);
|
||||
testing.expect(list.swapRemove(0) == 1);
|
||||
testing.expect(list.at(0) == 5);
|
||||
testing.expect(list.len == 4);
|
||||
}
|
||||
|
||||
test "std.ArrayList.swapRemoveOrError" {
|
||||
|
@ -308,27 +308,27 @@ test "std.ArrayList.swapRemoveOrError" {
|
|||
defer list.deinit();
|
||||
|
||||
// Test just after initialization
|
||||
assertError(list.swapRemoveOrError(0), error.OutOfBounds);
|
||||
testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0));
|
||||
|
||||
// Test after adding one item and remote it
|
||||
try list.append(1);
|
||||
assert((try list.swapRemoveOrError(0)) == 1);
|
||||
assertError(list.swapRemoveOrError(0), error.OutOfBounds);
|
||||
testing.expect((try list.swapRemoveOrError(0)) == 1);
|
||||
testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0));
|
||||
|
||||
// Test after adding two items and remote both
|
||||
try list.append(1);
|
||||
try list.append(2);
|
||||
assert((try list.swapRemoveOrError(1)) == 2);
|
||||
assert((try list.swapRemoveOrError(0)) == 1);
|
||||
assertError(list.swapRemoveOrError(0), error.OutOfBounds);
|
||||
testing.expect((try list.swapRemoveOrError(1)) == 2);
|
||||
testing.expect((try list.swapRemoveOrError(0)) == 1);
|
||||
testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0));
|
||||
|
||||
// Test out of bounds with one item
|
||||
try list.append(1);
|
||||
assertError(list.swapRemoveOrError(1), error.OutOfBounds);
|
||||
testing.expectError(error.OutOfBounds, list.swapRemoveOrError(1));
|
||||
|
||||
// Test out of bounds with two items
|
||||
try list.append(2);
|
||||
assertError(list.swapRemoveOrError(2), error.OutOfBounds);
|
||||
testing.expectError(error.OutOfBounds, list.swapRemoveOrError(2));
|
||||
}
|
||||
|
||||
test "std.ArrayList.iterator" {
|
||||
|
@ -342,22 +342,22 @@ test "std.ArrayList.iterator" {
|
|||
var count: i32 = 0;
|
||||
var it = list.iterator();
|
||||
while (it.next()) |next| {
|
||||
assert(next == count + 1);
|
||||
testing.expect(next == count + 1);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
assert(count == 3);
|
||||
assert(it.next() == null);
|
||||
testing.expect(count == 3);
|
||||
testing.expect(it.next() == null);
|
||||
it.reset();
|
||||
count = 0;
|
||||
while (it.next()) |next| {
|
||||
assert(next == count + 1);
|
||||
testing.expect(next == count + 1);
|
||||
count += 1;
|
||||
if (count == 2) break;
|
||||
}
|
||||
|
||||
it.reset();
|
||||
assert(it.next().? == 1);
|
||||
testing.expect(it.next().? == 1);
|
||||
}
|
||||
|
||||
test "std.ArrayList.insert" {
|
||||
|
@ -368,10 +368,10 @@ test "std.ArrayList.insert" {
|
|||
try list.append(2);
|
||||
try list.append(3);
|
||||
try list.insert(0, 5);
|
||||
assert(list.items[0] == 5);
|
||||
assert(list.items[1] == 1);
|
||||
assert(list.items[2] == 2);
|
||||
assert(list.items[3] == 3);
|
||||
testing.expect(list.items[0] == 5);
|
||||
testing.expect(list.items[1] == 1);
|
||||
testing.expect(list.items[2] == 2);
|
||||
testing.expect(list.items[3] == 3);
|
||||
}
|
||||
|
||||
test "std.ArrayList.insertSlice" {
|
||||
|
@ -386,15 +386,26 @@ test "std.ArrayList.insertSlice" {
|
|||
9,
|
||||
8,
|
||||
});
|
||||
assert(list.items[0] == 1);
|
||||
assert(list.items[1] == 9);
|
||||
assert(list.items[2] == 8);
|
||||
assert(list.items[3] == 2);
|
||||
assert(list.items[4] == 3);
|
||||
assert(list.items[5] == 4);
|
||||
testing.expect(list.items[0] == 1);
|
||||
testing.expect(list.items[1] == 9);
|
||||
testing.expect(list.items[2] == 8);
|
||||
testing.expect(list.items[3] == 2);
|
||||
testing.expect(list.items[4] == 3);
|
||||
testing.expect(list.items[5] == 4);
|
||||
|
||||
const items = []const i32{1};
|
||||
try list.insertSlice(0, items[0..0]);
|
||||
assert(list.len == 6);
|
||||
assert(list.items[0] == 1);
|
||||
testing.expect(list.len == 6);
|
||||
testing.expect(list.items[0] == 1);
|
||||
}
|
||||
|
||||
const Item = struct {
|
||||
integer: i32,
|
||||
sub_items: ArrayList(Item),
|
||||
};
|
||||
|
||||
test "std.ArrayList: ArrayList(T) of struct T" {
|
||||
var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
|
||||
try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );
|
||||
testing.expect(root.sub_items.items[0].integer == 42);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ const builtin = @import("builtin");
|
|||
const AtomicOrder = builtin.AtomicOrder;
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const assert = std.debug.assert;
|
||||
const expect = std.testing.expect;
|
||||
|
||||
/// Many producer, many consumer, non-allocating, thread-safe.
|
||||
/// Uses a mutex to protect access.
|
||||
|
@ -170,20 +171,36 @@ test "std.atomic.Queue" {
|
|||
.get_count = 0,
|
||||
};
|
||||
|
||||
var putters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startPuts);
|
||||
}
|
||||
var getters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startGets);
|
||||
}
|
||||
if (builtin.single_threaded) {
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < put_thread_count) : (i += 1) {
|
||||
expect(startPuts(&context) == 0);
|
||||
}
|
||||
}
|
||||
context.puts_done = 1;
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < put_thread_count) : (i += 1) {
|
||||
expect(startGets(&context) == 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var putters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startPuts);
|
||||
}
|
||||
var getters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startGets);
|
||||
}
|
||||
|
||||
for (putters) |t|
|
||||
t.wait();
|
||||
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
|
||||
for (getters) |t|
|
||||
t.wait();
|
||||
for (putters) |t|
|
||||
t.wait();
|
||||
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
|
||||
for (getters) |t|
|
||||
t.wait();
|
||||
}
|
||||
|
||||
if (context.put_sum != context.get_sum) {
|
||||
std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
|
||||
|
@ -205,11 +222,12 @@ fn startPuts(ctx: *Context) u8 {
|
|||
while (put_count != 0) : (put_count -= 1) {
|
||||
std.os.time.sleep(1); // let the os scheduler be our fuzz
|
||||
const x = @bitCast(i32, r.random.scalar(u32));
|
||||
const node = ctx.allocator.create(Queue(i32).Node{
|
||||
const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
|
||||
node.* = Queue(i32).Node{
|
||||
.prev = undefined,
|
||||
.next = undefined,
|
||||
.data = x,
|
||||
}) catch unreachable;
|
||||
};
|
||||
ctx.queue.put(node);
|
||||
_ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
|
||||
}
|
||||
|
@ -247,7 +265,7 @@ test "std.atomic.Queue single-threaded" {
|
|||
};
|
||||
queue.put(&node_1);
|
||||
|
||||
assert(queue.get().?.data == 0);
|
||||
expect(queue.get().?.data == 0);
|
||||
|
||||
var node_2 = Queue(i32).Node{
|
||||
.data = 2,
|
||||
|
@ -263,9 +281,9 @@ test "std.atomic.Queue single-threaded" {
|
|||
};
|
||||
queue.put(&node_3);
|
||||
|
||||
assert(queue.get().?.data == 1);
|
||||
expect(queue.get().?.data == 1);
|
||||
|
||||
assert(queue.get().?.data == 2);
|
||||
expect(queue.get().?.data == 2);
|
||||
|
||||
var node_4 = Queue(i32).Node{
|
||||
.data = 4,
|
||||
|
@ -274,12 +292,12 @@ test "std.atomic.Queue single-threaded" {
|
|||
};
|
||||
queue.put(&node_4);
|
||||
|
||||
assert(queue.get().?.data == 3);
|
||||
expect(queue.get().?.data == 3);
|
||||
node_3.next = null;
|
||||
|
||||
assert(queue.get().?.data == 4);
|
||||
expect(queue.get().?.data == 4);
|
||||
|
||||
assert(queue.get() == null);
|
||||
expect(queue.get() == null);
|
||||
}
|
||||
|
||||
test "std.atomic.Queue dump" {
|
||||
|
@ -294,7 +312,7 @@ test "std.atomic.Queue dump" {
|
|||
// Test empty stream
|
||||
sos.reset();
|
||||
try queue.dumpToStream(SliceOutStream.Error, &sos.stream);
|
||||
assert(mem.eql(u8, buffer[0..sos.pos],
|
||||
expect(mem.eql(u8, buffer[0..sos.pos],
|
||||
\\head: (null)
|
||||
\\tail: (null)
|
||||
\\
|
||||
|
@ -318,7 +336,7 @@ test "std.atomic.Queue dump" {
|
|||
\\ (null)
|
||||
\\
|
||||
, @ptrToInt(queue.head), @ptrToInt(queue.tail));
|
||||
assert(mem.eql(u8, buffer[0..sos.pos], expected));
|
||||
expect(mem.eql(u8, buffer[0..sos.pos], expected));
|
||||
|
||||
// Test a stream with two elements
|
||||
var node_1 = Queue(i32).Node{
|
||||
|
@ -339,5 +357,5 @@ test "std.atomic.Queue dump" {
|
|||
\\ (null)
|
||||
\\
|
||||
, @ptrToInt(queue.head), @ptrToInt(queue.head.?.next), @ptrToInt(queue.tail));
|
||||
assert(mem.eql(u8, buffer[0..sos.pos], expected));
|
||||
expect(mem.eql(u8, buffer[0..sos.pos], expected));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
const assert = std.debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
const expect = std.testing.expect;
|
||||
|
||||
/// Many reader, many writer, non-allocating, thread-safe
|
||||
/// Uses a spinlock to protect push() and pop()
|
||||
/// When building in single threaded mode, this is a simple linked list.
|
||||
pub fn Stack(comptime T: type) type {
|
||||
return struct {
|
||||
root: ?*Node,
|
||||
lock: u8,
|
||||
lock: @typeOf(lock_init),
|
||||
|
||||
const lock_init = if (builtin.single_threaded) {} else u8(0);
|
||||
|
||||
pub const Self = @This();
|
||||
|
||||
|
@ -19,7 +23,7 @@ pub fn Stack(comptime T: type) type {
|
|||
pub fn init() Self {
|
||||
return Self{
|
||||
.root = null,
|
||||
.lock = 0,
|
||||
.lock = lock_init,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -31,20 +35,31 @@ pub fn Stack(comptime T: type) type {
|
|||
}
|
||||
|
||||
pub fn push(self: *Self, node: *Node) void {
|
||||
while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
|
||||
defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
|
||||
if (builtin.single_threaded) {
|
||||
node.next = self.root;
|
||||
self.root = node;
|
||||
} else {
|
||||
while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
|
||||
defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
|
||||
|
||||
node.next = self.root;
|
||||
self.root = node;
|
||||
node.next = self.root;
|
||||
self.root = node;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(self: *Self) ?*Node {
|
||||
while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
|
||||
defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
|
||||
if (builtin.single_threaded) {
|
||||
const root = self.root orelse return null;
|
||||
self.root = root.next;
|
||||
return root;
|
||||
} else {
|
||||
while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
|
||||
defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
|
||||
|
||||
const root = self.root orelse return null;
|
||||
self.root = root.next;
|
||||
return root;
|
||||
const root = self.root orelse return null;
|
||||
self.root = root.next;
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
|
@ -90,20 +105,36 @@ test "std.atomic.stack" {
|
|||
.get_count = 0,
|
||||
};
|
||||
|
||||
var putters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startPuts);
|
||||
}
|
||||
var getters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startGets);
|
||||
}
|
||||
if (builtin.single_threaded) {
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < put_thread_count) : (i += 1) {
|
||||
expect(startPuts(&context) == 0);
|
||||
}
|
||||
}
|
||||
context.puts_done = 1;
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < put_thread_count) : (i += 1) {
|
||||
expect(startGets(&context) == 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var putters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startPuts);
|
||||
}
|
||||
var getters: [put_thread_count]*std.os.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.os.spawnThread(&context, startGets);
|
||||
}
|
||||
|
||||
for (putters) |t|
|
||||
t.wait();
|
||||
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
|
||||
for (getters) |t|
|
||||
t.wait();
|
||||
for (putters) |t|
|
||||
t.wait();
|
||||
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
|
||||
for (getters) |t|
|
||||
t.wait();
|
||||
}
|
||||
|
||||
if (context.put_sum != context.get_sum) {
|
||||
std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
|
||||
|
@ -125,10 +156,11 @@ fn startPuts(ctx: *Context) u8 {
|
|||
while (put_count != 0) : (put_count -= 1) {
|
||||
std.os.time.sleep(1); // let the os scheduler be our fuzz
|
||||
const x = @bitCast(i32, r.random.scalar(u32));
|
||||
const node = ctx.allocator.create(Stack(i32).Node{
|
||||
const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
|
||||
node.* = Stack(i32).Node{
|
||||
.next = undefined,
|
||||
.data = x,
|
||||
}) catch unreachable;
|
||||
};
|
||||
ctx.stack.push(node);
|
||||
_ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("index.zig");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
|
||||
pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
@ -394,7 +395,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
|
|||
var buffer: [0x100]u8 = undefined;
|
||||
var encoded = buffer[0..Base64Encoder.calcSize(expected_decoded.len)];
|
||||
standard_encoder.encode(encoded, expected_decoded);
|
||||
assert(mem.eql(u8, encoded, expected_encoded));
|
||||
testing.expectEqualSlices(u8, expected_encoded, encoded);
|
||||
}
|
||||
|
||||
// Base64Decoder
|
||||
|
@ -402,7 +403,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
|
|||
var buffer: [0x100]u8 = undefined;
|
||||
var decoded = buffer[0..try standard_decoder.calcSize(expected_encoded)];
|
||||
try standard_decoder.decode(decoded, expected_encoded);
|
||||
assert(mem.eql(u8, decoded, expected_decoded));
|
||||
testing.expectEqualSlices(u8, expected_decoded, decoded);
|
||||
}
|
||||
|
||||
// Base64DecoderWithIgnore
|
||||
|
@ -411,8 +412,8 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
|
|||
var buffer: [0x100]u8 = undefined;
|
||||
var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
|
||||
var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
|
||||
assert(written <= decoded.len);
|
||||
assert(mem.eql(u8, decoded[0..written], expected_decoded));
|
||||
testing.expect(written <= decoded.len);
|
||||
testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]);
|
||||
}
|
||||
|
||||
// Base64DecoderUnsafe
|
||||
|
@ -420,7 +421,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
|
|||
var buffer: [0x100]u8 = undefined;
|
||||
var decoded = buffer[0..standard_decoder_unsafe.calcSize(expected_encoded)];
|
||||
standard_decoder_unsafe.decode(decoded, expected_encoded);
|
||||
assert(mem.eql(u8, decoded, expected_decoded));
|
||||
testing.expectEqualSlices(u8, expected_decoded, decoded);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +430,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi
|
|||
var buffer: [0x100]u8 = undefined;
|
||||
var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
|
||||
var written = try standard_decoder_ignore_space.decode(decoded, encoded);
|
||||
assert(mem.eql(u8, decoded[0..written], expected_decoded));
|
||||
testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]);
|
||||
}
|
||||
|
||||
fn testError(encoded: []const u8, expected_err: anyerror) !void {
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("index.zig");
|
|||
const HashMap = std.HashMap;
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
|
||||
/// BufMap copies keys and values before they go into the map, and
|
||||
/// frees them when they get removed.
|
||||
|
@ -16,7 +16,7 @@ pub const BufMap = struct {
|
|||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *const BufMap) void {
|
||||
pub fn deinit(self: *BufMap) void {
|
||||
var it = self.hash_map.iterator();
|
||||
while (true) {
|
||||
const entry = it.next() orelse break;
|
||||
|
@ -27,16 +27,34 @@ pub const BufMap = struct {
|
|||
self.hash_map.deinit();
|
||||
}
|
||||
|
||||
pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void {
|
||||
self.delete(key);
|
||||
const key_copy = try self.copy(key);
|
||||
errdefer self.free(key_copy);
|
||||
const value_copy = try self.copy(value);
|
||||
errdefer self.free(value_copy);
|
||||
_ = try self.hash_map.put(key_copy, value_copy);
|
||||
/// Same as `set` but the key and value become owned by the BufMap rather
|
||||
/// than being copied.
|
||||
/// If `setMove` fails, the ownership of key and value does not transfer.
|
||||
pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void {
|
||||
const get_or_put = try self.hash_map.getOrPut(key);
|
||||
if (get_or_put.found_existing) {
|
||||
self.free(get_or_put.kv.key);
|
||||
get_or_put.kv.key = key;
|
||||
}
|
||||
get_or_put.kv.value = value;
|
||||
}
|
||||
|
||||
pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
|
||||
/// `key` and `value` are copied into the BufMap.
|
||||
pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void {
|
||||
const value_copy = try self.copy(value);
|
||||
errdefer self.free(value_copy);
|
||||
// Avoid copying key if it already exists
|
||||
const get_or_put = try self.hash_map.getOrPut(key);
|
||||
if (!get_or_put.found_existing) {
|
||||
get_or_put.kv.key = self.copy(key) catch |err| {
|
||||
_ = self.hash_map.remove(key);
|
||||
return err;
|
||||
};
|
||||
}
|
||||
get_or_put.kv.value = value_copy;
|
||||
}
|
||||
|
||||
pub fn get(self: BufMap, key: []const u8) ?[]const u8 {
|
||||
const entry = self.hash_map.get(key) orelse return null;
|
||||
return entry.value;
|
||||
}
|
||||
|
@ -47,7 +65,7 @@ pub const BufMap = struct {
|
|||
self.free(entry.value);
|
||||
}
|
||||
|
||||
pub fn count(self: *const BufMap) usize {
|
||||
pub fn count(self: BufMap) usize {
|
||||
return self.hash_map.count();
|
||||
}
|
||||
|
||||
|
@ -55,11 +73,11 @@ pub const BufMap = struct {
|
|||
return self.hash_map.iterator();
|
||||
}
|
||||
|
||||
fn free(self: *const BufMap, value: []const u8) void {
|
||||
fn free(self: BufMap, value: []const u8) void {
|
||||
self.hash_map.allocator.free(value);
|
||||
}
|
||||
|
||||
fn copy(self: *const BufMap, value: []const u8) ![]const u8 {
|
||||
fn copy(self: BufMap, value: []const u8) ![]u8 {
|
||||
return mem.dupe(self.hash_map.allocator, u8, value);
|
||||
}
|
||||
};
|
||||
|
@ -72,17 +90,17 @@ test "BufMap" {
|
|||
defer bufmap.deinit();
|
||||
|
||||
try bufmap.set("x", "1");
|
||||
assert(mem.eql(u8, bufmap.get("x").?, "1"));
|
||||
assert(1 == bufmap.count());
|
||||
testing.expect(mem.eql(u8, bufmap.get("x").?, "1"));
|
||||
testing.expect(1 == bufmap.count());
|
||||
|
||||
try bufmap.set("x", "2");
|
||||
assert(mem.eql(u8, bufmap.get("x").?, "2"));
|
||||
assert(1 == bufmap.count());
|
||||
testing.expect(mem.eql(u8, bufmap.get("x").?, "2"));
|
||||
testing.expect(1 == bufmap.count());
|
||||
|
||||
try bufmap.set("x", "3");
|
||||
assert(mem.eql(u8, bufmap.get("x").?, "3"));
|
||||
assert(1 == bufmap.count());
|
||||
testing.expect(mem.eql(u8, bufmap.get("x").?, "3"));
|
||||
testing.expect(1 == bufmap.count());
|
||||
|
||||
bufmap.delete("x");
|
||||
assert(0 == bufmap.count());
|
||||
testing.expect(0 == bufmap.count());
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("index.zig");
|
|||
const HashMap = @import("hash_map.zig").HashMap;
|
||||
const mem = @import("mem.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const BufSet = struct {
|
||||
hash_map: BufSetHashMap,
|
||||
|
@ -68,9 +68,9 @@ test "BufSet" {
|
|||
defer bufset.deinit();
|
||||
|
||||
try bufset.put("x");
|
||||
assert(bufset.count() == 1);
|
||||
testing.expect(bufset.count() == 1);
|
||||
bufset.delete("x");
|
||||
assert(bufset.count() == 0);
|
||||
testing.expect(bufset.count() == 0);
|
||||
|
||||
try bufset.put("x");
|
||||
try bufset.put("y");
|
||||
|
|
|
@ -3,6 +3,7 @@ const debug = std.debug;
|
|||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const assert = debug.assert;
|
||||
const testing = std.testing;
|
||||
const ArrayList = std.ArrayList;
|
||||
|
||||
/// A buffer that allocates memory and maintains a null byte at the end.
|
||||
|
@ -141,19 +142,19 @@ test "simple Buffer" {
|
|||
const cstr = @import("cstr.zig");
|
||||
|
||||
var buf = try Buffer.init(debug.global_allocator, "");
|
||||
assert(buf.len() == 0);
|
||||
testing.expect(buf.len() == 0);
|
||||
try buf.append("hello");
|
||||
try buf.append(" ");
|
||||
try buf.append("world");
|
||||
assert(buf.eql("hello world"));
|
||||
assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
|
||||
testing.expect(buf.eql("hello world"));
|
||||
testing.expect(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
|
||||
|
||||
var buf2 = try Buffer.initFromBuffer(buf);
|
||||
assert(buf.eql(buf2.toSliceConst()));
|
||||
testing.expect(buf.eql(buf2.toSliceConst()));
|
||||
|
||||
assert(buf.startsWith("hell"));
|
||||
assert(buf.endsWith("orld"));
|
||||
testing.expect(buf.startsWith("hell"));
|
||||
testing.expect(buf.endsWith("orld"));
|
||||
|
||||
try buf2.resize(4);
|
||||
assert(buf.startsWith(buf2.toSlice()));
|
||||
testing.expect(buf.startsWith(buf2.toSlice()));
|
||||
}
|
||||
|
|
149
std/build.zig
149
std/build.zig
|
@ -89,7 +89,7 @@ pub const Builder = struct {
|
|||
};
|
||||
|
||||
pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
|
||||
const env_map = allocator.createOne(BufMap) catch unreachable;
|
||||
const env_map = allocator.create(BufMap) catch unreachable;
|
||||
env_map.* = os.getEnvMap(allocator) catch unreachable;
|
||||
var self = Builder{
|
||||
.zig_exe = zig_exe,
|
||||
|
@ -145,8 +145,8 @@ pub const Builder = struct {
|
|||
|
||||
pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
|
||||
self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
|
||||
self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
|
||||
self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
|
||||
self.lib_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;
|
||||
self.exe_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
|
@ -170,7 +170,8 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
|
||||
const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable;
|
||||
const test_step = self.allocator.create(TestStep) catch unreachable;
|
||||
test_step.* = TestStep.init(self, root_src);
|
||||
return test_step;
|
||||
}
|
||||
|
||||
|
@ -202,18 +203,21 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
|
||||
const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable;
|
||||
const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
|
||||
write_file_step.* = WriteFileStep.init(self, file_path, data);
|
||||
return write_file_step;
|
||||
}
|
||||
|
||||
pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep {
|
||||
const data = self.fmt(format, args);
|
||||
const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable;
|
||||
const log_step = self.allocator.create(LogStep) catch unreachable;
|
||||
log_step.* = LogStep.init(self, data);
|
||||
return log_step;
|
||||
}
|
||||
|
||||
pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {
|
||||
const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable;
|
||||
const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
|
||||
remove_dir_step.* = RemoveDirStep.init(self, dir_path);
|
||||
return remove_dir_step;
|
||||
}
|
||||
|
||||
|
@ -320,7 +324,7 @@ pub const Builder = struct {
|
|||
|
||||
fn processNixOSEnvVars(self: *Builder) void {
|
||||
if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
|
||||
var it = mem.split(nix_cflags_compile, " ");
|
||||
var it = mem.tokenize(nix_cflags_compile, " ");
|
||||
while (true) {
|
||||
const word = it.next() orelse break;
|
||||
if (mem.eql(u8, word, "-isystem")) {
|
||||
|
@ -338,7 +342,7 @@ pub const Builder = struct {
|
|||
assert(err == error.EnvironmentVariableNotFound);
|
||||
}
|
||||
if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
|
||||
var it = mem.split(nix_ldflags, " ");
|
||||
var it = mem.tokenize(nix_ldflags, " ");
|
||||
while (true) {
|
||||
const word = it.next() orelse break;
|
||||
if (mem.eql(u8, word, "-rpath")) {
|
||||
|
@ -414,10 +418,11 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
|
||||
const step_info = self.allocator.create(TopLevelStep{
|
||||
const step_info = self.allocator.create(TopLevelStep) catch unreachable;
|
||||
step_info.* = TopLevelStep{
|
||||
.step = Step.initNoOp(name, self.allocator),
|
||||
.description = description,
|
||||
}) catch unreachable;
|
||||
};
|
||||
self.top_level_steps.append(step_info) catch unreachable;
|
||||
return &step_info.step;
|
||||
}
|
||||
|
@ -613,10 +618,14 @@ pub const Builder = struct {
|
|||
|
||||
///::dest_rel_path is relative to prefix path or it can be an absolute path
|
||||
pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
|
||||
const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;
|
||||
const full_dest_path = os.path.resolve(
|
||||
self.allocator,
|
||||
[][]const u8{ self.prefix, dest_rel_path },
|
||||
) catch unreachable;
|
||||
self.pushInstalledFile(full_dest_path);
|
||||
|
||||
const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable;
|
||||
const install_step = self.allocator.create(InstallFileStep) catch unreachable;
|
||||
install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
|
||||
return install_step;
|
||||
}
|
||||
|
||||
|
@ -647,7 +656,7 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
|
||||
return os.path.resolve(self.allocator, self.build_root, rel_path) catch unreachable;
|
||||
return os.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {
|
||||
|
@ -670,7 +679,7 @@ pub const Builder = struct {
|
|||
if (os.path.isAbsolute(name)) {
|
||||
return name;
|
||||
}
|
||||
const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
|
||||
const full_path = try os.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
|
@ -683,9 +692,9 @@ pub const Builder = struct {
|
|||
if (os.path.isAbsolute(name)) {
|
||||
return name;
|
||||
}
|
||||
var it = mem.split(PATH, []u8{os.path.delimiter});
|
||||
var it = mem.tokenize(PATH, []u8{os.path.delimiter});
|
||||
while (it.next()) |path| {
|
||||
const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
|
||||
const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
|
@ -699,7 +708,7 @@ pub const Builder = struct {
|
|||
return name;
|
||||
}
|
||||
for (paths) |path| {
|
||||
const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
|
||||
const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
|
@ -865,43 +874,51 @@ pub const LibExeObjStep = struct {
|
|||
};
|
||||
|
||||
pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initC(builder, name, Kind.Lib, version, false);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
|
||||
self.object_src = src;
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable;
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1116,10 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
|
||||
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;
|
||||
return if (self.output_path) |output_path| output_path else os.path.join(
|
||||
self.builder.allocator,
|
||||
[][]const u8{ self.builder.cache_root, self.out_filename },
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
|
||||
|
@ -1112,7 +1132,10 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
|
||||
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;
|
||||
return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(
|
||||
self.builder.allocator,
|
||||
[][]const u8{ self.builder.cache_root, self.out_h_filename },
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
|
||||
|
@ -1212,7 +1235,10 @@ pub const LibExeObjStep = struct {
|
|||
}
|
||||
|
||||
if (self.build_options_contents.len() > 0) {
|
||||
const build_options_file = try os.path.join(builder.allocator, builder.cache_root, builder.fmt("{}_build_options.zig", self.name));
|
||||
const build_options_file = try os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) },
|
||||
);
|
||||
try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst());
|
||||
try zig_args.append("--pkg-begin");
|
||||
try zig_args.append("build_options");
|
||||
|
@ -1462,7 +1488,10 @@ pub const LibExeObjStep = struct {
|
|||
cc_args.append("-c") catch unreachable;
|
||||
cc_args.append(abs_source_file) catch unreachable;
|
||||
|
||||
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
||||
const cache_o_src = os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, source_file },
|
||||
) catch unreachable;
|
||||
if (os.path.dirname(cache_o_src)) |cache_o_dir| {
|
||||
try builder.makePath(cache_o_dir);
|
||||
}
|
||||
|
@ -1514,7 +1543,10 @@ pub const LibExeObjStep = struct {
|
|||
cc_args.append("-current_version") catch unreachable;
|
||||
cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;
|
||||
|
||||
const install_name = builder.pathFromRoot(os.path.join(builder.allocator, builder.cache_root, self.major_only_filename) catch unreachable);
|
||||
const install_name = builder.pathFromRoot(os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, self.major_only_filename },
|
||||
) catch unreachable);
|
||||
cc_args.append("-install_name") catch unreachable;
|
||||
cc_args.append(install_name) catch unreachable;
|
||||
} else {
|
||||
|
@ -1580,7 +1612,10 @@ pub const LibExeObjStep = struct {
|
|||
cc_args.append("-c") catch unreachable;
|
||||
cc_args.append(abs_source_file) catch unreachable;
|
||||
|
||||
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
||||
const cache_o_src = os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.cache_root, source_file },
|
||||
) catch unreachable;
|
||||
if (os.path.dirname(cache_o_src)) |cache_o_dir| {
|
||||
try builder.makePath(cache_o_dir);
|
||||
}
|
||||
|
@ -1672,6 +1707,7 @@ pub const TestStep = struct {
|
|||
no_rosegment: bool,
|
||||
output_path: ?[]const u8,
|
||||
system_linker_hack: bool,
|
||||
override_std_dir: ?[]const u8,
|
||||
|
||||
pub fn init(builder: *Builder, root_src: []const u8) TestStep {
|
||||
const step_name = builder.fmt("test {}", root_src);
|
||||
|
@ -1693,6 +1729,7 @@ pub const TestStep = struct {
|
|||
.no_rosegment = false,
|
||||
.output_path = null,
|
||||
.system_linker_hack = false,
|
||||
.override_std_dir = null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1723,6 +1760,10 @@ pub const TestStep = struct {
|
|||
self.build_mode = mode;
|
||||
}
|
||||
|
||||
pub fn overrideStdDir(self: *TestStep, dir_path: []const u8) void {
|
||||
self.override_std_dir = dir_path;
|
||||
}
|
||||
|
||||
pub fn setOutputPath(self: *TestStep, file_path: []const u8) void {
|
||||
self.output_path = file_path;
|
||||
|
||||
|
@ -1737,7 +1778,10 @@ pub const TestStep = struct {
|
|||
return output_path;
|
||||
} else {
|
||||
const basename = self.builder.fmt("test{}", self.target.exeFileExt());
|
||||
return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable;
|
||||
return os.path.join(
|
||||
self.builder.allocator,
|
||||
[][]const u8{ self.builder.cache_root, basename },
|
||||
) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1900,6 +1944,10 @@ pub const TestStep = struct {
|
|||
if (self.system_linker_hack) {
|
||||
try zig_args.append("--system-linker-hack");
|
||||
}
|
||||
if (self.override_std_dir) |dir| {
|
||||
try zig_args.append("--override-std-dir");
|
||||
try zig_args.append(builder.pathFromRoot(dir));
|
||||
}
|
||||
|
||||
try builder.spawnChild(zig_args.toSliceConst());
|
||||
}
|
||||
|
@ -1914,13 +1962,14 @@ pub const CommandStep = struct {
|
|||
|
||||
/// ::argv is copied.
|
||||
pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
|
||||
const self = builder.allocator.create(CommandStep{
|
||||
const self = builder.allocator.create(CommandStep) catch unreachable;
|
||||
self.* = CommandStep{
|
||||
.builder = builder,
|
||||
.step = Step.init(argv[0], builder.allocator, make),
|
||||
.argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
|
||||
.cwd = cwd,
|
||||
.env_map = env_map,
|
||||
}) catch unreachable;
|
||||
};
|
||||
|
||||
mem.copy([]const u8, self.argv, argv);
|
||||
self.step.name = self.argv[0];
|
||||
|
@ -1949,17 +1998,27 @@ const InstallArtifactStep = struct {
|
|||
LibExeObjStep.Kind.Exe => builder.exe_dir,
|
||||
LibExeObjStep.Kind.Lib => builder.lib_dir,
|
||||
};
|
||||
const self = builder.allocator.create(Self{
|
||||
const self = builder.allocator.create(Self) catch unreachable;
|
||||
self.* = Self{
|
||||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
|
||||
.artifact = artifact,
|
||||
.dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
|
||||
}) catch unreachable;
|
||||
.dest_file = os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ dest_dir, artifact.out_filename },
|
||||
) catch unreachable,
|
||||
};
|
||||
self.step.dependOn(&artifact.step);
|
||||
builder.pushInstalledFile(self.dest_file);
|
||||
if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
|
||||
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable);
|
||||
builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable);
|
||||
builder.pushInstalledFile(os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.lib_dir, artifact.major_only_filename },
|
||||
) catch unreachable);
|
||||
builder.pushInstalledFile(os.path.join(
|
||||
builder.allocator,
|
||||
[][]const u8{ builder.lib_dir, artifact.name_only_filename },
|
||||
) catch unreachable);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -2115,13 +2174,19 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj
|
|||
const out_dir = os.path.dirname(output_path) orelse ".";
|
||||
const out_basename = os.path.basename(output_path);
|
||||
// sym link for libfoo.so.1 to libfoo.so.1.2.3
|
||||
const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
|
||||
const major_only_path = os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ out_dir, filename_major_only },
|
||||
) catch unreachable;
|
||||
os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
|
||||
warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
|
||||
return err;
|
||||
};
|
||||
// sym link for libfoo.so to libfoo.so.1
|
||||
const name_only_path = os.path.join(allocator, out_dir, filename_name_only) catch unreachable;
|
||||
const name_only_path = os.path.join(
|
||||
allocator,
|
||||
[][]const u8{ out_dir, filename_name_only },
|
||||
) catch unreachable;
|
||||
os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
|
||||
warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
|
||||
return err;
|
||||
|
|
|
@ -73,8 +73,8 @@ pub const sockaddr_in6 = extern struct {
|
|||
};
|
||||
|
||||
pub const timeval = extern struct {
|
||||
tv_sec: isize,
|
||||
tv_usec: isize,
|
||||
tv_sec: c_long,
|
||||
tv_usec: i32,
|
||||
};
|
||||
|
||||
pub const timezone = extern struct {
|
||||
|
@ -176,6 +176,24 @@ pub const kevent64_s = extern struct {
|
|||
ext: [2]u64,
|
||||
};
|
||||
|
||||
pub const mach_port_t = c_uint;
|
||||
pub const clock_serv_t = mach_port_t;
|
||||
pub const clock_res_t = c_int;
|
||||
pub const mach_port_name_t = natural_t;
|
||||
pub const natural_t = c_uint;
|
||||
pub const mach_timespec_t = extern struct {
|
||||
tv_sec: c_uint,
|
||||
tv_nsec: clock_res_t,
|
||||
};
|
||||
pub const kern_return_t = c_int;
|
||||
pub const host_t = mach_port_t;
|
||||
pub const CALENDAR_CLOCK = 1;
|
||||
|
||||
pub extern fn mach_host_self() mach_port_t;
|
||||
pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t;
|
||||
pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t;
|
||||
pub extern fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t;
|
||||
|
||||
// sys/types.h on macos uses #pragma pack() so these checks are
|
||||
// to make sure the struct is laid out the same. These values were
|
||||
// produced from C code using the offsetof macro.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const timespec = @import("../os/freebsd/index.zig").timespec;
|
||||
|
||||
extern "c" fn __error() *c_int;
|
||||
pub const _errno = __error;
|
||||
|
||||
|
@ -15,6 +13,17 @@ pub extern "c" fn kevent(
|
|||
pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
|
||||
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
|
||||
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
|
||||
pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
|
||||
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
|
||||
pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
|
||||
pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
|
||||
pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
|
||||
pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
|
||||
pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
|
||||
pub extern "c" fn setuid(uid: c_uint) c_int;
|
||||
pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
|
||||
pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
|
||||
pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
|
||||
|
||||
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
|
||||
pub const Kevent = extern struct {
|
||||
|
@ -31,3 +40,81 @@ pub const pthread_attr_t = extern struct {
|
|||
__size: [56]u8,
|
||||
__align: c_long,
|
||||
};
|
||||
|
||||
pub const msghdr = extern struct {
|
||||
msg_name: *u8,
|
||||
msg_namelen: socklen_t,
|
||||
msg_iov: *iovec,
|
||||
msg_iovlen: i32,
|
||||
__pad1: i32,
|
||||
msg_control: *u8,
|
||||
msg_controllen: socklen_t,
|
||||
__pad2: socklen_t,
|
||||
msg_flags: i32,
|
||||
};
|
||||
|
||||
pub const Stat = extern struct {
|
||||
dev: u64,
|
||||
ino: u64,
|
||||
nlink: usize,
|
||||
|
||||
mode: u16,
|
||||
__pad0: u16,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
__pad1: u32,
|
||||
rdev: u64,
|
||||
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
birthtim: timespec,
|
||||
|
||||
size: i64,
|
||||
blocks: i64,
|
||||
blksize: isize,
|
||||
flags: u32,
|
||||
gen: u64,
|
||||
__spare: [10]u64,
|
||||
};
|
||||
|
||||
pub const timespec = extern struct {
|
||||
tv_sec: isize,
|
||||
tv_nsec: isize,
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_fileno: usize,
|
||||
d_off: i64,
|
||||
d_reclen: u16,
|
||||
d_type: u8,
|
||||
d_pad0: u8,
|
||||
d_namlen: u16,
|
||||
d_pad1: u16,
|
||||
d_name: [256]u8,
|
||||
};
|
||||
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = u16;
|
||||
|
||||
pub const sockaddr = extern union {
|
||||
in: sockaddr_in,
|
||||
in6: sockaddr_in6,
|
||||
};
|
||||
|
||||
pub const sockaddr_in = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
port: in_port_t,
|
||||
addr: [16]u8,
|
||||
zero: [8]u8,
|
||||
};
|
||||
|
||||
pub const sockaddr_in6 = extern struct {
|
||||
len: u8,
|
||||
family: sa_family_t,
|
||||
port: in_port_t,
|
||||
flowinfo: u32,
|
||||
addr: [16]u8,
|
||||
scope_id: u32,
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
|
|||
pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
||||
pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
|
||||
pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
|
||||
pub extern "c" fn gettimeofday(tv: ?*timeval, tz: ?*timezone) c_int;
|
||||
pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
|
||||
pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
|
||||
pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
|
||||
pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
|
||||
|
|
44
std/coff.zig
44
std/coff.zig
|
@ -51,7 +51,7 @@ pub const Coff = struct {
|
|||
|
||||
// Seek to PE File Header (coff header)
|
||||
try self.in_file.seekTo(pe_pointer_offset);
|
||||
const pe_magic_offset = try in.readIntLe(u32);
|
||||
const pe_magic_offset = try in.readIntLittle(u32);
|
||||
try self.in_file.seekTo(pe_magic_offset);
|
||||
|
||||
var pe_header_magic: [4]u8 = undefined;
|
||||
|
@ -60,13 +60,13 @@ pub const Coff = struct {
|
|||
return error.InvalidPEHeader;
|
||||
|
||||
self.coff_header = CoffHeader{
|
||||
.machine = try in.readIntLe(u16),
|
||||
.number_of_sections = try in.readIntLe(u16),
|
||||
.timedate_stamp = try in.readIntLe(u32),
|
||||
.pointer_to_symbol_table = try in.readIntLe(u32),
|
||||
.number_of_symbols = try in.readIntLe(u32),
|
||||
.size_of_optional_header = try in.readIntLe(u16),
|
||||
.characteristics = try in.readIntLe(u16),
|
||||
.machine = try in.readIntLittle(u16),
|
||||
.number_of_sections = try in.readIntLittle(u16),
|
||||
.timedate_stamp = try in.readIntLittle(u32),
|
||||
.pointer_to_symbol_table = try in.readIntLittle(u32),
|
||||
.number_of_symbols = try in.readIntLittle(u32),
|
||||
.size_of_optional_header = try in.readIntLittle(u16),
|
||||
.characteristics = try in.readIntLittle(u16),
|
||||
};
|
||||
|
||||
switch (self.coff_header.machine) {
|
||||
|
@ -79,7 +79,7 @@ pub const Coff = struct {
|
|||
|
||||
fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void {
|
||||
const in = &file_stream.stream;
|
||||
self.pe_header.magic = try in.readIntLe(u16);
|
||||
self.pe_header.magic = try in.readIntLittle(u16);
|
||||
// For now we're only interested in finding the reference to the .pdb,
|
||||
// so we'll skip most of this header, which size is different in 32
|
||||
// 64 bits by the way.
|
||||
|
@ -93,14 +93,14 @@ pub const Coff = struct {
|
|||
|
||||
try self.in_file.seekForward(skip_size);
|
||||
|
||||
const number_of_rva_and_sizes = try in.readIntLe(u32);
|
||||
const number_of_rva_and_sizes = try in.readIntLittle(u32);
|
||||
if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
|
||||
return error.InvalidPEHeader;
|
||||
|
||||
for (self.pe_header.data_directory) |*data_dir| {
|
||||
data_dir.* = OptionalHeader.DataDirectory{
|
||||
.virtual_address = try in.readIntLe(u32),
|
||||
.size = try in.readIntLe(u32),
|
||||
.virtual_address = try in.readIntLittle(u32),
|
||||
.size = try in.readIntLittle(u32),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ pub const Coff = struct {
|
|||
if (!mem.eql(u8, cv_signature, "RSDS"))
|
||||
return error.InvalidPEMagic;
|
||||
try in.readNoEof(self.guid[0..]);
|
||||
self.age = try in.readIntLe(u32);
|
||||
self.age = try in.readIntLittle(u32);
|
||||
|
||||
// Finally read the null-terminated string.
|
||||
var byte = try in.readByte();
|
||||
|
@ -157,15 +157,15 @@ pub const Coff = struct {
|
|||
try self.sections.append(Section{
|
||||
.header = SectionHeader{
|
||||
.name = name,
|
||||
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) },
|
||||
.virtual_address = try in.readIntLe(u32),
|
||||
.size_of_raw_data = try in.readIntLe(u32),
|
||||
.pointer_to_raw_data = try in.readIntLe(u32),
|
||||
.pointer_to_relocations = try in.readIntLe(u32),
|
||||
.pointer_to_line_numbers = try in.readIntLe(u32),
|
||||
.number_of_relocations = try in.readIntLe(u16),
|
||||
.number_of_line_numbers = try in.readIntLe(u16),
|
||||
.characteristics = try in.readIntLe(u32),
|
||||
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) },
|
||||
.virtual_address = try in.readIntLittle(u32),
|
||||
.size_of_raw_data = try in.readIntLittle(u32),
|
||||
.pointer_to_raw_data = try in.readIntLittle(u32),
|
||||
.pointer_to_relocations = try in.readIntLittle(u32),
|
||||
.pointer_to_line_numbers = try in.readIntLittle(u32),
|
||||
.number_of_relocations = try in.readIntLittle(u16),
|
||||
.number_of_line_numbers = try in.readIntLittle(u16),
|
||||
.characteristics = try in.readIntLittle(u32),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type {
|
|||
const rr = d.h[0 .. out_len / 32];
|
||||
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type {
|
|||
var v: [16]u32 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
|
@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type {
|
|||
const rr = d.h[0 .. out_len / 64];
|
||||
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type {
|
|||
var v: [16]u64 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]);
|
||||
r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
|
|
|
@ -4,6 +4,7 @@ const std = @import("../index.zig");
|
|||
const mem = std.mem;
|
||||
const endian = std.endian;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const builtin = @import("builtin");
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
|
@ -59,7 +60,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
|
|||
}
|
||||
|
||||
for (x) |_, i| {
|
||||
mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo
|
|||
|
||||
const c = "expand 32-byte k";
|
||||
const constant_le = []u32{
|
||||
mem.readIntLE(u32, c[0..4]),
|
||||
mem.readIntLE(u32, c[4..8]),
|
||||
mem.readIntLE(u32, c[8..12]),
|
||||
mem.readIntLE(u32, c[12..16]),
|
||||
mem.readIntSliceLittle(u32, c[0..4]),
|
||||
mem.readIntSliceLittle(u32, c[4..8]),
|
||||
mem.readIntSliceLittle(u32, c[8..12]),
|
||||
mem.readIntSliceLittle(u32, c[12..16]),
|
||||
};
|
||||
|
||||
mem.copy(u32, ctx[0..], constant_le[0..4]);
|
||||
|
@ -117,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
|
|||
var k: [8]u32 = undefined;
|
||||
var c: [4]u32 = undefined;
|
||||
|
||||
k[0] = mem.readIntLE(u32, key[0..4]);
|
||||
k[1] = mem.readIntLE(u32, key[4..8]);
|
||||
k[2] = mem.readIntLE(u32, key[8..12]);
|
||||
k[3] = mem.readIntLE(u32, key[12..16]);
|
||||
k[4] = mem.readIntLE(u32, key[16..20]);
|
||||
k[5] = mem.readIntLE(u32, key[20..24]);
|
||||
k[6] = mem.readIntLE(u32, key[24..28]);
|
||||
k[7] = mem.readIntLE(u32, key[28..32]);
|
||||
k[0] = mem.readIntSliceLittle(u32, key[0..4]);
|
||||
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
|
||||
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
|
||||
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
|
||||
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
|
||||
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
|
||||
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
|
||||
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
|
||||
|
||||
c[0] = counter;
|
||||
c[1] = mem.readIntLE(u32, nonce[0..4]);
|
||||
c[2] = mem.readIntLE(u32, nonce[4..8]);
|
||||
c[3] = mem.readIntLE(u32, nonce[8..12]);
|
||||
c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);
|
||||
c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);
|
||||
c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);
|
||||
chaCha20_internal(out, in, k, c);
|
||||
}
|
||||
|
||||
|
@ -144,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
|
|||
var k: [8]u32 = undefined;
|
||||
var c: [4]u32 = undefined;
|
||||
|
||||
k[0] = mem.readIntLE(u32, key[0..4]);
|
||||
k[1] = mem.readIntLE(u32, key[4..8]);
|
||||
k[2] = mem.readIntLE(u32, key[8..12]);
|
||||
k[3] = mem.readIntLE(u32, key[12..16]);
|
||||
k[4] = mem.readIntLE(u32, key[16..20]);
|
||||
k[5] = mem.readIntLE(u32, key[20..24]);
|
||||
k[6] = mem.readIntLE(u32, key[24..28]);
|
||||
k[7] = mem.readIntLE(u32, key[28..32]);
|
||||
k[0] = mem.readIntSliceLittle(u32, key[0..4]);
|
||||
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
|
||||
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
|
||||
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
|
||||
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
|
||||
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
|
||||
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
|
||||
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
|
||||
|
||||
c[0] = @truncate(u32, counter);
|
||||
c[1] = @truncate(u32, counter >> 32);
|
||||
c[2] = mem.readIntLE(u32, nonce[0..4]);
|
||||
c[3] = mem.readIntLE(u32, nonce[4..8]);
|
||||
c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);
|
||||
c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);
|
||||
|
||||
const block_size = (1 << 6);
|
||||
const big_block = (block_size << 32);
|
||||
|
@ -215,12 +217,12 @@ test "crypto.chacha20 test vector sunscreen" {
|
|||
};
|
||||
|
||||
chaCha20IETF(result[0..], input[0..], 1, key, nonce);
|
||||
assert(mem.eql(u8, expected_result, result));
|
||||
testing.expectEqualSlices(u8, expected_result, result);
|
||||
|
||||
// Chacha20 is self-reversing.
|
||||
var plaintext: [114]u8 = undefined;
|
||||
chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce);
|
||||
assert(mem.compare(u8, input, plaintext) == mem.Compare.Equal);
|
||||
testing.expect(mem.compare(u8, input, plaintext) == mem.Compare.Equal);
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
|
||||
|
@ -255,7 +257,7 @@ test "crypto.chacha20 test vector 1" {
|
|||
const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
|
||||
assert(mem.eql(u8, expected_result, result));
|
||||
testing.expectEqualSlices(u8, expected_result, result);
|
||||
}
|
||||
|
||||
test "crypto.chacha20 test vector 2" {
|
||||
|
@ -289,7 +291,7 @@ test "crypto.chacha20 test vector 2" {
|
|||
const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
|
||||
assert(mem.eql(u8, expected_result, result));
|
||||
testing.expectEqualSlices(u8, expected_result, result);
|
||||
}
|
||||
|
||||
test "crypto.chacha20 test vector 3" {
|
||||
|
@ -323,7 +325,7 @@ test "crypto.chacha20 test vector 3" {
|
|||
const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
|
||||
assert(mem.eql(u8, expected_result, result));
|
||||
testing.expectEqualSlices(u8, expected_result, result);
|
||||
}
|
||||
|
||||
test "crypto.chacha20 test vector 4" {
|
||||
|
@ -357,7 +359,7 @@ test "crypto.chacha20 test vector 4" {
|
|||
const nonce = []u8{ 1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
|
||||
assert(mem.eql(u8, expected_result, result));
|
||||
testing.expectEqualSlices(u8, expected_result, result);
|
||||
}
|
||||
|
||||
test "crypto.chacha20 test vector 5" {
|
||||
|
@ -429,5 +431,5 @@ test "crypto.chacha20 test vector 5" {
|
|||
};
|
||||
|
||||
chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
|
||||
assert(mem.eql(u8, expected_result, result));
|
||||
testing.expectEqualSlices(u8, expected_result, result);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,8 @@ pub const Md5 = struct {
|
|||
d.round(d.buf[0..]);
|
||||
|
||||
for (d.s) |s, j| {
|
||||
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ const std = @import("../index.zig");
|
|||
const builtin = @import("builtin");
|
||||
|
||||
const Endian = builtin.Endian;
|
||||
const readInt = std.mem.readInt;
|
||||
const writeInt = std.mem.writeInt;
|
||||
const readIntSliceLittle = std.mem.readIntSliceLittle;
|
||||
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
|
||||
|
||||
pub const Poly1305 = struct {
|
||||
const Self = @This();
|
||||
|
@ -59,19 +59,19 @@ pub const Poly1305 = struct {
|
|||
{
|
||||
var i: usize = 0;
|
||||
while (i < 1) : (i += 1) {
|
||||
ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff;
|
||||
ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;
|
||||
}
|
||||
}
|
||||
{
|
||||
var i: usize = 1;
|
||||
while (i < 4) : (i += 1) {
|
||||
ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc;
|
||||
ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;
|
||||
}
|
||||
}
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < 4) : (i += 1) {
|
||||
ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little);
|
||||
ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,10 +168,10 @@ pub const Poly1305 = struct {
|
|||
const nb_blocks = nmsg.len >> 4;
|
||||
var i: usize = 0;
|
||||
while (i < nb_blocks) : (i += 1) {
|
||||
ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little);
|
||||
ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little);
|
||||
ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little);
|
||||
ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little);
|
||||
ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);
|
||||
ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);
|
||||
ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);
|
||||
ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);
|
||||
polyBlock(ctx);
|
||||
nmsg = nmsg[16..];
|
||||
}
|
||||
|
@ -210,10 +210,11 @@ pub const Poly1305 = struct {
|
|||
const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
|
||||
const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
|
||||
|
||||
writeInt(out[0..], @truncate(u32, uu0), Endian.Little);
|
||||
writeInt(out[4..], @truncate(u32, uu1), Endian.Little);
|
||||
writeInt(out[8..], @truncate(u32, uu2), Endian.Little);
|
||||
writeInt(out[12..], @truncate(u32, uu3), Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));
|
||||
writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));
|
||||
writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));
|
||||
writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
|
||||
|
||||
ctx.secureZero();
|
||||
}
|
||||
|
@ -229,5 +230,5 @@ test "poly1305 rfc7439 vector1" {
|
|||
var mac: [16]u8 = undefined;
|
||||
Poly1305.create(mac[0..], msg, key);
|
||||
|
||||
std.debug.assert(std.mem.eql(u8, mac, expected_mac));
|
||||
std.testing.expectEqualSlices(u8, expected_mac, mac);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,8 @@ pub const Sha1 = struct {
|
|||
d.round(d.buf[0..]);
|
||||
|
||||
for (d.s) |s, j| {
|
||||
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type {
|
|||
const rr = d.s[0 .. params.out_len / 32];
|
||||
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type {
|
|||
const rr = d.s[0 .. params.out_len / 64];
|
||||
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
|
|||
var c = []const u64{0} ** 5;
|
||||
|
||||
for (s) |*r, i| {
|
||||
r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]);
|
||||
r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]);
|
||||
}
|
||||
|
||||
comptime var x: usize = 0;
|
||||
|
@ -167,7 +167,8 @@ fn keccak_f(comptime F: usize, d: []u8) void {
|
|||
}
|
||||
|
||||
for (s) |r, i| {
|
||||
mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const debug = @import("../debug/index.zig");
|
||||
const mem = @import("../mem.zig");
|
||||
const fmt = @import("../fmt/index.zig");
|
||||
const std = @import("../index.zig");
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const fmt = std.fmt;
|
||||
|
||||
// Hash using the specified hasher `H` asserting `expected == H(input)`.
|
||||
pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, input: []const u8) void {
|
||||
|
@ -17,5 +18,5 @@ pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
|
|||
r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable;
|
||||
}
|
||||
|
||||
debug.assert(mem.eql(u8, expected_bytes, input));
|
||||
testing.expectEqualSlices(u8, expected_bytes, input);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ const builtin = @import("builtin");
|
|||
const fmt = std.fmt;
|
||||
|
||||
const Endian = builtin.Endian;
|
||||
const readInt = std.mem.readInt;
|
||||
const writeInt = std.mem.writeInt;
|
||||
const readIntSliceLittle = std.mem.readIntSliceLittle;
|
||||
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
|
||||
|
||||
// Based on Supercop's ref10 implementation.
|
||||
pub const X25519 = struct {
|
||||
|
@ -255,16 +255,16 @@ const Fe = struct {
|
|||
|
||||
var t: [10]i64 = undefined;
|
||||
|
||||
t[0] = readInt(s[0..4], u32, Endian.Little);
|
||||
t[1] = readInt(s[4..7], u32, Endian.Little) << 6;
|
||||
t[2] = readInt(s[7..10], u32, Endian.Little) << 5;
|
||||
t[3] = readInt(s[10..13], u32, Endian.Little) << 3;
|
||||
t[4] = readInt(s[13..16], u32, Endian.Little) << 2;
|
||||
t[5] = readInt(s[16..20], u32, Endian.Little);
|
||||
t[6] = readInt(s[20..23], u32, Endian.Little) << 7;
|
||||
t[7] = readInt(s[23..26], u32, Endian.Little) << 5;
|
||||
t[8] = readInt(s[26..29], u32, Endian.Little) << 4;
|
||||
t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2;
|
||||
t[0] = readIntSliceLittle(u32, s[0..4]);
|
||||
t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6;
|
||||
t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5;
|
||||
t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3;
|
||||
t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2;
|
||||
t[5] = readIntSliceLittle(u32, s[16..20]);
|
||||
t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7;
|
||||
t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5;
|
||||
t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4;
|
||||
t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2;
|
||||
|
||||
carry1(h, t[0..]);
|
||||
}
|
||||
|
@ -544,14 +544,15 @@ const Fe = struct {
|
|||
ut[i] = @bitCast(u32, @intCast(i32, t[i]));
|
||||
}
|
||||
|
||||
writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little);
|
||||
writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little);
|
||||
writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little);
|
||||
writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little);
|
||||
writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little);
|
||||
writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little);
|
||||
writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little);
|
||||
writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
|
||||
writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
|
||||
writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
|
||||
writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
|
||||
writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
|
||||
writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
|
||||
writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
|
||||
writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6));
|
||||
|
||||
std.mem.secureZero(i64, t[0..]);
|
||||
}
|
||||
|
@ -580,8 +581,8 @@ test "x25519 public key calculation from secret key" {
|
|||
var pk_calculated: [32]u8 = undefined;
|
||||
try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
|
||||
try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");
|
||||
std.debug.assert(X25519.createPublicKey(pk_calculated[0..], sk));
|
||||
std.debug.assert(std.mem.eql(u8, pk_calculated, pk_expected));
|
||||
std.testing.expect(X25519.createPublicKey(pk_calculated[0..], sk));
|
||||
std.testing.expect(std.mem.eql(u8, pk_calculated, pk_expected));
|
||||
}
|
||||
|
||||
test "x25519 rfc7748 vector1" {
|
||||
|
@ -592,8 +593,8 @@ test "x25519 rfc7748 vector1" {
|
|||
|
||||
var output: [32]u8 = undefined;
|
||||
|
||||
std.debug.assert(X25519.create(output[0..], secret_key, public_key));
|
||||
std.debug.assert(std.mem.eql(u8, output, expected_output));
|
||||
std.testing.expect(X25519.create(output[0..], secret_key, public_key));
|
||||
std.testing.expect(std.mem.eql(u8, output, expected_output));
|
||||
}
|
||||
|
||||
test "x25519 rfc7748 vector2" {
|
||||
|
@ -604,8 +605,8 @@ test "x25519 rfc7748 vector2" {
|
|||
|
||||
var output: [32]u8 = undefined;
|
||||
|
||||
std.debug.assert(X25519.create(output[0..], secret_key, public_key));
|
||||
std.debug.assert(std.mem.eql(u8, output, expected_output));
|
||||
std.testing.expect(X25519.create(output[0..], secret_key, public_key));
|
||||
std.testing.expect(std.mem.eql(u8, output, expected_output));
|
||||
}
|
||||
|
||||
test "x25519 rfc7748 one iteration" {
|
||||
|
@ -618,13 +619,13 @@ test "x25519 rfc7748 one iteration" {
|
|||
var i: usize = 0;
|
||||
while (i < 1) : (i += 1) {
|
||||
var output: [32]u8 = undefined;
|
||||
std.debug.assert(X25519.create(output[0..], k, u));
|
||||
std.testing.expect(X25519.create(output[0..], k, u));
|
||||
|
||||
std.mem.copy(u8, u[0..], k[0..]);
|
||||
std.mem.copy(u8, k[0..], output[0..]);
|
||||
}
|
||||
|
||||
std.debug.assert(std.mem.eql(u8, k[0..], expected_output));
|
||||
std.testing.expect(std.mem.eql(u8, k[0..], expected_output));
|
||||
}
|
||||
|
||||
test "x25519 rfc7748 1,000 iterations" {
|
||||
|
@ -642,13 +643,13 @@ test "x25519 rfc7748 1,000 iterations" {
|
|||
var i: usize = 0;
|
||||
while (i < 1000) : (i += 1) {
|
||||
var output: [32]u8 = undefined;
|
||||
std.debug.assert(X25519.create(output[0..], k, u));
|
||||
std.testing.expect(X25519.create(output[0..], k, u));
|
||||
|
||||
std.mem.copy(u8, u[0..], k[0..]);
|
||||
std.mem.copy(u8, k[0..], output[0..]);
|
||||
}
|
||||
|
||||
std.debug.assert(std.mem.eql(u8, k[0..], expected_output));
|
||||
std.testing.expect(std.mem.eql(u8, k[0..], expected_output));
|
||||
}
|
||||
|
||||
test "x25519 rfc7748 1,000,000 iterations" {
|
||||
|
@ -665,11 +666,11 @@ test "x25519 rfc7748 1,000,000 iterations" {
|
|||
var i: usize = 0;
|
||||
while (i < 1000000) : (i += 1) {
|
||||
var output: [32]u8 = undefined;
|
||||
std.debug.assert(X25519.create(output[0..], k, u));
|
||||
std.testing.expect(X25519.create(output[0..], k, u));
|
||||
|
||||
std.mem.copy(u8, u[0..], k[0..]);
|
||||
std.mem.copy(u8, k[0..], output[0..]);
|
||||
}
|
||||
|
||||
std.debug.assert(std.mem.eql(u8, k[0..], expected_output));
|
||||
std.testing.expect(std.mem.eql(u8, k[0..], expected_output));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("index.zig");
|
|||
const builtin = @import("builtin");
|
||||
const debug = std.debug;
|
||||
const mem = std.mem;
|
||||
const assert = debug.assert;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const line_sep = switch (builtin.os) {
|
||||
builtin.Os.windows => "\r\n",
|
||||
|
@ -42,8 +42,8 @@ test "cstr fns" {
|
|||
}
|
||||
|
||||
fn testCStrFnsImpl() void {
|
||||
assert(cmp(c"aoeu", c"aoez") == -1);
|
||||
assert(len(c"123456789") == 9);
|
||||
testing.expect(cmp(c"aoeu", c"aoez") == -1);
|
||||
testing.expect(len(c"123456789") == 9);
|
||||
}
|
||||
|
||||
/// Returns a mutable slice with 1 more byte of length which is a null byte.
|
||||
|
|
|
@ -37,7 +37,6 @@ const Module = struct {
|
|||
var stderr_file: os.File = undefined;
|
||||
var stderr_file_out_stream: os.File.OutStream = undefined;
|
||||
|
||||
/// TODO multithreaded awareness
|
||||
var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
|
||||
var stderr_mutex = std.Mutex.init();
|
||||
pub fn warn(comptime fmt: []const u8, args: ...) void {
|
||||
|
@ -108,37 +107,15 @@ pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {
|
|||
/// This function invokes undefined behavior when `ok` is `false`.
|
||||
/// In Debug and ReleaseSafe modes, calls to this function are always
|
||||
/// generated, and the `unreachable` statement triggers a panic.
|
||||
/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
|
||||
/// optimized away.
|
||||
/// In ReleaseFast and ReleaseSmall modes, calls to this function are
|
||||
/// optimized away, and in fact the optimizer is able to use the assertion
|
||||
/// in its heuristics.
|
||||
/// Inside a test block, it is best to use the `std.testing` module rather
|
||||
/// than this function, because this function may not detect a test failure
|
||||
/// in ReleaseFast and ReleaseSafe mode. Outside of a test block, this assert
|
||||
/// function is the correct function to use.
|
||||
pub fn assert(ok: bool) void {
|
||||
if (!ok) {
|
||||
// In ReleaseFast test mode, we still want assert(false) to crash, so
|
||||
// we insert an explicit call to @panic instead of unreachable.
|
||||
// TODO we should use `assertOrPanic` in tests and remove this logic.
|
||||
if (builtin.is_test) {
|
||||
@panic("assertion failure");
|
||||
} else {
|
||||
unreachable; // assertion failure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: add `==` operator for `error_union == error_set`, and then
|
||||
/// remove this function
|
||||
pub fn assertError(value: var, expected_error: anyerror) void {
|
||||
if (value) {
|
||||
@panic("expected error");
|
||||
} else |actual_error| {
|
||||
assert(actual_error == expected_error);
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this function when you want to panic if the condition is not true.
|
||||
/// If `ok` is `false`, this function will panic in every release mode.
|
||||
pub fn assertOrPanic(ok: bool) void {
|
||||
if (!ok) {
|
||||
@panic("assertion failure");
|
||||
}
|
||||
if (!ok) unreachable; // assertion failure
|
||||
}
|
||||
|
||||
pub fn panic(comptime format: []const u8, args: ...) noreturn {
|
||||
|
@ -247,8 +224,7 @@ pub fn writeCurrentStackTraceWindows(
|
|||
start_addr: ?usize,
|
||||
) !void {
|
||||
var addr_buf: [1024]usize = undefined;
|
||||
const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast
|
||||
const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null);
|
||||
const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
|
||||
const addrs = addr_buf[0..n];
|
||||
var start_i: usize = if (start_addr) |saddr| blk: {
|
||||
for (addrs) |addr, i| {
|
||||
|
@ -264,7 +240,7 @@ pub fn writeCurrentStackTraceWindows(
|
|||
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
|
||||
builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
|
||||
builtin.Os.linux, builtin.Os.freebsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
|
||||
builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
|
||||
else => return error.UnsupportedOperatingSystem,
|
||||
}
|
||||
|
@ -338,50 +314,74 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
|||
|
||||
switch (subsect_hdr.Kind) {
|
||||
pdb.DebugSubsectionKind.Lines => {
|
||||
var line_index: usize = sect_offset;
|
||||
var line_index = sect_offset;
|
||||
|
||||
const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
|
||||
if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
|
||||
line_index += @sizeOf(pdb.LineFragmentHeader);
|
||||
|
||||
const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
|
||||
line_index += @sizeOf(pdb.LineBlockFragmentHeader);
|
||||
|
||||
const has_column = line_hdr.Flags.LF_HaveColumns;
|
||||
|
||||
const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
|
||||
const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
|
||||
if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
|
||||
var line_i: usize = 0;
|
||||
|
||||
// There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
|
||||
// from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
|
||||
// breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
|
||||
const subsection_end_index = sect_offset + subsect_hdr.Length;
|
||||
while (line_index < subsection_end_index) {
|
||||
const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
|
||||
line_index += @sizeOf(pdb.LineBlockFragmentHeader);
|
||||
const start_line_index = line_index;
|
||||
while (line_i < block_hdr.NumLines) : (line_i += 1) {
|
||||
const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
|
||||
line_index += @sizeOf(pdb.LineNumberEntry);
|
||||
const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
|
||||
const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
|
||||
const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
|
||||
if (relative_address >= vaddr_start and relative_address < vaddr_end) {
|
||||
|
||||
const has_column = line_hdr.Flags.LF_HaveColumns;
|
||||
|
||||
if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
|
||||
// All line entries are stored inside their line block by ascending start address.
|
||||
// Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address.
|
||||
// This is done with a simple linear search.
|
||||
var line_i: u32 = 0;
|
||||
while (line_i < block_hdr.NumLines) : (line_i += 1) {
|
||||
const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
|
||||
line_index += @sizeOf(pdb.LineNumberEntry);
|
||||
|
||||
const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
|
||||
if (relative_address <= vaddr_start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// line_i == 0 would mean that no matching LineNumberEntry was found.
|
||||
if (line_i > 0) {
|
||||
const subsect_index = checksum_offset + block_hdr.NameIndex;
|
||||
const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
|
||||
const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
|
||||
try di.pdb.string_table.seekTo(strtab_offset);
|
||||
const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
|
||||
const line = flags.Start;
|
||||
|
||||
const line_entry_idx = line_i - 1;
|
||||
|
||||
const column = if (has_column) blk: {
|
||||
line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
|
||||
line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i;
|
||||
const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]);
|
||||
const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
|
||||
const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
|
||||
const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
|
||||
break :blk col_num_entry.StartColumn;
|
||||
} else 0;
|
||||
|
||||
const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
|
||||
const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
|
||||
const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
|
||||
|
||||
break :subsections LineInfo{
|
||||
.allocator = allocator,
|
||||
.file_name = source_file_name,
|
||||
.line = line,
|
||||
.line = flags.Start,
|
||||
.column = column,
|
||||
};
|
||||
}
|
||||
}
|
||||
break :subsections null;
|
||||
}
|
||||
|
||||
// Checking that we are not reading garbage after the (possibly) multiple block fragments.
|
||||
if (line_index != subsection_end_index) {
|
||||
return error.InvalidDebugInfo;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
|
@ -523,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void {
|
|||
|
||||
const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
|
||||
|
||||
const signature = try modi.stream.readIntLe(u32);
|
||||
const signature = try modi.stream.readIntLittle(u32);
|
||||
if (signature != 4)
|
||||
return error.InvalidDebugInfo;
|
||||
|
||||
|
@ -717,7 +717,7 @@ pub const OpenSelfDebugInfoError = error{
|
|||
|
||||
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.linux => return openSelfDebugInfoLinux(allocator),
|
||||
builtin.Os.linux, builtin.Os.freebsd => return openSelfDebugInfoLinux(allocator),
|
||||
builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
|
||||
builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
|
||||
else => return error.UnsupportedOperatingSystem,
|
||||
|
@ -728,7 +728,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
const self_file = try os.openSelfExe();
|
||||
defer self_file.close();
|
||||
|
||||
const coff_obj = try allocator.createOne(coff.Coff);
|
||||
const coff_obj = try allocator.create(coff.Coff);
|
||||
coff_obj.* = coff.Coff{
|
||||
.in_file = self_file,
|
||||
.allocator = allocator,
|
||||
|
@ -752,14 +752,14 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
const len = try di.coff.getPdbPath(path_buf[0..]);
|
||||
const raw_path = path_buf[0..len];
|
||||
|
||||
const path = try os.path.resolve(allocator, raw_path);
|
||||
const path = try os.path.resolve(allocator, [][]const u8{raw_path});
|
||||
|
||||
try di.pdb.openFile(di.coff, path);
|
||||
|
||||
var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
|
||||
const version = try pdb_stream.stream.readIntLe(u32);
|
||||
const signature = try pdb_stream.stream.readIntLe(u32);
|
||||
const age = try pdb_stream.stream.readIntLe(u32);
|
||||
const version = try pdb_stream.stream.readIntLittle(u32);
|
||||
const signature = try pdb_stream.stream.readIntLittle(u32);
|
||||
const age = try pdb_stream.stream.readIntLittle(u32);
|
||||
var guid: [16]u8 = undefined;
|
||||
try pdb_stream.stream.readNoEof(guid[0..]);
|
||||
if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
|
||||
|
@ -767,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
// We validated the executable and pdb match.
|
||||
|
||||
const string_table_index = str_tab_index: {
|
||||
const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
|
||||
const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
|
||||
const name_bytes = try allocator.alloc(u8, name_bytes_len);
|
||||
try pdb_stream.stream.readNoEof(name_bytes);
|
||||
|
||||
|
@ -797,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
};
|
||||
const bucket_list = try allocator.alloc(Bucket, present.len);
|
||||
for (present) |_| {
|
||||
const name_offset = try pdb_stream.stream.readIntLe(u32);
|
||||
const name_index = try pdb_stream.stream.readIntLe(u32);
|
||||
const name_offset = try pdb_stream.stream.readIntLittle(u32);
|
||||
const name_index = try pdb_stream.stream.readIntLittle(u32);
|
||||
const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
|
||||
if (mem.eql(u8, name, "/names")) {
|
||||
break :str_tab_index name_index;
|
||||
|
@ -859,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
|
||||
var sect_cont_offset: usize = 0;
|
||||
if (section_contrib_size != 0) {
|
||||
const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
|
||||
const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
|
||||
if (ver != pdb.SectionContrSubstreamVersion.Ver60)
|
||||
return error.InvalidDebugInfo;
|
||||
sect_cont_offset += @sizeOf(u32);
|
||||
|
@ -879,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
}
|
||||
|
||||
fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
|
||||
const num_words = try stream.readIntLe(u32);
|
||||
const num_words = try stream.readIntLittle(u32);
|
||||
var word_i: usize = 0;
|
||||
var list = ArrayList(usize).init(allocator);
|
||||
while (word_i != num_words) : (word_i += 1) {
|
||||
const word = try stream.readIntLe(u32);
|
||||
const word = try stream.readIntLittle(u32);
|
||||
var bit_i: u5 = 0;
|
||||
while (true) : (bit_i += 1) {
|
||||
if (word & (u32(1) << bit_i) != 0) {
|
||||
|
@ -1013,7 +1013,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
const sentinel = try allocator.createOne(macho.nlist_64);
|
||||
const sentinel = try allocator.create(macho.nlist_64);
|
||||
sentinel.* = macho.nlist_64{
|
||||
.n_strx = 0,
|
||||
.n_type = 36,
|
||||
|
@ -1135,14 +1135,13 @@ pub const DebugInfo = switch (builtin.os) {
|
|||
return self.ofiles.allocator;
|
||||
}
|
||||
},
|
||||
builtin.Os.windows => struct {
|
||||
builtin.Os.uefi, builtin.Os.windows => struct {
|
||||
pdb: pdb.Pdb,
|
||||
coff: *coff.Coff,
|
||||
sect_contribs: []pdb.SectionContribEntry,
|
||||
modules: []Module,
|
||||
},
|
||||
builtin.Os.linux => DwarfInfo,
|
||||
builtin.Os.freebsd => struct {},
|
||||
builtin.Os.linux, builtin.Os.freebsd => DwarfInfo,
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
|
||||
|
@ -1200,7 +1199,7 @@ const Constant = struct {
|
|||
fn asUnsignedLe(self: *const Constant) !u64 {
|
||||
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
|
||||
if (self.signed) return error.InvalidDebugInfo;
|
||||
return mem.readInt(self.payload, u64, builtin.Endian.Little);
|
||||
return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1331,7 +1330,7 @@ const LineNumberProgram = struct {
|
|||
return error.InvalidDebugInfo;
|
||||
} else
|
||||
self.include_dirs[file_entry.dir_index];
|
||||
const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
|
||||
const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
|
||||
errdefer self.file_entries.allocator.free(file_name);
|
||||
return LineInfo{
|
||||
.line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
|
||||
|
@ -1381,7 +1380,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize
|
|||
}
|
||||
|
||||
fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||
const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);
|
||||
const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
|
||||
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
||||
}
|
||||
|
||||
|
@ -1395,11 +1394,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
|
|||
}
|
||||
|
||||
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
|
||||
return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
|
||||
return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
|
||||
}
|
||||
|
||||
fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
|
||||
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
|
||||
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
|
||||
}
|
||||
|
||||
fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||
|
@ -1408,7 +1407,7 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize)
|
|||
}
|
||||
|
||||
fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
|
||||
const block_len = try in_stream.readIntLe(T);
|
||||
const block_len = try in_stream.readIntLittle(T);
|
||||
return parseFormValueRefLen(allocator, in_stream, block_len);
|
||||
}
|
||||
|
||||
|
@ -1450,7 +1449,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
|
|||
},
|
||||
|
||||
DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
|
||||
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
|
||||
|
||||
DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
|
||||
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
|
@ -1747,11 +1746,11 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
|
|||
continue;
|
||||
}
|
||||
|
||||
const version = try di.dwarf_in_stream.readInt(di.endian, u16);
|
||||
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
// TODO support 3 and 5
|
||||
if (version != 2 and version != 4) return error.InvalidDebugInfo;
|
||||
|
||||
const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32);
|
||||
const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
|
||||
const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
|
||||
|
||||
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
|
||||
|
@ -1820,7 +1819,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
|
|||
return error.MissingDebugInfo;
|
||||
},
|
||||
DW.LNE_set_address => {
|
||||
const addr = try di.dwarf_in_stream.readInt(di.endian, usize);
|
||||
const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
|
||||
prog.address = addr;
|
||||
},
|
||||
DW.LNE_define_file => {
|
||||
|
@ -1882,7 +1881,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
|
|||
prog.address += inc_addr;
|
||||
},
|
||||
DW.LNS_fixed_advance_pc => {
|
||||
const arg = try di.dwarf_in_stream.readInt(di.endian, u16);
|
||||
const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
prog.address += arg;
|
||||
},
|
||||
DW.LNS_set_prologue_end => {},
|
||||
|
@ -1914,10 +1913,10 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
|
|||
if (unit_length == 0) return;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
||||
const version = try di.dwarf_in_stream.readInt(di.endian, u16);
|
||||
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
if (version < 2 or version > 5) return error.InvalidDebugInfo;
|
||||
|
||||
const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32);
|
||||
const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
|
||||
|
||||
const address_size = try di.dwarf_in_stream.readByte();
|
||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||
|
@ -1927,7 +1926,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
|
|||
|
||||
try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
|
||||
|
||||
const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64));
|
||||
const compile_unit_die = try di.allocator().create(Die);
|
||||
compile_unit_die.* = try parseDie(di, abbrev_table, is_64);
|
||||
|
||||
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
|
||||
|
||||
|
@ -1978,8 +1978,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
|
|||
if (di.debug_ranges) |debug_ranges| {
|
||||
try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
|
||||
while (true) {
|
||||
const begin_addr = try di.dwarf_in_stream.readIntLe(usize);
|
||||
const end_addr = try di.dwarf_in_stream.readIntLe(usize);
|
||||
const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
|
||||
const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
|
||||
if (begin_addr == 0 and end_addr == 0) {
|
||||
break;
|
||||
}
|
||||
|
@ -2001,7 +2001,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
|
|||
}
|
||||
|
||||
fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
|
||||
const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian);
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
|
||||
ptr.* += @sizeOf(T);
|
||||
return result;
|
||||
}
|
||||
|
@ -2017,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 {
|
|||
}
|
||||
|
||||
fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
|
||||
const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]);
|
||||
// TODO this code can be improved with https://github.com/ziglang/zig/issues/863
|
||||
const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
|
||||
is_64.* = (first_32_bits == 0xffffffff);
|
||||
if (is_64.*) {
|
||||
ptr.* += 4;
|
||||
const result = mem.readIntLE(u64, ptr.*[0..8]);
|
||||
const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
|
||||
ptr.* += 8;
|
||||
return result;
|
||||
} else {
|
||||
|
@ -2084,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 {
|
|||
}
|
||||
|
||||
fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
|
||||
const first_32_bits = try in_stream.readIntLe(u32);
|
||||
const first_32_bits = try in_stream.readIntLittle(u32);
|
||||
is_64.* = (first_32_bits == 0xffffffff);
|
||||
if (is_64.*) {
|
||||
return in_stream.readIntLe(u64);
|
||||
return in_stream.readIntLittle(u64);
|
||||
} else {
|
||||
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
||||
return u64(first_32_bits);
|
||||
|
|
|
@ -6,6 +6,7 @@ const mem = std.mem;
|
|||
const cstr = std.cstr;
|
||||
const os = std.os;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const elf = std.elf;
|
||||
const linux = os.linux;
|
||||
const windows = os.windows;
|
||||
|
@ -19,7 +20,6 @@ pub const DynLib = switch (builtin.os) {
|
|||
};
|
||||
|
||||
pub const LinuxDynLib = struct {
|
||||
allocator: *mem.Allocator,
|
||||
elf_lib: ElfLib,
|
||||
fd: i32,
|
||||
map_addr: usize,
|
||||
|
@ -27,7 +27,7 @@ pub const LinuxDynLib = struct {
|
|||
|
||||
/// Trusts the file
|
||||
pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {
|
||||
const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
|
||||
const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
|
||||
errdefer std.os.close(fd);
|
||||
|
||||
const size = @intCast(usize, (try std.os.posixFStat(fd)).size);
|
||||
|
@ -45,7 +45,6 @@ pub const LinuxDynLib = struct {
|
|||
const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size];
|
||||
|
||||
return DynLib{
|
||||
.allocator = allocator,
|
||||
.elf_lib = try ElfLib.init(bytes),
|
||||
.fd = fd,
|
||||
.map_addr = addr,
|
||||
|
@ -208,7 +207,7 @@ test "dynamic_library" {
|
|||
};
|
||||
|
||||
const dynlib = DynLib.open(std.debug.global_allocator, libname) catch |err| {
|
||||
assert(err == error.FileNotFound);
|
||||
testing.expect(err == error.FileNotFound);
|
||||
return;
|
||||
};
|
||||
@panic("Expected error from function");
|
||||
|
|
70
std/elf.zig
70
std/elf.zig
|
@ -412,7 +412,7 @@ pub const Elf = struct {
|
|||
// skip over padding
|
||||
try seekable_stream.seekForward(9);
|
||||
|
||||
elf.file_type = switch (try in.readInt(elf.endian, u16)) {
|
||||
elf.file_type = switch (try in.readInt(u16, elf.endian)) {
|
||||
1 => FileType.Relocatable,
|
||||
2 => FileType.Executable,
|
||||
3 => FileType.Shared,
|
||||
|
@ -420,7 +420,7 @@ pub const Elf = struct {
|
|||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
elf.arch = switch (try in.readInt(elf.endian, u16)) {
|
||||
elf.arch = switch (try in.readInt(u16, elf.endian)) {
|
||||
0x02 => Arch.Sparc,
|
||||
0x03 => Arch.x86,
|
||||
0x08 => Arch.Mips,
|
||||
|
@ -433,32 +433,32 @@ pub const Elf = struct {
|
|||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
const elf_version = try in.readInt(elf.endian, u32);
|
||||
const elf_version = try in.readInt(u32, elf.endian);
|
||||
if (elf_version != 1) return error.InvalidFormat;
|
||||
|
||||
if (elf.is_64) {
|
||||
elf.entry_addr = try in.readInt(elf.endian, u64);
|
||||
elf.program_header_offset = try in.readInt(elf.endian, u64);
|
||||
elf.section_header_offset = try in.readInt(elf.endian, u64);
|
||||
elf.entry_addr = try in.readInt(u64, elf.endian);
|
||||
elf.program_header_offset = try in.readInt(u64, elf.endian);
|
||||
elf.section_header_offset = try in.readInt(u64, elf.endian);
|
||||
} else {
|
||||
elf.entry_addr = u64(try in.readInt(elf.endian, u32));
|
||||
elf.program_header_offset = u64(try in.readInt(elf.endian, u32));
|
||||
elf.section_header_offset = u64(try in.readInt(elf.endian, u32));
|
||||
elf.entry_addr = u64(try in.readInt(u32, elf.endian));
|
||||
elf.program_header_offset = u64(try in.readInt(u32, elf.endian));
|
||||
elf.section_header_offset = u64(try in.readInt(u32, elf.endian));
|
||||
}
|
||||
|
||||
// skip over flags
|
||||
try seekable_stream.seekForward(4);
|
||||
|
||||
const header_size = try in.readInt(elf.endian, u16);
|
||||
const header_size = try in.readInt(u16, elf.endian);
|
||||
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
const ph_entry_size = try in.readInt(elf.endian, u16);
|
||||
const ph_entry_count = try in.readInt(elf.endian, u16);
|
||||
const sh_entry_size = try in.readInt(elf.endian, u16);
|
||||
const sh_entry_count = try in.readInt(elf.endian, u16);
|
||||
elf.string_section_index = u64(try in.readInt(elf.endian, u16));
|
||||
const ph_entry_size = try in.readInt(u16, elf.endian);
|
||||
const ph_entry_count = try in.readInt(u16, elf.endian);
|
||||
const sh_entry_size = try in.readInt(u16, elf.endian);
|
||||
const sh_entry_count = try in.readInt(u16, elf.endian);
|
||||
elf.string_section_index = u64(try in.readInt(u16, elf.endian));
|
||||
|
||||
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
|
||||
|
||||
|
@ -481,32 +481,32 @@ pub const Elf = struct {
|
|||
if (sh_entry_size != 64) return error.InvalidFormat;
|
||||
|
||||
for (elf.section_headers) |*elf_section| {
|
||||
elf_section.name = try in.readInt(elf.endian, u32);
|
||||
elf_section.sh_type = try in.readInt(elf.endian, u32);
|
||||
elf_section.flags = try in.readInt(elf.endian, u64);
|
||||
elf_section.addr = try in.readInt(elf.endian, u64);
|
||||
elf_section.offset = try in.readInt(elf.endian, u64);
|
||||
elf_section.size = try in.readInt(elf.endian, u64);
|
||||
elf_section.link = try in.readInt(elf.endian, u32);
|
||||
elf_section.info = try in.readInt(elf.endian, u32);
|
||||
elf_section.addr_align = try in.readInt(elf.endian, u64);
|
||||
elf_section.ent_size = try in.readInt(elf.endian, u64);
|
||||
elf_section.name = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_type = try in.readInt(u32, elf.endian);
|
||||
elf_section.flags = try in.readInt(u64, elf.endian);
|
||||
elf_section.addr = try in.readInt(u64, elf.endian);
|
||||
elf_section.offset = try in.readInt(u64, elf.endian);
|
||||
elf_section.size = try in.readInt(u64, elf.endian);
|
||||
elf_section.link = try in.readInt(u32, elf.endian);
|
||||
elf_section.info = try in.readInt(u32, elf.endian);
|
||||
elf_section.addr_align = try in.readInt(u64, elf.endian);
|
||||
elf_section.ent_size = try in.readInt(u64, elf.endian);
|
||||
}
|
||||
} else {
|
||||
if (sh_entry_size != 40) return error.InvalidFormat;
|
||||
|
||||
for (elf.section_headers) |*elf_section| {
|
||||
// TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ?
|
||||
elf_section.name = try in.readInt(elf.endian, u32);
|
||||
elf_section.sh_type = try in.readInt(elf.endian, u32);
|
||||
elf_section.flags = u64(try in.readInt(elf.endian, u32));
|
||||
elf_section.addr = u64(try in.readInt(elf.endian, u32));
|
||||
elf_section.offset = u64(try in.readInt(elf.endian, u32));
|
||||
elf_section.size = u64(try in.readInt(elf.endian, u32));
|
||||
elf_section.link = try in.readInt(elf.endian, u32);
|
||||
elf_section.info = try in.readInt(elf.endian, u32);
|
||||
elf_section.addr_align = u64(try in.readInt(elf.endian, u32));
|
||||
elf_section.ent_size = u64(try in.readInt(elf.endian, u32));
|
||||
elf_section.name = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_type = try in.readInt(u32, elf.endian);
|
||||
elf_section.flags = u64(try in.readInt(u32, elf.endian));
|
||||
elf_section.addr = u64(try in.readInt(u32, elf.endian));
|
||||
elf_section.offset = u64(try in.readInt(u32, elf.endian));
|
||||
elf_section.size = u64(try in.readInt(u32, elf.endian));
|
||||
elf_section.link = try in.readInt(u32, elf.endian);
|
||||
elf_section.info = try in.readInt(u32, elf.endian);
|
||||
elf_section.addr_align = u64(try in.readInt(u32, elf.endian));
|
||||
elf_section.ent_size = u64(try in.readInt(u32, elf.endian));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("../index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
const Loop = std.event.Loop;
|
||||
|
@ -54,7 +55,8 @@ pub fn Channel(comptime T: type) type {
|
|||
const buffer_nodes = try loop.allocator.alloc(T, capacity);
|
||||
errdefer loop.allocator.free(buffer_nodes);
|
||||
|
||||
const self = try loop.allocator.create(SelfChannel{
|
||||
const self = try loop.allocator.create(SelfChannel);
|
||||
self.* = SelfChannel{
|
||||
.loop = loop,
|
||||
.buffer_len = 0,
|
||||
.buffer_nodes = buffer_nodes,
|
||||
|
@ -66,7 +68,7 @@ pub fn Channel(comptime T: type) type {
|
|||
.or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(),
|
||||
.get_count = 0,
|
||||
.put_count = 0,
|
||||
});
|
||||
};
|
||||
errdefer loop.allocator.destroy(self);
|
||||
|
||||
return self;
|
||||
|
@ -319,6 +321,9 @@ pub fn Channel(comptime T: type) type {
|
|||
}
|
||||
|
||||
test "std.event.Channel" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -346,19 +351,19 @@ async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
|
|||
|
||||
const value1_promise = try async channel.get();
|
||||
const value1 = await value1_promise;
|
||||
assert(value1 == 1234);
|
||||
testing.expect(value1 == 1234);
|
||||
|
||||
const value2_promise = try async channel.get();
|
||||
const value2 = await value2_promise;
|
||||
assert(value2 == 4567);
|
||||
testing.expect(value2 == 4567);
|
||||
|
||||
const value3_promise = try async channel.getOrNull();
|
||||
const value3 = await value3_promise;
|
||||
assert(value3 == null);
|
||||
testing.expect(value3 == null);
|
||||
|
||||
const last_put = try async testPut(channel, 4444);
|
||||
const value4 = await try async channel.getOrNull();
|
||||
assert(value4.? == 4444);
|
||||
testing.expect(value4.? == 4444);
|
||||
await last_put;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ const builtin = @import("builtin");
|
|||
const std = @import("../index.zig");
|
||||
const event = std.event;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const posix = os.posix;
|
||||
|
@ -495,7 +496,7 @@ pub const CloseOperation = struct {
|
|||
};
|
||||
|
||||
pub fn start(loop: *Loop) (error{OutOfMemory}!*CloseOperation) {
|
||||
const self = try loop.allocator.createOne(CloseOperation);
|
||||
const self = try loop.allocator.create(CloseOperation);
|
||||
self.* = CloseOperation{
|
||||
.loop = loop,
|
||||
.os_data = switch (builtin.os) {
|
||||
|
@ -787,7 +788,7 @@ pub fn Watch(comptime V: type) type {
|
|||
},
|
||||
|
||||
builtin.Os.windows => {
|
||||
const self = try loop.allocator.createOne(Self);
|
||||
const self = try loop.allocator.create(Self);
|
||||
errdefer loop.allocator.destroy(self);
|
||||
self.* = Self{
|
||||
.channel = channel,
|
||||
|
@ -802,7 +803,7 @@ pub fn Watch(comptime V: type) type {
|
|||
},
|
||||
|
||||
builtin.Os.macosx, builtin.Os.freebsd => {
|
||||
const self = try loop.allocator.createOne(Self);
|
||||
const self = try loop.allocator.create(Self);
|
||||
errdefer loop.allocator.destroy(self);
|
||||
|
||||
self.* = Self{
|
||||
|
@ -871,7 +872,7 @@ pub fn Watch(comptime V: type) type {
|
|||
}
|
||||
|
||||
async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
|
||||
const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path);
|
||||
const resolved_path = try os.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
|
||||
var resolved_path_consumed = false;
|
||||
defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
|
||||
|
||||
|
@ -1068,7 +1069,7 @@ pub fn Watch(comptime V: type) type {
|
|||
}
|
||||
} else {
|
||||
errdefer _ = self.os_data.dir_table.remove(dirname);
|
||||
const dir = try self.channel.loop.allocator.createOne(OsData.Dir);
|
||||
const dir = try self.channel.loop.allocator.create(OsData.Dir);
|
||||
errdefer self.channel.loop.allocator.destroy(dir);
|
||||
|
||||
dir.* = OsData.Dir{
|
||||
|
@ -1307,39 +1308,36 @@ pub fn Watch(comptime V: type) type {
|
|||
|
||||
const test_tmp_dir = "std_event_fs_test";
|
||||
|
||||
test "write a file, watch it, write it again" {
|
||||
if (builtin.os == builtin.Os.windows) {
|
||||
// TODO this test is disabled on windows until the coroutine rewrite is finished.
|
||||
// https://github.com/ziglang/zig/issues/1363
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
const allocator = &da.allocator;
|
||||
|
||||
// TODO move this into event loop too
|
||||
try os.makePath(allocator, test_tmp_dir);
|
||||
defer os.deleteTree(allocator, test_tmp_dir) catch {};
|
||||
|
||||
var loop: Loop = undefined;
|
||||
try loop.initMultiThreaded(allocator);
|
||||
defer loop.deinit();
|
||||
|
||||
var result: anyerror!void = error.ResultNeverWritten;
|
||||
const handle = try async<allocator> testFsWatchCantFail(&loop, &result);
|
||||
defer cancel handle;
|
||||
|
||||
loop.run();
|
||||
return result;
|
||||
}
|
||||
// TODO this test is disabled until the coroutine rewrite is finished.
|
||||
//test "write a file, watch it, write it again" {
|
||||
// return error.SkipZigTest;
|
||||
// var da = std.heap.DirectAllocator.init();
|
||||
// defer da.deinit();
|
||||
//
|
||||
// const allocator = &da.allocator;
|
||||
//
|
||||
// // TODO move this into event loop too
|
||||
// try os.makePath(allocator, test_tmp_dir);
|
||||
// defer os.deleteTree(allocator, test_tmp_dir) catch {};
|
||||
//
|
||||
// var loop: Loop = undefined;
|
||||
// try loop.initMultiThreaded(allocator);
|
||||
// defer loop.deinit();
|
||||
//
|
||||
// var result: anyerror!void = error.ResultNeverWritten;
|
||||
// const handle = try async<allocator> testFsWatchCantFail(&loop, &result);
|
||||
// defer cancel handle;
|
||||
//
|
||||
// loop.run();
|
||||
// return result;
|
||||
//}
|
||||
|
||||
async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
|
||||
result.* = await (async testFsWatch(loop) catch unreachable);
|
||||
}
|
||||
|
||||
async fn testFsWatch(loop: *Loop) !void {
|
||||
const file_path = try os.path.join(loop.allocator, test_tmp_dir, "file.txt");
|
||||
const file_path = try os.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });
|
||||
defer loop.allocator.free(file_path);
|
||||
|
||||
const contents =
|
||||
|
@ -1352,13 +1350,13 @@ async fn testFsWatch(loop: *Loop) !void {
|
|||
try await try async writeFile(loop, file_path, contents);
|
||||
|
||||
const read_contents = try await try async readFile(loop, file_path, 1024 * 1024);
|
||||
assert(mem.eql(u8, read_contents, contents));
|
||||
testing.expectEqualSlices(u8, contents, read_contents);
|
||||
|
||||
// now watch the file
|
||||
var watch = try Watch(void).create(loop, 0);
|
||||
defer watch.destroy();
|
||||
|
||||
assert((try await try async watch.addFile(file_path, {})) == null);
|
||||
testing.expect((try await try async watch.addFile(file_path, {})) == null);
|
||||
|
||||
const ev = try async watch.channel.get();
|
||||
var ev_consumed = false;
|
||||
|
@ -1378,10 +1376,10 @@ async fn testFsWatch(loop: *Loop) !void {
|
|||
WatchEventId.Delete => @panic("wrong event"),
|
||||
}
|
||||
const contents_updated = try await try async readFile(loop, file_path, 1024 * 1024);
|
||||
assert(mem.eql(u8, contents_updated,
|
||||
testing.expectEqualSlices(u8,
|
||||
\\line 1
|
||||
\\lorem ipsum
|
||||
));
|
||||
, contents_updated);
|
||||
|
||||
// TODO test deleting the file and then re-adding it. we should get events for both
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("../index.zig");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const builtin = @import("builtin");
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
|
@ -84,6 +85,9 @@ pub fn Future(comptime T: type) type {
|
|||
}
|
||||
|
||||
test "std.event.Future" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -111,7 +115,7 @@ async fn testFuture(loop: *Loop) void {
|
|||
|
||||
const result = (await a) + (await b);
|
||||
cancel c;
|
||||
assert(result == 12);
|
||||
testing.expect(result == 12);
|
||||
}
|
||||
|
||||
async fn waitOnFuture(future: *Future(i32)) i32 {
|
||||
|
|
|
@ -4,7 +4,7 @@ const Lock = std.event.Lock;
|
|||
const Loop = std.event.Loop;
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
|
||||
/// ReturnType must be `void` or `E!void`
|
||||
pub fn Group(comptime ReturnType: type) type {
|
||||
|
@ -42,10 +42,11 @@ pub fn Group(comptime ReturnType: type) type {
|
|||
|
||||
/// Add a promise to the group. Thread-safe.
|
||||
pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) {
|
||||
const node = try self.lock.loop.allocator.create(Stack.Node{
|
||||
const node = try self.lock.loop.allocator.create(Stack.Node);
|
||||
node.* = Stack.Node{
|
||||
.next = undefined,
|
||||
.data = handle,
|
||||
});
|
||||
};
|
||||
self.alloc_stack.push(node);
|
||||
}
|
||||
|
||||
|
@ -121,6 +122,9 @@ pub fn Group(comptime ReturnType: type) type {
|
|||
}
|
||||
|
||||
test "std.event.Group" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -142,12 +146,12 @@ async fn testGroup(loop: *Loop) void {
|
|||
group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory");
|
||||
group.call(increaseByTen, &count) catch @panic("memory");
|
||||
await (async group.wait() catch @panic("memory"));
|
||||
assert(count == 11);
|
||||
testing.expect(count == 11);
|
||||
|
||||
var another = Group(anyerror!void).init(loop);
|
||||
another.add(async somethingElse() catch @panic("memory")) catch @panic("memory");
|
||||
another.call(doSomethingThatFails) catch @panic("memory");
|
||||
std.debug.assertError(await (async another.wait() catch @panic("memory")), error.ItBroke);
|
||||
testing.expectError(error.ItBroke, await (async another.wait() catch @panic("memory")));
|
||||
}
|
||||
|
||||
async fn sleepALittle(count: *usize) void {
|
||||
|
|
|
@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type {
|
|||
if (amt_read < buf.len) return error.EndOfStream;
|
||||
}
|
||||
|
||||
pub async fn readIntLe(self: *Self, comptime T: type) !T {
|
||||
return await (async self.readInt(builtin.Endian.Little, T) catch unreachable);
|
||||
pub async fn readIntLittle(self: *Self, comptime T: type) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try await (async self.readNoEof(bytes[0..]) catch unreachable);
|
||||
return mem.readIntLittle(T, &bytes);
|
||||
}
|
||||
|
||||
pub async fn readIntBe(self: *Self, comptime T: type) !T {
|
||||
return await (async self.readInt(builtin.Endian.Big, T) catch unreachable);
|
||||
}
|
||||
|
||||
pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try await (async self.readNoEof(bytes[0..]) catch unreachable);
|
||||
return mem.readInt(bytes, T, endian);
|
||||
return mem.readIntBig(T, &bytes);
|
||||
}
|
||||
|
||||
pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try await (async self.readNoEof(bytes[0..]) catch unreachable);
|
||||
return mem.readInt(T, &bytes, endian);
|
||||
}
|
||||
|
||||
pub async fn readStruct(self: *Self, comptime T: type) !T {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("../index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
|
@ -122,6 +123,9 @@ pub const Lock = struct {
|
|||
};
|
||||
|
||||
test "std.event.Lock" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -138,7 +142,7 @@ test "std.event.Lock" {
|
|||
defer cancel handle;
|
||||
loop.run();
|
||||
|
||||
assert(mem.eql(i32, shared_test_data, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len));
|
||||
testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);
|
||||
}
|
||||
|
||||
async fn testLock(loop: *Loop, lock: *Lock) void {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("../index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
|
@ -97,6 +98,7 @@ pub const Loop = struct {
|
|||
/// TODO copy elision / named return values so that the threads referencing *Loop
|
||||
/// have the correct pointer value.
|
||||
pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
|
||||
if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
|
||||
const core_count = try os.cpuCount(allocator);
|
||||
return self.initInternal(allocator, core_count);
|
||||
}
|
||||
|
@ -201,6 +203,11 @@ pub const Loop = struct {
|
|||
self.os_data.fs_thread.wait();
|
||||
}
|
||||
|
||||
if (builtin.single_threaded) {
|
||||
assert(extra_thread_count == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var extra_thread_index: usize = 0;
|
||||
errdefer {
|
||||
// writing 8 bytes to an eventfd cannot fail
|
||||
|
@ -301,6 +308,11 @@ pub const Loop = struct {
|
|||
self.os_data.fs_thread.wait();
|
||||
}
|
||||
|
||||
if (builtin.single_threaded) {
|
||||
assert(extra_thread_count == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var extra_thread_index: usize = 0;
|
||||
errdefer {
|
||||
_ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable;
|
||||
|
@ -338,6 +350,11 @@ pub const Loop = struct {
|
|||
self.available_eventfd_resume_nodes.push(eventfd_node);
|
||||
}
|
||||
|
||||
if (builtin.single_threaded) {
|
||||
assert(extra_thread_count == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var extra_thread_index: usize = 0;
|
||||
errdefer {
|
||||
var i: usize = 0;
|
||||
|
@ -845,6 +862,9 @@ pub const Loop = struct {
|
|||
};
|
||||
|
||||
test "std.event.Loop - basic" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -858,6 +878,9 @@ test "std.event.Loop - basic" {
|
|||
}
|
||||
|
||||
test "std.event.Loop - call" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -874,7 +897,7 @@ test "std.event.Loop - call" {
|
|||
|
||||
loop.run();
|
||||
|
||||
assert(did_it);
|
||||
testing.expect(did_it);
|
||||
}
|
||||
|
||||
async fn testEventLoop() i32 {
|
||||
|
@ -883,6 +906,6 @@ async fn testEventLoop() i32 {
|
|||
|
||||
async fn testEventLoop2(h: promise->i32, did_it: *bool) void {
|
||||
const value = await h;
|
||||
assert(value == 1234);
|
||||
testing.expect(value == 1234);
|
||||
did_it.* = true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const std = @import("../index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const event = std.event;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
|
@ -269,6 +269,9 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File {
|
|||
}
|
||||
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
if (builtin.os != builtin.Os.linux) {
|
||||
// TODO build abstractions for other operating systems
|
||||
return error.SkipZigTest;
|
||||
|
@ -323,7 +326,7 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Serv
|
|||
var buf: [512]u8 = undefined;
|
||||
const amt_read = try socket_file.read(buf[0..]);
|
||||
const msg = buf[0..amt_read];
|
||||
assert(mem.eql(u8, msg, "hello from server\n"));
|
||||
testing.expect(mem.eql(u8, msg, "hello from server\n"));
|
||||
server.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("../index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
|
@ -211,6 +212,9 @@ pub const RwLock = struct {
|
|||
};
|
||||
|
||||
test "std.event.RwLock" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var da = std.heap.DirectAllocator.init();
|
||||
defer da.deinit();
|
||||
|
||||
|
@ -228,7 +232,7 @@ test "std.event.RwLock" {
|
|||
loop.run();
|
||||
|
||||
const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
|
||||
assert(mem.eql(i32, shared_test_data, expected_result));
|
||||
testing.expectEqualSlices(i32, expected_result, shared_test_data);
|
||||
}
|
||||
|
||||
async fn testLock(loop: *Loop, lock: *RwLock) void {
|
||||
|
@ -290,7 +294,7 @@ async fn readRunner(lock: *RwLock) void {
|
|||
const handle = await lock_promise;
|
||||
defer handle.release();
|
||||
|
||||
assert(shared_test_index == 0);
|
||||
assert(shared_test_data[i] == @intCast(i32, shared_count));
|
||||
testing.expect(shared_test_index == 0);
|
||||
testing.expect(shared_test_data[i] == @intCast(i32, shared_count));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("../index.zig");
|
|||
const math = std.math;
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const assertError = debug.assertError;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const builtin = @import("builtin");
|
||||
const errol = @import("errol/index.zig");
|
||||
|
@ -117,7 +117,7 @@ pub fn formatType(
|
|||
return output(context, @errorName(value));
|
||||
}
|
||||
switch (@typeInfo(T)) {
|
||||
builtin.TypeId.Int, builtin.TypeId.Float => {
|
||||
builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
|
||||
return formatValue(value, fmt, context, Errors, output);
|
||||
},
|
||||
builtin.TypeId.Void => {
|
||||
|
@ -236,6 +236,9 @@ pub fn formatType(
|
|||
const casted_value = ([]const u8)(value);
|
||||
return output(context, casted_value);
|
||||
},
|
||||
builtin.TypeInfo.Pointer.Size.C => {
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||
},
|
||||
},
|
||||
builtin.TypeId.Array => |info| {
|
||||
if (info.child == u8) {
|
||||
|
@ -243,6 +246,9 @@ pub fn formatType(
|
|||
}
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
|
||||
},
|
||||
builtin.TypeId.Fn => {
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
|
||||
},
|
||||
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
}
|
||||
|
@ -268,11 +274,15 @@ fn formatValue(
|
|||
}
|
||||
}
|
||||
|
||||
comptime var T = @typeOf(value);
|
||||
const T = @typeOf(value);
|
||||
switch (@typeId(T)) {
|
||||
builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
|
||||
builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
|
||||
else => unreachable,
|
||||
builtin.TypeId.ComptimeInt => {
|
||||
const Int = math.IntFittingRange(value, value);
|
||||
return formatIntValue(Int(value), fmt, context, Errors, output);
|
||||
},
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,9 +299,10 @@ pub fn formatIntValue(
|
|||
if (fmt.len > 0) {
|
||||
switch (fmt[0]) {
|
||||
'c' => {
|
||||
if (@typeOf(value) == u8) {
|
||||
if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]});
|
||||
return formatAsciiChar(value, context, Errors, output);
|
||||
if (@typeOf(value).bit_count <= 8) {
|
||||
if (fmt.len > 1)
|
||||
@compileError("Unknown format character: " ++ []u8{fmt[1]});
|
||||
return formatAsciiChar(u8(value), context, Errors, output);
|
||||
}
|
||||
},
|
||||
'b' => {
|
||||
|
@ -580,7 +591,7 @@ pub fn formatFloatDecimal(
|
|||
}
|
||||
|
||||
// Remaining fractional portion, zero-padding if insufficient.
|
||||
debug.assert(precision >= printed);
|
||||
assert(precision >= printed);
|
||||
if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
|
||||
return;
|
||||
|
@ -790,13 +801,13 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
|
|||
}
|
||||
|
||||
test "fmt.parseInt" {
|
||||
assert((parseInt(i32, "-10", 10) catch unreachable) == -10);
|
||||
assert((parseInt(i32, "+10", 10) catch unreachable) == 10);
|
||||
assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
assert((parseInt(u8, "255", 10) catch unreachable) == 255);
|
||||
assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
|
||||
testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
|
||||
testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
|
||||
testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
|
||||
testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
|
||||
testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
|
||||
}
|
||||
|
||||
const ParseUnsignedError = error{
|
||||
|
@ -820,31 +831,37 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
|
|||
return x;
|
||||
}
|
||||
|
||||
test "parseUnsigned" {
|
||||
assert((try parseUnsigned(u16, "050124", 10)) == 50124);
|
||||
assert((try parseUnsigned(u16, "65535", 10)) == 65535);
|
||||
assertError(parseUnsigned(u16, "65536", 10), error.Overflow);
|
||||
test "fmt.parseUnsigned" {
|
||||
testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
|
||||
testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
|
||||
testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
|
||||
|
||||
assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
|
||||
assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow);
|
||||
testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
|
||||
testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
|
||||
|
||||
assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
|
||||
testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
|
||||
|
||||
assert((try parseUnsigned(u7, "1", 10)) == 1);
|
||||
assert((try parseUnsigned(u7, "1000", 2)) == 8);
|
||||
testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
|
||||
testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
|
||||
|
||||
assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter);
|
||||
assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter);
|
||||
testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
|
||||
testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
|
||||
|
||||
assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
|
||||
testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
|
||||
|
||||
// these numbers should fit even though the radix itself doesn't fit in the destination type
|
||||
assert((try parseUnsigned(u1, "0", 10)) == 0);
|
||||
assert((try parseUnsigned(u1, "1", 10)) == 1);
|
||||
assertError(parseUnsigned(u1, "2", 10), error.Overflow);
|
||||
assert((try parseUnsigned(u1, "001", 16)) == 1);
|
||||
assert((try parseUnsigned(u2, "3", 16)) == 3);
|
||||
assertError(parseUnsigned(u2, "4", 16), error.Overflow);
|
||||
testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
|
||||
testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
|
||||
testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
|
||||
testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
|
||||
testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
|
||||
testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
|
||||
}
|
||||
|
||||
pub const parseFloat = @import("parse_float.zig").parseFloat;
|
||||
|
||||
test "fmt.parseFloat" {
|
||||
_ = @import("parse_float.zig");
|
||||
}
|
||||
|
||||
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
|
||||
|
@ -902,19 +919,19 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
|
|||
test "buf print int" {
|
||||
var buffer: [max_int_digits]u8 = undefined;
|
||||
const buf = buffer[0..];
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
|
||||
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
|
||||
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
|
||||
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
|
||||
assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
|
||||
testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
|
||||
}
|
||||
|
||||
fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 {
|
||||
|
@ -931,7 +948,7 @@ test "parse u64 digit too big" {
|
|||
|
||||
test "parse unsigned comptime" {
|
||||
comptime {
|
||||
assert((try parseUnsigned(usize, "2", 10)) == 2);
|
||||
testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -964,6 +981,23 @@ test "fmt.format" {
|
|||
const value: u8 = 0b1100;
|
||||
try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
var context = BufPrintContext{ .remaining = buf1[0..] };
|
||||
try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite);
|
||||
var res = buf1[0 .. buf1.len - context.remaining.len];
|
||||
testing.expect(mem.eql(u8, res, "1234"));
|
||||
|
||||
context = BufPrintContext{ .remaining = buf1[0..] };
|
||||
try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
|
||||
res = buf1[0 .. buf1.len - context.remaining.len];
|
||||
testing.expect(mem.eql(u8, res, "a"));
|
||||
|
||||
context = BufPrintContext{ .remaining = buf1[0..] };
|
||||
try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
|
||||
res = buf1[0 .. buf1.len - context.remaining.len];
|
||||
testing.expect(mem.eql(u8, res, "1100"));
|
||||
}
|
||||
{
|
||||
const value: [3]u8 = "abc";
|
||||
try testFmt("array: abc\n", "array: {}\n", value);
|
||||
|
@ -985,6 +1019,14 @@ test "fmt.format" {
|
|||
try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
|
||||
try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
|
||||
}
|
||||
{
|
||||
const value = @intToPtr(fn () void, 0xdeadbeef);
|
||||
try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
|
||||
}
|
||||
{
|
||||
const value = @intToPtr(fn () void, 0xdeadbeef);
|
||||
try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
|
||||
}
|
||||
try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
|
||||
try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
|
||||
try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
|
||||
|
@ -1020,19 +1062,19 @@ test "fmt.format" {
|
|||
var buf1: [32]u8 = undefined;
|
||||
const value: f32 = 1.34;
|
||||
const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
|
||||
assert(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
|
||||
testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f32 = 12.34;
|
||||
const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
|
||||
assert(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
|
||||
testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = -12.34e10;
|
||||
const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: -1.234e+11\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
|
||||
}
|
||||
{
|
||||
// This fails on release due to a minor rounding difference.
|
||||
|
@ -1042,26 +1084,26 @@ test "fmt.format" {
|
|||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 9.999960e-40;
|
||||
const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 9.99996e-40\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
|
||||
}
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 1.409706e-42;
|
||||
const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 1.40971e-42\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = @bitCast(f32, u32(814313563));
|
||||
const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 1.00000e-09\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = @bitCast(f32, u32(1006632960));
|
||||
const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 7.81250e-03\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
|
||||
}
|
||||
{
|
||||
// libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
|
||||
|
@ -1069,47 +1111,47 @@ test "fmt.format" {
|
|||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = @bitCast(f32, u32(1203982400));
|
||||
const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 1.00001e+05\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
|
||||
assert(mem.eql(u8, result, "f64: nan\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: nan\n"));
|
||||
}
|
||||
if (builtin.arch != builtin.Arch.armv8) {
|
||||
// negative nan is not defined by IEE 754,
|
||||
// and ARM thus normalizes it to positive nan
|
||||
var buf1: [32]u8 = undefined;
|
||||
const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
|
||||
assert(mem.eql(u8, result, "f64: -nan\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: -nan\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
|
||||
assert(mem.eql(u8, result, "f64: inf\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: inf\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
|
||||
assert(mem.eql(u8, result, "f64: -inf\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: -inf\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [64]u8 = undefined;
|
||||
const value: f64 = 1.52314e+29;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f32 = 1.1234;
|
||||
const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
|
||||
assert(mem.eql(u8, result, "f32: 1.1\n"));
|
||||
testing.expect(mem.eql(u8, result, "f32: 1.1\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f32 = 1234.567;
|
||||
const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
|
||||
assert(mem.eql(u8, result, "f32: 1234.57\n"));
|
||||
testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
|
@ -1117,92 +1159,92 @@ test "fmt.format" {
|
|||
const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
|
||||
// -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
|
||||
// -11.12339... is rounded back up to -11.1234
|
||||
assert(mem.eql(u8, result, "f32: -11.1234\n"));
|
||||
testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f32 = 91.12345;
|
||||
const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f32: 91.12345\n"));
|
||||
testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 91.12345678901235;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 91.1234567890\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 0.0;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.00000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 5.700;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 6\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 6\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 9.999;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 10.0\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 1.0;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 1.000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 0.0003;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.00030000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 1.40130e-45;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.00000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = 9.999960e-40;
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.00000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
|
||||
}
|
||||
// libc checks
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = f64(@bitCast(f32, u32(916964781)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.00001\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = f64(@bitCast(f32, u32(925353389)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.00001\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = f64(@bitCast(f32, u32(1036831278)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.10000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = f64(@bitCast(f32, u32(1065353133)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 1.00000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = f64(@bitCast(f32, u32(1092616192)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 10.00000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
|
||||
}
|
||||
// libc differences
|
||||
{
|
||||
|
@ -1212,7 +1254,7 @@ test "fmt.format" {
|
|||
// floats of the form x.yyyy25 on a precision point.
|
||||
const value: f64 = f64(@bitCast(f32, u32(1015021568)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 0.01563\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));
|
||||
}
|
||||
// std-windows-x86_64-Debug-bare test case fails
|
||||
{
|
||||
|
@ -1222,7 +1264,7 @@ test "fmt.format" {
|
|||
var buf1: [32]u8 = undefined;
|
||||
const value: f64 = f64(@bitCast(f32, u32(1518338049)));
|
||||
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
|
||||
assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
|
||||
testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
|
||||
}
|
||||
//custom type format
|
||||
{
|
||||
|
@ -1303,10 +1345,10 @@ test "fmt.format" {
|
|||
|
||||
var buf: [100]u8 = undefined;
|
||||
const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
|
||||
debug.assert(mem.eql(u8, uu_result[0..3], "UU@"));
|
||||
testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
|
||||
|
||||
const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
|
||||
debug.assert(mem.eql(u8, uu_result[0..3], "EU@"));
|
||||
testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
|
||||
}
|
||||
//enum format
|
||||
{
|
||||
|
@ -1365,11 +1407,11 @@ pub fn trim(buf: []const u8) []const u8 {
|
|||
}
|
||||
|
||||
test "fmt.trim" {
|
||||
assert(mem.eql(u8, "abc", trim("\n abc \t")));
|
||||
assert(mem.eql(u8, "", trim(" ")));
|
||||
assert(mem.eql(u8, "", trim("")));
|
||||
assert(mem.eql(u8, "abc", trim(" abc")));
|
||||
assert(mem.eql(u8, "abc", trim("abc ")));
|
||||
testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
|
||||
testing.expect(mem.eql(u8, "", trim(" ")));
|
||||
testing.expect(mem.eql(u8, "", trim("")));
|
||||
testing.expect(mem.eql(u8, "abc", trim(" abc")));
|
||||
testing.expect(mem.eql(u8, "abc", trim("abc ")));
|
||||
}
|
||||
|
||||
pub fn isWhiteSpace(byte: u8) bool {
|
||||
|
|
|
@ -0,0 +1,420 @@
|
|||
// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.
|
||||
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2016 Grzegorz Kraszewski
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
// Be aware that this implementation has the following limitations:
|
||||
//
|
||||
// - Is not round-trip accurate for all values
|
||||
// - Only supports round-to-zero
|
||||
// - Does not handle denormals
|
||||
|
||||
const std = @import("../index.zig");
|
||||
|
||||
const max_digits = 25;
|
||||
|
||||
const f64_plus_zero: u64 = 0x0000000000000000;
|
||||
const f64_minus_zero: u64 = 0x8000000000000000;
|
||||
const f64_plus_infinity: u64 = 0x7FF0000000000000;
|
||||
const f64_minus_infinity: u64 = 0xFFF0000000000000;
|
||||
|
||||
const Z96 = struct {
|
||||
d0: u32,
|
||||
d1: u32,
|
||||
d2: u32,
|
||||
|
||||
// d = s >> 1
|
||||
inline fn shiftRight1(d: *Z96, s: Z96) void {
|
||||
d.d0 = (s.d0 >> 1) | ((s.d1 & 1) << 31);
|
||||
d.d1 = (s.d1 >> 1) | ((s.d2 & 1) << 31);
|
||||
d.d2 = s.d2 >> 1;
|
||||
}
|
||||
|
||||
// d = s << 1
|
||||
inline fn shiftLeft1(d: *Z96, s: Z96) void {
|
||||
d.d2 = (s.d2 << 1) | ((s.d1 & (1 << 31)) >> 31);
|
||||
d.d1 = (s.d1 << 1) | ((s.d0 & (1 << 31)) >> 31);
|
||||
d.d0 = s.d0 << 1;
|
||||
}
|
||||
|
||||
// d += s
|
||||
inline fn add(d: *Z96, s: Z96) void {
|
||||
var w = u64(d.d0) + u64(s.d0);
|
||||
d.d0 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d1) + u64(s.d1);
|
||||
d.d1 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d2) + u64(s.d2);
|
||||
d.d2 = @truncate(u32, w);
|
||||
}
|
||||
|
||||
// d -= s
|
||||
inline fn sub(d: *Z96, s: Z96) void {
|
||||
var w = u64(d.d0) -% u64(s.d0);
|
||||
d.d0 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d1) -% u64(s.d1);
|
||||
d.d1 = @truncate(u32, w);
|
||||
|
||||
w >>= 32;
|
||||
w += u64(d.d2) -% u64(s.d2);
|
||||
d.d2 = @truncate(u32, w);
|
||||
}
|
||||
};
|
||||
|
||||
const FloatRepr = struct {
|
||||
negative: bool,
|
||||
exponent: i32,
|
||||
mantissa: u64,
|
||||
};
|
||||
|
||||
fn convertRepr(comptime T: type, n: FloatRepr) T {
|
||||
const mask28: u32 = 0xf << 28;
|
||||
|
||||
var s: Z96 = undefined;
|
||||
var q: Z96 = undefined;
|
||||
var r: Z96 = undefined;
|
||||
|
||||
s.d0 = @truncate(u32, n.mantissa);
|
||||
s.d1 = @truncate(u32, n.mantissa >> 32);
|
||||
s.d2 = 0;
|
||||
|
||||
var binary_exponent: u64 = 92;
|
||||
var exp = n.exponent;
|
||||
|
||||
while (exp > 0) : (exp -= 1) {
|
||||
q.shiftLeft1(s); // q = p << 1
|
||||
r.shiftLeft1(q); // r = p << 2
|
||||
s.shiftLeft1(r); // p = p << 3
|
||||
q.add(s); // p = (p << 3) + (p << 1)
|
||||
|
||||
exp -= 1;
|
||||
|
||||
while (s.d2 & mask28 != 0) {
|
||||
q.shiftRight1(s);
|
||||
binary_exponent += 1;
|
||||
s = q;
|
||||
}
|
||||
}
|
||||
|
||||
while (exp < 0) {
|
||||
while (s.d2 & (1 << 31) == 0) {
|
||||
q.shiftLeft1(s);
|
||||
binary_exponent -= 1;
|
||||
s = q;
|
||||
}
|
||||
|
||||
q.d2 = s.d2 / 10;
|
||||
r.d1 = s.d2 % 10;
|
||||
r.d2 = (s.d1 >> 8) | (r.d1 << 24);
|
||||
q.d1 = r.d2 / 10;
|
||||
r.d1 = r.d2 % 10;
|
||||
r.d2 = ((s.d1 & 0xff) << 16) | (s.d0 >> 16) | (r.d1 << 24);
|
||||
r.d0 = r.d2 / 10;
|
||||
r.d1 = r.d2 % 10;
|
||||
q.d1 = (q.d1 << 8) | ((r.d0 & 0x00ff0000) >> 16);
|
||||
q.d0 = r.d0 << 16;
|
||||
r.d2 = (s.d0 *% 0xffff) | (r.d1 << 16);
|
||||
q.d0 |= r.d2 / 10;
|
||||
s = q;
|
||||
|
||||
exp += 1;
|
||||
}
|
||||
|
||||
if (s.d0 != 0 or s.d1 != 0 or s.d2 != 0) {
|
||||
while (s.d2 & mask28 == 0) {
|
||||
q.shiftLeft1(s);
|
||||
binary_exponent -= 1;
|
||||
s = q;
|
||||
}
|
||||
}
|
||||
|
||||
binary_exponent += 1023;
|
||||
|
||||
const repr: u64 = blk: {
|
||||
if (binary_exponent > 2046) {
|
||||
break :blk if (n.negative) f64_minus_infinity else f64_plus_infinity;
|
||||
} else if (binary_exponent < 1) {
|
||||
break :blk if (n.negative) f64_minus_zero else f64_plus_zero;
|
||||
} else if (s.d2 != 0) {
|
||||
const binexs2 = u64(binary_exponent) << 52;
|
||||
const rr = (u64(s.d2 & ~mask28) << 24) | ((u64(s.d1) + 128) >> 8) | binexs2;
|
||||
break :blk if (n.negative) rr | (1 << 63) else rr;
|
||||
} else {
|
||||
break :blk 0;
|
||||
}
|
||||
};
|
||||
|
||||
const f = @bitCast(f64, repr);
|
||||
return @floatCast(T, f);
|
||||
}
|
||||
|
||||
const State = enum {
|
||||
MaybeSign,
|
||||
LeadingMantissaZeros,
|
||||
LeadingFractionalZeros,
|
||||
MantissaIntegral,
|
||||
MantissaFractional,
|
||||
ExponentSign,
|
||||
LeadingExponentZeros,
|
||||
Exponent,
|
||||
};
|
||||
|
||||
const ParseResult = enum {
|
||||
Ok,
|
||||
PlusZero,
|
||||
MinusZero,
|
||||
PlusInf,
|
||||
MinusInf,
|
||||
};
|
||||
|
||||
inline fn isDigit(c: u8) bool {
|
||||
return c >= '0' and c <= '9';
|
||||
}
|
||||
|
||||
inline fn isSpace(c: u8) bool {
|
||||
return (c >= 0x09 and c <= 0x13) or c == 0x20;
|
||||
}
|
||||
|
||||
fn parseRepr(s: []const u8, n: *FloatRepr) !ParseResult {
|
||||
var digit_index: usize = 0;
|
||||
var negative = false;
|
||||
var negative_exp = false;
|
||||
var exponent: i32 = 0;
|
||||
|
||||
var state = State.MaybeSign;
|
||||
|
||||
var i: usize = 0;
|
||||
loop: while (i < s.len) {
|
||||
const c = s[i];
|
||||
|
||||
switch (state) {
|
||||
State.MaybeSign => {
|
||||
state = State.LeadingMantissaZeros;
|
||||
|
||||
if (c == '+') {
|
||||
i += 1;
|
||||
} else if (c == '-') {
|
||||
n.negative = true;
|
||||
i += 1;
|
||||
} else if (isDigit(c) or c == '.') {
|
||||
// continue
|
||||
} else {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
},
|
||||
|
||||
State.LeadingMantissaZeros => {
|
||||
if (c == '0') {
|
||||
i += 1;
|
||||
} else if (c == '.') {
|
||||
i += 1;
|
||||
state = State.LeadingFractionalZeros;
|
||||
} else {
|
||||
state = State.MantissaIntegral;
|
||||
}
|
||||
},
|
||||
|
||||
State.LeadingFractionalZeros => {
|
||||
if (c == '0') {
|
||||
i += 1;
|
||||
if (n.exponent > std.math.minInt(i32)) {
|
||||
n.exponent -= 1;
|
||||
}
|
||||
} else {
|
||||
state = State.MantissaFractional;
|
||||
}
|
||||
},
|
||||
|
||||
State.MantissaIntegral => {
|
||||
if (isDigit(c)) {
|
||||
if (digit_index < max_digits) {
|
||||
n.mantissa *%= 10;
|
||||
n.mantissa += s[i] - '0';
|
||||
digit_index += 1;
|
||||
} else if (n.exponent < std.math.maxInt(i32)) {
|
||||
n.exponent += 1;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
} else if (c == '.') {
|
||||
i += 1;
|
||||
state = State.MantissaFractional;
|
||||
} else {
|
||||
state = State.MantissaFractional;
|
||||
}
|
||||
},
|
||||
|
||||
State.MantissaFractional => {
|
||||
if (isDigit(c)) {
|
||||
if (digit_index < max_digits) {
|
||||
n.mantissa *%= 10;
|
||||
n.mantissa += c - '0';
|
||||
n.exponent -%= 1;
|
||||
digit_index += 1;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
} else if (c == 'e' or c == 'E') {
|
||||
i += 1;
|
||||
state = State.ExponentSign;
|
||||
} else {
|
||||
state = State.ExponentSign;
|
||||
}
|
||||
},
|
||||
|
||||
State.ExponentSign => {
|
||||
if (c == '+') {
|
||||
i += 1;
|
||||
} else if (c == '-') {
|
||||
negative_exp = true;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
state = State.LeadingExponentZeros;
|
||||
},
|
||||
|
||||
State.LeadingExponentZeros => {
|
||||
if (c == '0') {
|
||||
i += 1;
|
||||
} else {
|
||||
state = State.Exponent;
|
||||
}
|
||||
},
|
||||
|
||||
State.Exponent => {
|
||||
if (isDigit(c)) {
|
||||
if (exponent < std.math.maxInt(i32)) {
|
||||
exponent *= 10;
|
||||
exponent += @intCast(i32, c - '0');
|
||||
}
|
||||
|
||||
i += 1;
|
||||
} else {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (negative_exp) exponent = -exponent;
|
||||
n.exponent += exponent;
|
||||
|
||||
if (n.mantissa == 0) {
|
||||
return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero;
|
||||
} else if (n.exponent > 309) {
|
||||
return if (n.negative) ParseResult.MinusInf else ParseResult.PlusInf;
|
||||
} else if (n.exponent < -328) {
|
||||
return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero;
|
||||
}
|
||||
|
||||
return ParseResult.Ok;
|
||||
}
|
||||
|
||||
inline fn isLower(c: u8) bool {
|
||||
return c -% 'a' < 26;
|
||||
}
|
||||
|
||||
inline fn toUpper(c: u8) u8 {
|
||||
return if (isLower(c)) (c & 0x5f) else c;
|
||||
}
|
||||
|
||||
fn caseInEql(a: []const u8, b: []const u8) bool {
|
||||
if (a.len != b.len) return false;
|
||||
|
||||
for (a) |_, i| {
|
||||
if (toUpper(a[i]) != toUpper(b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn parseFloat(comptime T: type, s: []const u8) !T {
|
||||
if (s.len == 0) {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
|
||||
if (caseInEql(s, "nan")) {
|
||||
return std.math.nan(T);
|
||||
} else if (caseInEql(s, "inf") or caseInEql(s, "+inf")) {
|
||||
return std.math.inf(T);
|
||||
} else if (caseInEql(s, "-inf")) {
|
||||
return -std.math.inf(T);
|
||||
}
|
||||
|
||||
var r = FloatRepr{
|
||||
.negative = false,
|
||||
.exponent = 0,
|
||||
.mantissa = 0,
|
||||
};
|
||||
|
||||
return switch (try parseRepr(s, &r)) {
|
||||
ParseResult.Ok => convertRepr(T, r),
|
||||
ParseResult.PlusZero => 0.0,
|
||||
ParseResult.MinusZero => -T(0.0),
|
||||
ParseResult.PlusInf => std.math.inf(T),
|
||||
ParseResult.MinusInf => -std.math.inf(T),
|
||||
};
|
||||
}
|
||||
|
||||
test "fmt.parseFloat" {
|
||||
const testing = std.testing;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const approxEq = std.math.approxEq;
|
||||
const epsilon = 1e-7;
|
||||
|
||||
inline for ([]type{ f16, f32, f64, f128 }) |T| {
|
||||
const Z = @IntType(false, T.bit_count);
|
||||
|
||||
testing.expectError(error.InvalidCharacter, parseFloat(T, ""));
|
||||
testing.expectError(error.InvalidCharacter, parseFloat(T, " 1"));
|
||||
testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc"));
|
||||
|
||||
expectEqual(try parseFloat(T, "0"), 0.0);
|
||||
expectEqual((try parseFloat(T, "0")), 0.0);
|
||||
expectEqual((try parseFloat(T, "+0")), 0.0);
|
||||
expectEqual((try parseFloat(T, "-0")), 0.0);
|
||||
|
||||
expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon));
|
||||
|
||||
expectEqual((try parseFloat(T, "1e-700")), 0);
|
||||
expectEqual((try parseFloat(T, "1e+700")), std.math.inf(T));
|
||||
|
||||
expectEqual(@bitCast(Z, try parseFloat(T, "nAn")), @bitCast(Z, std.math.nan(T)));
|
||||
expectEqual((try parseFloat(T, "inF")), std.math.inf(T));
|
||||
expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T));
|
||||
|
||||
if (T != f16) {
|
||||
expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
// https://github.com/madler/zlib/blob/master/adler32.c
|
||||
|
||||
const std = @import("../index.zig");
|
||||
const debug = std.debug;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const Adler32 = struct {
|
||||
const base = 65521;
|
||||
|
@ -89,19 +89,19 @@ pub const Adler32 = struct {
|
|||
};
|
||||
|
||||
test "adler32 sanity" {
|
||||
debug.assert(Adler32.hash("a") == 0x620062);
|
||||
debug.assert(Adler32.hash("example") == 0xbc002ed);
|
||||
testing.expect(Adler32.hash("a") == 0x620062);
|
||||
testing.expect(Adler32.hash("example") == 0xbc002ed);
|
||||
}
|
||||
|
||||
test "adler32 long" {
|
||||
const long1 = []u8{1} ** 1024;
|
||||
debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
|
||||
testing.expect(Adler32.hash(long1[0..]) == 0x06780401);
|
||||
|
||||
const long2 = []u8{1} ** 1025;
|
||||
debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
|
||||
testing.expect(Adler32.hash(long2[0..]) == 0x0a7a0402);
|
||||
}
|
||||
|
||||
test "adler32 very long" {
|
||||
const long = []u8{1} ** 5553;
|
||||
debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
|
||||
testing.expect(Adler32.hash(long[0..]) == 0x707f15b2);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
const std = @import("../index.zig");
|
||||
const debug = std.debug;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const Polynomial = struct {
|
||||
const IEEE = 0xedb88320;
|
||||
|
@ -101,17 +102,17 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
|
|||
test "crc32 ieee" {
|
||||
const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);
|
||||
|
||||
debug.assert(Crc32Ieee.hash("") == 0x00000000);
|
||||
debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
|
||||
debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
|
||||
testing.expect(Crc32Ieee.hash("") == 0x00000000);
|
||||
testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
|
||||
testing.expect(Crc32Ieee.hash("abc") == 0x352441c2);
|
||||
}
|
||||
|
||||
test "crc32 castagnoli" {
|
||||
const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);
|
||||
|
||||
debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
|
||||
debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
|
||||
debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
|
||||
testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
|
||||
testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
|
||||
testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
|
||||
}
|
||||
|
||||
// half-byte lookup table implementation.
|
||||
|
@ -165,15 +166,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
|
|||
test "small crc32 ieee" {
|
||||
const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);
|
||||
|
||||
debug.assert(Crc32Ieee.hash("") == 0x00000000);
|
||||
debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
|
||||
debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
|
||||
testing.expect(Crc32Ieee.hash("") == 0x00000000);
|
||||
testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
|
||||
testing.expect(Crc32Ieee.hash("abc") == 0x352441c2);
|
||||
}
|
||||
|
||||
test "small crc32 castagnoli" {
|
||||
const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);
|
||||
|
||||
debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
|
||||
debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
|
||||
debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
|
||||
testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
|
||||
testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
|
||||
testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// https://tools.ietf.org/html/draft-eastlake-fnv-14
|
||||
|
||||
const std = @import("../index.zig");
|
||||
const debug = std.debug;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);
|
||||
pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
|
||||
|
@ -41,18 +41,18 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
|
|||
}
|
||||
|
||||
test "fnv1a-32" {
|
||||
debug.assert(Fnv1a_32.hash("") == 0x811c9dc5);
|
||||
debug.assert(Fnv1a_32.hash("a") == 0xe40c292c);
|
||||
debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968);
|
||||
testing.expect(Fnv1a_32.hash("") == 0x811c9dc5);
|
||||
testing.expect(Fnv1a_32.hash("a") == 0xe40c292c);
|
||||
testing.expect(Fnv1a_32.hash("foobar") == 0xbf9cf968);
|
||||
}
|
||||
|
||||
test "fnv1a-64" {
|
||||
debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325);
|
||||
debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c);
|
||||
debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8);
|
||||
testing.expect(Fnv1a_64.hash("") == 0xcbf29ce484222325);
|
||||
testing.expect(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c);
|
||||
testing.expect(Fnv1a_64.hash("foobar") == 0x85944171f73967e8);
|
||||
}
|
||||
|
||||
test "fnv1a-128" {
|
||||
debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d);
|
||||
debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964);
|
||||
testing.expect(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d);
|
||||
testing.expect(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
// https://131002.net/siphash/
|
||||
|
||||
const std = @import("../index.zig");
|
||||
const debug = std.debug;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
|
@ -21,8 +22,8 @@ pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type {
|
|||
}
|
||||
|
||||
fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type {
|
||||
debug.assert(T == u64 or T == u128);
|
||||
debug.assert(c_rounds > 0 and d_rounds > 0);
|
||||
assert(T == u64 or T == u128);
|
||||
assert(c_rounds > 0 and d_rounds > 0);
|
||||
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
@ -40,10 +41,10 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
|
|||
msg_len: u8,
|
||||
|
||||
pub fn init(key: []const u8) Self {
|
||||
debug.assert(key.len >= 16);
|
||||
assert(key.len >= 16);
|
||||
|
||||
const k0 = mem.readInt(key[0..8], u64, Endian.Little);
|
||||
const k1 = mem.readInt(key[8..16], u64, Endian.Little);
|
||||
const k0 = mem.readIntSliceLittle(u64, key[0..8]);
|
||||
const k1 = mem.readIntSliceLittle(u64, key[8..16]);
|
||||
|
||||
var d = Self{
|
||||
.v0 = k0 ^ 0x736f6d6570736575,
|
||||
|
@ -119,9 +120,9 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
|
|||
}
|
||||
|
||||
fn round(d: *Self, b: []const u8) void {
|
||||
debug.assert(b.len == 8);
|
||||
assert(b.len == 8);
|
||||
|
||||
const m = mem.readInt(b[0..], u64, Endian.Little);
|
||||
const m = mem.readIntSliceLittle(u64, b[0..]);
|
||||
d.v3 ^= m;
|
||||
|
||||
comptime var i: usize = 0;
|
||||
|
@ -162,7 +163,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
|
|||
const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
|
||||
|
||||
test "siphash64-2-4 sanity" {
|
||||
const vectors = [][]const u8{
|
||||
const vectors = [][8]u8{
|
||||
"\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
|
||||
"\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
|
||||
"\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
|
||||
|
@ -235,13 +236,13 @@ test "siphash64-2-4 sanity" {
|
|||
for (vectors) |vector, i| {
|
||||
buffer[i] = @intCast(u8, i);
|
||||
|
||||
const expected = mem.readInt(vector, u64, Endian.Little);
|
||||
debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
|
||||
const expected = mem.readIntLittle(u64, &vector);
|
||||
testing.expect(siphash.hash(test_key, buffer[0..i]) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
test "siphash128-2-4 sanity" {
|
||||
const vectors = [][]const u8{
|
||||
const vectors = [][16]u8{
|
||||
"\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
|
||||
"\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
|
||||
"\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
|
||||
|
@ -314,7 +315,7 @@ test "siphash128-2-4 sanity" {
|
|||
for (vectors) |vector, i| {
|
||||
buffer[i] = @intCast(u8, i);
|
||||
|
||||
const expected = mem.readInt(vector, u128, Endian.Little);
|
||||
debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
|
||||
const expected = mem.readIntLittle(u128, &vector);
|
||||
testing.expect(siphash.hash(test_key, buffer[0..i]) == expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("index.zig");
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const testing = std.testing;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
@ -342,37 +343,37 @@ test "basic hash map usage" {
|
|||
var map = AutoHashMap(i32, i32).init(&direct_allocator.allocator);
|
||||
defer map.deinit();
|
||||
|
||||
assert((try map.put(1, 11)) == null);
|
||||
assert((try map.put(2, 22)) == null);
|
||||
assert((try map.put(3, 33)) == null);
|
||||
assert((try map.put(4, 44)) == null);
|
||||
assert((try map.put(5, 55)) == null);
|
||||
testing.expect((try map.put(1, 11)) == null);
|
||||
testing.expect((try map.put(2, 22)) == null);
|
||||
testing.expect((try map.put(3, 33)) == null);
|
||||
testing.expect((try map.put(4, 44)) == null);
|
||||
testing.expect((try map.put(5, 55)) == null);
|
||||
|
||||
assert((try map.put(5, 66)).?.value == 55);
|
||||
assert((try map.put(5, 55)).?.value == 66);
|
||||
testing.expect((try map.put(5, 66)).?.value == 55);
|
||||
testing.expect((try map.put(5, 55)).?.value == 66);
|
||||
|
||||
const gop1 = try map.getOrPut(5);
|
||||
assert(gop1.found_existing == true);
|
||||
assert(gop1.kv.value == 55);
|
||||
testing.expect(gop1.found_existing == true);
|
||||
testing.expect(gop1.kv.value == 55);
|
||||
gop1.kv.value = 77;
|
||||
assert(map.get(5).?.value == 77);
|
||||
testing.expect(map.get(5).?.value == 77);
|
||||
|
||||
const gop2 = try map.getOrPut(99);
|
||||
assert(gop2.found_existing == false);
|
||||
testing.expect(gop2.found_existing == false);
|
||||
gop2.kv.value = 42;
|
||||
assert(map.get(99).?.value == 42);
|
||||
testing.expect(map.get(99).?.value == 42);
|
||||
|
||||
const gop3 = try map.getOrPutValue(5, 5);
|
||||
assert(gop3.value == 77);
|
||||
testing.expect(gop3.value == 77);
|
||||
|
||||
const gop4 = try map.getOrPutValue(100, 41);
|
||||
assert(gop4.value == 41);
|
||||
testing.expect(gop4.value == 41);
|
||||
|
||||
assert(map.contains(2));
|
||||
assert(map.get(2).?.value == 22);
|
||||
testing.expect(map.contains(2));
|
||||
testing.expect(map.get(2).?.value == 22);
|
||||
_ = map.remove(2);
|
||||
assert(map.remove(2) == null);
|
||||
assert(map.get(2) == null);
|
||||
testing.expect(map.remove(2) == null);
|
||||
testing.expect(map.get(2) == null);
|
||||
}
|
||||
|
||||
test "iterator hash map" {
|
||||
|
@ -382,9 +383,9 @@ test "iterator hash map" {
|
|||
var reset_map = AutoHashMap(i32, i32).init(&direct_allocator.allocator);
|
||||
defer reset_map.deinit();
|
||||
|
||||
assert((try reset_map.put(1, 11)) == null);
|
||||
assert((try reset_map.put(2, 22)) == null);
|
||||
assert((try reset_map.put(3, 33)) == null);
|
||||
testing.expect((try reset_map.put(1, 11)) == null);
|
||||
testing.expect((try reset_map.put(2, 22)) == null);
|
||||
testing.expect((try reset_map.put(3, 33)) == null);
|
||||
|
||||
var keys = []i32{
|
||||
3,
|
||||
|
@ -400,26 +401,26 @@ test "iterator hash map" {
|
|||
var it = reset_map.iterator();
|
||||
var count: usize = 0;
|
||||
while (it.next()) |next| {
|
||||
assert(next.key == keys[count]);
|
||||
assert(next.value == values[count]);
|
||||
testing.expect(next.key == keys[count]);
|
||||
testing.expect(next.value == values[count]);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
assert(count == 3);
|
||||
assert(it.next() == null);
|
||||
testing.expect(count == 3);
|
||||
testing.expect(it.next() == null);
|
||||
it.reset();
|
||||
count = 0;
|
||||
while (it.next()) |next| {
|
||||
assert(next.key == keys[count]);
|
||||
assert(next.value == values[count]);
|
||||
testing.expect(next.key == keys[count]);
|
||||
testing.expect(next.value == values[count]);
|
||||
count += 1;
|
||||
if (count == 2) break;
|
||||
}
|
||||
|
||||
it.reset();
|
||||
var entry = it.next().?;
|
||||
assert(entry.key == keys[0]);
|
||||
assert(entry.value == values[0]);
|
||||
testing.expect(entry.key == keys[0]);
|
||||
testing.expect(entry.value == values[0]);
|
||||
}
|
||||
|
||||
pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
|
||||
|
@ -495,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
|
|||
builtin.TypeId.Pointer => |info| switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
const interval = std.math.max(1, key.len / 256);
|
||||
var i: usize = 0;
|
||||
|
@ -508,6 +510,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
|
|||
|
||||
builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"),
|
||||
builtin.TypeId.Array => @compileError("TODO auto hash for arrays"),
|
||||
builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"),
|
||||
builtin.TypeId.Struct => @compileError("TODO auto hash for structs"),
|
||||
builtin.TypeId.Union => @compileError("TODO auto hash for unions"),
|
||||
builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"),
|
||||
|
@ -541,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
|
|||
builtin.TypeId.Pointer => |info| switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
if (a.len != b.len) return false;
|
||||
for (a) |a_item, i| {
|
||||
|
@ -555,5 +559,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
|
|||
builtin.TypeId.Struct => @compileError("TODO auto eql for structs"),
|
||||
builtin.TypeId.Union => @compileError("TODO auto eql for unions"),
|
||||
builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"),
|
||||
builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"),
|
||||
}
|
||||
}
|
||||
|
|
157
std/heap.zig
157
std/heap.zig
|
@ -1,6 +1,7 @@
|
|||
const std = @import("index.zig");
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
const builtin = @import("builtin");
|
||||
|
@ -66,7 +67,7 @@ pub const DirectAllocator = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
|
||||
fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
|
||||
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
|
||||
|
||||
switch (builtin.os) {
|
||||
|
@ -106,9 +107,7 @@ pub const DirectAllocator = struct {
|
|||
};
|
||||
const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
|
||||
const root_addr = @ptrToInt(ptr);
|
||||
const rem = @rem(root_addr, alignment);
|
||||
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
||||
const adjusted_addr = root_addr + march_forward_bytes;
|
||||
const adjusted_addr = mem.alignForward(root_addr, alignment);
|
||||
const record_addr = adjusted_addr + n;
|
||||
@intToPtr(*align(1) usize, record_addr).* = root_addr;
|
||||
return @intToPtr([*]u8, adjusted_addr)[0..n];
|
||||
|
@ -126,8 +125,7 @@ pub const DirectAllocator = struct {
|
|||
const base_addr = @ptrToInt(old_mem.ptr);
|
||||
const old_addr_end = base_addr + old_mem.len;
|
||||
const new_addr_end = base_addr + new_size;
|
||||
const rem = @rem(new_addr_end, os.page_size);
|
||||
const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem);
|
||||
const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);
|
||||
if (old_addr_end > new_addr_end_rounded) {
|
||||
_ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded);
|
||||
}
|
||||
|
@ -324,51 +322,57 @@ pub const FixedBufferAllocator = struct {
|
|||
fn free(allocator: *Allocator, bytes: []u8) void {}
|
||||
};
|
||||
|
||||
/// lock free
|
||||
pub const ThreadSafeFixedBufferAllocator = struct {
|
||||
allocator: Allocator,
|
||||
end_index: usize,
|
||||
buffer: []u8,
|
||||
pub const ThreadSafeFixedBufferAllocator = blk: {
|
||||
if (builtin.single_threaded) {
|
||||
break :blk FixedBufferAllocator;
|
||||
} else {
|
||||
/// lock free
|
||||
break :blk struct {
|
||||
allocator: Allocator,
|
||||
end_index: usize,
|
||||
buffer: []u8,
|
||||
|
||||
pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {
|
||||
return ThreadSafeFixedBufferAllocator{
|
||||
.allocator = Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
},
|
||||
.buffer = buffer,
|
||||
.end_index = 0,
|
||||
pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {
|
||||
return ThreadSafeFixedBufferAllocator{
|
||||
.allocator = Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
},
|
||||
.buffer = buffer,
|
||||
.end_index = 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
|
||||
const self = @fieldParentPtr(ThreadSafeFixedBufferAllocator, "allocator", allocator);
|
||||
var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst);
|
||||
while (true) {
|
||||
const addr = @ptrToInt(self.buffer.ptr) + end_index;
|
||||
const rem = @rem(addr, alignment);
|
||||
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
||||
const adjusted_index = end_index + march_forward_bytes;
|
||||
const new_end_index = adjusted_index + n;
|
||||
if (new_end_index > self.buffer.len) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
|
||||
if (new_size <= old_mem.len) {
|
||||
return old_mem[0..new_size];
|
||||
} else {
|
||||
const result = try alloc(allocator, new_size, alignment);
|
||||
mem.copy(u8, result, old_mem);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
fn free(allocator: *Allocator, bytes: []u8) void {}
|
||||
};
|
||||
}
|
||||
|
||||
fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
|
||||
const self = @fieldParentPtr(ThreadSafeFixedBufferAllocator, "allocator", allocator);
|
||||
var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst);
|
||||
while (true) {
|
||||
const addr = @ptrToInt(self.buffer.ptr) + end_index;
|
||||
const rem = @rem(addr, alignment);
|
||||
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
||||
const adjusted_index = end_index + march_forward_bytes;
|
||||
const new_end_index = adjusted_index + n;
|
||||
if (new_end_index > self.buffer.len) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
|
||||
if (new_size <= old_mem.len) {
|
||||
return old_mem[0..new_size];
|
||||
} else {
|
||||
const result = try alloc(allocator, new_size, alignment);
|
||||
mem.copy(u8, result, old_mem);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
fn free(allocator: *Allocator, bytes: []u8) void {}
|
||||
};
|
||||
|
||||
pub fn stackFallback(comptime size: usize, fallback_allocator: *Allocator) StackFallbackAllocator(size) {
|
||||
|
@ -484,11 +488,11 @@ test "FixedBufferAllocator Reuse memory on realloc" {
|
|||
var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]);
|
||||
|
||||
var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 5);
|
||||
assert(slice0.len == 5);
|
||||
testing.expect(slice0.len == 5);
|
||||
var slice1 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 10);
|
||||
assert(slice1.ptr == slice0.ptr);
|
||||
assert(slice1.len == 10);
|
||||
debug.assertError(fixed_buffer_allocator.allocator.realloc(u8, slice1, 11), error.OutOfMemory);
|
||||
testing.expect(slice1.ptr == slice0.ptr);
|
||||
testing.expect(slice1.len == 10);
|
||||
testing.expectError(error.OutOfMemory, fixed_buffer_allocator.allocator.realloc(u8, slice1, 11));
|
||||
}
|
||||
// check that we don't re-use the memory if it's not the most recent block
|
||||
{
|
||||
|
@ -499,10 +503,10 @@ test "FixedBufferAllocator Reuse memory on realloc" {
|
|||
slice0[1] = 2;
|
||||
var slice1 = try fixed_buffer_allocator.allocator.alloc(u8, 2);
|
||||
var slice2 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 4);
|
||||
assert(slice0.ptr != slice2.ptr);
|
||||
assert(slice1.ptr != slice2.ptr);
|
||||
assert(slice2[0] == 1);
|
||||
assert(slice2[1] == 2);
|
||||
testing.expect(slice0.ptr != slice2.ptr);
|
||||
testing.expect(slice1.ptr != slice2.ptr);
|
||||
testing.expect(slice2[0] == 1);
|
||||
testing.expect(slice2[1] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,27 +520,28 @@ test "ThreadSafeFixedBufferAllocator" {
|
|||
|
||||
fn testAllocator(allocator: *mem.Allocator) !void {
|
||||
var slice = try allocator.alloc(*i32, 100);
|
||||
assert(slice.len == 100);
|
||||
testing.expect(slice.len == 100);
|
||||
for (slice) |*item, i| {
|
||||
item.* = try allocator.create(@intCast(i32, i));
|
||||
item.* = try allocator.create(i32);
|
||||
item.*.* = @intCast(i32, i);
|
||||
}
|
||||
|
||||
slice = try allocator.realloc(*i32, slice, 20000);
|
||||
assert(slice.len == 20000);
|
||||
testing.expect(slice.len == 20000);
|
||||
|
||||
for (slice[0..100]) |item, i| {
|
||||
assert(item.* == @intCast(i32, i));
|
||||
testing.expect(item.* == @intCast(i32, i));
|
||||
allocator.destroy(item);
|
||||
}
|
||||
|
||||
slice = try allocator.realloc(*i32, slice, 50);
|
||||
assert(slice.len == 50);
|
||||
testing.expect(slice.len == 50);
|
||||
slice = try allocator.realloc(*i32, slice, 25);
|
||||
assert(slice.len == 25);
|
||||
testing.expect(slice.len == 25);
|
||||
slice = try allocator.realloc(*i32, slice, 0);
|
||||
assert(slice.len == 0);
|
||||
testing.expect(slice.len == 0);
|
||||
slice = try allocator.realloc(*i32, slice, 10);
|
||||
assert(slice.len == 10);
|
||||
testing.expect(slice.len == 10);
|
||||
|
||||
allocator.free(slice);
|
||||
}
|
||||
|
@ -544,25 +549,25 @@ fn testAllocator(allocator: *mem.Allocator) !void {
|
|||
fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !void {
|
||||
// initial
|
||||
var slice = try allocator.alignedAlloc(u8, alignment, 10);
|
||||
assert(slice.len == 10);
|
||||
testing.expect(slice.len == 10);
|
||||
// grow
|
||||
slice = try allocator.alignedRealloc(u8, alignment, slice, 100);
|
||||
assert(slice.len == 100);
|
||||
testing.expect(slice.len == 100);
|
||||
// shrink
|
||||
slice = try allocator.alignedRealloc(u8, alignment, slice, 10);
|
||||
assert(slice.len == 10);
|
||||
testing.expect(slice.len == 10);
|
||||
// go to zero
|
||||
slice = try allocator.alignedRealloc(u8, alignment, slice, 0);
|
||||
assert(slice.len == 0);
|
||||
testing.expect(slice.len == 0);
|
||||
// realloc from zero
|
||||
slice = try allocator.alignedRealloc(u8, alignment, slice, 100);
|
||||
assert(slice.len == 100);
|
||||
testing.expect(slice.len == 100);
|
||||
// shrink with shrink
|
||||
slice = allocator.alignedShrink(u8, alignment, slice, 10);
|
||||
assert(slice.len == 10);
|
||||
testing.expect(slice.len == 10);
|
||||
// shrink to zero
|
||||
slice = allocator.alignedShrink(u8, alignment, slice, 0);
|
||||
assert(slice.len == 0);
|
||||
testing.expect(slice.len == 0);
|
||||
}
|
||||
|
||||
fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void {
|
||||
|
@ -577,19 +582,19 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo
|
|||
_ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
|
||||
|
||||
var slice = try allocator.allocFn(allocator, 500, large_align);
|
||||
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
|
||||
slice = try allocator.reallocFn(allocator, slice, 100, large_align);
|
||||
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
|
||||
slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
|
||||
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
|
||||
slice = try allocator.reallocFn(allocator, slice, 10, large_align);
|
||||
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
|
||||
slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
|
||||
debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
|
||||
|
||||
allocator.free(slice);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
|
|||
pub const HashMap = @import("hash_map.zig").HashMap;
|
||||
pub const LinkedList = @import("linked_list.zig").LinkedList;
|
||||
pub const Mutex = @import("mutex.zig").Mutex;
|
||||
pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
|
||||
pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
|
||||
pub const SpinLock = @import("spinlock.zig").SpinLock;
|
||||
|
||||
|
@ -30,21 +31,21 @@ pub const hash_map = @import("hash_map.zig");
|
|||
pub const heap = @import("heap.zig");
|
||||
pub const io = @import("io.zig");
|
||||
pub const json = @import("json.zig");
|
||||
pub const lazyInit = @import("lazy_init.zig").lazyInit;
|
||||
pub const macho = @import("macho.zig");
|
||||
pub const math = @import("math/index.zig");
|
||||
pub const meta = @import("meta/index.zig");
|
||||
pub const mem = @import("mem.zig");
|
||||
pub const meta = @import("meta/index.zig");
|
||||
pub const net = @import("net.zig");
|
||||
pub const os = @import("os/index.zig");
|
||||
pub const pdb = @import("pdb.zig");
|
||||
pub const rand = @import("rand/index.zig");
|
||||
pub const rb = @import("rb.zig");
|
||||
pub const sort = @import("sort.zig");
|
||||
pub const testing = @import("testing.zig");
|
||||
pub const unicode = @import("unicode.zig");
|
||||
pub const zig = @import("zig/index.zig");
|
||||
|
||||
pub const lazyInit = @import("lazy_init.zig").lazyInit;
|
||||
|
||||
test "std" {
|
||||
// run tests from these
|
||||
_ = @import("array_list.zig");
|
||||
|
@ -55,9 +56,10 @@ test "std" {
|
|||
_ = @import("hash_map.zig");
|
||||
_ = @import("linked_list.zig");
|
||||
_ = @import("mutex.zig");
|
||||
_ = @import("statically_initialized_mutex.zig");
|
||||
_ = @import("segmented_list.zig");
|
||||
_ = @import("spinlock.zig");
|
||||
|
||||
|
||||
_ = @import("base64.zig");
|
||||
_ = @import("build.zig");
|
||||
_ = @import("c/index.zig");
|
||||
|
@ -66,24 +68,26 @@ test "std" {
|
|||
_ = @import("cstr.zig");
|
||||
_ = @import("debug/index.zig");
|
||||
_ = @import("dwarf.zig");
|
||||
_ = @import("dynamic_library.zig");
|
||||
_ = @import("elf.zig");
|
||||
_ = @import("empty.zig");
|
||||
_ = @import("event.zig");
|
||||
_ = @import("fmt/index.zig");
|
||||
_ = @import("hash/index.zig");
|
||||
_ = @import("heap.zig");
|
||||
_ = @import("io.zig");
|
||||
_ = @import("json.zig");
|
||||
_ = @import("lazy_init.zig");
|
||||
_ = @import("macho.zig");
|
||||
_ = @import("math/index.zig");
|
||||
_ = @import("meta/index.zig");
|
||||
_ = @import("mem.zig");
|
||||
_ = @import("meta/index.zig");
|
||||
_ = @import("net.zig");
|
||||
_ = @import("heap.zig");
|
||||
_ = @import("os/index.zig");
|
||||
_ = @import("rand/index.zig");
|
||||
_ = @import("pdb.zig");
|
||||
_ = @import("rand/index.zig");
|
||||
_ = @import("sort.zig");
|
||||
_ = @import("testing.zig");
|
||||
_ = @import("unicode.zig");
|
||||
_ = @import("zig/index.zig");
|
||||
_ = @import("lazy_init.zig");
|
||||
}
|
||||
|
|
812
std/io.zig
812
std/io.zig
|
@ -8,9 +8,12 @@ const debug = std.debug;
|
|||
const assert = debug.assert;
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const meta = std.meta;
|
||||
const trait = meta.trait;
|
||||
const Buffer = std.Buffer;
|
||||
const fmt = std.fmt;
|
||||
const File = std.os.File;
|
||||
const testing = std.testing;
|
||||
|
||||
const is_posix = builtin.os != builtin.Os.windows;
|
||||
const is_windows = builtin.os == builtin.Os.windows;
|
||||
|
@ -152,35 +155,43 @@ pub fn InStream(comptime ReadError: type) type {
|
|||
}
|
||||
|
||||
/// Reads a native-endian integer
|
||||
pub fn readIntNe(self: *Self, comptime T: type) !T {
|
||||
return self.readInt(builtin.endian, T);
|
||||
}
|
||||
|
||||
pub fn readIntLe(self: *Self, comptime T: type) !T {
|
||||
pub fn readIntNative(self: *Self, comptime T: type) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntLE(T, bytes);
|
||||
return mem.readIntNative(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readIntBe(self: *Self, comptime T: type) !T {
|
||||
/// Reads a foreign-endian integer
|
||||
pub fn readIntForeign(self: *Self, comptime T: type) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntBE(T, bytes);
|
||||
return mem.readIntForeign(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
|
||||
pub fn readIntLittle(self: *Self, comptime T: type) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readInt(bytes, T, endian);
|
||||
return mem.readIntLittle(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
|
||||
assert(size <= @sizeOf(T));
|
||||
assert(size <= 8);
|
||||
var input_buf: [8]u8 = undefined;
|
||||
const input_slice = input_buf[0..size];
|
||||
try self.readNoEof(input_slice);
|
||||
return mem.readInt(input_slice, T, endian);
|
||||
pub fn readIntBig(self: *Self, comptime T: type) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntBig(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readInt(T, &bytes, endian);
|
||||
}
|
||||
|
||||
pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
|
||||
assert(size <= @sizeOf(ReturnType));
|
||||
var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
|
||||
const bytes = bytes_buf[0..size];
|
||||
try self.readNoEof(bytes);
|
||||
return mem.readVarInt(ReturnType, bytes, endian);
|
||||
}
|
||||
|
||||
pub fn skipBytes(self: *Self, num_bytes: usize) !void {
|
||||
|
@ -229,25 +240,34 @@ pub fn OutStream(comptime WriteError: type) type {
|
|||
}
|
||||
|
||||
/// Write a native-endian integer.
|
||||
pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void {
|
||||
return self.writeInt(builtin.endian, T, value);
|
||||
}
|
||||
|
||||
pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void {
|
||||
pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
mem.writeIntLE(T, &bytes, value);
|
||||
mem.writeIntNative(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void {
|
||||
/// Write a foreign-endian integer.
|
||||
pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
mem.writeIntBE(T, &bytes, value);
|
||||
mem.writeIntForeign(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void {
|
||||
pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
mem.writeInt(bytes[0..], value, endian);
|
||||
mem.writeIntLittle(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
mem.writeIntBig(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
|
||||
var bytes: [@sizeOf(T)]u8 = undefined;
|
||||
mem.writeInt(T, &bytes, value, endian);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
};
|
||||
|
@ -323,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
|||
const amt_buffered = self.end_index - self.start_index;
|
||||
if (amt_buffered == 0) {
|
||||
assert(self.end_index <= buffer_size);
|
||||
if (self.end_index == buffer_size) {
|
||||
// we can read more data from the unbuffered stream
|
||||
if (dest_space < buffer_size) {
|
||||
self.start_index = 0;
|
||||
self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
|
||||
} else {
|
||||
// asking for so much data that buffering is actually less efficient.
|
||||
// forward the request directly to the unbuffered stream
|
||||
const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
|
||||
return dest_index + amt_read;
|
||||
}
|
||||
} else {
|
||||
// reading from the unbuffered stream returned less than we asked for
|
||||
// so we cannot read any more data.
|
||||
// Make sure the last read actually gave us some data
|
||||
if (self.end_index == 0) {
|
||||
// reading from the unbuffered stream returned nothing
|
||||
// so we have nothing left to read.
|
||||
return dest_index;
|
||||
}
|
||||
// we can read more data from the unbuffered stream
|
||||
if (dest_space < buffer_size) {
|
||||
self.start_index = 0;
|
||||
self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
|
||||
} else {
|
||||
// asking for so much data that buffering is actually less efficient.
|
||||
// forward the request directly to the unbuffered stream
|
||||
const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
|
||||
return dest_index + amt_read;
|
||||
}
|
||||
}
|
||||
|
||||
const copy_amount = math.min(dest_space, amt_buffered);
|
||||
const copy_end_index = self.start_index + copy_amount;
|
||||
mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]);
|
||||
|
@ -350,6 +371,46 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
|||
};
|
||||
}
|
||||
|
||||
test "io.BufferedInStream" {
|
||||
const OneByteReadInStream = struct {
|
||||
const Error = error{NoError};
|
||||
const Stream = InStream(Error);
|
||||
|
||||
stream: Stream,
|
||||
str: []const u8,
|
||||
curr: usize,
|
||||
|
||||
fn init(str: []const u8) @This() {
|
||||
return @This(){
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
.str = str,
|
||||
.curr = 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
|
||||
const self = @fieldParentPtr(@This(), "stream", in_stream);
|
||||
if (self.str.len <= self.curr or dest.len == 0)
|
||||
return 0;
|
||||
|
||||
dest[0] = self.str[self.curr];
|
||||
self.curr += 1;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
|
||||
|
||||
const str = "This is a test";
|
||||
var one_byte_stream = OneByteReadInStream.init(str);
|
||||
var buf_in_stream = BufferedInStream(OneByteReadInStream.Error).init(&one_byte_stream.stream);
|
||||
const stream = &buf_in_stream.stream;
|
||||
|
||||
const res = try stream.readAllAlloc(allocator, str.len + 1);
|
||||
testing.expectEqualSlices(u8, str, res);
|
||||
}
|
||||
|
||||
/// Creates a stream which supports 'un-reading' data, so that it can be read again.
|
||||
/// This makes look-ahead style parsing much easier.
|
||||
pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type {
|
||||
|
@ -446,6 +507,153 @@ pub const SliceInStream = struct {
|
|||
}
|
||||
};
|
||||
|
||||
/// Creates a stream which allows for reading bit fields from another stream
|
||||
pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
in_stream: *Stream,
|
||||
bit_buffer: u7,
|
||||
bit_count: u3,
|
||||
stream: Stream,
|
||||
|
||||
pub const Stream = InStream(Error);
|
||||
const u8_bit_count = comptime meta.bitCount(u8);
|
||||
const u7_bit_count = comptime meta.bitCount(u7);
|
||||
const u4_bit_count = comptime meta.bitCount(u4);
|
||||
|
||||
pub fn init(in_stream: *Stream) Self {
|
||||
return Self{
|
||||
.in_stream = in_stream,
|
||||
.bit_buffer = 0,
|
||||
.bit_count = 0,
|
||||
.stream = Stream{ .readFn = read },
|
||||
};
|
||||
}
|
||||
|
||||
/// Reads `bits` bits from the stream and returns a specified unsigned int type
|
||||
/// containing them in the least significant end, returning an error if the
|
||||
/// specified number of bits could not be read.
|
||||
pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U {
|
||||
var n: usize = undefined;
|
||||
const result = try self.readBits(U, bits, &n);
|
||||
if (n < bits) return error.EndOfStream;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Reads `bits` bits from the stream and returns a specified unsigned int type
|
||||
/// containing them in the least significant end. The number of bits successfully
|
||||
/// read is placed in `out_bits`, as reaching the end of the stream is not an error.
|
||||
pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
|
||||
comptime assert(trait.isUnsignedInt(U));
|
||||
|
||||
//by extending the buffer to a minimum of u8 we can cover a number of edge cases
|
||||
// related to shifting and casting.
|
||||
const u_bit_count = comptime meta.bitCount(U);
|
||||
const buf_bit_count = bc: {
|
||||
assert(u_bit_count >= bits);
|
||||
break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
|
||||
};
|
||||
const Buf = @IntType(false, buf_bit_count);
|
||||
const BufShift = math.Log2Int(Buf);
|
||||
|
||||
out_bits.* = usize(0);
|
||||
if (U == u0 or bits == 0) return 0;
|
||||
var out_buffer = Buf(0);
|
||||
|
||||
if (self.bit_count > 0) {
|
||||
const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
|
||||
const shift = u7_bit_count - n;
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
out_buffer = Buf(self.bit_buffer >> shift);
|
||||
self.bit_buffer <<= n;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
const value = (self.bit_buffer << shift) >> shift;
|
||||
out_buffer = Buf(value);
|
||||
self.bit_buffer >>= n;
|
||||
},
|
||||
}
|
||||
self.bit_count -= n;
|
||||
out_bits.* = n;
|
||||
}
|
||||
//at this point we know bit_buffer is empty
|
||||
|
||||
//copy bytes until we have enough bits, then leave the rest in bit_buffer
|
||||
while (out_bits.* < bits) {
|
||||
const n = bits - out_bits.*;
|
||||
const next_byte = self.in_stream.readByte() catch |err| {
|
||||
if (err == error.EndOfStream) {
|
||||
return @intCast(U, out_buffer);
|
||||
}
|
||||
//@BUG: See #1810. Not sure if the bug is that I have to do this for some
|
||||
// streams, or that I don't for streams with emtpy errorsets.
|
||||
return @errSetCast(Error, err);
|
||||
};
|
||||
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
if (n >= u8_bit_count) {
|
||||
out_buffer <<= @intCast(u3, u8_bit_count - 1);
|
||||
out_buffer <<= 1;
|
||||
out_buffer |= Buf(next_byte);
|
||||
out_bits.* += u8_bit_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
const shift = @intCast(u3, u8_bit_count - n);
|
||||
out_buffer <<= @intCast(BufShift, n);
|
||||
out_buffer |= Buf(next_byte >> shift);
|
||||
out_bits.* += n;
|
||||
self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
|
||||
self.bit_count = shift;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
if (n >= u8_bit_count) {
|
||||
out_buffer |= Buf(next_byte) << @intCast(BufShift, out_bits.*);
|
||||
out_bits.* += u8_bit_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
const shift = @intCast(u3, u8_bit_count - n);
|
||||
const value = (next_byte << shift) >> shift;
|
||||
out_buffer |= Buf(value) << @intCast(BufShift, out_bits.*);
|
||||
out_bits.* += n;
|
||||
self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n));
|
||||
self.bit_count = shift;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return @intCast(U, out_buffer);
|
||||
}
|
||||
|
||||
pub fn alignToByte(self: *Self) void {
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
|
||||
pub fn read(self_stream: *Stream, buffer: []u8) Error!usize {
|
||||
var self = @fieldParentPtr(Self, "stream", self_stream);
|
||||
|
||||
var out_bits: usize = undefined;
|
||||
var out_bits_total = usize(0);
|
||||
//@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced
|
||||
if (self.bit_count > 0) {
|
||||
for (buffer) |*b, i| {
|
||||
b.* = try self.readBits(u8, u8_bit_count, &out_bits);
|
||||
out_bits_total += out_bits;
|
||||
}
|
||||
const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0);
|
||||
return (out_bits_total / u8_bit_count) + incomplete_byte;
|
||||
}
|
||||
|
||||
return self.in_stream.read(buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// This is a simple OutStream that writes to a slice, and returns an error
|
||||
/// when it runs out of space.
|
||||
pub const SliceOutStream = struct {
|
||||
|
@ -498,7 +706,7 @@ test "io.SliceOutStream" {
|
|||
const stream = &slice_stream.stream;
|
||||
|
||||
try stream.print("{}{}!", "Hello", "World");
|
||||
debug.assert(mem.eql(u8, "HelloWorld!", slice_stream.getWritten()));
|
||||
testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten());
|
||||
}
|
||||
|
||||
var null_out_stream_state = NullOutStream.init();
|
||||
|
@ -560,7 +768,7 @@ test "io.CountingOutStream" {
|
|||
|
||||
const bytes = "yay" ** 10000;
|
||||
stream.write(bytes) catch unreachable;
|
||||
debug.assert(counting_stream.bytes_written == bytes.len);
|
||||
testing.expect(counting_stream.bytes_written == bytes.len);
|
||||
}
|
||||
|
||||
pub fn BufferedOutStream(comptime Error: type) type {
|
||||
|
@ -639,6 +847,135 @@ pub const BufferOutStream = struct {
|
|||
}
|
||||
};
|
||||
|
||||
/// Creates a stream which allows for writing bit fields to another stream
|
||||
pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
out_stream: *Stream,
|
||||
bit_buffer: u8,
|
||||
bit_count: u4,
|
||||
stream: Stream,
|
||||
|
||||
pub const Stream = OutStream(Error);
|
||||
const u8_bit_count = comptime meta.bitCount(u8);
|
||||
const u4_bit_count = comptime meta.bitCount(u4);
|
||||
|
||||
pub fn init(out_stream: *Stream) Self {
|
||||
return Self{
|
||||
.out_stream = out_stream,
|
||||
.bit_buffer = 0,
|
||||
.bit_count = 0,
|
||||
.stream = Stream{ .writeFn = write },
|
||||
};
|
||||
}
|
||||
|
||||
/// Write the specified number of bits to the stream from the least significant bits of
|
||||
/// the specified unsigned int value. Bits will only be written to the stream when there
|
||||
/// are enough to fill a byte.
|
||||
pub fn writeBits(self: *Self, value: var, bits: usize) Error!void {
|
||||
if (bits == 0) return;
|
||||
|
||||
const U = @typeOf(value);
|
||||
comptime assert(trait.isUnsignedInt(U));
|
||||
|
||||
//by extending the buffer to a minimum of u8 we can cover a number of edge cases
|
||||
// related to shifting and casting.
|
||||
const u_bit_count = comptime meta.bitCount(U);
|
||||
const buf_bit_count = bc: {
|
||||
assert(u_bit_count >= bits);
|
||||
break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
|
||||
};
|
||||
const Buf = @IntType(false, buf_bit_count);
|
||||
const BufShift = math.Log2Int(Buf);
|
||||
|
||||
const buf_value = @intCast(Buf, value);
|
||||
|
||||
const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
|
||||
var in_buffer = switch (endian) {
|
||||
builtin.Endian.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
|
||||
builtin.Endian.Little => buf_value,
|
||||
};
|
||||
var in_bits = bits;
|
||||
|
||||
if (self.bit_count > 0) {
|
||||
const bits_remaining = u8_bit_count - self.bit_count;
|
||||
const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
|
||||
const v = @intCast(u8, in_buffer >> shift);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer <<= n;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer >>= n;
|
||||
},
|
||||
}
|
||||
self.bit_count += n;
|
||||
in_bits -= n;
|
||||
|
||||
//if we didn't fill the buffer, it's because bits < bits_remaining;
|
||||
if (self.bit_count != u8_bit_count) return;
|
||||
try self.out_stream.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
//at this point we know bit_buffer is empty
|
||||
|
||||
//copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
|
||||
while (in_bits >= u8_bit_count) {
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
const v = @intCast(u8, in_buffer >> high_byte_shift);
|
||||
try self.out_stream.writeByte(v);
|
||||
in_buffer <<= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer <<= 1;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
const v = @truncate(u8, in_buffer);
|
||||
try self.out_stream.writeByte(v);
|
||||
in_buffer >>= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer >>= 1;
|
||||
},
|
||||
}
|
||||
in_bits -= u8_bit_count;
|
||||
}
|
||||
|
||||
if (in_bits > 0) {
|
||||
self.bit_count = @intCast(u4, in_bits);
|
||||
self.bit_buffer = switch (endian) {
|
||||
builtin.Endian.Big => @truncate(u8, in_buffer >> high_byte_shift),
|
||||
builtin.Endian.Little => @truncate(u8, in_buffer),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Flush any remaining bits to the stream.
|
||||
pub fn flushBits(self: *Self) Error!void {
|
||||
if (self.bit_count == 0) return;
|
||||
try self.out_stream.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
|
||||
pub fn write(self_stream: *Stream, buffer: []const u8) Error!void {
|
||||
var self = @fieldParentPtr(Self, "stream", self_stream);
|
||||
|
||||
//@NOTE: I'm not sure this is a good idea, maybe flushBits should be forced
|
||||
if (self.bit_count > 0) {
|
||||
for (buffer) |b, i|
|
||||
try self.writeBits(b, u8_bit_count);
|
||||
return;
|
||||
}
|
||||
|
||||
return self.out_stream.write(buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const BufferedAtomicFile = struct {
|
||||
atomic_file: os.AtomicFile,
|
||||
file_stream: os.File.OutStream,
|
||||
|
@ -647,12 +984,13 @@ pub const BufferedAtomicFile = struct {
|
|||
|
||||
pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
|
||||
// TODO with well defined copy elision we don't need this allocation
|
||||
var self = try allocator.create(BufferedAtomicFile{
|
||||
var self = try allocator.create(BufferedAtomicFile);
|
||||
self.* = BufferedAtomicFile{
|
||||
.atomic_file = undefined,
|
||||
.file_stream = undefined,
|
||||
.buffered_stream = undefined,
|
||||
.allocator = allocator,
|
||||
});
|
||||
};
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode);
|
||||
|
@ -679,12 +1017,6 @@ pub const BufferedAtomicFile = struct {
|
|||
}
|
||||
};
|
||||
|
||||
test "import io tests" {
|
||||
comptime {
|
||||
_ = @import("io_test.zig");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readLine(buf: *std.Buffer) ![]u8 {
|
||||
var stdin = try getStdIn();
|
||||
var stdin_stream = stdin.inStream();
|
||||
|
@ -721,10 +1053,10 @@ test "io.readLineFrom" {
|
|||
);
|
||||
const stream = &mem_stream.stream;
|
||||
|
||||
debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
|
||||
debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
|
||||
debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
|
||||
debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
|
||||
testing.expectEqualSlices(u8, "Line 1", try readLineFrom(stream, &buf));
|
||||
testing.expectEqualSlices(u8, "Line 22", try readLineFrom(stream, &buf));
|
||||
testing.expectError(error.EndOfStream, readLineFrom(stream, &buf));
|
||||
testing.expectEqualSlices(u8, "Line 1Line 22Line 333", buf.toSlice());
|
||||
}
|
||||
|
||||
pub fn readLineSlice(slice: []u8) ![]u8 {
|
||||
|
@ -752,6 +1084,372 @@ test "io.readLineSliceFrom" {
|
|||
);
|
||||
const stream = &mem_stream.stream;
|
||||
|
||||
debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
|
||||
debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
|
||||
testing.expectEqualSlices(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]));
|
||||
testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..]));
|
||||
}
|
||||
|
||||
/// Creates a deserializer that deserializes types from any stream.
|
||||
/// If `is_packed` is true, the data stream is treated as bit-packed,
|
||||
/// otherwise data is expected to be packed to the smallest byte.
|
||||
/// Types may implement a custom deserialization routine with a
|
||||
/// function named `deserialize` in the form of:
|
||||
/// pub fn deserialize(self: *Self, deserializer: var) !void
|
||||
/// which will be called when the deserializer is used to deserialize
|
||||
/// that type. It will pass a pointer to the type instance to deserialize
|
||||
/// into and a pointer to the deserializer struct.
|
||||
pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
in_stream: if (is_packed) BitInStream(endian, Stream.Error) else *Stream,
|
||||
|
||||
pub const Stream = InStream(Error);
|
||||
|
||||
pub fn init(in_stream: *Stream) Self {
|
||||
return Self{ .in_stream = switch (is_packed) {
|
||||
true => BitInStream(endian, Stream.Error).init(in_stream),
|
||||
else => in_stream,
|
||||
} };
|
||||
}
|
||||
|
||||
pub fn alignToByte(self: *Self) void {
|
||||
if (!is_packed) return;
|
||||
self.in_stream.alignToByte();
|
||||
}
|
||||
|
||||
//@BUG: inferred error issue. See: #1386
|
||||
fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T {
|
||||
comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
|
||||
|
||||
const u8_bit_count = 8;
|
||||
const t_bit_count = comptime meta.bitCount(T);
|
||||
|
||||
const U = @IntType(false, t_bit_count);
|
||||
const Log2U = math.Log2Int(U);
|
||||
const int_size = (U.bit_count + 7) / 8;
|
||||
|
||||
if (is_packed) {
|
||||
const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
|
||||
return @bitCast(T, result);
|
||||
}
|
||||
|
||||
var buffer: [int_size]u8 = undefined;
|
||||
const read_size = try self.in_stream.read(buffer[0..]);
|
||||
if (read_size < int_size) return error.EndOfStream;
|
||||
|
||||
if (int_size == 1) {
|
||||
if (t_bit_count == 8) return @bitCast(T, buffer[0]);
|
||||
const PossiblySignedByte = @IntType(T.is_signed, 8);
|
||||
return @truncate(T, @bitCast(PossiblySignedByte, buffer[0]));
|
||||
}
|
||||
|
||||
var result = U(0);
|
||||
for (buffer) |byte, i| {
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
result = (result << u8_bit_count) | byte;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
result |= U(byte) << @intCast(Log2U, u8_bit_count * i);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return @bitCast(T, result);
|
||||
}
|
||||
|
||||
//@TODO: Replace this with @unionInit or whatever when it is added
|
||||
// see: #1315
|
||||
fn setTag(ptr: var, tag: var) void {
|
||||
const T = @typeOf(ptr);
|
||||
comptime assert(trait.isPtrTo(builtin.TypeId.Union)(T));
|
||||
const U = meta.Child(T);
|
||||
|
||||
const info = @typeInfo(U).Union;
|
||||
if (info.tag_type) |TagType| {
|
||||
comptime assert(TagType == @typeOf(tag));
|
||||
|
||||
var ptr_tag = ptr: {
|
||||
if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr);
|
||||
const offset = comptime max: {
|
||||
var max_field_size: comptime_int = 0;
|
||||
for (info.fields) |field_info| {
|
||||
const field_size = @sizeOf(field_info.field_type);
|
||||
max_field_size = math.max(max_field_size, field_size);
|
||||
}
|
||||
break :max math.max(max_field_size, @alignOf(U));
|
||||
};
|
||||
break :ptr @intToPtr(*TagType, @ptrToInt(ptr) + offset);
|
||||
};
|
||||
ptr_tag.* = tag;
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes and returns data of the specified type from the stream
|
||||
pub fn deserialize(self: *Self, comptime T: type) !T {
|
||||
var value: T = undefined;
|
||||
try self.deserializeInto(&value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Deserializes data into the type pointed to by `ptr`
|
||||
pub fn deserializeInto(self: *Self, ptr: var) !void {
|
||||
const T = @typeOf(ptr);
|
||||
comptime assert(trait.is(builtin.TypeId.Pointer)(T));
|
||||
|
||||
if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) {
|
||||
for (ptr) |*v|
|
||||
try self.deserializeInto(v);
|
||||
return;
|
||||
}
|
||||
|
||||
comptime assert(trait.isSingleItemPtr(T));
|
||||
|
||||
const C = comptime meta.Child(T);
|
||||
const child_type_id = @typeId(C);
|
||||
|
||||
//custom deserializer: fn(self: *Self, deserializer: var) !void
|
||||
if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self);
|
||||
|
||||
if (comptime trait.isPacked(C) and !is_packed) {
|
||||
var packed_deserializer = Deserializer(endian, true, Error).init(self.in_stream);
|
||||
return packed_deserializer.deserializeInto(ptr);
|
||||
}
|
||||
|
||||
switch (child_type_id) {
|
||||
builtin.TypeId.Void => return,
|
||||
builtin.TypeId.Bool => ptr.* = (try self.deserializeInt(u1)) > 0,
|
||||
builtin.TypeId.Float, builtin.TypeId.Int => ptr.* = try self.deserializeInt(C),
|
||||
builtin.TypeId.Struct => {
|
||||
const info = @typeInfo(C).Struct;
|
||||
|
||||
inline for (info.fields) |*field_info| {
|
||||
const name = field_info.name;
|
||||
const FieldType = field_info.field_type;
|
||||
|
||||
if (FieldType == void or FieldType == u0) continue;
|
||||
|
||||
//it doesn't make any sense to read pointers
|
||||
if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) {
|
||||
@compileError("Will not " ++ "read field " ++ name ++ " of struct " ++
|
||||
@typeName(C) ++ " because it " ++ "is of pointer-type " ++
|
||||
@typeName(FieldType) ++ ".");
|
||||
}
|
||||
|
||||
try self.deserializeInto(&@field(ptr, name));
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Union => {
|
||||
const info = @typeInfo(C).Union;
|
||||
if (info.tag_type) |TagType| {
|
||||
//we avoid duplicate iteration over the enum tags
|
||||
// by getting the int directly and casting it without
|
||||
// safety. If it is bad, it will be caught anyway.
|
||||
const TagInt = @TagType(TagType);
|
||||
const tag = try self.deserializeInt(TagInt);
|
||||
|
||||
{
|
||||
@setRuntimeSafety(false);
|
||||
//See: #1315
|
||||
setTag(ptr, @intToEnum(TagType, tag));
|
||||
}
|
||||
|
||||
inline for (info.fields) |field_info| {
|
||||
if (field_info.enum_field.?.value == tag) {
|
||||
const name = field_info.name;
|
||||
const FieldType = field_info.field_type;
|
||||
@field(ptr, name) = FieldType(undefined);
|
||||
try self.deserializeInto(&@field(ptr, name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
//This is reachable if the enum data is bad
|
||||
return error.InvalidEnumTag;
|
||||
}
|
||||
@compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++
|
||||
" because it is an untagged union Use a custom deserialize().");
|
||||
},
|
||||
builtin.TypeId.Optional => {
|
||||
const OC = comptime meta.Child(C);
|
||||
const exists = (try self.deserializeInt(u1)) > 0;
|
||||
if (!exists) {
|
||||
ptr.* = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//The way non-pointer optionals are implemented ensures a pointer to them
|
||||
// will point to the value. The flag is stored at the end of that data.
|
||||
var val_ptr = @ptrCast(*OC, ptr);
|
||||
try self.deserializeInto(val_ptr);
|
||||
//This bit ensures the null flag isn't set. Any actual copying should be
|
||||
// optimized out... I hope.
|
||||
ptr.* = val_ptr.*;
|
||||
},
|
||||
builtin.TypeId.Enum => {
|
||||
var value = try self.deserializeInt(@TagType(C));
|
||||
ptr.* = try meta.intToEnum(C, value);
|
||||
},
|
||||
else => {
|
||||
@compileError("Cannot deserialize " ++ @tagName(child_type_id) ++ " types (unimplemented).");
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates a serializer that serializes types to any stream.
|
||||
/// If `is_packed` is true, the data will be bit-packed into the stream.
|
||||
/// Note that the you must call `serializer.flush()` when you are done
|
||||
/// writing bit-packed data in order ensure any unwritten bits are committed.
|
||||
/// If `is_packed` is false, data is packed to the smallest byte. In the case
|
||||
/// of packed structs, the struct will written bit-packed and with the specified
|
||||
/// endianess, after which data will resume being written at the next byte boundary.
|
||||
/// Types may implement a custom serialization routine with a
|
||||
/// function named `serialize` in the form of:
|
||||
/// pub fn serialize(self: Self, serializer: var) !void
|
||||
/// which will be called when the serializer is used to serialize that type. It will
|
||||
/// pass a const pointer to the type instance to be serialized and a pointer
|
||||
/// to the serializer struct.
|
||||
pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
out_stream: if (is_packed) BitOutStream(endian, Stream.Error) else *Stream,
|
||||
|
||||
pub const Stream = OutStream(Error);
|
||||
|
||||
pub fn init(out_stream: *Stream) Self {
|
||||
return Self{ .out_stream = switch (is_packed) {
|
||||
true => BitOutStream(endian, Stream.Error).init(out_stream),
|
||||
else => out_stream,
|
||||
} };
|
||||
}
|
||||
|
||||
/// Flushes any unwritten bits to the stream
|
||||
pub fn flush(self: *Self) Error!void {
|
||||
if (is_packed) return self.out_stream.flushBits();
|
||||
}
|
||||
|
||||
fn serializeInt(self: *Self, value: var) Error!void {
|
||||
const T = @typeOf(value);
|
||||
comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
|
||||
|
||||
const t_bit_count = comptime meta.bitCount(T);
|
||||
const u8_bit_count = comptime meta.bitCount(u8);
|
||||
|
||||
const U = @IntType(false, t_bit_count);
|
||||
const Log2U = math.Log2Int(U);
|
||||
const int_size = (U.bit_count + 7) / 8;
|
||||
|
||||
const u_value = @bitCast(U, value);
|
||||
|
||||
if (is_packed) return self.out_stream.writeBits(u_value, t_bit_count);
|
||||
|
||||
var buffer: [int_size]u8 = undefined;
|
||||
if (int_size == 1) buffer[0] = u_value;
|
||||
|
||||
for (buffer) |*byte, i| {
|
||||
const idx = switch (endian) {
|
||||
builtin.Endian.Big => int_size - i - 1,
|
||||
builtin.Endian.Little => i,
|
||||
};
|
||||
const shift = @intCast(Log2U, idx * u8_bit_count);
|
||||
const v = u_value >> shift;
|
||||
byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v);
|
||||
}
|
||||
|
||||
try self.out_stream.write(buffer);
|
||||
}
|
||||
|
||||
/// Serializes the passed value into the stream
|
||||
pub fn serialize(self: *Self, value: var) Error!void {
|
||||
const T = comptime @typeOf(value);
|
||||
|
||||
if (comptime trait.isIndexable(T)) {
|
||||
for (value) |v|
|
||||
try self.serialize(v);
|
||||
return;
|
||||
}
|
||||
|
||||
//custom serializer: fn(self: Self, serializer: var) !void
|
||||
if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self);
|
||||
|
||||
if (comptime trait.isPacked(T) and !is_packed) {
|
||||
var packed_serializer = Serializer(endian, true, Error).init(self.out_stream);
|
||||
try packed_serializer.serialize(value);
|
||||
try packed_serializer.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (@typeId(T)) {
|
||||
builtin.TypeId.Void => return,
|
||||
builtin.TypeId.Bool => try self.serializeInt(u1(@boolToInt(value))),
|
||||
builtin.TypeId.Float, builtin.TypeId.Int => try self.serializeInt(value),
|
||||
builtin.TypeId.Struct => {
|
||||
const info = @typeInfo(T);
|
||||
|
||||
inline for (info.Struct.fields) |*field_info| {
|
||||
const name = field_info.name;
|
||||
const FieldType = field_info.field_type;
|
||||
|
||||
if (FieldType == void or FieldType == u0) continue;
|
||||
|
||||
//It doesn't make sense to write pointers
|
||||
if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) {
|
||||
@compileError("Will not " ++ "serialize field " ++ name ++
|
||||
" of struct " ++ @typeName(T) ++ " because it " ++
|
||||
"is of pointer-type " ++ @typeName(FieldType) ++ ".");
|
||||
}
|
||||
try self.serialize(@field(value, name));
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Union => {
|
||||
const info = @typeInfo(T).Union;
|
||||
if (info.tag_type) |TagType| {
|
||||
const active_tag = meta.activeTag(value);
|
||||
try self.serialize(active_tag);
|
||||
//This inline loop is necessary because active_tag is a runtime
|
||||
// value, but @field requires a comptime value. Our alternative
|
||||
// is to check each field for a match
|
||||
inline for (info.fields) |field_info| {
|
||||
if (field_info.enum_field.?.value == @enumToInt(active_tag)) {
|
||||
const name = field_info.name;
|
||||
const FieldType = field_info.field_type;
|
||||
try self.serialize(@field(value, name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
@compileError("Cannot meaningfully serialize " ++ @typeName(T) ++
|
||||
" because it is an untagged union Use a custom serialize().");
|
||||
},
|
||||
builtin.TypeId.Optional => {
|
||||
if (value == null) {
|
||||
try self.serializeInt(u1(@boolToInt(false)));
|
||||
return;
|
||||
}
|
||||
try self.serializeInt(u1(@boolToInt(true)));
|
||||
|
||||
const OC = comptime meta.Child(T);
|
||||
|
||||
//The way non-pointer optionals are implemented ensures a pointer to them
|
||||
// will point to the value. The flag is stored at the end of that data.
|
||||
var val_ptr = @ptrCast(*const OC, &value);
|
||||
try self.serialize(val_ptr.*);
|
||||
},
|
||||
builtin.TypeId.Enum => {
|
||||
try self.serializeInt(@enumToInt(value));
|
||||
},
|
||||
else => @compileError("Cannot serialize " ++ @tagName(@typeId(T)) ++ " types (unimplemented)."),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test "import io tests" {
|
||||
comptime {
|
||||
_ = @import("io_test.zig");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
506
std/io_test.zig
506
std/io_test.zig
|
@ -1,8 +1,10 @@
|
|||
const std = @import("index.zig");
|
||||
const io = std.io;
|
||||
const meta = std.meta;
|
||||
const trait = std.trait;
|
||||
const DefaultPrng = std.rand.DefaultPrng;
|
||||
const assert = std.debug.assert;
|
||||
const assertError = std.debug.assertError;
|
||||
const expect = std.testing.expect;
|
||||
const expectError = std.testing.expectError;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
const builtin = @import("builtin");
|
||||
|
@ -33,7 +35,7 @@ test "write a file, read it, then delete it" {
|
|||
|
||||
const file_size = try file.getEndPos();
|
||||
const expected_file_size = "begin".len + data.len + "end".len;
|
||||
assert(file_size == expected_file_size);
|
||||
expect(file_size == expected_file_size);
|
||||
|
||||
var file_in_stream = file.inStream();
|
||||
var buf_stream = io.BufferedInStream(os.File.ReadError).init(&file_in_stream.stream);
|
||||
|
@ -41,9 +43,9 @@ test "write a file, read it, then delete it" {
|
|||
const contents = try st.readAllAlloc(allocator, 2 * 1024);
|
||||
defer allocator.free(contents);
|
||||
|
||||
assert(mem.eql(u8, contents[0.."begin".len], "begin"));
|
||||
assert(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));
|
||||
assert(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
|
||||
expect(mem.eql(u8, contents[0.."begin".len], "begin"));
|
||||
expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));
|
||||
expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
|
||||
}
|
||||
try os.deleteFile(tmp_file_name);
|
||||
}
|
||||
|
@ -59,7 +61,7 @@ test "BufferOutStream" {
|
|||
const y: i32 = 1234;
|
||||
try buf_stream.print("x: {}\ny: {}\n", x, y);
|
||||
|
||||
assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n"));
|
||||
expect(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n"));
|
||||
}
|
||||
|
||||
test "SliceInStream" {
|
||||
|
@ -69,15 +71,15 @@ test "SliceInStream" {
|
|||
var dest: [4]u8 = undefined;
|
||||
|
||||
var read = try ss.stream.read(dest[0..4]);
|
||||
assert(read == 4);
|
||||
assert(mem.eql(u8, dest[0..4], bytes[0..4]));
|
||||
expect(read == 4);
|
||||
expect(mem.eql(u8, dest[0..4], bytes[0..4]));
|
||||
|
||||
read = try ss.stream.read(dest[0..4]);
|
||||
assert(read == 3);
|
||||
assert(mem.eql(u8, dest[0..3], bytes[4..7]));
|
||||
expect(read == 3);
|
||||
expect(mem.eql(u8, dest[0..3], bytes[4..7]));
|
||||
|
||||
read = try ss.stream.read(dest[0..4]);
|
||||
assert(read == 0);
|
||||
expect(read == 0);
|
||||
}
|
||||
|
||||
test "PeekStream" {
|
||||
|
@ -91,26 +93,26 @@ test "PeekStream" {
|
|||
ps.putBackByte(10);
|
||||
|
||||
var read = try ps.stream.read(dest[0..4]);
|
||||
assert(read == 4);
|
||||
assert(dest[0] == 10);
|
||||
assert(dest[1] == 9);
|
||||
assert(mem.eql(u8, dest[2..4], bytes[0..2]));
|
||||
expect(read == 4);
|
||||
expect(dest[0] == 10);
|
||||
expect(dest[1] == 9);
|
||||
expect(mem.eql(u8, dest[2..4], bytes[0..2]));
|
||||
|
||||
read = try ps.stream.read(dest[0..4]);
|
||||
assert(read == 4);
|
||||
assert(mem.eql(u8, dest[0..4], bytes[2..6]));
|
||||
expect(read == 4);
|
||||
expect(mem.eql(u8, dest[0..4], bytes[2..6]));
|
||||
|
||||
read = try ps.stream.read(dest[0..4]);
|
||||
assert(read == 2);
|
||||
assert(mem.eql(u8, dest[0..2], bytes[6..8]));
|
||||
expect(read == 2);
|
||||
expect(mem.eql(u8, dest[0..2], bytes[6..8]));
|
||||
|
||||
ps.putBackByte(11);
|
||||
ps.putBackByte(12);
|
||||
|
||||
read = try ps.stream.read(dest[0..4]);
|
||||
assert(read == 2);
|
||||
assert(dest[0] == 12);
|
||||
assert(dest[1] == 11);
|
||||
expect(read == 2);
|
||||
expect(dest[0] == 12);
|
||||
expect(dest[1] == 11);
|
||||
}
|
||||
|
||||
test "SliceOutStream" {
|
||||
|
@ -118,17 +120,461 @@ test "SliceOutStream" {
|
|||
var ss = io.SliceOutStream.init(buffer[0..]);
|
||||
|
||||
try ss.stream.write("Hello");
|
||||
assert(mem.eql(u8, ss.getWritten(), "Hello"));
|
||||
expect(mem.eql(u8, ss.getWritten(), "Hello"));
|
||||
|
||||
try ss.stream.write("world");
|
||||
assert(mem.eql(u8, ss.getWritten(), "Helloworld"));
|
||||
expect(mem.eql(u8, ss.getWritten(), "Helloworld"));
|
||||
|
||||
assertError(ss.stream.write("!"), error.OutOfSpace);
|
||||
assert(mem.eql(u8, ss.getWritten(), "Helloworld"));
|
||||
expectError(error.OutOfSpace, ss.stream.write("!"));
|
||||
expect(mem.eql(u8, ss.getWritten(), "Helloworld"));
|
||||
|
||||
ss.reset();
|
||||
assert(ss.getWritten().len == 0);
|
||||
expect(ss.getWritten().len == 0);
|
||||
|
||||
assertError(ss.stream.write("Hello world!"), error.OutOfSpace);
|
||||
assert(mem.eql(u8, ss.getWritten(), "Hello worl"));
|
||||
expectError(error.OutOfSpace, ss.stream.write("Hello world!"));
|
||||
expect(mem.eql(u8, ss.getWritten(), "Hello worl"));
|
||||
}
|
||||
|
||||
test "BitInStream" {
|
||||
const mem_be = []u8{ 0b11001101, 0b00001011 };
|
||||
const mem_le = []u8{ 0b00011101, 0b10010101 };
|
||||
|
||||
var mem_in_be = io.SliceInStream.init(mem_be[0..]);
|
||||
const InError = io.SliceInStream.Error;
|
||||
var bit_stream_be = io.BitInStream(builtin.Endian.Big, InError).init(&mem_in_be.stream);
|
||||
|
||||
var out_bits: usize = undefined;
|
||||
|
||||
expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
|
||||
expect(out_bits == 1);
|
||||
expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
|
||||
expect(out_bits == 2);
|
||||
expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
|
||||
expect(out_bits == 3);
|
||||
expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
|
||||
expect(out_bits == 4);
|
||||
expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
|
||||
expect(out_bits == 5);
|
||||
expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
|
||||
expect(out_bits == 1);
|
||||
|
||||
mem_in_be.pos = 0;
|
||||
bit_stream_be.bit_count = 0;
|
||||
expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
|
||||
expect(out_bits == 15);
|
||||
|
||||
mem_in_be.pos = 0;
|
||||
bit_stream_be.bit_count = 0;
|
||||
expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
|
||||
expect(out_bits == 16);
|
||||
|
||||
_ = try bit_stream_be.readBits(u0, 0, &out_bits);
|
||||
|
||||
expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
|
||||
expect(out_bits == 0);
|
||||
expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1));
|
||||
|
||||
var mem_in_le = io.SliceInStream.init(mem_le[0..]);
|
||||
var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream);
|
||||
|
||||
expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
|
||||
expect(out_bits == 1);
|
||||
expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
|
||||
expect(out_bits == 2);
|
||||
expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
|
||||
expect(out_bits == 3);
|
||||
expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
|
||||
expect(out_bits == 4);
|
||||
expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
|
||||
expect(out_bits == 5);
|
||||
expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
|
||||
expect(out_bits == 1);
|
||||
|
||||
mem_in_le.pos = 0;
|
||||
bit_stream_le.bit_count = 0;
|
||||
expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
|
||||
expect(out_bits == 15);
|
||||
|
||||
mem_in_le.pos = 0;
|
||||
bit_stream_le.bit_count = 0;
|
||||
expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
|
||||
expect(out_bits == 16);
|
||||
|
||||
_ = try bit_stream_le.readBits(u0, 0, &out_bits);
|
||||
|
||||
expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
|
||||
expect(out_bits == 0);
|
||||
expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1));
|
||||
}
|
||||
|
||||
test "BitOutStream" {
|
||||
var mem_be = []u8{0} ** 2;
|
||||
var mem_le = []u8{0} ** 2;
|
||||
|
||||
var mem_out_be = io.SliceOutStream.init(mem_be[0..]);
|
||||
const OutError = io.SliceOutStream.Error;
|
||||
var bit_stream_be = io.BitOutStream(builtin.Endian.Big, OutError).init(&mem_out_be.stream);
|
||||
|
||||
try bit_stream_be.writeBits(u2(1), 1);
|
||||
try bit_stream_be.writeBits(u5(2), 2);
|
||||
try bit_stream_be.writeBits(u128(3), 3);
|
||||
try bit_stream_be.writeBits(u8(4), 4);
|
||||
try bit_stream_be.writeBits(u9(5), 5);
|
||||
try bit_stream_be.writeBits(u1(1), 1);
|
||||
|
||||
expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011);
|
||||
|
||||
mem_out_be.pos = 0;
|
||||
|
||||
try bit_stream_be.writeBits(u15(0b110011010000101), 15);
|
||||
try bit_stream_be.flushBits();
|
||||
expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010);
|
||||
|
||||
mem_out_be.pos = 0;
|
||||
try bit_stream_be.writeBits(u32(0b110011010000101), 16);
|
||||
expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101);
|
||||
|
||||
try bit_stream_be.writeBits(u0(0), 0);
|
||||
|
||||
var mem_out_le = io.SliceOutStream.init(mem_le[0..]);
|
||||
var bit_stream_le = io.BitOutStream(builtin.Endian.Little, OutError).init(&mem_out_le.stream);
|
||||
|
||||
try bit_stream_le.writeBits(u2(1), 1);
|
||||
try bit_stream_le.writeBits(u5(2), 2);
|
||||
try bit_stream_le.writeBits(u128(3), 3);
|
||||
try bit_stream_le.writeBits(u8(4), 4);
|
||||
try bit_stream_le.writeBits(u9(5), 5);
|
||||
try bit_stream_le.writeBits(u1(1), 1);
|
||||
|
||||
expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101);
|
||||
|
||||
mem_out_le.pos = 0;
|
||||
try bit_stream_le.writeBits(u15(0b110011010000101), 15);
|
||||
try bit_stream_le.flushBits();
|
||||
expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110);
|
||||
|
||||
mem_out_le.pos = 0;
|
||||
try bit_stream_le.writeBits(u32(0b1100110100001011), 16);
|
||||
expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101);
|
||||
|
||||
try bit_stream_le.writeBits(u0(0), 0);
|
||||
}
|
||||
|
||||
test "BitStreams with File Stream" {
|
||||
const tmp_file_name = "temp_test_file.txt";
|
||||
{
|
||||
var file = try os.File.openWrite(tmp_file_name);
|
||||
defer file.close();
|
||||
|
||||
var file_out = file.outStream();
|
||||
var file_out_stream = &file_out.stream;
|
||||
const OutError = os.File.WriteError;
|
||||
var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream);
|
||||
|
||||
try bit_stream.writeBits(u2(1), 1);
|
||||
try bit_stream.writeBits(u5(2), 2);
|
||||
try bit_stream.writeBits(u128(3), 3);
|
||||
try bit_stream.writeBits(u8(4), 4);
|
||||
try bit_stream.writeBits(u9(5), 5);
|
||||
try bit_stream.writeBits(u1(1), 1);
|
||||
try bit_stream.flushBits();
|
||||
}
|
||||
{
|
||||
var file = try os.File.openRead(tmp_file_name);
|
||||
defer file.close();
|
||||
|
||||
var file_in = file.inStream();
|
||||
var file_in_stream = &file_in.stream;
|
||||
const InError = os.File.ReadError;
|
||||
var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream);
|
||||
|
||||
var out_bits: usize = undefined;
|
||||
|
||||
expect(1 == try bit_stream.readBits(u2, 1, &out_bits));
|
||||
expect(out_bits == 1);
|
||||
expect(2 == try bit_stream.readBits(u5, 2, &out_bits));
|
||||
expect(out_bits == 2);
|
||||
expect(3 == try bit_stream.readBits(u128, 3, &out_bits));
|
||||
expect(out_bits == 3);
|
||||
expect(4 == try bit_stream.readBits(u8, 4, &out_bits));
|
||||
expect(out_bits == 4);
|
||||
expect(5 == try bit_stream.readBits(u9, 5, &out_bits));
|
||||
expect(out_bits == 5);
|
||||
expect(1 == try bit_stream.readBits(u1, 1, &out_bits));
|
||||
expect(out_bits == 1);
|
||||
|
||||
expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
|
||||
}
|
||||
try os.deleteFile(tmp_file_name);
|
||||
}
|
||||
|
||||
fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void {
|
||||
//@NOTE: if this test is taking too long, reduce the maximum tested bitsize
|
||||
const max_test_bitsize = 128;
|
||||
|
||||
const total_bytes = comptime blk: {
|
||||
var bytes = 0;
|
||||
comptime var i = 0;
|
||||
while (i <= max_test_bitsize) : (i += 1) bytes += (i / 8) + @boolToInt(i % 8 > 0);
|
||||
break :blk bytes * 2;
|
||||
};
|
||||
|
||||
var data_mem: [total_bytes]u8 = undefined;
|
||||
var out = io.SliceOutStream.init(data_mem[0..]);
|
||||
const OutError = io.SliceOutStream.Error;
|
||||
var out_stream = &out.stream;
|
||||
var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
|
||||
|
||||
var in = io.SliceInStream.init(data_mem[0..]);
|
||||
const InError = io.SliceInStream.Error;
|
||||
var in_stream = &in.stream;
|
||||
var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
|
||||
|
||||
comptime var i = 0;
|
||||
inline while (i <= max_test_bitsize) : (i += 1) {
|
||||
const U = @IntType(false, i);
|
||||
const S = @IntType(true, i);
|
||||
try serializer.serializeInt(U(i));
|
||||
if (i != 0) try serializer.serializeInt(S(-1)) else try serializer.serialize(S(0));
|
||||
}
|
||||
try serializer.flush();
|
||||
|
||||
i = 0;
|
||||
inline while (i <= max_test_bitsize) : (i += 1) {
|
||||
const U = @IntType(false, i);
|
||||
const S = @IntType(true, i);
|
||||
const x = try deserializer.deserializeInt(U);
|
||||
const y = try deserializer.deserializeInt(S);
|
||||
expect(x == U(i));
|
||||
if (i != 0) expect(y == S(-1)) else expect(y == 0);
|
||||
}
|
||||
|
||||
const u8_bit_count = comptime meta.bitCount(u8);
|
||||
//0 + 1 + 2 + ... n = (n * (n + 1)) / 2
|
||||
//and we have each for unsigned and signed, so * 2
|
||||
const total_bits = (max_test_bitsize * (max_test_bitsize + 1));
|
||||
const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0);
|
||||
const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;
|
||||
|
||||
expect(in.pos == if (is_packed) total_packed_bytes else total_bytes);
|
||||
|
||||
//Verify that empty error set works with serializer.
|
||||
//deserializer is covered by SliceInStream
|
||||
const NullError = io.NullOutStream.Error;
|
||||
var null_out = io.NullOutStream.init();
|
||||
var null_out_stream = &null_out.stream;
|
||||
var null_serializer = io.Serializer(endian, is_packed, NullError).init(null_out_stream);
|
||||
try null_serializer.serialize(data_mem[0..]);
|
||||
try null_serializer.flush();
|
||||
}
|
||||
|
||||
test "Serializer/Deserializer Int" {
|
||||
try testIntSerializerDeserializer(builtin.Endian.Big, false);
|
||||
try testIntSerializerDeserializer(builtin.Endian.Little, false);
|
||||
try testIntSerializerDeserializer(builtin.Endian.Big, true);
|
||||
try testIntSerializerDeserializer(builtin.Endian.Little, true);
|
||||
}
|
||||
|
||||
fn testIntSerializerDeserializerInfNaN(comptime endian: builtin.Endian,
|
||||
comptime is_packed: bool) !void
|
||||
{
|
||||
const mem_size = (16*2 + 32*2 + 64*2 + 128*2) / comptime meta.bitCount(u8);
|
||||
var data_mem: [mem_size]u8 = undefined;
|
||||
|
||||
var out = io.SliceOutStream.init(data_mem[0..]);
|
||||
const OutError = io.SliceOutStream.Error;
|
||||
var out_stream = &out.stream;
|
||||
var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
|
||||
|
||||
var in = io.SliceInStream.init(data_mem[0..]);
|
||||
const InError = io.SliceInStream.Error;
|
||||
var in_stream = &in.stream;
|
||||
var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
|
||||
|
||||
//@TODO: isInf/isNan not currently implemented for f128.
|
||||
try serializer.serialize(std.math.nan(f16));
|
||||
try serializer.serialize(std.math.inf(f16));
|
||||
try serializer.serialize(std.math.nan(f32));
|
||||
try serializer.serialize(std.math.inf(f32));
|
||||
try serializer.serialize(std.math.nan(f64));
|
||||
try serializer.serialize(std.math.inf(f64));
|
||||
//try serializer.serialize(std.math.nan(f128));
|
||||
//try serializer.serialize(std.math.inf(f128));
|
||||
const nan_check_f16 = try deserializer.deserialize(f16);
|
||||
const inf_check_f16 = try deserializer.deserialize(f16);
|
||||
const nan_check_f32 = try deserializer.deserialize(f32);
|
||||
const inf_check_f32 = try deserializer.deserialize(f32);
|
||||
const nan_check_f64 = try deserializer.deserialize(f64);
|
||||
const inf_check_f64 = try deserializer.deserialize(f64);
|
||||
//const nan_check_f128 = try deserializer.deserialize(f128);
|
||||
//const inf_check_f128 = try deserializer.deserialize(f128);
|
||||
expect(std.math.isNan(nan_check_f16));
|
||||
expect(std.math.isInf(inf_check_f16));
|
||||
expect(std.math.isNan(nan_check_f32));
|
||||
expect(std.math.isInf(inf_check_f32));
|
||||
expect(std.math.isNan(nan_check_f64));
|
||||
expect(std.math.isInf(inf_check_f64));
|
||||
//expect(std.math.isNan(nan_check_f128));
|
||||
//expect(std.math.isInf(inf_check_f128));
|
||||
}
|
||||
|
||||
test "Serializer/Deserializer Int: Inf/NaN" {
|
||||
try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, false);
|
||||
try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, false);
|
||||
try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, true);
|
||||
try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, true);
|
||||
}
|
||||
|
||||
fn testAlternateSerializer(self: var, serializer: var) !void {
|
||||
try serializer.serialize(self.f_f16);
|
||||
}
|
||||
|
||||
fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void {
|
||||
const ColorType = enum(u4) {
|
||||
RGB8 = 1,
|
||||
RA16 = 2,
|
||||
R32 = 3,
|
||||
};
|
||||
|
||||
const TagAlign = union(enum(u32)) {
|
||||
A: u8,
|
||||
B: u8,
|
||||
C: u8,
|
||||
};
|
||||
|
||||
const Color = union(ColorType) {
|
||||
RGB8: struct {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
},
|
||||
RA16: struct {
|
||||
r: u16,
|
||||
a: u16,
|
||||
},
|
||||
R32: u32,
|
||||
};
|
||||
|
||||
const PackedStruct = packed struct {
|
||||
f_i3: i3,
|
||||
f_u2: u2,
|
||||
};
|
||||
|
||||
|
||||
|
||||
//to test custom serialization
|
||||
const Custom = struct {
|
||||
f_f16: f16,
|
||||
f_unused_u32: u32,
|
||||
|
||||
pub fn deserialize(self: *@This(), deserializer: var) !void {
|
||||
try deserializer.deserializeInto(&self.f_f16);
|
||||
self.f_unused_u32 = 47;
|
||||
}
|
||||
|
||||
pub const serialize = testAlternateSerializer;
|
||||
};
|
||||
|
||||
const MyStruct = struct {
|
||||
f_i3: i3,
|
||||
f_u8: u8,
|
||||
f_tag_align: TagAlign,
|
||||
f_u24: u24,
|
||||
f_i19: i19,
|
||||
f_void: void,
|
||||
f_f32: f32,
|
||||
f_f128: f128,
|
||||
f_packed_0: PackedStruct,
|
||||
f_i7arr: [10]i7,
|
||||
f_of64n: ?f64,
|
||||
f_of64v: ?f64,
|
||||
f_color_type: ColorType,
|
||||
f_packed_1: PackedStruct,
|
||||
f_custom: Custom,
|
||||
f_color: Color,
|
||||
};
|
||||
|
||||
const my_inst = MyStruct{
|
||||
.f_i3 = -1,
|
||||
.f_u8 = 8,
|
||||
.f_tag_align = TagAlign{ .B = 148 },
|
||||
.f_u24 = 24,
|
||||
.f_i19 = 19,
|
||||
.f_void = {},
|
||||
.f_f32 = 32.32,
|
||||
.f_f128 = 128.128,
|
||||
.f_packed_0 = PackedStruct{ .f_i3 = -1, .f_u2 = 2 },
|
||||
.f_i7arr = [10]i7{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.f_of64n = null,
|
||||
.f_of64v = 64.64,
|
||||
.f_color_type = ColorType.R32,
|
||||
.f_packed_1 = PackedStruct{ .f_i3 = 1, .f_u2 = 1 },
|
||||
.f_custom = Custom{ .f_f16 = 38.63, .f_unused_u32 = 47 },
|
||||
.f_color = Color{ .R32 = 123822 },
|
||||
};
|
||||
|
||||
var data_mem: [@sizeOf(MyStruct)]u8 = undefined;
|
||||
var out = io.SliceOutStream.init(data_mem[0..]);
|
||||
const OutError = io.SliceOutStream.Error;
|
||||
var out_stream = &out.stream;
|
||||
var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
|
||||
|
||||
var in = io.SliceInStream.init(data_mem[0..]);
|
||||
const InError = io.SliceInStream.Error;
|
||||
var in_stream = &in.stream;
|
||||
var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
|
||||
|
||||
try serializer.serialize(my_inst);
|
||||
|
||||
const my_copy = try deserializer.deserialize(MyStruct);
|
||||
expect(meta.eql(my_copy, my_inst));
|
||||
}
|
||||
|
||||
test "Serializer/Deserializer generic" {
|
||||
try testSerializerDeserializer(builtin.Endian.Big, false);
|
||||
try testSerializerDeserializer(builtin.Endian.Little, false);
|
||||
try testSerializerDeserializer(builtin.Endian.Big, true);
|
||||
try testSerializerDeserializer(builtin.Endian.Little, true);
|
||||
}
|
||||
|
||||
fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void {
|
||||
const E = enum(u14) {
|
||||
One = 1,
|
||||
Two = 2,
|
||||
};
|
||||
|
||||
const A = struct {
|
||||
e: E,
|
||||
};
|
||||
|
||||
const C = union(E) {
|
||||
One: u14,
|
||||
Two: f16,
|
||||
};
|
||||
|
||||
var data_mem: [4]u8 = undefined;
|
||||
var out = io.SliceOutStream.init(data_mem[0..]);
|
||||
const OutError = io.SliceOutStream.Error;
|
||||
var out_stream = &out.stream;
|
||||
var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream);
|
||||
|
||||
var in = io.SliceInStream.init(data_mem[0..]);
|
||||
const InError = io.SliceInStream.Error;
|
||||
var in_stream = &in.stream;
|
||||
var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream);
|
||||
|
||||
try serializer.serialize(u14(3));
|
||||
expectError(error.InvalidEnumTag, deserializer.deserialize(A));
|
||||
out.pos = 0;
|
||||
try serializer.serialize(u14(3));
|
||||
try serializer.serialize(u14(88));
|
||||
expectError(error.InvalidEnumTag, deserializer.deserialize(C));
|
||||
}
|
||||
|
||||
test "Deserializer bad data" {
|
||||
try testBadData(builtin.Endian.Big, false);
|
||||
try testBadData(builtin.Endian.Little, false);
|
||||
try testBadData(builtin.Endian.Big, true);
|
||||
try testBadData(builtin.Endian.Little, true);
|
||||
}
|
||||
|
|
25
std/json.zig
25
std/json.zig
|
@ -4,6 +4,7 @@
|
|||
|
||||
const std = @import("index.zig");
|
||||
const debug = std.debug;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
|
@ -960,7 +961,7 @@ test "json.token" {
|
|||
checkNext(&p, Token.Id.ObjectEnd);
|
||||
checkNext(&p, Token.Id.ObjectEnd);
|
||||
|
||||
debug.assert((try p.next()) == null);
|
||||
testing.expect((try p.next()) == null);
|
||||
}
|
||||
|
||||
// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
|
||||
|
@ -981,7 +982,7 @@ pub fn validate(s: []const u8) bool {
|
|||
}
|
||||
|
||||
test "json.validate" {
|
||||
debug.assert(validate("{}"));
|
||||
testing.expect(validate("{}"));
|
||||
}
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
@ -1344,7 +1345,7 @@ pub const Parser = struct {
|
|||
return if (token.number_is_integer)
|
||||
Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
|
||||
else
|
||||
@panic("TODO: fmt.parseFloat not yet implemented");
|
||||
Value{ .Float = try std.fmt.parseFloat(f64, token.slice(input, i)) };
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1365,7 +1366,8 @@ test "json.parser.dynamic" {
|
|||
\\ },
|
||||
\\ "Animated" : false,
|
||||
\\ "IDs": [116, 943, 234, 38793],
|
||||
\\ "ArrayOfObject": [{"n": "m"}]
|
||||
\\ "ArrayOfObject": [{"n": "m"}],
|
||||
\\ "double": 1.3412
|
||||
\\ }
|
||||
\\}
|
||||
;
|
||||
|
@ -1378,20 +1380,23 @@ test "json.parser.dynamic" {
|
|||
var image = root.Object.get("Image").?.value;
|
||||
|
||||
const width = image.Object.get("Width").?.value;
|
||||
debug.assert(width.Integer == 800);
|
||||
testing.expect(width.Integer == 800);
|
||||
|
||||
const height = image.Object.get("Height").?.value;
|
||||
debug.assert(height.Integer == 600);
|
||||
testing.expect(height.Integer == 600);
|
||||
|
||||
const title = image.Object.get("Title").?.value;
|
||||
debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
|
||||
testing.expect(mem.eql(u8, title.String, "View from 15th Floor"));
|
||||
|
||||
const animated = image.Object.get("Animated").?.value;
|
||||
debug.assert(animated.Bool == false);
|
||||
testing.expect(animated.Bool == false);
|
||||
|
||||
const array_of_object = image.Object.get("ArrayOfObject").?.value;
|
||||
debug.assert(array_of_object.Array.len == 1);
|
||||
testing.expect(array_of_object.Array.len == 1);
|
||||
|
||||
const obj0 = array_of_object.Array.at(0).Object.get("n").?.value;
|
||||
debug.assert(mem.eql(u8, obj0.String, "m"));
|
||||
testing.expect(mem.eql(u8, obj0.String, "m"));
|
||||
|
||||
const double = image.Object.get("double").?.value;
|
||||
testing.expect(double.Float == 1.3412);
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
const std = @import("index.zig");
|
||||
|
||||
fn ok(comptime s: []const u8) void {
|
||||
std.debug.assert(std.json.validate(s));
|
||||
std.testing.expect(std.json.validate(s));
|
||||
}
|
||||
|
||||
fn err(comptime s: []const u8) void {
|
||||
std.debug.assert(!std.json.validate(s));
|
||||
std.testing.expect(!std.json.validate(s));
|
||||
}
|
||||
|
||||
fn any(comptime s: []const u8) void {
|
||||
std.debug.assert(true);
|
||||
std.testing.expect(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue