Merge pull request #2 from ziglang/master

Refreshing fork.
master
BenoitJGirard 2019-02-17 14:38:55 -05:00 committed by GitHub
commit 6daa041932
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
356 changed files with 18565 additions and 9780 deletions

43
.builds/freebsd.yml Normal file
View File

@ -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.

View File

@ -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/")

View File

@ -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
```

View File

@ -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);

View File

@ -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"

View File

@ -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

View File

@ -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,

View File

@ -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 &lt;- KEYWORD_comptime BlockExpr
TopLevelDecl
&lt;- (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 &lt;- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
@ -8032,7 +8223,8 @@ ArrayTypeStart &lt;- LBRACKET Expr? RBRACKET
PtrTypeStart
&lt;- ASTERISK
/ ASTERISK2
/ LBRACKET ASTERISK RBRACKET
/ PTRUNKNOWN
/ PTRC
# ContainerDecl specific
ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE
@ -8130,7 +8322,7 @@ LARROW2 &lt;- '&lt;&lt;' ![=] skip
LARROW2EQUAL &lt;- '&lt;&lt;=' skip
LARROWEQUAL &lt;- '&lt;=' skip
LBRACE &lt;- '{' skip
LBRACKET &lt;- '[' skip
LBRACKET &lt;- '[' ![*] skip
LPAREN &lt;- '(' skip
MINUS &lt;- '-' ![%=&gt;] skip
MINUSEQUAL &lt;- '-=' skip
@ -8147,6 +8339,8 @@ PLUS2 &lt;- '++' skip
PLUSEQUAL &lt;- '+=' skip
PLUSPERCENT &lt;- '+%' ![=] skip
PLUSPERCENTEQUAL &lt;- '+%=' skip
PTRC &lt;- '[*c]' skip
PTRUNKNOWN &lt;- '[*]' skip
QUESTIONMARK &lt;- '?' skip
RARROW &lt;- '&gt;' ![&gt;=] skip
RARROW2 &lt;- '&gt;&gt;' ![=] skip
@ -8201,6 +8395,7 @@ KEYWORD_struct &lt;- 'struct' end_of_word
KEYWORD_suspend &lt;- 'suspend' end_of_word
KEYWORD_switch &lt;- 'switch' end_of_word
KEYWORD_test &lt;- 'test' end_of_word
KEYWORD_threadlocal &lt;- 'threadlocal' end_of_word
KEYWORD_true &lt;- 'true' end_of_word
KEYWORD_try &lt;- 'try' end_of_word
KEYWORD_undefined &lt;- 'undefined' end_of_word
@ -8221,7 +8416,7 @@ keyword &lt;- 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#}

View File

@ -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.

View File

@ -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;

View File

@ -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");

View File

@ -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"));
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View 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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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 {

View File

@ -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,

View File

@ -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,

View File

@ -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();

View File

@ -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),

View File

@ -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();

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) {
bigint_add(x, &copy, &one);
}

View File

@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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");
}

View File

@ -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"));
//}
//}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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";

View File

@ -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,

File diff suppressed because it is too large Load Diff

214
src/zig_clang.cpp Normal file
View File

@ -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));
}

259
src/zig_clang.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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 {

View File

@ -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());
}

View File

@ -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");

View File

@ -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()));
}

View File

@ -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;

View File

@ -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.

View File

@ -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,
};

View File

@ -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;

View File

@ -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),
},
});
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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.

View File

@ -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);

View File

@ -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");

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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));
}
}

View File

@ -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 {

420
std/fmt/parse_float.zig Normal file
View File

@ -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));
}
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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"),
}
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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");
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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