mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
commit
8174f972a7
@ -196,7 +196,7 @@ else()
|
||||
if(MSVC)
|
||||
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")
|
||||
else()
|
||||
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment")
|
||||
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment -Wno-class-memaccess -Wno-unknown-warning-option")
|
||||
endif()
|
||||
set_target_properties(embedded_lld_lib PROPERTIES
|
||||
COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS}
|
||||
|
||||
11
README.md
11
README.md
@ -1,9 +1,9 @@
|
||||

|
||||

|
||||
|
||||
A programming language designed for robustness, optimality, and
|
||||
clarity.
|
||||
|
||||
[ziglang.org](http://ziglang.org)
|
||||
[ziglang.org](https://ziglang.org)
|
||||
|
||||
## Feature Highlights
|
||||
|
||||
@ -114,7 +114,7 @@ libc. Create demo games using Zig.
|
||||
|
||||
## Building
|
||||
|
||||
[](https://travis-ci.org/zig-lang/zig)
|
||||
[](https://travis-ci.org/ziglang/zig)
|
||||
[](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)
|
||||
|
||||
### Stage 1: Build Zig from C++ Source Code
|
||||
@ -161,7 +161,7 @@ bin/zig build --build-file ../build.zig test
|
||||
|
||||
##### Windows
|
||||
|
||||
See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows
|
||||
See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
|
||||
|
||||
### Stage 2: Build Self-Hosted Zig from Zig Source Code
|
||||
|
||||
@ -182,6 +182,9 @@ binary.
|
||||
|
||||
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.*
|
||||
|
||||
#### Debug / Development Build
|
||||
|
||||
```
|
||||
|
||||
59
build.zig
59
build.zig
@ -16,7 +16,7 @@ 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);
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8 {
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
|
||||
docgen_exe.getOutputPath(),
|
||||
rel_zig_exe,
|
||||
"doc/langref.html.in",
|
||||
@ -30,7 +30,10 @@ pub fn build(b: &Builder) !void {
|
||||
const test_step = b.step("test", "Run all the tests");
|
||||
|
||||
// find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
|
||||
const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
|
||||
const build_info = try b.exec([][]const u8{
|
||||
b.zig_exe,
|
||||
"BUILD_INFO",
|
||||
});
|
||||
var index: usize = 0;
|
||||
const cmake_binary_dir = nextValue(&index, build_info);
|
||||
const cxx_compiler = nextValue(&index, build_info);
|
||||
@ -67,7 +70,10 @@ pub fn build(b: &Builder) !void {
|
||||
dependOnLib(exe, llvm);
|
||||
|
||||
if (exe.target.getOs() == builtin.Os.linux) {
|
||||
const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
|
||||
const libstdcxx_path_padded = try b.exec([][]const u8{
|
||||
cxx_compiler,
|
||||
"-print-file-name=libstdc++.a",
|
||||
});
|
||||
const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
|
||||
if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
|
||||
warn(
|
||||
@ -111,17 +117,11 @@ pub fn build(b: &Builder) !void {
|
||||
|
||||
test_step.dependOn(docs_step);
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter,
|
||||
"test/behavior.zig", "behavior", "Run the behavior tests",
|
||||
with_lldb));
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", with_lldb));
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter,
|
||||
"std/index.zig", "std", "Run the standard library tests",
|
||||
with_lldb));
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", with_lldb));
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter,
|
||||
"std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests",
|
||||
with_lldb));
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", with_lldb));
|
||||
|
||||
test_step.dependOn(tests.addCompareOutputTests(b, test_filter));
|
||||
test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
|
||||
@ -149,8 +149,7 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) vo
|
||||
|
||||
fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, 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, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
|
||||
}
|
||||
|
||||
const LibraryDep = struct {
|
||||
@ -161,11 +160,21 @@ const LibraryDep = struct {
|
||||
};
|
||||
|
||||
fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
|
||||
const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
|
||||
const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
|
||||
const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
|
||||
const libs_output = try b.exec([][]const u8{
|
||||
llvm_config_exe,
|
||||
"--libs",
|
||||
"--system-libs",
|
||||
});
|
||||
const includes_output = try b.exec([][]const u8{
|
||||
llvm_config_exe,
|
||||
"--includedir",
|
||||
});
|
||||
const libdir_output = try b.exec([][]const u8{
|
||||
llvm_config_exe,
|
||||
"--libdir",
|
||||
});
|
||||
|
||||
var result = LibraryDep {
|
||||
var result = LibraryDep{
|
||||
.libs = ArrayList([]const u8).init(b.allocator),
|
||||
.system_libs = ArrayList([]const u8).init(b.allocator),
|
||||
.includes = ArrayList([]const u8).init(b.allocator),
|
||||
@ -227,17 +236,17 @@ pub fn installCHeaders(b: &Builder, c_header_files: []const u8) void {
|
||||
}
|
||||
|
||||
fn nextValue(index: &usize, build_info: []const u8) []const u8 {
|
||||
const start = *index;
|
||||
while (true) : (*index += 1) {
|
||||
switch (build_info[*index]) {
|
||||
const start = index.*;
|
||||
while (true) : (index.* += 1) {
|
||||
switch (build_info[index.*]) {
|
||||
'\n' => {
|
||||
const result = build_info[start..*index];
|
||||
*index += 1;
|
||||
const result = build_info[start..index.*];
|
||||
index.* += 1;
|
||||
return result;
|
||||
},
|
||||
'\r' => {
|
||||
const result = build_info[start..*index];
|
||||
*index += 2;
|
||||
const result = build_info[start..index.*];
|
||||
index.* += 2;
|
||||
return result;
|
||||
},
|
||||
else => continue,
|
||||
|
||||
182
doc/docgen.zig
182
doc/docgen.zig
@ -95,7 +95,7 @@ const Tokenizer = struct {
|
||||
};
|
||||
|
||||
fn init(source_file_name: []const u8, buffer: []const u8) Tokenizer {
|
||||
return Tokenizer {
|
||||
return Tokenizer{
|
||||
.buffer = buffer,
|
||||
.index = 0,
|
||||
.state = State.Start,
|
||||
@ -105,7 +105,7 @@ const Tokenizer = struct {
|
||||
}
|
||||
|
||||
fn next(self: &Tokenizer) Token {
|
||||
var result = Token {
|
||||
var result = Token{
|
||||
.id = Token.Id.Eof,
|
||||
.start = self.index,
|
||||
.end = undefined,
|
||||
@ -197,7 +197,7 @@ const Tokenizer = struct {
|
||||
};
|
||||
|
||||
fn getTokenLocation(self: &Tokenizer, token: &const Token) Location {
|
||||
var loc = Location {
|
||||
var loc = Location{
|
||||
.line = 0,
|
||||
.column = 0,
|
||||
.line_start = 0,
|
||||
@ -346,7 +346,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
break;
|
||||
},
|
||||
Token.Id.Content => {
|
||||
try nodes.append(Node {.Content = tokenizer.buffer[token.start..token.end] });
|
||||
try nodes.append(Node{ .Content = tokenizer.buffer[token.start..token.end] });
|
||||
},
|
||||
Token.Id.BracketOpen => {
|
||||
const tag_token = try eatToken(tokenizer, Token.Id.TagContent);
|
||||
@ -365,11 +365,13 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
header_stack_size += 1;
|
||||
|
||||
const urlized = try urlize(allocator, content);
|
||||
try nodes.append(Node{.HeaderOpen = HeaderOpen {
|
||||
.name = content,
|
||||
.url = urlized,
|
||||
.n = header_stack_size,
|
||||
}});
|
||||
try nodes.append(Node{
|
||||
.HeaderOpen = HeaderOpen{
|
||||
.name = content,
|
||||
.url = urlized,
|
||||
.n = header_stack_size,
|
||||
},
|
||||
});
|
||||
if (try urls.put(urlized, tag_token)) |other_tag_token| {
|
||||
parseError(tokenizer, tag_token, "duplicate header url: #{}", urlized) catch {};
|
||||
parseError(tokenizer, other_tag_token, "other tag here") catch {};
|
||||
@ -407,14 +409,14 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
switch (see_also_tok.id) {
|
||||
Token.Id.TagContent => {
|
||||
const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end];
|
||||
try list.append(SeeAlsoItem {
|
||||
try list.append(SeeAlsoItem{
|
||||
.name = content,
|
||||
.token = see_also_tok,
|
||||
});
|
||||
},
|
||||
Token.Id.Separator => {},
|
||||
Token.Id.BracketClose => {
|
||||
try nodes.append(Node {.SeeAlso = list.toOwnedSlice() } );
|
||||
try nodes.append(Node{ .SeeAlso = list.toOwnedSlice() });
|
||||
break;
|
||||
},
|
||||
else => return parseError(tokenizer, see_also_tok, "invalid see_also token"),
|
||||
@ -438,8 +440,8 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
}
|
||||
};
|
||||
|
||||
try nodes.append(Node {
|
||||
.Link = Link {
|
||||
try nodes.append(Node{
|
||||
.Link = Link{
|
||||
.url = try urlize(allocator, url_name),
|
||||
.name = name,
|
||||
.token = name_tok,
|
||||
@ -463,24 +465,24 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
var code_kind_id: Code.Id = undefined;
|
||||
var is_inline = false;
|
||||
if (mem.eql(u8, code_kind_str, "exe")) {
|
||||
code_kind_id = Code.Id { .Exe = ExpectedOutcome.Succeed };
|
||||
code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Succeed };
|
||||
} else if (mem.eql(u8, code_kind_str, "exe_err")) {
|
||||
code_kind_id = Code.Id { .Exe = ExpectedOutcome.Fail };
|
||||
code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Fail };
|
||||
} else if (mem.eql(u8, code_kind_str, "test")) {
|
||||
code_kind_id = Code.Id.Test;
|
||||
} else if (mem.eql(u8, code_kind_str, "test_err")) {
|
||||
code_kind_id = Code.Id { .TestError = name};
|
||||
code_kind_id = Code.Id{ .TestError = name };
|
||||
name = "test";
|
||||
} else if (mem.eql(u8, code_kind_str, "test_safety")) {
|
||||
code_kind_id = Code.Id { .TestSafety = name};
|
||||
code_kind_id = Code.Id{ .TestSafety = name };
|
||||
name = "test";
|
||||
} else if (mem.eql(u8, code_kind_str, "obj")) {
|
||||
code_kind_id = Code.Id { .Obj = null };
|
||||
code_kind_id = Code.Id{ .Obj = null };
|
||||
} else if (mem.eql(u8, code_kind_str, "obj_err")) {
|
||||
code_kind_id = Code.Id { .Obj = name };
|
||||
code_kind_id = Code.Id{ .Obj = name };
|
||||
name = "test";
|
||||
} else if (mem.eql(u8, code_kind_str, "syntax")) {
|
||||
code_kind_id = Code.Id { .Obj = null };
|
||||
code_kind_id = Code.Id{ .Obj = null };
|
||||
is_inline = true;
|
||||
} else {
|
||||
return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str);
|
||||
@ -514,17 +516,20 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
return parseError(tokenizer, end_code_tag, "invalid token inside code_begin: {}", end_tag_name);
|
||||
}
|
||||
_ = try eatToken(tokenizer, Token.Id.BracketClose);
|
||||
} else unreachable; // TODO issue #707
|
||||
try nodes.append(Node {.Code = Code {
|
||||
.id = code_kind_id,
|
||||
.name = name,
|
||||
.source_token = source_token,
|
||||
.is_inline = is_inline,
|
||||
.mode = mode,
|
||||
.link_objects = link_objects.toOwnedSlice(),
|
||||
.target_windows = target_windows,
|
||||
.link_libc = link_libc,
|
||||
}});
|
||||
} else
|
||||
unreachable; // TODO issue #707
|
||||
try nodes.append(Node{
|
||||
.Code = Code{
|
||||
.id = code_kind_id,
|
||||
.name = name,
|
||||
.source_token = source_token,
|
||||
.is_inline = is_inline,
|
||||
.mode = mode,
|
||||
.link_objects = link_objects.toOwnedSlice(),
|
||||
.target_windows = target_windows,
|
||||
.link_libc = link_libc,
|
||||
},
|
||||
});
|
||||
tokenizer.code_node_count += 1;
|
||||
} else {
|
||||
return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);
|
||||
@ -534,7 +539,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) !Toc {
|
||||
}
|
||||
}
|
||||
|
||||
return Toc {
|
||||
return Toc{
|
||||
.nodes = nodes.toOwnedSlice(),
|
||||
.toc = toc_buf.toOwnedSlice(),
|
||||
.urls = urls,
|
||||
@ -727,16 +732,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
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);
|
||||
try io.writeFile(allocator, 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);
|
||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer build_args.deinit();
|
||||
try build_args.appendSlice([][]const u8 {zig_exe,
|
||||
"build-exe", tmp_source_file_name,
|
||||
"--output", tmp_bin_file_name,
|
||||
try build_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
"build-exe",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
tmp_bin_file_name,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
@ -766,10 +774,9 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
try build_args.append("c");
|
||||
try out.print(" --library c");
|
||||
}
|
||||
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(
|
||||
tokenizer, code.source_token, "example failed to compile");
|
||||
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
|
||||
|
||||
const run_args = [][]const u8 {tmp_bin_file_name};
|
||||
const run_args = [][]const u8{tmp_bin_file_name};
|
||||
|
||||
const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {
|
||||
const result = try os.ChildProcess.exec(allocator, run_args, null, null, max_doc_file_size);
|
||||
@ -777,7 +784,10 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
os.ChildProcess.Term.Exited => |exit_code| {
|
||||
if (exit_code == 0) {
|
||||
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
|
||||
for (run_args) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (run_args) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example incorrectly compiled");
|
||||
}
|
||||
},
|
||||
@ -785,11 +795,9 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
}
|
||||
break :blk result;
|
||||
} else blk: {
|
||||
break :blk exec(allocator, run_args) catch return parseError(
|
||||
tokenizer, code.source_token, "example crashed");
|
||||
break :blk exec(allocator, run_args) catch return parseError(tokenizer, code.source_token, "example crashed");
|
||||
};
|
||||
|
||||
|
||||
const escaped_stderr = try escapeHtml(allocator, result.stderr);
|
||||
const escaped_stdout = try escapeHtml(allocator, result.stdout);
|
||||
|
||||
@ -802,7 +810,11 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
var test_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer test_args.deinit();
|
||||
|
||||
try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
|
||||
try test_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
"test",
|
||||
tmp_source_file_name,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
@ -821,13 +833,15 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
}
|
||||
if (code.target_windows) {
|
||||
try test_args.appendSlice([][]const u8{
|
||||
"--target-os", "windows",
|
||||
"--target-arch", "x86_64",
|
||||
"--target-environ", "msvc",
|
||||
"--target-os",
|
||||
"windows",
|
||||
"--target-arch",
|
||||
"x86_64",
|
||||
"--target-environ",
|
||||
"msvc",
|
||||
});
|
||||
}
|
||||
const result = exec(allocator, test_args.toSliceConst()) catch return parseError(
|
||||
tokenizer, code.source_token, "test failed");
|
||||
const result = exec(allocator, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");
|
||||
const escaped_stderr = try escapeHtml(allocator, result.stderr);
|
||||
const escaped_stdout = try escapeHtml(allocator, result.stdout);
|
||||
try out.print("\n{}{}</code></pre>\n", escaped_stderr, escaped_stdout);
|
||||
@ -836,7 +850,13 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
var test_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer test_args.deinit();
|
||||
|
||||
try test_args.appendSlice([][]const u8 {zig_exe, "test", "--color", "on", tmp_source_file_name});
|
||||
try test_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
"test",
|
||||
"--color",
|
||||
"on",
|
||||
tmp_source_file_name,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
@ -858,13 +878,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
os.ChildProcess.Term.Exited => |exit_code| {
|
||||
if (exit_code == 0) {
|
||||
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
|
||||
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (test_args.toSliceConst()) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example incorrectly compiled");
|
||||
}
|
||||
},
|
||||
else => {
|
||||
warn("{}\nThe following command crashed:\n", result.stderr);
|
||||
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (test_args.toSliceConst()) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example compile crashed");
|
||||
},
|
||||
}
|
||||
@ -881,7 +907,11 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
var test_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer test_args.deinit();
|
||||
|
||||
try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
|
||||
try test_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
"test",
|
||||
tmp_source_file_name,
|
||||
});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => try test_args.append("--release-safe"),
|
||||
@ -894,13 +924,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
os.ChildProcess.Term.Exited => |exit_code| {
|
||||
if (exit_code == 0) {
|
||||
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
|
||||
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (test_args.toSliceConst()) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example test incorrectly succeeded");
|
||||
}
|
||||
},
|
||||
else => {
|
||||
warn("{}\nThe following command crashed:\n", result.stderr);
|
||||
for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (test_args.toSliceConst()) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example compile crashed");
|
||||
},
|
||||
}
|
||||
@ -918,9 +954,15 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||
defer build_args.deinit();
|
||||
|
||||
try build_args.appendSlice([][]const u8 {zig_exe, "build-obj", tmp_source_file_name,
|
||||
"--color", "on",
|
||||
"--output", tmp_obj_file_name});
|
||||
try build_args.appendSlice([][]const u8{
|
||||
zig_exe,
|
||||
"build-obj",
|
||||
tmp_source_file_name,
|
||||
"--color",
|
||||
"on",
|
||||
"--output",
|
||||
tmp_obj_file_name,
|
||||
});
|
||||
|
||||
if (!code.is_inline) {
|
||||
try out.print("<pre><code class=\"shell\">$ zig build-obj {}.zig", code.name);
|
||||
@ -954,13 +996,19 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
os.ChildProcess.Term.Exited => |exit_code| {
|
||||
if (exit_code == 0) {
|
||||
warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
|
||||
for (build_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (build_args.toSliceConst()) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example build incorrectly succeeded");
|
||||
}
|
||||
},
|
||||
else => {
|
||||
warn("{}\nThe following command crashed:\n", result.stderr);
|
||||
for (build_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (build_args.toSliceConst()) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return parseError(tokenizer, code.source_token, "example compile crashed");
|
||||
},
|
||||
}
|
||||
@ -975,8 +1023,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
try out.print("</code></pre>\n");
|
||||
}
|
||||
} else {
|
||||
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(
|
||||
tokenizer, code.source_token, "example failed to compile");
|
||||
_ = exec(allocator, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile");
|
||||
}
|
||||
if (!code.is_inline) {
|
||||
try out.print("</code></pre>\n");
|
||||
@ -987,7 +1034,6 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.ExecResult {
|
||||
@ -996,13 +1042,19 @@ fn exec(allocator: &mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex
|
||||
os.ChildProcess.Term.Exited => |exit_code| {
|
||||
if (exit_code != 0) {
|
||||
warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);
|
||||
for (args) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (args) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return error.ChildExitError;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
warn("{}\nThe following command crashed:\n", result.stderr);
|
||||
for (args) |arg| warn("{} ", arg) else warn("\n");
|
||||
for (args) |arg|
|
||||
warn("{} ", arg)
|
||||
else
|
||||
warn("\n");
|
||||
return error.ChildCrashed;
|
||||
},
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@
|
||||
</p>
|
||||
<p>
|
||||
If you search for something specific in this documentation and do not find it,
|
||||
please <a href="https://github.com/zig-lang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
|
||||
please <a href="https://github.com/ziglang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
|
||||
</p>
|
||||
<p>
|
||||
The code samples in this document are compiled and tested as part of the main test suite of Zig.
|
||||
@ -1232,7 +1232,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><pre><code class="zig">*a<code></pre></td>
|
||||
<td><pre><code class="zig">a.*<code></pre></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>{#link|Pointers#}</li>
|
||||
@ -1244,7 +1244,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
|
||||
<td>
|
||||
<pre><code class="zig">const x: u32 = 1234;
|
||||
const ptr = &x;
|
||||
*x == 1234</code></pre>
|
||||
x.* == 1234</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -1258,7 +1258,7 @@ const ptr = &x;
|
||||
<td>
|
||||
<pre><code class="zig">const x: u32 = 1234;
|
||||
const ptr = &x;
|
||||
*x == 1234</code></pre>
|
||||
x.* == 1234</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -1267,8 +1267,8 @@ const ptr = &x;
|
||||
{#header_open|Precedence#}
|
||||
<pre><code>x() x[] x.y
|
||||
a!b
|
||||
!x -x -%x ~x *x &x ?x ??x
|
||||
x{}
|
||||
!x -x -%x ~x &x ?x ??x
|
||||
x{} x.*
|
||||
! * / % ** *%
|
||||
+ - ++ +% -%
|
||||
<< >>
|
||||
@ -1316,7 +1316,7 @@ var some_integers: [100]i32 = undefined;
|
||||
|
||||
test "modify an array" {
|
||||
for (some_integers) |*item, i| {
|
||||
*item = i32(i);
|
||||
item.* = i32(i);
|
||||
}
|
||||
assert(some_integers[10] == 10);
|
||||
assert(some_integers[99] == 99);
|
||||
@ -1357,7 +1357,7 @@ comptime {
|
||||
var fancy_array = init: {
|
||||
var initial_value: [10]Point = undefined;
|
||||
for (initial_value) |*pt, i| {
|
||||
*pt = Point {
|
||||
pt.* = Point {
|
||||
.x = i32(i),
|
||||
.y = i32(i) * 2,
|
||||
};
|
||||
@ -1400,7 +1400,7 @@ test "address of syntax" {
|
||||
const x_ptr = &x;
|
||||
|
||||
// Deference a pointer:
|
||||
assert(*x_ptr == 1234);
|
||||
assert(x_ptr.* == 1234);
|
||||
|
||||
// When you get the address of a const variable, you get a const pointer.
|
||||
assert(@typeOf(x_ptr) == &const i32);
|
||||
@ -1409,8 +1409,8 @@ test "address of syntax" {
|
||||
var y: i32 = 5678;
|
||||
const y_ptr = &y;
|
||||
assert(@typeOf(y_ptr) == &i32);
|
||||
*y_ptr += 1;
|
||||
assert(*y_ptr == 5679);
|
||||
y_ptr.* += 1;
|
||||
assert(y_ptr.* == 5679);
|
||||
}
|
||||
|
||||
test "pointer array access" {
|
||||
@ -1448,9 +1448,9 @@ comptime {
|
||||
// @ptrCast.
|
||||
var x: i32 = 1;
|
||||
const ptr = &x;
|
||||
*ptr += 1;
|
||||
ptr.* += 1;
|
||||
x += 1;
|
||||
assert(*ptr == 3);
|
||||
assert(ptr.* == 3);
|
||||
}
|
||||
|
||||
test "@ptrToInt and @intToPtr" {
|
||||
@ -1492,7 +1492,7 @@ test "nullable pointers" {
|
||||
var x: i32 = 1;
|
||||
ptr = &x;
|
||||
|
||||
assert(*??ptr == 1);
|
||||
assert((??ptr).* == 1);
|
||||
|
||||
// Nullable pointers are the same size as normal pointers, because pointer
|
||||
// value 0 is used as the null value.
|
||||
@ -1505,7 +1505,7 @@ test "pointer casting" {
|
||||
// conversions are not possible.
|
||||
const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
|
||||
const u32_ptr = @ptrCast(&const u32, &bytes[0]);
|
||||
assert(*u32_ptr == 0x12121212);
|
||||
assert(u32_ptr.* == 0x12121212);
|
||||
|
||||
// Even this example is contrived - there are better ways to do the above than
|
||||
// pointer casting. For example, using a slice narrowing cast:
|
||||
@ -1610,7 +1610,7 @@ fn foo(bytes: []u8) u32 {
|
||||
<code>u8</code> can alias any memory.
|
||||
</p>
|
||||
<p>As an example, this code produces undefined behavior:</p>
|
||||
<pre><code class="zig">*@ptrCast(&u32, f32(12.34))</code></pre>
|
||||
<pre><code class="zig">@ptrCast(&u32, f32(12.34)).*</code></pre>
|
||||
<p>Instead, use {#link|@bitCast#}:
|
||||
<pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>
|
||||
<p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p>
|
||||
@ -2040,7 +2040,7 @@ const Variant = union(enum) {
|
||||
Bool: bool,
|
||||
|
||||
fn truthy(self: &const Variant) bool {
|
||||
return switch (*self) {
|
||||
return switch (self.*) {
|
||||
Variant.Int => |x_int| x_int != 0,
|
||||
Variant.Bool => |x_bool| x_bool,
|
||||
};
|
||||
@ -2151,7 +2151,7 @@ test "switch enum" {
|
||||
|
||||
// A reference to the matched value can be obtained using `*` syntax.
|
||||
Item.C => |*item| blk: {
|
||||
(*item).x += 1;
|
||||
item.*.x += 1;
|
||||
break :blk 6;
|
||||
},
|
||||
|
||||
@ -2374,7 +2374,7 @@ test "for reference" {
|
||||
// Iterate over the slice by reference by
|
||||
// specifying that the capture value is a pointer.
|
||||
for (items) |*value| {
|
||||
*value += 1;
|
||||
value.* += 1;
|
||||
}
|
||||
|
||||
assert(items[0] == 4);
|
||||
@ -2483,7 +2483,7 @@ test "if nullable" {
|
||||
// Access the value by reference using a pointer capture.
|
||||
var c: ?u32 = 3;
|
||||
if (c) |*value| {
|
||||
*value = 2;
|
||||
value.* = 2;
|
||||
}
|
||||
|
||||
if (c) |value| {
|
||||
@ -2524,7 +2524,7 @@ test "if error union" {
|
||||
// Access the value by reference using a pointer capture.
|
||||
var c: error!u32 = 3;
|
||||
if (c) |*value| {
|
||||
*value = 9;
|
||||
value.* = 9;
|
||||
} else |err| {
|
||||
unreachable;
|
||||
}
|
||||
@ -2827,7 +2827,7 @@ test "fn reflection" {
|
||||
</p>
|
||||
<p>
|
||||
The number of unique error values across the entire compilation should determine the size of the error set type.
|
||||
However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/zig-lang/zig/issues/786">#768</a>.
|
||||
However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/ziglang/zig/issues/786">#768</a>.
|
||||
</p>
|
||||
<p>
|
||||
You can implicitly cast an error from a subset to its superset:
|
||||
@ -3111,7 +3111,48 @@ test "error union" {
|
||||
{#code_end#}
|
||||
<p>TODO the <code>||</code> operator for error sets</p>
|
||||
{#header_open|Inferred Error Sets#}
|
||||
<p>TODO</p>
|
||||
<p>
|
||||
Because many functions in Zig return a possible error, Zig supports inferring the error set.
|
||||
To infer the error set for a function, use this syntax:
|
||||
</p>
|
||||
{#code_begin|test#}
|
||||
// With an inferred error set
|
||||
pub fn add_inferred(comptime T: type, a: T, b: T) !T {
|
||||
var answer: T = undefined;
|
||||
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||
}
|
||||
|
||||
// With an explicit error set
|
||||
pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
|
||||
var answer: T = undefined;
|
||||
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||
}
|
||||
|
||||
const Error = error {
|
||||
Overflow,
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
test "inferred error set" {
|
||||
if (add_inferred(u8, 255, 1)) |_| unreachable else |err| switch (err) {
|
||||
error.Overflow => {}, // ok
|
||||
}
|
||||
}
|
||||
{#code_end#}
|
||||
<p>
|
||||
When a function has an inferred error set, that function becomes generic and thus it becomes
|
||||
trickier to do certain things with it, such as obtain a function pointer, or have an error
|
||||
set that is consistent across different build targets. Additionally, inferred error sets
|
||||
are incompatible with recursion.
|
||||
</p>
|
||||
<p>
|
||||
In these situations, it is recommended to use an explicit error set. You can generally start
|
||||
with an empty error set and let compile errors guide you toward completing the set.
|
||||
</p>
|
||||
<p>
|
||||
These limitations may be overcome in a future version of Zig.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
{#header_open|Error Return Traces#}
|
||||
@ -3872,13 +3913,22 @@ pub fn main() void {
|
||||
{#header_open|@addWithOverflow#}
|
||||
<pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool</code></pre>
|
||||
<p>
|
||||
Performs <code>*result = a + b</code>. If overflow or underflow occurs,
|
||||
Performs <code>result.* = a + b</code>. If overflow or underflow occurs,
|
||||
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
|
||||
If no overflow or underflow occurs, returns <code>false</code>.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@ArgType#}
|
||||
<p>TODO</p>
|
||||
<pre><code class="zig">@ArgType(comptime T: type, comptime n: usize) -> type</code></pre>
|
||||
<p>
|
||||
This builtin function takes a function type and returns the type of the parameter at index <code>n</code>.
|
||||
</p>
|
||||
<p>
|
||||
<code>T</code> must be a function type.
|
||||
</p>
|
||||
<p>
|
||||
Note: This function is deprecated. Use {#link|@typeInfo#} instead.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@atomicLoad#}
|
||||
<pre><code class="zig">@atomicLoad(comptime T: type, ptr: &const T, comptime ordering: builtin.AtomicOrder) -> T</code></pre>
|
||||
@ -4073,9 +4123,9 @@ comptime {
|
||||
</p>
|
||||
{#code_begin|syntax#}
|
||||
fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
|
||||
const old_value = *ptr;
|
||||
const old_value = ptr.*;
|
||||
if (old_value == expected_value) {
|
||||
*ptr = new_value;
|
||||
ptr.* = new_value;
|
||||
return null;
|
||||
} else {
|
||||
return old_value;
|
||||
@ -4100,9 +4150,9 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_v
|
||||
</p>
|
||||
{#code_begin|syntax#}
|
||||
fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
|
||||
const old_value = *ptr;
|
||||
const old_value = ptr.*;
|
||||
if (old_value == expected_value and usuallyTrueButSometimesFalse()) {
|
||||
*ptr = new_value;
|
||||
ptr.* = new_value;
|
||||
return null;
|
||||
} else {
|
||||
return old_value;
|
||||
@ -4447,7 +4497,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></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><code class="zig">for (dest[0...byte_count]) |*b| *b = c;</code></pre>
|
||||
<pre><code class="zig">for (dest[0...byte_count]) |*b| b.* = c;</code></pre>
|
||||
<p>
|
||||
The optimizer is intelligent enough to turn the above snippet into a memset.
|
||||
</p>
|
||||
@ -4480,22 +4530,63 @@ mem.set(u8, dest, c);</code></pre>
|
||||
{#header_open|@mulWithOverflow#}
|
||||
<pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool</code></pre>
|
||||
<p>
|
||||
Performs <code>*result = a * b</code>. If overflow or underflow occurs,
|
||||
Performs <code>result.* = a * b</code>. If overflow or underflow occurs,
|
||||
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
|
||||
If no overflow or underflow occurs, returns <code>false</code>.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@newStackCall#}
|
||||
<pre><code class="zig">@newStackCall(new_stack: []u8, function: var, args: ...) -> var</code></pre>
|
||||
<p>
|
||||
This calls a function, in the same way that invoking an expression with parentheses does. However,
|
||||
instead of using the same stack as the caller, the function uses the stack provided in the <code>new_stack</code>
|
||||
parameter.
|
||||
</p>
|
||||
{#code_begin|test#}
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
var new_stack_bytes: [1024]u8 = undefined;
|
||||
|
||||
test "calling a function with a new stack" {
|
||||
const arg = 1234;
|
||||
|
||||
const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
|
||||
const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
|
||||
_ = targetFunction(arg);
|
||||
|
||||
assert(arg == 1234);
|
||||
assert(a < b);
|
||||
}
|
||||
|
||||
fn targetFunction(x: i32) usize {
|
||||
assert(x == 1234);
|
||||
|
||||
var local_variable: i32 = 42;
|
||||
const ptr = &local_variable;
|
||||
ptr.* += 1;
|
||||
|
||||
assert(local_variable == 43);
|
||||
return @ptrToInt(ptr);
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
{#header_open|@noInlineCall#}
|
||||
<pre><code class="zig">@noInlineCall(function: var, args: ...) -> var</code></pre>
|
||||
<p>
|
||||
This calls a function, in the same way that invoking an expression with parentheses does:
|
||||
</p>
|
||||
<pre><code class="zig">const assert = @import("std").debug.assert;
|
||||
{#code_begin|test#}
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
test "noinline function call" {
|
||||
assert(@noInlineCall(add, 3, 9) == 12);
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) -> i32 { a + b }</code></pre>
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
{#code_end#}
|
||||
<p>
|
||||
Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call
|
||||
will not be inlined. If the call must be inlined, a compile error is emitted.
|
||||
@ -4705,7 +4796,7 @@ pub const FloatMode = enum {
|
||||
{#header_open|@shlWithOverflow#}
|
||||
<pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -> bool</code></pre>
|
||||
<p>
|
||||
Performs <code>*result = a << b</code>. If overflow or underflow occurs,
|
||||
Performs <code>result.* = a << b</code>. If overflow or underflow occurs,
|
||||
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
|
||||
If no overflow or underflow occurs, returns <code>false</code>.
|
||||
</p>
|
||||
@ -4749,7 +4840,7 @@ pub const FloatMode = enum {
|
||||
{#header_open|@subWithOverflow#}
|
||||
<pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool</code></pre>
|
||||
<p>
|
||||
Performs <code>*result = a - b</code>. If overflow or underflow occurs,
|
||||
Performs <code>result.* = a - b</code>. If overflow or underflow occurs,
|
||||
stores the overflowed bits in <code>result</code> and returns <code>true</code>.
|
||||
If no overflow or underflow occurs, returns <code>false</code>.
|
||||
</p>
|
||||
@ -5867,7 +5958,7 @@ pub fn main() void {
|
||||
{#code_begin|exe#}
|
||||
{#link_libc#}
|
||||
const c = @cImport({
|
||||
// See https://github.com/zig-lang/zig/issues/515
|
||||
// See https://github.com/ziglang/zig/issues/515
|
||||
@cDefine("_NO_CRT_STDIO_INLINE", "1");
|
||||
@cInclude("stdio.h");
|
||||
});
|
||||
@ -6210,7 +6301,7 @@ fn readU32Be() u32 {}
|
||||
<li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
|
||||
</ul>
|
||||
<p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>
|
||||
<p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>
|
||||
<p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/ziglang/zig/issues/663">issue #663</a></p>
|
||||
{#header_close#}
|
||||
{#header_open|Grammar#}
|
||||
<pre><code class="nohighlight">Root = many(TopLevelItem) EOF
|
||||
@ -6341,10 +6432,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
|
||||
|
||||
PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
|
||||
|
||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression)
|
||||
|
||||
FieldAccessExpression = "." Symbol
|
||||
|
||||
PtrDerefExpression = ".*"
|
||||
|
||||
FnCallExpression = "(" list(Expression, ",") ")"
|
||||
|
||||
ArrayAccessExpression = "[" Expression "]"
|
||||
@ -6357,7 +6450,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
|
||||
|
||||
StructLiteralField = "." Symbol "=" Expression
|
||||
|
||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
|
||||
PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
|
||||
|
||||
PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
|
||||
|
||||
@ -6451,7 +6544,7 @@ hljs.registerLanguage("zig", function(t) {
|
||||
a = t.IR + "\\s*\\(",
|
||||
c = {
|
||||
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
|
||||
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",
|
||||
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo newStackCall",
|
||||
literal: "true false null undefined"
|
||||
},
|
||||
n = [e, t.CLCM, t.CBCM, s, r];
|
||||
|
||||
@ -23,7 +23,7 @@ pub fn main() !void {
|
||||
|
||||
while (true) {
|
||||
try stdout.print("\nGuess a number between 1 and 100: ");
|
||||
var line_buf : [20]u8 = undefined;
|
||||
var line_buf: [20]u8 = undefined;
|
||||
|
||||
const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
|
||||
error.InputTooLong => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
const c = @cImport({
|
||||
// See https://github.com/zig-lang/zig/issues/515
|
||||
// See https://github.com/ziglang/zig/issues/515
|
||||
@cDefine("_NO_CRT_STDIO_INLINE", "1");
|
||||
@cInclude("stdio.h");
|
||||
@cInclude("string.h");
|
||||
@ -8,8 +8,7 @@ const c = @cImport({
|
||||
const msg = c"Hello, world!\n";
|
||||
|
||||
export fn main(argc: c_int, argv: &&u8) c_int {
|
||||
if (c.printf(msg) != c_int(c.strlen(msg)))
|
||||
return -1;
|
||||
if (c.printf(msg) != c_int(c.strlen(msg))) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4,9 +4,7 @@ pub fn build(b: &Builder) void {
|
||||
const obj = b.addObject("base64", "base64.zig");
|
||||
|
||||
const exe = b.addCExecutable("test");
|
||||
exe.addCompileFlags([][]const u8 {
|
||||
"-std=c99",
|
||||
});
|
||||
exe.addCompileFlags([][]const u8{"-std=c99"});
|
||||
exe.addSourceFile("test.c");
|
||||
exe.addObject(obj);
|
||||
|
||||
|
||||
@ -4,9 +4,7 @@ pub fn build(b: &Builder) void {
|
||||
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
|
||||
|
||||
const exe = b.addCExecutable("test");
|
||||
exe.addCompileFlags([][]const u8 {
|
||||
"-std=c99",
|
||||
});
|
||||
exe.addCompileFlags([][]const u8{"-std=c99"});
|
||||
exe.addSourceFile("test.c");
|
||||
exe.linkLibrary(lib);
|
||||
|
||||
|
||||
@ -30,24 +30,22 @@ fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
|
||||
}
|
||||
|
||||
// Modifies the current argument index during iteration
|
||||
fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,
|
||||
allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
|
||||
|
||||
fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize, allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
|
||||
switch (required) {
|
||||
0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?
|
||||
0 => return FlagArg{ .None = undefined }, // TODO: Required to force non-tag but value?
|
||||
1 => {
|
||||
if (*index + 1 >= args.len) {
|
||||
if (index.* + 1 >= args.len) {
|
||||
return error.MissingFlagArguments;
|
||||
}
|
||||
|
||||
*index += 1;
|
||||
const arg = args[*index];
|
||||
index.* += 1;
|
||||
const arg = args[index.*];
|
||||
|
||||
if (!argInAllowedSet(allowed_set, arg)) {
|
||||
return error.ArgumentNotInAllowedSet;
|
||||
}
|
||||
|
||||
return FlagArg { .Single = arg };
|
||||
return FlagArg{ .Single = arg };
|
||||
},
|
||||
else => |needed| {
|
||||
var extra = ArrayList([]const u8).init(allocator);
|
||||
@ -55,12 +53,12 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
|
||||
|
||||
var j: usize = 0;
|
||||
while (j < needed) : (j += 1) {
|
||||
if (*index + 1 >= args.len) {
|
||||
if (index.* + 1 >= args.len) {
|
||||
return error.MissingFlagArguments;
|
||||
}
|
||||
|
||||
*index += 1;
|
||||
const arg = args[*index];
|
||||
index.* += 1;
|
||||
const arg = args[index.*];
|
||||
|
||||
if (!argInAllowedSet(allowed_set, arg)) {
|
||||
return error.ArgumentNotInAllowedSet;
|
||||
@ -69,7 +67,7 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
|
||||
try extra.append(arg);
|
||||
}
|
||||
|
||||
return FlagArg { .Many = extra };
|
||||
return FlagArg{ .Many = extra };
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -82,7 +80,7 @@ pub const Args = struct {
|
||||
positionals: ArrayList([]const u8),
|
||||
|
||||
pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
|
||||
var parsed = Args {
|
||||
var parsed = Args{
|
||||
.flags = HashMapFlags.init(allocator),
|
||||
.positionals = ArrayList([]const u8).init(allocator),
|
||||
};
|
||||
@ -116,11 +114,7 @@ pub const Args = struct {
|
||||
};
|
||||
|
||||
if (flag.mergable) {
|
||||
var prev =
|
||||
if (parsed.flags.get(flag_name_trimmed)) |entry|
|
||||
entry.value.Many
|
||||
else
|
||||
ArrayList([]const u8).init(allocator);
|
||||
var prev = if (parsed.flags.get(flag_name_trimmed)) |entry| entry.value.Many else ArrayList([]const u8).init(allocator);
|
||||
|
||||
// MergeN creation disallows 0 length flag entry (doesn't make sense)
|
||||
switch (flag_args) {
|
||||
@ -129,7 +123,7 @@ pub const Args = struct {
|
||||
FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
|
||||
}
|
||||
|
||||
_ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });
|
||||
_ = try parsed.flags.put(flag_name_trimmed, FlagArg{ .Many = prev });
|
||||
} else {
|
||||
_ = try parsed.flags.put(flag_name_trimmed, flag_args);
|
||||
}
|
||||
@ -163,7 +157,9 @@ pub const Args = struct {
|
||||
pub fn single(self: &Args, name: []const u8) ?[]const u8 {
|
||||
if (self.flags.get(name)) |entry| {
|
||||
switch (entry.value) {
|
||||
FlagArg.Single => |inner| { return inner; },
|
||||
FlagArg.Single => |inner| {
|
||||
return inner;
|
||||
},
|
||||
else => @panic("attempted to retrieve flag with wrong type"),
|
||||
}
|
||||
} else {
|
||||
@ -175,7 +171,9 @@ pub const Args = struct {
|
||||
pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
|
||||
if (self.flags.get(name)) |entry| {
|
||||
switch (entry.value) {
|
||||
FlagArg.Many => |inner| { return inner.toSliceConst(); },
|
||||
FlagArg.Many => |inner| {
|
||||
return inner.toSliceConst();
|
||||
},
|
||||
else => @panic("attempted to retrieve flag with wrong type"),
|
||||
}
|
||||
} else {
|
||||
@ -207,7 +205,7 @@ pub const Flag = struct {
|
||||
}
|
||||
|
||||
pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
|
||||
return Flag {
|
||||
return Flag{
|
||||
.name = name,
|
||||
.required = n,
|
||||
.mergable = false,
|
||||
@ -220,7 +218,7 @@ pub const Flag = struct {
|
||||
@compileError("n must be greater than 0");
|
||||
}
|
||||
|
||||
return Flag {
|
||||
return Flag{
|
||||
.name = name,
|
||||
.required = n,
|
||||
.mergable = true,
|
||||
@ -229,7 +227,7 @@ pub const Flag = struct {
|
||||
}
|
||||
|
||||
pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
|
||||
return Flag {
|
||||
return Flag{
|
||||
.name = name,
|
||||
.required = 1,
|
||||
.mergable = false,
|
||||
@ -239,26 +237,36 @@ pub const Flag = struct {
|
||||
};
|
||||
|
||||
test "parse arguments" {
|
||||
const spec1 = comptime []const Flag {
|
||||
const spec1 = comptime []const Flag{
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--init"),
|
||||
Flag.Arg1("--build-file"),
|
||||
Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),
|
||||
Flag.Option("--color", []const []const u8{
|
||||
"on",
|
||||
"off",
|
||||
"auto",
|
||||
}),
|
||||
Flag.ArgN("--pkg-begin", 2),
|
||||
Flag.ArgMergeN("--object", 1),
|
||||
Flag.ArgN("--library", 1),
|
||||
};
|
||||
|
||||
const cliargs = []const []const u8 {
|
||||
const cliargs = []const []const u8{
|
||||
"build",
|
||||
"--help",
|
||||
"pos1",
|
||||
"--build-file", "build.zig",
|
||||
"--object", "obj1",
|
||||
"--object", "obj2",
|
||||
"--library", "lib1",
|
||||
"--library", "lib2",
|
||||
"--color", "on",
|
||||
"--build-file",
|
||||
"build.zig",
|
||||
"--object",
|
||||
"obj1",
|
||||
"--object",
|
||||
"obj2",
|
||||
"--library",
|
||||
"lib1",
|
||||
"--library",
|
||||
"lib2",
|
||||
"--color",
|
||||
"on",
|
||||
"pos2",
|
||||
};
|
||||
|
||||
|
||||
@ -48,9 +48,7 @@ pub fn resolveZigLibDir(allocator: &mem.Allocator) ![]u8 {
|
||||
\\Unable to find zig lib directory: {}.
|
||||
\\Reinstall Zig or use --zig-install-prefix.
|
||||
\\
|
||||
,
|
||||
@errorName(err)
|
||||
);
|
||||
, @errorName(err));
|
||||
|
||||
return error.ZigLibDirNotFound;
|
||||
};
|
||||
|
||||
@ -108,5 +108,4 @@ pub const Instruction = struct {
|
||||
ArgType,
|
||||
Export,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@ -37,7 +37,7 @@ const usage =
|
||||
\\ zen Print zen of zig and exit
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
const Command = struct {
|
||||
name: []const u8,
|
||||
@ -63,22 +63,61 @@ pub fn main() !void {
|
||||
os.exit(1);
|
||||
}
|
||||
|
||||
const commands = []Command {
|
||||
Command { .name = "build", .exec = cmdBuild },
|
||||
Command { .name = "build-exe", .exec = cmdBuildExe },
|
||||
Command { .name = "build-lib", .exec = cmdBuildLib },
|
||||
Command { .name = "build-obj", .exec = cmdBuildObj },
|
||||
Command { .name = "fmt", .exec = cmdFmt },
|
||||
Command { .name = "run", .exec = cmdRun },
|
||||
Command { .name = "targets", .exec = cmdTargets },
|
||||
Command { .name = "test", .exec = cmdTest },
|
||||
Command { .name = "translate-c", .exec = cmdTranslateC },
|
||||
Command { .name = "version", .exec = cmdVersion },
|
||||
Command { .name = "zen", .exec = cmdZen },
|
||||
const commands = []Command{
|
||||
Command{
|
||||
.name = "build",
|
||||
.exec = cmdBuild,
|
||||
},
|
||||
Command{
|
||||
.name = "build-exe",
|
||||
.exec = cmdBuildExe,
|
||||
},
|
||||
Command{
|
||||
.name = "build-lib",
|
||||
.exec = cmdBuildLib,
|
||||
},
|
||||
Command{
|
||||
.name = "build-obj",
|
||||
.exec = cmdBuildObj,
|
||||
},
|
||||
Command{
|
||||
.name = "fmt",
|
||||
.exec = cmdFmt,
|
||||
},
|
||||
Command{
|
||||
.name = "run",
|
||||
.exec = cmdRun,
|
||||
},
|
||||
Command{
|
||||
.name = "targets",
|
||||
.exec = cmdTargets,
|
||||
},
|
||||
Command{
|
||||
.name = "test",
|
||||
.exec = cmdTest,
|
||||
},
|
||||
Command{
|
||||
.name = "translate-c",
|
||||
.exec = cmdTranslateC,
|
||||
},
|
||||
Command{
|
||||
.name = "version",
|
||||
.exec = cmdVersion,
|
||||
},
|
||||
Command{
|
||||
.name = "zen",
|
||||
.exec = cmdZen,
|
||||
},
|
||||
|
||||
// undocumented commands
|
||||
Command { .name = "help", .exec = cmdHelp },
|
||||
Command { .name = "internal", .exec = cmdInternal },
|
||||
Command{
|
||||
.name = "help",
|
||||
.exec = cmdHelp,
|
||||
},
|
||||
Command{
|
||||
.name = "internal",
|
||||
.exec = cmdInternal,
|
||||
},
|
||||
};
|
||||
|
||||
for (commands) |command| {
|
||||
@ -120,9 +159,9 @@ const usage_build =
|
||||
\\ --verbose-cimport Enable compiler debug output for C imports
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
const args_build_spec = []Flag {
|
||||
const args_build_spec = []Flag{
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--init"),
|
||||
Flag.Arg1("--build-file"),
|
||||
@ -148,7 +187,7 @@ const missing_build_file =
|
||||
\\
|
||||
\\See: `zig build --help` or `zig help` for more options.
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void {
|
||||
var flags = try Args.parse(allocator, args_build_spec, args);
|
||||
@ -317,15 +356,23 @@ const usage_build_generic =
|
||||
\\ --ver-patch [ver] Dynamic library semver patch version
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
const args_build_generic = []Flag {
|
||||
const args_build_generic = []Flag{
|
||||
Flag.Bool("--help"),
|
||||
Flag.Option("--color", []const []const u8 { "auto", "off", "on" }),
|
||||
Flag.Option("--color", []const []const u8{
|
||||
"auto",
|
||||
"off",
|
||||
"on",
|
||||
}),
|
||||
|
||||
Flag.ArgMergeN("--assembly", 1),
|
||||
Flag.Arg1("--cache-dir"),
|
||||
Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }),
|
||||
Flag.Option("--emit", []const []const u8{
|
||||
"asm",
|
||||
"bin",
|
||||
"llvm-ir",
|
||||
}),
|
||||
Flag.Bool("--enable-timing-info"),
|
||||
Flag.Arg1("--libc-include-dir"),
|
||||
Flag.Arg1("--name"),
|
||||
@ -471,7 +518,7 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
const asm_a= flags.many("assembly");
|
||||
const asm_a = flags.many("assembly");
|
||||
const obj_a = flags.many("object");
|
||||
if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) {
|
||||
try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
|
||||
@ -493,17 +540,16 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
|
||||
const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
|
||||
defer allocator.free(zig_lib_dir);
|
||||
|
||||
var module =
|
||||
try Module.create(
|
||||
allocator,
|
||||
root_name,
|
||||
zig_root_source_file,
|
||||
Target.Native,
|
||||
out_type,
|
||||
build_mode,
|
||||
zig_lib_dir,
|
||||
full_cache_dir
|
||||
);
|
||||
var module = try Module.create(
|
||||
allocator,
|
||||
root_name,
|
||||
zig_root_source_file,
|
||||
Target.Native,
|
||||
out_type,
|
||||
build_mode,
|
||||
zig_lib_dir,
|
||||
full_cache_dir,
|
||||
);
|
||||
defer module.destroy();
|
||||
|
||||
module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
|
||||
@ -588,10 +634,10 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
|
||||
}
|
||||
|
||||
if (flags.single("mmacosx-version-min")) |ver| {
|
||||
module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
|
||||
module.darwin_version_min = Module.DarwinVersionMin{ .MacOS = ver };
|
||||
}
|
||||
if (flags.single("mios-version-min")) |ver| {
|
||||
module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
|
||||
module.darwin_version_min = Module.DarwinVersionMin{ .Ios = ver };
|
||||
}
|
||||
|
||||
module.emit_file_type = emit_type;
|
||||
@ -637,15 +683,11 @@ const usage_fmt =
|
||||
\\
|
||||
\\Options:
|
||||
\\ --help Print this help and exit
|
||||
\\ --keep-backups Retain backup entries for every file
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
const args_fmt_spec = []Flag {
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--keep-backups"),
|
||||
};
|
||||
const args_fmt_spec = []Flag{Flag.Bool("--help")};
|
||||
|
||||
fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
|
||||
var flags = try Args.parse(allocator, args_fmt_spec, args);
|
||||
@ -677,7 +719,6 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
|
||||
};
|
||||
defer tree.deinit();
|
||||
|
||||
|
||||
var error_it = tree.errors.iterator(0);
|
||||
while (error_it.next()) |parse_error| {
|
||||
const token = tree.tokens.at(parse_error.loc());
|
||||
@ -723,8 +764,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
|
||||
inline while (i < @memberCount(builtin.Arch)) : (i += 1) {
|
||||
comptime const arch_tag = @memberName(builtin.Arch, i);
|
||||
// NOTE: Cannot use empty string, see #918.
|
||||
comptime const native_str =
|
||||
if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
|
||||
comptime const native_str = if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
|
||||
|
||||
try stdout.print(" {}{}", arch_tag, native_str);
|
||||
}
|
||||
@ -737,8 +777,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
|
||||
inline while (i < @memberCount(builtin.Os)) : (i += 1) {
|
||||
comptime const os_tag = @memberName(builtin.Os, i);
|
||||
// NOTE: Cannot use empty string, see #918.
|
||||
comptime const native_str =
|
||||
if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
|
||||
comptime const native_str = if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
|
||||
|
||||
try stdout.print(" {}{}", os_tag, native_str);
|
||||
}
|
||||
@ -751,8 +790,7 @@ fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
|
||||
inline while (i < @memberCount(builtin.Environ)) : (i += 1) {
|
||||
comptime const environ_tag = @memberName(builtin.Environ, i);
|
||||
// NOTE: Cannot use empty string, see #918.
|
||||
comptime const native_str =
|
||||
if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
|
||||
comptime const native_str = if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
|
||||
|
||||
try stdout.print(" {}{}", environ_tag, native_str);
|
||||
}
|
||||
@ -774,12 +812,9 @@ const usage_test =
|
||||
\\ --help Print this help and exit
|
||||
\\
|
||||
\\
|
||||
;
|
||||
|
||||
const args_test_spec = []Flag {
|
||||
Flag.Bool("--help"),
|
||||
};
|
||||
;
|
||||
|
||||
const args_test_spec = []Flag{Flag.Bool("--help")};
|
||||
|
||||
fn cmdTest(allocator: &Allocator, args: []const []const u8) !void {
|
||||
var flags = try Args.parse(allocator, args_build_spec, args);
|
||||
@ -812,21 +847,18 @@ const usage_run =
|
||||
\\ --help Print this help and exit
|
||||
\\
|
||||
\\
|
||||
;
|
||||
|
||||
const args_run_spec = []Flag {
|
||||
Flag.Bool("--help"),
|
||||
};
|
||||
;
|
||||
|
||||
const args_run_spec = []Flag{Flag.Bool("--help")};
|
||||
|
||||
fn cmdRun(allocator: &Allocator, args: []const []const u8) !void {
|
||||
var compile_args = args;
|
||||
var runtime_args: []const []const u8 = []const []const u8 {};
|
||||
var runtime_args: []const []const u8 = []const []const u8{};
|
||||
|
||||
for (args) |argv, i| {
|
||||
if (mem.eql(u8, argv, "--")) {
|
||||
compile_args = args[0..i];
|
||||
runtime_args = args[i+1..];
|
||||
runtime_args = args[i + 1..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -860,9 +892,9 @@ const usage_translate_c =
|
||||
\\ --output [path] Output file to write generated zig file (default: stdout)
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
const args_translate_c_spec = []Flag {
|
||||
const args_translate_c_spec = []Flag{
|
||||
Flag.Bool("--help"),
|
||||
Flag.Bool("--enable-timing-info"),
|
||||
Flag.Arg1("--libc-include-dir"),
|
||||
@ -936,7 +968,7 @@ const info_zen =
|
||||
\\ * Together we serve end users.
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
fn cmdZen(allocator: &Allocator, args: []const []const u8) !void {
|
||||
try stdout.write(info_zen);
|
||||
@ -951,7 +983,7 @@ const usage_internal =
|
||||
\\ build-info Print static compiler build-info
|
||||
\\
|
||||
\\
|
||||
;
|
||||
;
|
||||
|
||||
fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
|
||||
if (args.len == 0) {
|
||||
@ -959,9 +991,10 @@ fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
|
||||
os.exit(1);
|
||||
}
|
||||
|
||||
const sub_commands = []Command {
|
||||
Command { .name = "build-info", .exec = cmdInternalBuildInfo },
|
||||
};
|
||||
const sub_commands = []Command{Command{
|
||||
.name = "build-info",
|
||||
.exec = cmdInternalBuildInfo,
|
||||
}};
|
||||
|
||||
for (sub_commands) |sub_command| {
|
||||
if (mem.eql(u8, sub_command.name, args[0])) {
|
||||
@ -985,7 +1018,7 @@ fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
|
||||
\\ZIG_C_HEADER_FILES {}
|
||||
\\ZIG_DIA_GUIDS_LIB {}
|
||||
\\
|
||||
,
|
||||
,
|
||||
std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
|
||||
std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
|
||||
std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE),
|
||||
|
||||
@ -96,6 +96,7 @@ pub const Module = struct {
|
||||
pub const LinkLib = struct {
|
||||
name: []const u8,
|
||||
path: ?[]const u8,
|
||||
|
||||
/// the list of symbols we depend on from this lib
|
||||
symbols: ArrayList([]u8),
|
||||
provided_explicitly: bool,
|
||||
@ -130,9 +131,7 @@ pub const Module = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
|
||||
kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
|
||||
{
|
||||
pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module {
|
||||
var name_buffer = try Buffer.init(allocator, name);
|
||||
errdefer name_buffer.deinit();
|
||||
|
||||
@ -148,14 +147,14 @@ pub const Module = struct {
|
||||
const module_ptr = try allocator.create(Module);
|
||||
errdefer allocator.destroy(module_ptr);
|
||||
|
||||
*module_ptr = Module {
|
||||
module_ptr.* = Module{
|
||||
.allocator = allocator,
|
||||
.name = name_buffer,
|
||||
.root_src_path = root_src_path,
|
||||
.module = module,
|
||||
.context = context,
|
||||
.builder = builder,
|
||||
.target = *target,
|
||||
.target = target.*,
|
||||
.kind = kind,
|
||||
.build_mode = build_mode,
|
||||
.zig_lib_dir = zig_lib_dir,
|
||||
@ -221,8 +220,10 @@ pub const Module = struct {
|
||||
|
||||
pub fn build(self: &Module) !void {
|
||||
if (self.llvm_argv.len != 0) {
|
||||
var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
|
||||
[][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
|
||||
var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, [][]const []const u8{
|
||||
[][]const u8{"zig (LLVM option parsing)"},
|
||||
self.llvm_argv,
|
||||
});
|
||||
defer c_compatible_args.deinit();
|
||||
c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
|
||||
}
|
||||
@ -261,7 +262,6 @@ pub const Module = struct {
|
||||
|
||||
warn("====llvm ir:====\n");
|
||||
self.dump();
|
||||
|
||||
}
|
||||
|
||||
pub fn link(self: &Module, out_file: ?[]const u8) !void {
|
||||
@ -285,7 +285,7 @@ pub const Module = struct {
|
||||
}
|
||||
|
||||
const link_lib = try self.allocator.create(LinkLib);
|
||||
*link_lib = LinkLib {
|
||||
link_lib.* = LinkLib{
|
||||
.name = name,
|
||||
.path = null,
|
||||
.provided_explicitly = provided_explicitly,
|
||||
|
||||
@ -12,7 +12,7 @@ pub const Target = union(enum) {
|
||||
Cross: CrossTarget,
|
||||
|
||||
pub fn oFileExt(self: &const Target) []const u8 {
|
||||
const environ = switch (*self) {
|
||||
const environ = switch (self.*) {
|
||||
Target.Native => builtin.environ,
|
||||
Target.Cross => |t| t.environ,
|
||||
};
|
||||
@ -30,7 +30,7 @@ pub const Target = union(enum) {
|
||||
}
|
||||
|
||||
pub fn getOs(self: &const Target) builtin.Os {
|
||||
return switch (*self) {
|
||||
return switch (self.*) {
|
||||
Target.Native => builtin.os,
|
||||
Target.Cross => |t| t.os,
|
||||
};
|
||||
|
||||
@ -379,6 +379,7 @@ enum NodeType {
|
||||
NodeTypeArrayAccessExpr,
|
||||
NodeTypeSliceExpr,
|
||||
NodeTypeFieldAccessExpr,
|
||||
NodeTypePtrDeref,
|
||||
NodeTypeUse,
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
@ -603,13 +604,16 @@ struct AstNodeFieldAccessExpr {
|
||||
Buf *field_name;
|
||||
};
|
||||
|
||||
struct AstNodePtrDerefExpr {
|
||||
AstNode *target;
|
||||
};
|
||||
|
||||
enum PrefixOp {
|
||||
PrefixOpInvalid,
|
||||
PrefixOpBoolNot,
|
||||
PrefixOpBinNot,
|
||||
PrefixOpNegation,
|
||||
PrefixOpNegationWrap,
|
||||
PrefixOpDereference,
|
||||
PrefixOpMaybe,
|
||||
PrefixOpUnwrapMaybe,
|
||||
};
|
||||
@ -911,6 +915,7 @@ struct AstNode {
|
||||
AstNodeCompTime comptime_expr;
|
||||
AstNodeAsmExpr asm_expr;
|
||||
AstNodeFieldAccessExpr field_access_expr;
|
||||
AstNodePtrDerefExpr ptr_deref_expr;
|
||||
AstNodeContainerDecl container_decl;
|
||||
AstNodeStructField struct_field;
|
||||
AstNodeStringLiteral string_literal;
|
||||
@ -1340,6 +1345,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdOffsetOf,
|
||||
BuiltinFnIdInlineCall,
|
||||
BuiltinFnIdNoInlineCall,
|
||||
BuiltinFnIdNewStackCall,
|
||||
BuiltinFnIdTypeId,
|
||||
BuiltinFnIdShlExact,
|
||||
BuiltinFnIdShrExact,
|
||||
@ -1656,8 +1662,13 @@ struct CodeGen {
|
||||
LLVMValueRef coro_alloc_helper_fn_val;
|
||||
LLVMValueRef merge_err_ret_traces_fn_val;
|
||||
LLVMValueRef add_error_return_trace_addr_fn_val;
|
||||
LLVMValueRef stacksave_fn_val;
|
||||
LLVMValueRef stackrestore_fn_val;
|
||||
LLVMValueRef write_register_fn_val;
|
||||
bool error_during_imports;
|
||||
|
||||
LLVMValueRef sp_md_node;
|
||||
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
ZigList<const char *> lib_dirs;
|
||||
@ -2280,6 +2291,7 @@ struct IrInstructionCall {
|
||||
bool is_async;
|
||||
|
||||
IrInstruction *async_allocator;
|
||||
IrInstruction *new_stack;
|
||||
};
|
||||
|
||||
struct IrInstructionConst {
|
||||
|
||||
@ -25,6 +25,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type);
|
||||
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type);
|
||||
static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type);
|
||||
static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type);
|
||||
static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
|
||||
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
if (node->owner->c_import_node != nullptr) {
|
||||
@ -1007,7 +1008,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
if (fn_type_id->return_type != nullptr) {
|
||||
ensure_complete_type(g, fn_type_id->return_type);
|
||||
} else {
|
||||
zig_panic("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447");
|
||||
zig_panic("TODO implement inferred return types https://github.com/ziglang/zig/issues/447");
|
||||
}
|
||||
|
||||
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
|
||||
@ -1556,7 +1557,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
add_node_error(g, proto_node,
|
||||
buf_sprintf("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447"));
|
||||
buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
//return get_generic_fn_type(g, &fn_type_id);
|
||||
}
|
||||
@ -3281,6 +3282,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeUnreachable:
|
||||
case NodeTypeAsmExpr:
|
||||
case NodeTypeFieldAccessExpr:
|
||||
case NodeTypePtrDeref:
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeContainerInitExpr:
|
||||
case NodeTypeStructValueField:
|
||||
@ -3879,7 +3881,7 @@ static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entr
|
||||
}
|
||||
}
|
||||
|
||||
static bool analyze_resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
|
||||
bool resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
|
||||
FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
|
||||
if (infer_fn != nullptr) {
|
||||
if (infer_fn->anal_state == FnAnalStateInvalid) {
|
||||
@ -3931,7 +3933,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
|
||||
}
|
||||
|
||||
if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
|
||||
if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
|
||||
if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
|
||||
fn_table_entry->anal_state = FnAnalStateInvalid;
|
||||
return;
|
||||
}
|
||||
@ -3961,7 +3963,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
|
||||
fn_table_entry->anal_state = FnAnalStateComplete;
|
||||
}
|
||||
|
||||
void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
assert(fn_table_entry->anal_state != FnAnalStateProbing);
|
||||
if (fn_table_entry->anal_state != FnAnalStateReady)
|
||||
return;
|
||||
|
||||
@ -191,7 +191,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
|
||||
|
||||
ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
|
||||
TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
|
||||
void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
|
||||
bool resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node);
|
||||
|
||||
TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
|
||||
|
||||
|
||||
@ -66,7 +66,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
|
||||
case PrefixOpNegationWrap: return "-%";
|
||||
case PrefixOpBoolNot: return "!";
|
||||
case PrefixOpBinNot: return "~";
|
||||
case PrefixOpDereference: return "*";
|
||||
case PrefixOpMaybe: return "?";
|
||||
case PrefixOpUnwrapMaybe: return "??";
|
||||
}
|
||||
@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "AsmExpr";
|
||||
case NodeTypeFieldAccessExpr:
|
||||
return "FieldAccessExpr";
|
||||
case NodeTypePtrDeref:
|
||||
return "PtrDerefExpr";
|
||||
case NodeTypeContainerDecl:
|
||||
return "ContainerDecl";
|
||||
case NodeTypeStructField:
|
||||
@ -696,6 +697,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
print_symbol(ar, rhs);
|
||||
break;
|
||||
}
|
||||
case NodeTypePtrDeref:
|
||||
{
|
||||
AstNode *lhs = node->data.ptr_deref_expr.target;
|
||||
render_node_ungrouped(ar, lhs);
|
||||
fprintf(ar->f, ".*");
|
||||
break;
|
||||
}
|
||||
case NodeTypeUndefinedLiteral:
|
||||
fprintf(ar->f, "undefined");
|
||||
break;
|
||||
|
||||
105
src/codegen.cpp
105
src/codegen.cpp
@ -582,7 +582,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
|
||||
}
|
||||
// Note: byval is disabled on windows due to an LLVM bug:
|
||||
// https://github.com/zig-lang/zig/issues/536
|
||||
// https://github.com/ziglang/zig/issues/536
|
||||
if (is_byval && g->zig_target.os != OsWindows) {
|
||||
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
|
||||
}
|
||||
@ -938,6 +938,53 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
|
||||
return g->memcpy_fn_val;
|
||||
}
|
||||
|
||||
static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
|
||||
if (g->stacksave_fn_val)
|
||||
return g->stacksave_fn_val;
|
||||
|
||||
// declare i8* @llvm.stacksave()
|
||||
|
||||
LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false);
|
||||
g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type);
|
||||
assert(LLVMGetIntrinsicID(g->stacksave_fn_val));
|
||||
|
||||
return g->stacksave_fn_val;
|
||||
}
|
||||
|
||||
static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) {
|
||||
if (g->stackrestore_fn_val)
|
||||
return g->stackrestore_fn_val;
|
||||
|
||||
// declare void @llvm.stackrestore(i8* %ptr)
|
||||
|
||||
LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0);
|
||||
LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), ¶m_type, 1, false);
|
||||
g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type);
|
||||
assert(LLVMGetIntrinsicID(g->stackrestore_fn_val));
|
||||
|
||||
return g->stackrestore_fn_val;
|
||||
}
|
||||
|
||||
static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
|
||||
if (g->write_register_fn_val)
|
||||
return g->write_register_fn_val;
|
||||
|
||||
// declare void @llvm.write_register.i64(metadata, i64 @value)
|
||||
// !0 = !{!"sp\00"}
|
||||
|
||||
LLVMTypeRef param_types[] = {
|
||||
LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
|
||||
LLVMIntType(g->pointer_size_bytes * 8),
|
||||
};
|
||||
|
||||
LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
|
||||
Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8);
|
||||
g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
|
||||
assert(LLVMGetIntrinsicID(g->write_register_fn_val));
|
||||
|
||||
return g->write_register_fn_val;
|
||||
}
|
||||
|
||||
static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
|
||||
if (g->coro_destroy_fn_val)
|
||||
return g->coro_destroy_fn_val;
|
||||
@ -2901,6 +2948,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
return 1 + get_async_allocator_arg_index(g, fn_type_id);
|
||||
}
|
||||
|
||||
|
||||
static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
|
||||
|
||||
LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
|
||||
LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
|
||||
|
||||
LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
|
||||
LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
|
||||
LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
|
||||
LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
|
||||
return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
|
||||
}
|
||||
|
||||
static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
|
||||
LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
|
||||
|
||||
if (g->sp_md_node == nullptr) {
|
||||
Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
|
||||
LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
|
||||
g->sp_md_node = LLVMMDNode(&str_node, 1);
|
||||
}
|
||||
|
||||
LLVMValueRef params[] = {
|
||||
g->sp_md_node,
|
||||
aligned_end_addr,
|
||||
};
|
||||
|
||||
LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
|
||||
LLVMValueRef fn_val;
|
||||
TypeTableEntry *fn_type;
|
||||
@ -2967,13 +3046,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
}
|
||||
|
||||
LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
|
||||
LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
|
||||
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
|
||||
LLVMValueRef result;
|
||||
|
||||
if (instruction->new_stack == nullptr) {
|
||||
result = ZigLLVMBuildCall(g->builder, fn_val,
|
||||
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
|
||||
} else {
|
||||
LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
|
||||
LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
|
||||
|
||||
LLVMValueRef new_stack_addr = get_new_stack_addr(g, ir_llvm_value(g, instruction->new_stack));
|
||||
LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
|
||||
gen_set_stack_pointer(g, new_stack_addr);
|
||||
result = ZigLLVMBuildCall(g->builder, fn_val,
|
||||
gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
|
||||
LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
|
||||
}
|
||||
|
||||
|
||||
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
|
||||
FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
|
||||
// Note: byval is disabled on windows due to an LLVM bug:
|
||||
// https://github.com/zig-lang/zig/issues/536
|
||||
// https://github.com/ziglang/zig/issues/536
|
||||
if (gen_info->is_byval && g->zig_target.os != OsWindows) {
|
||||
addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
|
||||
}
|
||||
@ -6171,6 +6265,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
|
||||
create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
|
||||
create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
|
||||
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
|
||||
@ -6635,7 +6730,7 @@ static void init(CodeGen *g) {
|
||||
const char *target_specific_features;
|
||||
if (g->is_native_target) {
|
||||
// LLVM creates invalid binaries on Windows sometimes.
|
||||
// See https://github.com/zig-lang/zig/issues/508
|
||||
// See https://github.com/ziglang/zig/issues/508
|
||||
// As a workaround we do not use target native features on Windows.
|
||||
if (g->zig_target.os == OsWindows) {
|
||||
target_specific_cpu_args = "";
|
||||
|
||||
177
src/ir.cpp
177
src/ir.cpp
@ -1102,7 +1102,8 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
|
||||
|
||||
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
|
||||
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
|
||||
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
|
||||
IrInstruction *new_stack)
|
||||
{
|
||||
IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
|
||||
call_instruction->fn_entry = fn_entry;
|
||||
@ -1113,6 +1114,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
|
||||
call_instruction->arg_count = arg_count;
|
||||
call_instruction->is_async = is_async;
|
||||
call_instruction->async_allocator = async_allocator;
|
||||
call_instruction->new_stack = new_stack;
|
||||
|
||||
if (fn_ref)
|
||||
ir_ref_instruction(fn_ref, irb->current_basic_block);
|
||||
@ -1120,16 +1122,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
|
||||
ir_ref_instruction(args[i], irb->current_basic_block);
|
||||
if (async_allocator)
|
||||
ir_ref_instruction(async_allocator, irb->current_basic_block);
|
||||
if (new_stack != nullptr)
|
||||
ir_ref_instruction(new_stack, irb->current_basic_block);
|
||||
|
||||
return &call_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
|
||||
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
|
||||
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
|
||||
IrInstruction *new_stack)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
|
||||
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
|
||||
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator, new_stack);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
@ -4303,7 +4308,37 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
}
|
||||
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
|
||||
|
||||
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
|
||||
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
|
||||
return ir_lval_wrap(irb, scope, call, lval);
|
||||
}
|
||||
case BuiltinFnIdNewStackCall:
|
||||
{
|
||||
if (node->data.fn_call_expr.params.length == 0) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
|
||||
if (new_stack == irb->codegen->invalid_instruction)
|
||||
return new_stack;
|
||||
|
||||
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
|
||||
if (fn_ref == irb->codegen->invalid_instruction)
|
||||
return fn_ref;
|
||||
|
||||
size_t arg_count = node->data.fn_call_expr.params.length - 2;
|
||||
|
||||
IrInstruction **args = allocate<IrInstruction*>(arg_count);
|
||||
for (size_t i = 0; i < arg_count; i += 1) {
|
||||
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
|
||||
args[i] = ir_gen_node(irb, arg_node, scope);
|
||||
if (args[i] == irb->codegen->invalid_instruction)
|
||||
return args[i];
|
||||
}
|
||||
|
||||
IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
|
||||
return ir_lval_wrap(irb, scope, call, lval);
|
||||
}
|
||||
case BuiltinFnIdTypeId:
|
||||
@ -4513,7 +4548,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
|
||||
}
|
||||
}
|
||||
|
||||
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
|
||||
IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
|
||||
return ir_lval_wrap(irb, scope, fn_call, lval);
|
||||
}
|
||||
|
||||
@ -4574,8 +4609,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
|
||||
assert(node->type == NodeTypePrefixOpExpr);
|
||||
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
|
||||
AstNode *expr_node;
|
||||
if (node->type == NodeTypePrefixOpExpr) {
|
||||
expr_node = node->data.prefix_op_expr.primary_expr;
|
||||
} else if (node->type == NodeTypePtrDeref) {
|
||||
expr_node = node->data.ptr_deref_expr.target;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
|
||||
if (value == irb->codegen->invalid_instruction)
|
||||
@ -4716,8 +4757,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
|
||||
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
|
||||
case PrefixOpNegationWrap:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
|
||||
case PrefixOpDereference:
|
||||
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
|
||||
case PrefixOpMaybe:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
|
||||
case PrefixOpUnwrapMaybe:
|
||||
@ -6553,6 +6592,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
|
||||
|
||||
return ir_build_load_ptr(irb, scope, node, ptr_instruction);
|
||||
}
|
||||
case NodeTypePtrDeref:
|
||||
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
|
||||
case NodeTypeThisLiteral:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
|
||||
case NodeTypeBoolLiteral:
|
||||
@ -6825,7 +6866,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
|
||||
IrInstruction **args = allocate<IrInstruction *>(arg_count);
|
||||
args[0] = implicit_allocator_ptr; // self
|
||||
args[1] = mem_slice; // old_mem
|
||||
ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr);
|
||||
ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
|
||||
|
||||
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
|
||||
ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
|
||||
@ -7592,38 +7633,16 @@ static bool slice_is_const(TypeTableEntry *type) {
|
||||
return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
|
||||
}
|
||||
|
||||
static bool resolve_inferred_error_set(IrAnalyze *ira, TypeTableEntry *err_set_type, AstNode *source_node) {
|
||||
assert(err_set_type->id == TypeTableEntryIdErrorSet);
|
||||
FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
|
||||
if (infer_fn != nullptr) {
|
||||
if (infer_fn->anal_state == FnAnalStateInvalid) {
|
||||
return false;
|
||||
} else if (infer_fn->anal_state == FnAnalStateReady) {
|
||||
analyze_fn_body(ira->codegen, infer_fn);
|
||||
if (err_set_type->data.error_set.infer_fn != nullptr) {
|
||||
assert(ira->codegen->errors.length != 0);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
|
||||
buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry *set1, TypeTableEntry *set2,
|
||||
AstNode *source_node)
|
||||
{
|
||||
assert(set1->id == TypeTableEntryIdErrorSet);
|
||||
assert(set2->id == TypeTableEntryIdErrorSet);
|
||||
|
||||
if (!resolve_inferred_error_set(ira, set1, source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, set1, source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (!resolve_inferred_error_set(ira, set2, source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, set2, source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (type_is_global_error_set(set1)) {
|
||||
@ -7762,7 +7781,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!resolve_inferred_error_set(ira, contained_set, source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, contained_set, source_node)) {
|
||||
result.id = ConstCastResultIdUnresolvedInferredErrSet;
|
||||
return result;
|
||||
}
|
||||
@ -8151,7 +8170,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
|
||||
} else {
|
||||
err_set_type = prev_inst->value.type;
|
||||
if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
update_errors_helper(ira->codegen, &errors, &errors_count);
|
||||
@ -8190,7 +8209,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
if (type_is_global_error_set(err_set_type)) {
|
||||
continue;
|
||||
}
|
||||
if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (type_is_global_error_set(cur_type)) {
|
||||
@ -8256,7 +8275,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
continue;
|
||||
}
|
||||
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
|
||||
if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (type_is_global_error_set(cur_err_set_type)) {
|
||||
@ -8319,7 +8338,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
|
||||
continue;
|
||||
}
|
||||
if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -8376,11 +8395,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
TypeTableEntry *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
|
||||
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
|
||||
|
||||
if (!resolve_inferred_error_set(ira, prev_err_set_type, cur_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -8490,7 +8509,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
{
|
||||
if (err_set_type != nullptr) {
|
||||
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
|
||||
if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (type_is_global_error_set(cur_err_set_type) || type_is_global_error_set(err_set_type)) {
|
||||
@ -8686,6 +8705,10 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
|
||||
*dest = *src;
|
||||
if (!same_global_refs) {
|
||||
dest->global_refs = global_refs;
|
||||
if (dest->type->id == TypeTableEntryIdStruct) {
|
||||
dest->data.x_struct.fields = allocate_nonzero<ConstExprValue>(dest->type->data.structure.src_field_count);
|
||||
memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9168,7 +9191,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
if (!type_is_global_error_set(wanted_type)) {
|
||||
@ -9609,7 +9632,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
|
||||
if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
@ -9707,7 +9730,7 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
|
||||
zig_unreachable();
|
||||
}
|
||||
if (!type_is_global_error_set(err_set_type)) {
|
||||
if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, err_set_type, source_instr->source_node)) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
if (err_set_type->data.error_set.err_count == 0) {
|
||||
@ -10602,7 +10625,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (!resolve_inferred_error_set(ira, intersect_type, source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, intersect_type, source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -11458,11 +11481,11 @@ static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstruction
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
}
|
||||
|
||||
if (!resolve_inferred_error_set(ira, op1_type, instruction->op1->other->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, op1_type, instruction->op1->other->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (!resolve_inferred_error_set(ira, op2_type, instruction->op2->other->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, op2_type, instruction->op2->other->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -11670,7 +11693,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
||||
if (var->mem_slot_index != SIZE_MAX) {
|
||||
assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
|
||||
ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
||||
*mem_slot = casted_init_value->value;
|
||||
copy_const_val(mem_slot, &casted_init_value->value,
|
||||
!is_comptime_var || var->gen_is_const);
|
||||
|
||||
if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
|
||||
ir_build_const_from(ira, &decl_var_instruction->base);
|
||||
@ -11987,7 +12011,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
|
||||
TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
|
||||
|
||||
IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
|
||||
fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst);
|
||||
fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
|
||||
result->value.type = async_return_type;
|
||||
return result;
|
||||
}
|
||||
@ -12084,7 +12108,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||
casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
ir_add_error(ira, casted_arg,
|
||||
buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));
|
||||
buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/ziglang/zig/issues/557"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -12285,7 +12309,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
|
||||
if (fn_proto_node->data.fn_proto.is_var_args) {
|
||||
ir_add_error(ira, &call_instruction->base,
|
||||
buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));
|
||||
buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/ziglang/zig/issues/313"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -12357,6 +12381,19 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
return ir_finish_anal(ira, return_type);
|
||||
}
|
||||
|
||||
IrInstruction *casted_new_stack = nullptr;
|
||||
if (call_instruction->new_stack != nullptr) {
|
||||
TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
|
||||
TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
IrInstruction *new_stack = call_instruction->new_stack->other;
|
||||
if (type_is_invalid(new_stack->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
|
||||
if (type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (fn_type->data.fn.is_generic) {
|
||||
if (!fn_entry) {
|
||||
ir_add_error(ira, call_instruction->fn_ref,
|
||||
@ -12365,7 +12402,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
}
|
||||
if (call_instruction->is_async && fn_type_id->is_var_args) {
|
||||
ir_add_error(ira, call_instruction->fn_ref,
|
||||
buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/zig-lang/zig/issues/557"));
|
||||
buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/ziglang/zig/issues/557"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -12448,7 +12485,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
|
||||
if (arg_var == nullptr) {
|
||||
ir_add_error(ira, arg,
|
||||
buf_sprintf("compiler bug: var args can't handle void. https://github.com/zig-lang/zig/issues/557"));
|
||||
buf_sprintf("compiler bug: var args can't handle void. https://github.com/ziglang/zig/issues/557"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);
|
||||
@ -12583,7 +12620,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
assert(async_allocator_inst == nullptr);
|
||||
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
|
||||
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
|
||||
call_instruction->is_async, nullptr);
|
||||
call_instruction->is_async, nullptr, casted_new_stack);
|
||||
|
||||
ir_add_alloca(ira, new_call_instruction, return_type);
|
||||
|
||||
@ -12674,7 +12711,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
|
||||
|
||||
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
|
||||
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
|
||||
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
|
||||
|
||||
ir_add_alloca(ira, new_call_instruction, return_type);
|
||||
return ir_finish_anal(ira, return_type);
|
||||
@ -13792,7 +13829,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
}
|
||||
err_set_type = err_entry->set_with_only_this_in_it;
|
||||
} else {
|
||||
if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
err_entry = find_err_table_entry(child_type, field_name);
|
||||
@ -15923,10 +15960,6 @@ static void ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
|
||||
FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
|
||||
assert(!fn_entry->is_test);
|
||||
|
||||
analyze_fn_body(ira->codegen, fn_entry);
|
||||
if (fn_entry->anal_state == FnAnalStateInvalid)
|
||||
return;
|
||||
|
||||
AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
|
||||
|
||||
ConstExprValue *fn_def_val = create_const_vals(1);
|
||||
@ -16496,6 +16529,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
|
||||
{
|
||||
size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
|
||||
inner_fields[1].data.x_maybe = create_const_vals(1);
|
||||
inner_fields[1].data.x_maybe->special = ConstValSpecialStatic;
|
||||
inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize;
|
||||
bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset);
|
||||
}
|
||||
@ -17503,7 +17537,7 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
|
||||
} else if (container_type->id == TypeTableEntryIdUnion) {
|
||||
result = container_type->data.unionation.src_field_count;
|
||||
} else if (container_type->id == TypeTableEntryIdErrorSet) {
|
||||
if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, container_type, instruction->base.source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (type_is_global_error_set(container_type)) {
|
||||
@ -17807,7 +17841,7 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
|
||||
}
|
||||
|
||||
TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
|
||||
if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (!type_is_global_error_set(err_set_type) &&
|
||||
@ -17880,6 +17914,15 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
TypeTableEntry *ptr_type = value->value.type;
|
||||
|
||||
// Because we don't have Pointer Reform yet, we can't have a pointer to a 'type'.
|
||||
// Therefor, we have to check for type 'type' here, so we can output a correct error
|
||||
// without asserting the assert below.
|
||||
if (ptr_type->id == TypeTableEntryIdMetaType) {
|
||||
ir_add_error(ira, value,
|
||||
buf_sprintf("expected error union type, found '%s'", buf_ptr(&ptr_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
// This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
|
||||
@ -18030,7 +18073,11 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
if (type_is_invalid(end_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
assert(start_value->value.type->id == TypeTableEntryIdEnum);
|
||||
if (start_value->value.type->id != TypeTableEntryIdEnum) {
|
||||
ir_add_error(ira, range->start, buf_sprintf("not an enum type"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
BigInt start_index;
|
||||
bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
|
||||
|
||||
@ -18071,7 +18118,7 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
}
|
||||
}
|
||||
} else if (switch_type->id == TypeTableEntryIdErrorSet) {
|
||||
if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) {
|
||||
if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->source_node)) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
|
||||
@ -1046,11 +1046,12 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
|
||||
}
|
||||
|
||||
/*
|
||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression)
|
||||
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
|
||||
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
|
||||
SliceExpression = "[" Expression ".." option(Expression) "]"
|
||||
FieldAccessExpression : token(Dot) token(Symbol)
|
||||
PtrDerefExpression = ".*"
|
||||
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
|
||||
*/
|
||||
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
@ -1131,13 +1132,27 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
|
||||
} else if (first_token->id == TokenIdDot) {
|
||||
*token_index += 1;
|
||||
|
||||
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
|
||||
node->data.field_access_expr.struct_expr = primary_expr;
|
||||
node->data.field_access_expr.field_name = token_buf(name_token);
|
||||
if (token->id == TokenIdSymbol) {
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
|
||||
node->data.field_access_expr.struct_expr = primary_expr;
|
||||
node->data.field_access_expr.field_name = token_buf(token);
|
||||
|
||||
primary_expr = node;
|
||||
} else if (token->id == TokenIdStar) {
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
|
||||
node->data.ptr_deref_expr.target = primary_expr;
|
||||
|
||||
primary_expr = node;
|
||||
} else {
|
||||
ast_invalid_token_error(pc, token);
|
||||
}
|
||||
|
||||
primary_expr = node;
|
||||
} else {
|
||||
return primary_expr;
|
||||
}
|
||||
@ -1150,10 +1165,8 @@ static PrefixOp tok_to_prefix_op(Token *token) {
|
||||
case TokenIdDash: return PrefixOpNegation;
|
||||
case TokenIdMinusPercent: return PrefixOpNegationWrap;
|
||||
case TokenIdTilde: return PrefixOpBinNot;
|
||||
case TokenIdStar: return PrefixOpDereference;
|
||||
case TokenIdMaybe: return PrefixOpMaybe;
|
||||
case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
|
||||
case TokenIdStarStar: return PrefixOpDereference;
|
||||
default: return PrefixOpInvalid;
|
||||
}
|
||||
}
|
||||
@ -1199,7 +1212,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
|
||||
|
||||
/*
|
||||
PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
|
||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
|
||||
PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
|
||||
*/
|
||||
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -1222,15 +1235,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
|
||||
AstNode *parent_node = node;
|
||||
if (token->id == TokenIdStarStar) {
|
||||
// pretend that we got 2 star tokens
|
||||
|
||||
parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
|
||||
parent_node->data.prefix_op_expr.primary_expr = node;
|
||||
parent_node->data.prefix_op_expr.prefix_op = PrefixOpDereference;
|
||||
|
||||
node->column += 1;
|
||||
}
|
||||
|
||||
AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
|
||||
node->data.prefix_op_expr.primary_expr = prefix_op_expr;
|
||||
@ -3012,6 +3016,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeFieldAccessExpr:
|
||||
visit_field(&node->data.field_access_expr.struct_expr, visit, context);
|
||||
break;
|
||||
case NodeTypePtrDeref:
|
||||
visit_field(&node->data.ptr_deref_expr.target, visit, context);
|
||||
break;
|
||||
case NodeTypeUse:
|
||||
visit_field(&node->data.use.expr, visit, context);
|
||||
break;
|
||||
|
||||
@ -702,6 +702,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
||||
case OsLinux:
|
||||
case OsMacOSX:
|
||||
case OsZen:
|
||||
case OsOpenBSD:
|
||||
switch (id) {
|
||||
case CIntTypeShort:
|
||||
case CIntTypeUShort:
|
||||
@ -742,7 +743,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
||||
case OsKFreeBSD:
|
||||
case OsLv2:
|
||||
case OsNetBSD:
|
||||
case OsOpenBSD:
|
||||
case OsSolaris:
|
||||
case OsHaiku:
|
||||
case OsMinix:
|
||||
@ -896,3 +896,65 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *arch_stack_pointer_register_name(const ArchType *arch) {
|
||||
switch (arch->arch) {
|
||||
case ZigLLVM_UnknownArch:
|
||||
zig_unreachable();
|
||||
case ZigLLVM_x86:
|
||||
return "sp";
|
||||
case ZigLLVM_x86_64:
|
||||
return "rsp";
|
||||
|
||||
case ZigLLVM_aarch64:
|
||||
case ZigLLVM_arm:
|
||||
case ZigLLVM_thumb:
|
||||
case ZigLLVM_aarch64_be:
|
||||
case ZigLLVM_amdgcn:
|
||||
case ZigLLVM_amdil:
|
||||
case ZigLLVM_amdil64:
|
||||
case ZigLLVM_armeb:
|
||||
case ZigLLVM_arc:
|
||||
case ZigLLVM_avr:
|
||||
case ZigLLVM_bpfeb:
|
||||
case ZigLLVM_bpfel:
|
||||
case ZigLLVM_hexagon:
|
||||
case ZigLLVM_lanai:
|
||||
case ZigLLVM_hsail:
|
||||
case ZigLLVM_hsail64:
|
||||
case ZigLLVM_kalimba:
|
||||
case ZigLLVM_le32:
|
||||
case ZigLLVM_le64:
|
||||
case ZigLLVM_mips:
|
||||
case ZigLLVM_mips64:
|
||||
case ZigLLVM_mips64el:
|
||||
case ZigLLVM_mipsel:
|
||||
case ZigLLVM_msp430:
|
||||
case ZigLLVM_nios2:
|
||||
case ZigLLVM_nvptx:
|
||||
case ZigLLVM_nvptx64:
|
||||
case ZigLLVM_ppc64le:
|
||||
case ZigLLVM_r600:
|
||||
case ZigLLVM_renderscript32:
|
||||
case ZigLLVM_renderscript64:
|
||||
case ZigLLVM_riscv32:
|
||||
case ZigLLVM_riscv64:
|
||||
case ZigLLVM_shave:
|
||||
case ZigLLVM_sparc:
|
||||
case ZigLLVM_sparcel:
|
||||
case ZigLLVM_sparcv9:
|
||||
case ZigLLVM_spir:
|
||||
case ZigLLVM_spir64:
|
||||
case ZigLLVM_systemz:
|
||||
case ZigLLVM_tce:
|
||||
case ZigLLVM_tcele:
|
||||
case ZigLLVM_thumbeb:
|
||||
case ZigLLVM_wasm32:
|
||||
case ZigLLVM_wasm64:
|
||||
case ZigLLVM_xcore:
|
||||
case ZigLLVM_ppc:
|
||||
case ZigLLVM_ppc64:
|
||||
zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
@ -77,6 +77,8 @@ size_t target_arch_count(void);
|
||||
const ArchType *get_target_arch(size_t index);
|
||||
void get_arch_name(char *out_str, const ArchType *arch);
|
||||
|
||||
const char *arch_stack_pointer_register_name(const ArchType *arch);
|
||||
|
||||
size_t target_vendor_count(void);
|
||||
ZigLLVM_VendorType get_target_vendor(size_t index);
|
||||
|
||||
|
||||
@ -247,6 +247,12 @@ static AstNode *trans_create_node_field_access_str(Context *c, AstNode *containe
|
||||
return trans_create_node_field_access(c, container, buf_create_from_str(field_name));
|
||||
}
|
||||
|
||||
static AstNode *trans_create_node_ptr_deref(Context *c, AstNode *child_node) {
|
||||
AstNode *node = trans_create_node(c, NodeTypePtrDeref);
|
||||
node->data.ptr_deref_expr.target = child_node;
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {
|
||||
AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
|
||||
node->data.prefix_op_expr.prefix_op = op;
|
||||
@ -1412,8 +1418,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
||||
AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
|
||||
stmt->getComputationLHSType(),
|
||||
stmt->getLHS()->getType(),
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_symbol(c, tmp_var_name)));
|
||||
trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name)));
|
||||
|
||||
// result_type(... >> u5(rhs))
|
||||
AstNode *result_type_cast = trans_c_cast(c, rhs_location,
|
||||
@ -1426,7 +1431,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
||||
|
||||
// *_ref = ...
|
||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, tmp_var_name)),
|
||||
BinOpTypeAssign, result_type_cast);
|
||||
|
||||
@ -1436,7 +1441,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
|
||||
// break :x *_ref
|
||||
child_scope->node->data.block.statements.append(
|
||||
trans_create_node_break(c, label_name,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, tmp_var_name))));
|
||||
}
|
||||
|
||||
@ -1483,11 +1488,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
|
||||
if (rhs == nullptr) return nullptr;
|
||||
|
||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, tmp_var_name)),
|
||||
BinOpTypeAssign,
|
||||
trans_create_node_bin_op(c,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, tmp_var_name)),
|
||||
bin_op,
|
||||
rhs));
|
||||
@ -1496,7 +1501,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
|
||||
// break :x *_ref
|
||||
child_scope->node->data.block.statements.append(
|
||||
trans_create_node_break(c, label_name,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, tmp_var_name))));
|
||||
|
||||
return child_scope->node;
|
||||
@ -1817,13 +1822,13 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
|
||||
// const _tmp = *_ref;
|
||||
Buf* tmp_var_name = buf_create_from_str("_tmp");
|
||||
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, ref_var_name)));
|
||||
child_scope->node->data.block.statements.append(tmp_var_decl);
|
||||
|
||||
// *_ref += 1;
|
||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, ref_var_name)),
|
||||
assign_op,
|
||||
trans_create_node_unsigned(c, 1));
|
||||
@ -1871,14 +1876,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
|
||||
|
||||
// *_ref += 1;
|
||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, ref_var_name)),
|
||||
assign_op,
|
||||
trans_create_node_unsigned(c, 1));
|
||||
child_scope->node->data.block.statements.append(assign_statement);
|
||||
|
||||
// break :x *_ref
|
||||
AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||
AstNode *deref_expr = trans_create_node_ptr_deref(c,
|
||||
trans_create_node_symbol(c, ref_var_name));
|
||||
child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
|
||||
|
||||
@ -1923,7 +1928,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
||||
if (is_fn_ptr)
|
||||
return value_node;
|
||||
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
|
||||
return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped);
|
||||
return trans_create_node_ptr_deref(c, unwrapped);
|
||||
}
|
||||
case UO_Plus:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
|
||||
@ -4443,27 +4448,45 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
|
||||
}
|
||||
}
|
||||
|
||||
static PrefixOp ctok_to_prefix_op(CTok *token) {
|
||||
switch (token->id) {
|
||||
case CTokIdBang: return PrefixOpBoolNot;
|
||||
case CTokIdMinus: return PrefixOpNegation;
|
||||
case CTokIdTilde: return PrefixOpBinNot;
|
||||
case CTokIdAsterisk: return PrefixOpDereference;
|
||||
default: return PrefixOpInvalid;
|
||||
}
|
||||
}
|
||||
static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {
|
||||
CTok *op_tok = &ctok->tokens.at(*tok_i);
|
||||
PrefixOp prefix_op = ctok_to_prefix_op(op_tok);
|
||||
if (prefix_op == PrefixOpInvalid) {
|
||||
return parse_ctok_suffix_op_expr(c, ctok, tok_i);
|
||||
}
|
||||
*tok_i += 1;
|
||||
|
||||
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||
if (prefix_op_expr == nullptr)
|
||||
return nullptr;
|
||||
return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr);
|
||||
switch (op_tok->id) {
|
||||
case CTokIdBang:
|
||||
{
|
||||
*tok_i += 1;
|
||||
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||
if (prefix_op_expr == nullptr)
|
||||
return nullptr;
|
||||
return trans_create_node_prefix_op(c, PrefixOpBoolNot, prefix_op_expr);
|
||||
}
|
||||
case CTokIdMinus:
|
||||
{
|
||||
*tok_i += 1;
|
||||
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||
if (prefix_op_expr == nullptr)
|
||||
return nullptr;
|
||||
return trans_create_node_prefix_op(c, PrefixOpNegation, prefix_op_expr);
|
||||
}
|
||||
case CTokIdTilde:
|
||||
{
|
||||
*tok_i += 1;
|
||||
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||
if (prefix_op_expr == nullptr)
|
||||
return nullptr;
|
||||
return trans_create_node_prefix_op(c, PrefixOpBinNot, prefix_op_expr);
|
||||
}
|
||||
case CTokIdAsterisk:
|
||||
{
|
||||
*tok_i += 1;
|
||||
AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
|
||||
if (prefix_op_expr == nullptr)
|
||||
return nullptr;
|
||||
return trans_create_node_ptr_deref(c, prefix_op_expr);
|
||||
}
|
||||
default:
|
||||
return parse_ctok_suffix_op_expr(c, ctok, tok_i);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {
|
||||
|
||||
@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) type {
|
||||
return AlignedArrayList(T, @alignOf(T));
|
||||
}
|
||||
|
||||
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
|
||||
@ -21,7 +21,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
|
||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||
pub fn init(allocator: &Allocator) Self {
|
||||
return Self {
|
||||
return Self{
|
||||
.items = []align(A) T{},
|
||||
.len = 0,
|
||||
.allocator = allocator,
|
||||
@ -52,7 +52,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
/// allocated with `allocator`.
|
||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||
pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) Self {
|
||||
return Self {
|
||||
return Self{
|
||||
.items = slice,
|
||||
.len = slice.len,
|
||||
.allocator = allocator,
|
||||
@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
pub fn toOwnedSlice(self: &Self) []align(A) T {
|
||||
const allocator = self.allocator;
|
||||
const result = allocator.alignedShrink(T, A, self.items, self.len);
|
||||
*self = init(allocator);
|
||||
self.* = init(allocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -71,21 +71,21 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
try l.ensureCapacity(l.len + 1);
|
||||
l.len += 1;
|
||||
|
||||
mem.copy(T, l.items[n+1..l.len], l.items[n..l.len-1]);
|
||||
l.items[n] = *item;
|
||||
mem.copy(T, l.items[n + 1..l.len], l.items[n..l.len - 1]);
|
||||
l.items[n] = item.*;
|
||||
}
|
||||
|
||||
pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {
|
||||
try l.ensureCapacity(l.len + items.len);
|
||||
l.len += items.len;
|
||||
|
||||
mem.copy(T, l.items[n+items.len..l.len], l.items[n..l.len-items.len]);
|
||||
mem.copy(T, l.items[n..n+items.len], items);
|
||||
mem.copy(T, l.items[n + items.len..l.len], l.items[n..l.len - items.len]);
|
||||
mem.copy(T, l.items[n..n + items.len], items);
|
||||
}
|
||||
|
||||
pub fn append(l: &Self, item: &const T) !void {
|
||||
const new_item_ptr = try l.addOne();
|
||||
*new_item_ptr = *item;
|
||||
new_item_ptr.* = item.*;
|
||||
}
|
||||
|
||||
pub fn appendSlice(l: &Self, items: []align(A) const T) !void {
|
||||
@ -128,8 +128,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
}
|
||||
|
||||
pub fn popOrNull(self: &Self) ?T {
|
||||
if (self.len == 0)
|
||||
return null;
|
||||
if (self.len == 0) return null;
|
||||
return self.pop();
|
||||
}
|
||||
|
||||
@ -151,7 +150,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
|
||||
};
|
||||
|
||||
pub fn iterator(self: &const Self) Iterator {
|
||||
return Iterator { .list = self, .count = 0 };
|
||||
return Iterator{
|
||||
.list = self,
|
||||
.count = 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -160,13 +162,19 @@ test "basic ArrayList test" {
|
||||
var list = ArrayList(i32).init(debug.global_allocator);
|
||||
defer list.deinit();
|
||||
|
||||
{var i: usize = 0; while (i < 10) : (i += 1) {
|
||||
list.append(i32(i + 1)) catch unreachable;
|
||||
}}
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
list.append(i32(i + 1)) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
{var i: usize = 0; while (i < 10) : (i += 1) {
|
||||
assert(list.items[i] == i32(i + 1));
|
||||
}}
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
assert(list.items[i] == i32(i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
for (list.toSlice()) |v, i| {
|
||||
assert(v == i32(i + 1));
|
||||
@ -179,14 +187,18 @@ test "basic ArrayList test" {
|
||||
assert(list.pop() == 10);
|
||||
assert(list.len == 9);
|
||||
|
||||
list.appendSlice([]const i32 { 1, 2, 3 }) catch unreachable;
|
||||
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);
|
||||
|
||||
list.appendSlice([]const i32 {}) catch unreachable;
|
||||
list.appendSlice([]const i32{}) catch unreachable;
|
||||
assert(list.len == 9);
|
||||
}
|
||||
|
||||
@ -198,7 +210,7 @@ test "iterator ArrayList test" {
|
||||
try list.append(2);
|
||||
try list.append(3);
|
||||
|
||||
var count : i32 = 0;
|
||||
var count: i32 = 0;
|
||||
var it = list.iterator();
|
||||
while (it.next()) |next| {
|
||||
assert(next == count + 1);
|
||||
@ -216,7 +228,7 @@ test "iterator ArrayList test" {
|
||||
}
|
||||
|
||||
it.reset();
|
||||
assert(?? it.next() == 1);
|
||||
assert(??it.next() == 1);
|
||||
}
|
||||
|
||||
test "insert ArrayList test" {
|
||||
@ -228,12 +240,15 @@ test "insert ArrayList test" {
|
||||
assert(list.items[0] == 5);
|
||||
assert(list.items[1] == 1);
|
||||
|
||||
try list.insertSlice(1, []const i32 { 9, 8 });
|
||||
try list.insertSlice(1, []const i32{
|
||||
9,
|
||||
8,
|
||||
});
|
||||
assert(list.items[0] == 5);
|
||||
assert(list.items[1] == 9);
|
||||
assert(list.items[2] == 8);
|
||||
|
||||
const items = []const i32 { 1 };
|
||||
const items = []const i32{1};
|
||||
try list.insertSlice(0, items[0..0]);
|
||||
assert(list.items[0] == 5);
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ pub fn Queue(comptime T: type) type {
|
||||
data: T,
|
||||
};
|
||||
|
||||
// TODO: well defined copy elision: https://github.com/zig-lang/zig/issues/287
|
||||
// TODO: well defined copy elision: https://github.com/ziglang/zig/issues/287
|
||||
pub fn init(self: &Self) void {
|
||||
self.root.next = null;
|
||||
self.head = &self.root;
|
||||
@ -70,7 +70,7 @@ test "std.atomic.queue" {
|
||||
|
||||
var queue: Queue(i32) = undefined;
|
||||
queue.init();
|
||||
var context = Context {
|
||||
var context = Context{
|
||||
.allocator = a,
|
||||
.queue = &queue,
|
||||
.put_sum = 0,
|
||||
@ -81,16 +81,18 @@ test "std.atomic.queue" {
|
||||
|
||||
var putters: [put_thread_count]&std.os.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
*t = try std.os.spawnThread(&context, startPuts);
|
||||
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);
|
||||
t.* = try std.os.spawnThread(&context, startGets);
|
||||
}
|
||||
|
||||
for (putters) |t| t.wait();
|
||||
for (putters) |t|
|
||||
t.wait();
|
||||
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
|
||||
for (getters) |t| t.wait();
|
||||
for (getters) |t|
|
||||
t.wait();
|
||||
|
||||
std.debug.assert(context.put_sum == context.get_sum);
|
||||
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
|
||||
|
||||
@ -14,9 +14,7 @@ pub fn Stack(comptime T: type) type {
|
||||
};
|
||||
|
||||
pub fn init() Self {
|
||||
return Self {
|
||||
.root = null,
|
||||
};
|
||||
return Self{ .root = null };
|
||||
}
|
||||
|
||||
/// push operation, but only if you are the first item in the stack. if you did not succeed in
|
||||
@ -75,7 +73,7 @@ test "std.atomic.stack" {
|
||||
var a = &fixed_buffer_allocator.allocator;
|
||||
|
||||
var stack = Stack(i32).init();
|
||||
var context = Context {
|
||||
var context = Context{
|
||||
.allocator = a,
|
||||
.stack = &stack,
|
||||
.put_sum = 0,
|
||||
@ -86,16 +84,18 @@ test "std.atomic.stack" {
|
||||
|
||||
var putters: [put_thread_count]&std.os.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
*t = try std.os.spawnThread(&context, startPuts);
|
||||
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);
|
||||
t.* = try std.os.spawnThread(&context, startGets);
|
||||
}
|
||||
|
||||
for (putters) |t| t.wait();
|
||||
for (putters) |t|
|
||||
t.wait();
|
||||
_ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
|
||||
for (getters) |t| t.wait();
|
||||
for (getters) |t|
|
||||
t.wait();
|
||||
|
||||
std.debug.assert(context.put_sum == context.get_sum);
|
||||
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
|
||||
|
||||
118
std/base64.zig
118
std/base64.zig
@ -41,12 +41,10 @@ pub const Base64Encoder = struct {
|
||||
dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
|
||||
((source[i + 1] & 0xf0) >> 4)];
|
||||
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | ((source[i + 1] & 0xf0) >> 4)];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) |
|
||||
((source[i + 2] & 0xc0) >> 6)];
|
||||
dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) | ((source[i + 2] & 0xc0) >> 6)];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = encoder.alphabet_chars[source[i + 2] & 0x3f];
|
||||
@ -64,8 +62,7 @@ pub const Base64Encoder = struct {
|
||||
dest[out_index] = encoder.pad_char;
|
||||
out_index += 1;
|
||||
} else {
|
||||
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
|
||||
((source[i + 1] & 0xf0) >> 4)];
|
||||
dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | ((source[i + 1] & 0xf0) >> 4)];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2];
|
||||
@ -84,6 +81,7 @@ pub const Base64Decoder = struct {
|
||||
/// e.g. 'A' => 0.
|
||||
/// undefined for any value not in the 64 alphabet chars.
|
||||
char_to_index: [256]u8,
|
||||
|
||||
/// true only for the 64 chars in the alphabet, not the pad char.
|
||||
char_in_alphabet: [256]bool,
|
||||
pad_char: u8,
|
||||
@ -131,26 +129,20 @@ pub const Base64Decoder = struct {
|
||||
// common case
|
||||
if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
|
||||
if (!decoder.char_in_alphabet[source[src_cursor + 3]]) return error.InvalidCharacter;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
|
||||
decoder.char_to_index[source[src_cursor + 1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
|
||||
decoder.char_to_index[source[src_cursor + 2]] >> 2;
|
||||
dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 |
|
||||
decoder.char_to_index[source[src_cursor + 3]];
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | decoder.char_to_index[source[src_cursor + 2]] >> 2;
|
||||
dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 | decoder.char_to_index[source[src_cursor + 3]];
|
||||
dest_cursor += 3;
|
||||
} else if (source[src_cursor + 2] != decoder.pad_char) {
|
||||
// one pad char
|
||||
if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
|
||||
decoder.char_to_index[source[src_cursor + 1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
|
||||
decoder.char_to_index[source[src_cursor + 2]] >> 2;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | decoder.char_to_index[source[src_cursor + 2]] >> 2;
|
||||
if (decoder.char_to_index[source[src_cursor + 2]] << 6 != 0) return error.InvalidPadding;
|
||||
dest_cursor += 2;
|
||||
} else {
|
||||
// two pad chars
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
|
||||
decoder.char_to_index[source[src_cursor + 1]] >> 4;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | decoder.char_to_index[source[src_cursor + 1]] >> 4;
|
||||
if (decoder.char_to_index[source[src_cursor + 1]] << 4 != 0) return error.InvalidPadding;
|
||||
dest_cursor += 1;
|
||||
}
|
||||
@ -165,7 +157,7 @@ pub const Base64DecoderWithIgnore = struct {
|
||||
decoder: Base64Decoder,
|
||||
char_is_ignored: [256]bool,
|
||||
pub fn init(alphabet_chars: []const u8, pad_char: u8, ignore_chars: []const u8) Base64DecoderWithIgnore {
|
||||
var result = Base64DecoderWithIgnore {
|
||||
var result = Base64DecoderWithIgnore{
|
||||
.decoder = Base64Decoder.init(alphabet_chars, pad_char),
|
||||
.char_is_ignored = []bool{false} ** 256,
|
||||
};
|
||||
@ -223,10 +215,12 @@ pub const Base64DecoderWithIgnore = struct {
|
||||
} else if (decoder_with_ignore.char_is_ignored[c]) {
|
||||
// we can even ignore chars during the padding
|
||||
continue;
|
||||
} else return error.InvalidCharacter;
|
||||
} else
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
break;
|
||||
} else return error.InvalidCharacter;
|
||||
} else
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
|
||||
switch (available_chars) {
|
||||
@ -234,22 +228,17 @@ pub const Base64DecoderWithIgnore = struct {
|
||||
// common case
|
||||
if (dest_cursor + 3 > dest.len) return error.OutputTooSmall;
|
||||
assert(pad_char_count == 0);
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
|
||||
decoder.char_to_index[next_4_chars[1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
|
||||
decoder.char_to_index[next_4_chars[2]] >> 2;
|
||||
dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 |
|
||||
decoder.char_to_index[next_4_chars[3]];
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | decoder.char_to_index[next_4_chars[2]] >> 2;
|
||||
dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 | decoder.char_to_index[next_4_chars[3]];
|
||||
dest_cursor += 3;
|
||||
continue;
|
||||
},
|
||||
3 => {
|
||||
if (dest_cursor + 2 > dest.len) return error.OutputTooSmall;
|
||||
if (pad_char_count != 1) return error.InvalidPadding;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
|
||||
decoder.char_to_index[next_4_chars[1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
|
||||
decoder.char_to_index[next_4_chars[2]] >> 2;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
|
||||
dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | decoder.char_to_index[next_4_chars[2]] >> 2;
|
||||
if (decoder.char_to_index[next_4_chars[2]] << 6 != 0) return error.InvalidPadding;
|
||||
dest_cursor += 2;
|
||||
break;
|
||||
@ -257,8 +246,7 @@ pub const Base64DecoderWithIgnore = struct {
|
||||
2 => {
|
||||
if (dest_cursor + 1 > dest.len) return error.OutputTooSmall;
|
||||
if (pad_char_count != 2) return error.InvalidPadding;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
|
||||
decoder.char_to_index[next_4_chars[1]] >> 4;
|
||||
dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | decoder.char_to_index[next_4_chars[1]] >> 4;
|
||||
if (decoder.char_to_index[next_4_chars[1]] << 4 != 0) return error.InvalidPadding;
|
||||
dest_cursor += 1;
|
||||
break;
|
||||
@ -280,7 +268,6 @@ pub const Base64DecoderWithIgnore = struct {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
pub const standard_decoder_unsafe = Base64DecoderUnsafe.init(standard_alphabet_chars, standard_pad_char);
|
||||
|
||||
pub const Base64DecoderUnsafe = struct {
|
||||
@ -291,7 +278,7 @@ pub const Base64DecoderUnsafe = struct {
|
||||
|
||||
pub fn init(alphabet_chars: []const u8, pad_char: u8) Base64DecoderUnsafe {
|
||||
assert(alphabet_chars.len == 64);
|
||||
var result = Base64DecoderUnsafe {
|
||||
var result = Base64DecoderUnsafe{
|
||||
.char_to_index = undefined,
|
||||
.pad_char = pad_char,
|
||||
};
|
||||
@ -321,16 +308,13 @@ pub const Base64DecoderUnsafe = struct {
|
||||
}
|
||||
|
||||
while (in_buf_len > 4) {
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
|
||||
decoder.char_to_index[source[src_index + 1]] >> 4;
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | decoder.char_to_index[source[src_index + 1]] >> 4;
|
||||
dest_index += 1;
|
||||
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
|
||||
decoder.char_to_index[source[src_index + 2]] >> 2;
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | decoder.char_to_index[source[src_index + 2]] >> 2;
|
||||
dest_index += 1;
|
||||
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
|
||||
decoder.char_to_index[source[src_index + 3]];
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | decoder.char_to_index[source[src_index + 3]];
|
||||
dest_index += 1;
|
||||
|
||||
src_index += 4;
|
||||
@ -338,18 +322,15 @@ pub const Base64DecoderUnsafe = struct {
|
||||
}
|
||||
|
||||
if (in_buf_len > 1) {
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
|
||||
decoder.char_to_index[source[src_index + 1]] >> 4;
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | decoder.char_to_index[source[src_index + 1]] >> 4;
|
||||
dest_index += 1;
|
||||
}
|
||||
if (in_buf_len > 2) {
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
|
||||
decoder.char_to_index[source[src_index + 2]] >> 2;
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | decoder.char_to_index[source[src_index + 2]] >> 2;
|
||||
dest_index += 1;
|
||||
}
|
||||
if (in_buf_len > 3) {
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
|
||||
decoder.char_to_index[source[src_index + 3]];
|
||||
dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | decoder.char_to_index[source[src_index + 3]];
|
||||
dest_index += 1;
|
||||
}
|
||||
}
|
||||
@ -367,7 +348,6 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
test "base64" {
|
||||
@setEvalBranchQuota(8000);
|
||||
testBase64() catch unreachable;
|
||||
@ -375,26 +355,26 @@ test "base64" {
|
||||
}
|
||||
|
||||
fn testBase64() !void {
|
||||
try testAllApis("", "");
|
||||
try testAllApis("f", "Zg==");
|
||||
try testAllApis("fo", "Zm8=");
|
||||
try testAllApis("foo", "Zm9v");
|
||||
try testAllApis("foob", "Zm9vYg==");
|
||||
try testAllApis("fooba", "Zm9vYmE=");
|
||||
try testAllApis("", "");
|
||||
try testAllApis("f", "Zg==");
|
||||
try testAllApis("fo", "Zm8=");
|
||||
try testAllApis("foo", "Zm9v");
|
||||
try testAllApis("foob", "Zm9vYg==");
|
||||
try testAllApis("fooba", "Zm9vYmE=");
|
||||
try testAllApis("foobar", "Zm9vYmFy");
|
||||
|
||||
try testDecodeIgnoreSpace("", " ");
|
||||
try testDecodeIgnoreSpace("f", "Z g= =");
|
||||
try testDecodeIgnoreSpace("fo", " Zm8=");
|
||||
try testDecodeIgnoreSpace("foo", "Zm9v ");
|
||||
try testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
|
||||
try testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
|
||||
try testDecodeIgnoreSpace("", " ");
|
||||
try testDecodeIgnoreSpace("f", "Z g= =");
|
||||
try testDecodeIgnoreSpace("fo", " Zm8=");
|
||||
try testDecodeIgnoreSpace("foo", "Zm9v ");
|
||||
try testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
|
||||
try testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
|
||||
try testDecodeIgnoreSpace("foobar", " Z m 9 v Y m F y ");
|
||||
|
||||
// test getting some api errors
|
||||
try testError("A", error.InvalidPadding);
|
||||
try testError("AA", error.InvalidPadding);
|
||||
try testError("AAA", error.InvalidPadding);
|
||||
try testError("A", error.InvalidPadding);
|
||||
try testError("AA", error.InvalidPadding);
|
||||
try testError("AAA", error.InvalidPadding);
|
||||
try testError("A..A", error.InvalidCharacter);
|
||||
try testError("AA=A", error.InvalidCharacter);
|
||||
try testError("AA/=", error.InvalidPadding);
|
||||
@ -427,8 +407,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
|
||||
|
||||
// Base64DecoderWithIgnore
|
||||
{
|
||||
const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
|
||||
standard_alphabet_chars, standard_pad_char, "");
|
||||
const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, "");
|
||||
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);
|
||||
@ -446,8 +425,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void
|
||||
}
|
||||
|
||||
fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !void {
|
||||
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
|
||||
standard_alphabet_chars, standard_pad_char, " ");
|
||||
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
|
||||
var buffer: [0x100]u8 = undefined;
|
||||
var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
|
||||
var written = try standard_decoder_ignore_space.decode(decoded, encoded);
|
||||
@ -455,8 +433,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi
|
||||
}
|
||||
|
||||
fn testError(encoded: []const u8, expected_err: error) !void {
|
||||
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
|
||||
standard_alphabet_chars, standard_pad_char, " ");
|
||||
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
|
||||
var buffer: [0x100]u8 = undefined;
|
||||
if (standard_decoder.calcSize(encoded)) |decoded_size| {
|
||||
var decoded = buffer[0..decoded_size];
|
||||
@ -471,8 +448,7 @@ fn testError(encoded: []const u8, expected_err: error) !void {
|
||||
}
|
||||
|
||||
fn testOutputTooSmallError(encoded: []const u8) !void {
|
||||
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
|
||||
standard_alphabet_chars, standard_pad_char, " ");
|
||||
const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(standard_alphabet_chars, standard_pad_char, " ");
|
||||
var buffer: [0x100]u8 = undefined;
|
||||
var decoded = buffer[0..calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1];
|
||||
if (standard_decoder_ignore_space.decode(decoded, encoded)) |_| {
|
||||
|
||||
@ -12,9 +12,7 @@ pub const BufMap = struct {
|
||||
const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
|
||||
pub fn init(allocator: &Allocator) BufMap {
|
||||
var self = BufMap {
|
||||
.hash_map = BufMapHashMap.init(allocator),
|
||||
};
|
||||
var self = BufMap{ .hash_map = BufMapHashMap.init(allocator) };
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,7 @@ pub const BufSet = struct {
|
||||
const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
|
||||
pub fn init(a: &Allocator) BufSet {
|
||||
var self = BufSet {
|
||||
.hash_map = BufSetHashMap.init(a),
|
||||
};
|
||||
var self = BufSet{ .hash_map = BufSetHashMap.init(a) };
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@ -31,9 +31,7 @@ pub const Buffer = struct {
|
||||
/// * ::replaceContentsBuffer
|
||||
/// * ::resize
|
||||
pub fn initNull(allocator: &Allocator) Buffer {
|
||||
return Buffer {
|
||||
.list = ArrayList(u8).init(allocator),
|
||||
};
|
||||
return Buffer{ .list = ArrayList(u8).init(allocator) };
|
||||
}
|
||||
|
||||
/// Must deinitialize with deinit.
|
||||
@ -45,9 +43,7 @@ pub const Buffer = struct {
|
||||
/// allocated with `allocator`.
|
||||
/// Must deinitialize with deinit.
|
||||
pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) Buffer {
|
||||
var self = Buffer {
|
||||
.list = ArrayList(u8).fromOwnedSlice(allocator, slice),
|
||||
};
|
||||
var self = Buffer{ .list = ArrayList(u8).fromOwnedSlice(allocator, slice) };
|
||||
self.list.append(0);
|
||||
return self;
|
||||
}
|
||||
@ -57,11 +53,10 @@ pub const Buffer = struct {
|
||||
pub fn toOwnedSlice(self: &Buffer) []u8 {
|
||||
const allocator = self.list.allocator;
|
||||
const result = allocator.shrink(u8, self.list.items, self.len());
|
||||
*self = initNull(allocator);
|
||||
self.* = initNull(allocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
pub fn deinit(self: &Buffer) void {
|
||||
self.list.deinit();
|
||||
}
|
||||
|
||||
208
std/build.zig
208
std/build.zig
@ -82,10 +82,8 @@ pub const Builder = struct {
|
||||
description: []const u8,
|
||||
};
|
||||
|
||||
pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8,
|
||||
cache_root: []const u8) Builder
|
||||
{
|
||||
var self = Builder {
|
||||
pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
|
||||
var self = Builder{
|
||||
.zig_exe = zig_exe,
|
||||
.build_root = build_root,
|
||||
.cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,
|
||||
@ -112,12 +110,12 @@ pub const Builder = struct {
|
||||
.lib_dir = undefined,
|
||||
.exe_dir = undefined,
|
||||
.installed_files = ArrayList([]const u8).init(allocator),
|
||||
.uninstall_tls = TopLevelStep {
|
||||
.uninstall_tls = TopLevelStep{
|
||||
.step = Step.init("uninstall", allocator, makeUninstall),
|
||||
.description = "Remove build artifacts from prefix path",
|
||||
},
|
||||
.have_uninstall_step = false,
|
||||
.install_tls = TopLevelStep {
|
||||
.install_tls = TopLevelStep{
|
||||
.step = Step.initNoOp("install", allocator),
|
||||
.description = "Copy build artifacts to prefix path",
|
||||
},
|
||||
@ -151,9 +149,7 @@ pub const Builder = struct {
|
||||
return LibExeObjStep.createObject(self, name, root_src);
|
||||
}
|
||||
|
||||
pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8,
|
||||
ver: &const Version) &LibExeObjStep
|
||||
{
|
||||
pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
|
||||
return LibExeObjStep.createSharedLibrary(self, name, root_src, ver);
|
||||
}
|
||||
|
||||
@ -163,7 +159,7 @@ pub const Builder = struct {
|
||||
|
||||
pub fn addTest(self: &Builder, root_src: []const u8) &TestStep {
|
||||
const test_step = self.allocator.create(TestStep) catch unreachable;
|
||||
*test_step = TestStep.init(self, root_src);
|
||||
test_step.* = TestStep.init(self, root_src);
|
||||
return test_step;
|
||||
}
|
||||
|
||||
@ -190,33 +186,31 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
/// ::argv is copied.
|
||||
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
|
||||
argv: []const []const u8) &CommandStep
|
||||
{
|
||||
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
|
||||
return CommandStep.create(self, cwd, env_map, argv);
|
||||
}
|
||||
|
||||
pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) &WriteFileStep {
|
||||
const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
|
||||
*write_file_step = WriteFileStep.init(self, file_path, data);
|
||||
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) catch unreachable;
|
||||
*log_step = LogStep.init(self, data);
|
||||
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) catch unreachable;
|
||||
*remove_dir_step = RemoveDirStep.init(self, dir_path);
|
||||
remove_dir_step.* = RemoveDirStep.init(self, dir_path);
|
||||
return remove_dir_step;
|
||||
}
|
||||
|
||||
pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) Version {
|
||||
return Version {
|
||||
return Version{
|
||||
.major = major,
|
||||
.minor = minor,
|
||||
.patch = patch,
|
||||
@ -254,8 +248,7 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn getInstallStep(self: &Builder) &Step {
|
||||
if (self.have_install_step)
|
||||
return &self.install_tls.step;
|
||||
if (self.have_install_step) return &self.install_tls.step;
|
||||
|
||||
self.top_level_steps.append(&self.install_tls) catch unreachable;
|
||||
self.have_install_step = true;
|
||||
@ -263,8 +256,7 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn getUninstallStep(self: &Builder) &Step {
|
||||
if (self.have_uninstall_step)
|
||||
return &self.uninstall_tls.step;
|
||||
if (self.have_uninstall_step) return &self.uninstall_tls.step;
|
||||
|
||||
self.top_level_steps.append(&self.uninstall_tls) catch unreachable;
|
||||
self.have_uninstall_step = true;
|
||||
@ -360,7 +352,7 @@ pub const Builder = struct {
|
||||
|
||||
pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
|
||||
const type_id = comptime typeToEnum(T);
|
||||
const available_option = AvailableOption {
|
||||
const available_option = AvailableOption{
|
||||
.name = name,
|
||||
.type_id = type_id,
|
||||
.description = description,
|
||||
@ -413,7 +405,7 @@ pub const Builder = struct {
|
||||
|
||||
pub fn step(self: &Builder, name: []const u8, description: []const u8) &Step {
|
||||
const step_info = self.allocator.create(TopLevelStep) catch unreachable;
|
||||
*step_info = TopLevelStep {
|
||||
step_info.* = TopLevelStep{
|
||||
.step = Step.initNoOp(name, self.allocator),
|
||||
.description = description,
|
||||
};
|
||||
@ -428,15 +420,7 @@ pub const Builder = struct {
|
||||
const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
|
||||
const release_small = self.option(bool, "release-small", "size optimizations on and safety off") ?? false;
|
||||
|
||||
const mode = if (release_safe and !release_fast and !release_small)
|
||||
builtin.Mode.ReleaseSafe
|
||||
else if (release_fast and !release_safe and !release_small)
|
||||
builtin.Mode.ReleaseFast
|
||||
else if (release_small and !release_fast and !release_safe)
|
||||
builtin.Mode.ReleaseSmall
|
||||
else if (!release_fast and !release_safe and !release_small)
|
||||
builtin.Mode.Debug
|
||||
else x: {
|
||||
const mode = if (release_safe and !release_fast and !release_small) builtin.Mode.ReleaseSafe else if (release_fast and !release_safe and !release_small) builtin.Mode.ReleaseFast else if (release_small and !release_fast and !release_safe) builtin.Mode.ReleaseSmall else if (!release_fast and !release_safe and !release_small) builtin.Mode.Debug else x: {
|
||||
warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)");
|
||||
self.markInvalidUserInput();
|
||||
break :x builtin.Mode.Debug;
|
||||
@ -446,9 +430,9 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) bool {
|
||||
if (self.user_input_options.put(name, UserInputOption {
|
||||
if (self.user_input_options.put(name, UserInputOption{
|
||||
.name = name,
|
||||
.value = UserValue { .Scalar = value },
|
||||
.value = UserValue{ .Scalar = value },
|
||||
.used = false,
|
||||
}) catch unreachable) |*prev_value| {
|
||||
// option already exists
|
||||
@ -458,18 +442,18 @@ pub const Builder = struct {
|
||||
var list = ArrayList([]const u8).init(self.allocator);
|
||||
list.append(s) catch unreachable;
|
||||
list.append(value) catch unreachable;
|
||||
_ = self.user_input_options.put(name, UserInputOption {
|
||||
_ = self.user_input_options.put(name, UserInputOption{
|
||||
.name = name,
|
||||
.value = UserValue { .List = list },
|
||||
.value = UserValue{ .List = list },
|
||||
.used = false,
|
||||
}) catch unreachable;
|
||||
},
|
||||
UserValue.List => |*list| {
|
||||
// append to the list
|
||||
list.append(value) catch unreachable;
|
||||
_ = self.user_input_options.put(name, UserInputOption {
|
||||
_ = self.user_input_options.put(name, UserInputOption{
|
||||
.name = name,
|
||||
.value = UserValue { .List = *list },
|
||||
.value = UserValue{ .List = list.* },
|
||||
.used = false,
|
||||
}) catch unreachable;
|
||||
},
|
||||
@ -483,9 +467,9 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn addUserInputFlag(self: &Builder, name: []const u8) bool {
|
||||
if (self.user_input_options.put(name, UserInputOption {
|
||||
if (self.user_input_options.put(name, UserInputOption{
|
||||
.name = name,
|
||||
.value = UserValue {.Flag = {} },
|
||||
.value = UserValue{ .Flag = {} },
|
||||
.used = false,
|
||||
}) catch unreachable) |*prev_value| {
|
||||
switch (prev_value.value) {
|
||||
@ -556,9 +540,7 @@ pub const Builder = struct {
|
||||
warn("\n");
|
||||
}
|
||||
|
||||
fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
|
||||
argv: []const []const u8) !void
|
||||
{
|
||||
fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) !void {
|
||||
if (self.verbose) {
|
||||
printCmd(cwd, argv);
|
||||
}
|
||||
@ -617,7 +599,7 @@ pub const Builder = struct {
|
||||
self.pushInstalledFile(full_dest_path);
|
||||
|
||||
const install_step = self.allocator.create(InstallFileStep) catch unreachable;
|
||||
*install_step = InstallFileStep.init(self, src_path, full_dest_path);
|
||||
install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
|
||||
return install_step;
|
||||
}
|
||||
|
||||
@ -659,25 +641,19 @@ pub const Builder = struct {
|
||||
if (builtin.environ == builtin.Environ.msvc) {
|
||||
return "cl.exe";
|
||||
} else {
|
||||
return os.getEnvVarOwned(self.allocator, "CC") catch |err|
|
||||
if (err == error.EnvironmentVariableNotFound)
|
||||
([]const u8)("cc")
|
||||
else
|
||||
debug.panic("Unable to get environment variable: {}", err)
|
||||
;
|
||||
return os.getEnvVarOwned(self.allocator, "CC") catch |err| if (err == error.EnvironmentVariableNotFound) ([]const u8)("cc") else debug.panic("Unable to get environment variable: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
|
||||
// TODO report error for ambiguous situations
|
||||
const exe_extension = (Target { .Native = {}}).exeFileExt();
|
||||
const exe_extension = (Target{ .Native = {} }).exeFileExt();
|
||||
for (self.search_prefixes.toSliceConst()) |search_prefix| {
|
||||
for (names) |name| {
|
||||
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, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
|
||||
if (os.path.real(self.allocator, full_path)) |real_path| {
|
||||
return real_path;
|
||||
} else |_| {
|
||||
@ -761,7 +737,7 @@ pub const Target = union(enum) {
|
||||
Cross: CrossTarget,
|
||||
|
||||
pub fn oFileExt(self: &const Target) []const u8 {
|
||||
const environ = switch (*self) {
|
||||
const environ = switch (self.*) {
|
||||
Target.Native => builtin.environ,
|
||||
Target.Cross => |t| t.environ,
|
||||
};
|
||||
@ -786,7 +762,7 @@ pub const Target = union(enum) {
|
||||
}
|
||||
|
||||
pub fn getOs(self: &const Target) builtin.Os {
|
||||
return switch (*self) {
|
||||
return switch (self.*) {
|
||||
Target.Native => builtin.os,
|
||||
Target.Cross => |t| t.os,
|
||||
};
|
||||
@ -860,61 +836,57 @@ pub const LibExeObjStep = struct {
|
||||
Obj,
|
||||
};
|
||||
|
||||
pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8,
|
||||
ver: &const Version) &LibExeObjStep
|
||||
{
|
||||
pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
*self = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
|
||||
self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createCSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) &LibExeObjStep {
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
*self = initC(builder, name, Kind.Lib, version, false);
|
||||
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(LibExeObjStep) catch unreachable;
|
||||
*self = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
|
||||
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(LibExeObjStep) catch unreachable;
|
||||
*self = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
|
||||
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(LibExeObjStep) catch unreachable;
|
||||
*self = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
|
||||
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(LibExeObjStep) catch unreachable;
|
||||
*self = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
|
||||
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) &LibExeObjStep {
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
*self = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
|
||||
self.* = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createCExecutable(builder: &Builder, name: []const u8) &LibExeObjStep {
|
||||
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
|
||||
*self = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
|
||||
self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
|
||||
return self;
|
||||
}
|
||||
|
||||
fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind,
|
||||
static: bool, ver: &const Version) LibExeObjStep
|
||||
{
|
||||
var self = LibExeObjStep {
|
||||
fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, static: bool, ver: &const Version) LibExeObjStep {
|
||||
var self = LibExeObjStep{
|
||||
.strip = false,
|
||||
.builder = builder,
|
||||
.verbose_link = false,
|
||||
@ -930,7 +902,7 @@ pub const LibExeObjStep = struct {
|
||||
.step = Step.init(name, builder.allocator, make),
|
||||
.output_path = null,
|
||||
.output_h_path = null,
|
||||
.version = *ver,
|
||||
.version = ver.*,
|
||||
.out_filename = undefined,
|
||||
.out_h_filename = builder.fmt("{}.h", name),
|
||||
.major_only_filename = undefined,
|
||||
@ -953,11 +925,11 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
|
||||
fn initC(builder: &Builder, name: []const u8, kind: Kind, version: &const Version, static: bool) LibExeObjStep {
|
||||
var self = LibExeObjStep {
|
||||
var self = LibExeObjStep{
|
||||
.builder = builder,
|
||||
.name = name,
|
||||
.kind = kind,
|
||||
.version = *version,
|
||||
.version = version.*,
|
||||
.static = static,
|
||||
.target = Target.Native,
|
||||
.cflags = ArrayList([]const u8).init(builder.allocator),
|
||||
@ -1006,8 +978,7 @@ pub const LibExeObjStep = struct {
|
||||
} else {
|
||||
switch (self.target.getOs()) {
|
||||
builtin.Os.ios, builtin.Os.macosx => {
|
||||
self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib",
|
||||
self.name, self.version.major, self.version.minor, self.version.patch);
|
||||
self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
|
||||
self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
|
||||
self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
|
||||
},
|
||||
@ -1015,8 +986,7 @@ pub const LibExeObjStep = struct {
|
||||
self.out_filename = self.builder.fmt("{}.dll", self.name);
|
||||
},
|
||||
else => {
|
||||
self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
|
||||
self.name, self.version.major, self.version.minor, self.version.patch);
|
||||
self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
|
||||
self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
|
||||
self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
|
||||
},
|
||||
@ -1026,15 +996,13 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
|
||||
target_environ: builtin.Environ) void
|
||||
{
|
||||
self.target = Target {
|
||||
.Cross = CrossTarget {
|
||||
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
|
||||
self.target = Target{
|
||||
.Cross = CrossTarget{
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.environ = target_environ,
|
||||
}
|
||||
},
|
||||
};
|
||||
self.computeOutFileNames();
|
||||
}
|
||||
@ -1099,10 +1067,7 @@ 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, self.builder.cache_root, self.out_filename) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) void {
|
||||
@ -1115,10 +1080,7 @@ 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, self.builder.cache_root, self.out_h_filename) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) void {
|
||||
@ -1159,7 +1121,7 @@ pub const LibExeObjStep = struct {
|
||||
pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
|
||||
assert(self.is_zig);
|
||||
|
||||
self.packages.append(Pkg {
|
||||
self.packages.append(Pkg{
|
||||
.name = name,
|
||||
.path = pkg_index_path,
|
||||
}) catch unreachable;
|
||||
@ -1343,8 +1305,7 @@ pub const LibExeObjStep = struct {
|
||||
try builder.spawnChild(zig_args.toSliceConst());
|
||||
|
||||
if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
|
||||
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
|
||||
self.name_only_filename);
|
||||
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1505,8 +1466,7 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
|
||||
if (!is_darwin) {
|
||||
const rpath_arg = builder.fmt("-Wl,-rpath,{}",
|
||||
os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
|
||||
const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
|
||||
defer builder.allocator.free(rpath_arg);
|
||||
cc_args.append(rpath_arg) catch unreachable;
|
||||
|
||||
@ -1535,8 +1495,7 @@ pub const LibExeObjStep = struct {
|
||||
try builder.spawnChild(cc_args.toSliceConst());
|
||||
|
||||
if (self.target.wantSharedLibSymLinks()) {
|
||||
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
|
||||
self.name_only_filename);
|
||||
try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1581,8 +1540,7 @@ pub const LibExeObjStep = struct {
|
||||
cc_args.append("-o") catch unreachable;
|
||||
cc_args.append(output_path) catch unreachable;
|
||||
|
||||
const rpath_arg = builder.fmt("-Wl,-rpath,{}",
|
||||
os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
|
||||
const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
|
||||
defer builder.allocator.free(rpath_arg);
|
||||
cc_args.append(rpath_arg) catch unreachable;
|
||||
|
||||
@ -1635,7 +1593,7 @@ pub const TestStep = struct {
|
||||
|
||||
pub fn init(builder: &Builder, root_src: []const u8) TestStep {
|
||||
const step_name = builder.fmt("test {}", root_src);
|
||||
return TestStep {
|
||||
return TestStep{
|
||||
.step = Step.init(step_name, builder.allocator, make),
|
||||
.builder = builder,
|
||||
.root_src = root_src,
|
||||
@ -1644,7 +1602,7 @@ pub const TestStep = struct {
|
||||
.name_prefix = "",
|
||||
.filter = null,
|
||||
.link_libs = BufSet.init(builder.allocator),
|
||||
.target = Target { .Native = {} },
|
||||
.target = Target{ .Native = {} },
|
||||
.exec_cmd_args = null,
|
||||
.include_dirs = ArrayList([]const u8).init(builder.allocator),
|
||||
};
|
||||
@ -1674,15 +1632,13 @@ pub const TestStep = struct {
|
||||
self.filter = text;
|
||||
}
|
||||
|
||||
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,
|
||||
target_environ: builtin.Environ) void
|
||||
{
|
||||
self.target = Target {
|
||||
.Cross = CrossTarget {
|
||||
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
|
||||
self.target = Target{
|
||||
.Cross = CrossTarget{
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.environ = target_environ,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -1789,11 +1745,9 @@ pub const CommandStep = struct {
|
||||
env_map: &const BufMap,
|
||||
|
||||
/// ::argv is copied.
|
||||
pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
|
||||
argv: []const []const u8) &CommandStep
|
||||
{
|
||||
pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
|
||||
const self = builder.allocator.create(CommandStep) catch unreachable;
|
||||
*self = CommandStep {
|
||||
self.* = CommandStep{
|
||||
.builder = builder,
|
||||
.step = Step.init(argv[0], builder.allocator, make),
|
||||
.argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
|
||||
@ -1828,7 +1782,7 @@ const InstallArtifactStep = struct {
|
||||
LibExeObjStep.Kind.Exe => builder.exe_dir,
|
||||
LibExeObjStep.Kind.Lib => builder.lib_dir,
|
||||
};
|
||||
*self = Self {
|
||||
self.* = Self{
|
||||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
|
||||
.artifact = artifact,
|
||||
@ -1837,10 +1791,8 @@ const InstallArtifactStep = struct {
|
||||
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, 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);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -1859,8 +1811,7 @@ const InstallArtifactStep = struct {
|
||||
};
|
||||
try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
|
||||
if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
|
||||
try doAtomicSymLinks(builder.allocator, self.dest_file,
|
||||
self.artifact.major_only_filename, self.artifact.name_only_filename);
|
||||
try doAtomicSymLinks(builder.allocator, self.dest_file, self.artifact.major_only_filename, self.artifact.name_only_filename);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1872,7 +1823,7 @@ pub const InstallFileStep = struct {
|
||||
dest_path: []const u8,
|
||||
|
||||
pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) InstallFileStep {
|
||||
return InstallFileStep {
|
||||
return InstallFileStep{
|
||||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),
|
||||
.src_path = src_path,
|
||||
@ -1893,7 +1844,7 @@ pub const WriteFileStep = struct {
|
||||
data: []const u8,
|
||||
|
||||
pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) WriteFileStep {
|
||||
return WriteFileStep {
|
||||
return WriteFileStep{
|
||||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make),
|
||||
.file_path = file_path,
|
||||
@ -1922,7 +1873,7 @@ pub const LogStep = struct {
|
||||
data: []const u8,
|
||||
|
||||
pub fn init(builder: &Builder, data: []const u8) LogStep {
|
||||
return LogStep {
|
||||
return LogStep{
|
||||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("log {}", data), builder.allocator, make),
|
||||
.data = data,
|
||||
@ -1941,7 +1892,7 @@ pub const RemoveDirStep = struct {
|
||||
dir_path: []const u8,
|
||||
|
||||
pub fn init(builder: &Builder, dir_path: []const u8) RemoveDirStep {
|
||||
return RemoveDirStep {
|
||||
return RemoveDirStep{
|
||||
.builder = builder,
|
||||
.step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make),
|
||||
.dir_path = dir_path,
|
||||
@ -1966,8 +1917,8 @@ pub const Step = struct {
|
||||
loop_flag: bool,
|
||||
done_flag: bool,
|
||||
|
||||
pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step {
|
||||
return Step {
|
||||
pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn(&Step) error!void) Step {
|
||||
return Step{
|
||||
.name = name,
|
||||
.makeFn = makeFn,
|
||||
.dependencies = ArrayList(&Step).init(allocator),
|
||||
@ -1980,8 +1931,7 @@ pub const Step = struct {
|
||||
}
|
||||
|
||||
pub fn make(self: &Step) !void {
|
||||
if (self.done_flag)
|
||||
return;
|
||||
if (self.done_flag) return;
|
||||
|
||||
try self.makeFn(self);
|
||||
self.done_flag = true;
|
||||
@ -1994,9 +1944,7 @@ pub const Step = struct {
|
||||
fn makeNoOp(self: &Step) error!void {}
|
||||
};
|
||||
|
||||
fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,
|
||||
filename_name_only: []const u8) !void
|
||||
{
|
||||
fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
|
||||
const out_dir = os.path.dirname(output_path);
|
||||
const out_basename = os.path.basename(output_path);
|
||||
// sym link for libfoo.so.1 to libfoo.so.1.2.3
|
||||
|
||||
@ -60,7 +60,7 @@ pub const sigset_t = u32;
|
||||
|
||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
|
||||
pub const Sigaction = extern struct {
|
||||
handler: extern fn(c_int)void,
|
||||
handler: extern fn(c_int) void,
|
||||
sa_mask: sigset_t,
|
||||
sa_flags: c_int,
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
const builtin = @import("builtin");
|
||||
const Os = builtin.Os;
|
||||
|
||||
pub use switch(builtin.os) {
|
||||
pub use switch (builtin.os) {
|
||||
Os.linux => @import("linux.zig"),
|
||||
Os.windows => @import("windows.zig"),
|
||||
Os.macosx, Os.ios => @import("darwin.zig"),
|
||||
@ -21,8 +21,7 @@ pub extern "c" fn raise(sig: c_int) c_int;
|
||||
pub extern "c" fn read(fd: c_int, buf: &c_void, nbyte: usize) isize;
|
||||
pub extern "c" fn stat(noalias path: &const u8, noalias buf: &Stat) c_int;
|
||||
pub extern "c" fn write(fd: c_int, buf: &const c_void, nbyte: usize) isize;
|
||||
pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int,
|
||||
fd: c_int, offset: isize) ?&c_void;
|
||||
pub extern "c" fn mmap(addr: ?&c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?&c_void;
|
||||
pub extern "c" fn munmap(addr: &c_void, len: usize) c_int;
|
||||
pub extern "c" fn unlink(path: &const u8) c_int;
|
||||
pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;
|
||||
@ -34,8 +33,7 @@ pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;
|
||||
pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int;
|
||||
pub extern "c" fn rename(old: &const u8, new: &const u8) c_int;
|
||||
pub extern "c" fn chdir(path: &const u8) c_int;
|
||||
pub extern "c" fn execve(path: &const u8, argv: &const ?&const u8,
|
||||
envp: &const ?&const u8) c_int;
|
||||
pub extern "c" fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) c_int;
|
||||
pub extern "c" fn dup(fd: c_int) c_int;
|
||||
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;
|
||||
@ -54,9 +52,7 @@ pub extern "c" fn realloc(&c_void, usize) ?&c_void;
|
||||
pub extern "c" fn free(&c_void) void;
|
||||
pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) c_int;
|
||||
|
||||
pub extern "pthread" fn pthread_create(noalias newthread: &pthread_t,
|
||||
noalias attr: ?&const pthread_attr_t, start_routine: extern fn(?&c_void) ?&c_void,
|
||||
noalias arg: ?&c_void) c_int;
|
||||
pub extern "pthread" fn pthread_create(noalias newthread: &pthread_t, noalias attr: ?&const pthread_attr_t, start_routine: extern fn(?&c_void) ?&c_void, noalias arg: ?&c_void) c_int;
|
||||
pub extern "pthread" fn pthread_attr_init(attr: &pthread_attr_t) c_int;
|
||||
pub extern "pthread" fn pthread_attr_setstack(attr: &pthread_attr_t, stackaddr: &c_void, stacksize: usize) c_int;
|
||||
pub extern "pthread" fn pthread_attr_destroy(attr: &pthread_attr_t) c_int;
|
||||
|
||||
@ -6,11 +6,23 @@ const builtin = @import("builtin");
|
||||
const htest = @import("test.zig");
|
||||
|
||||
const RoundParam = struct {
|
||||
a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
x: usize,
|
||||
y: usize,
|
||||
};
|
||||
|
||||
fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
|
||||
return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
|
||||
return RoundParam{
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c,
|
||||
.d = d,
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
@ -19,145 +31,153 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
|
||||
pub const Blake2s224 = Blake2s(224);
|
||||
pub const Blake2s256 = Blake2s(256);
|
||||
|
||||
fn Blake2s(comptime out_len: usize) type { return struct {
|
||||
const Self = this;
|
||||
const block_size = 64;
|
||||
const digest_size = out_len / 8;
|
||||
fn Blake2s(comptime out_len: usize) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const block_size = 64;
|
||||
const digest_size = out_len / 8;
|
||||
|
||||
const iv = [8]u32 {
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
|
||||
};
|
||||
const iv = [8]u32{
|
||||
0x6A09E667,
|
||||
0xBB67AE85,
|
||||
0x3C6EF372,
|
||||
0xA54FF53A,
|
||||
0x510E527F,
|
||||
0x9B05688C,
|
||||
0x1F83D9AB,
|
||||
0x5BE0CD19,
|
||||
};
|
||||
|
||||
const sigma = [10][16]u8 {
|
||||
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
[]const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||
[]const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||
[]const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||
[]const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||
[]const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||
[]const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||
[]const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||
[]const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
|
||||
};
|
||||
const sigma = [10][16]u8{
|
||||
[]const u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
[]const u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
[]const u8{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||
[]const u8{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||
[]const u8{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||
[]const u8{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||
[]const u8{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||
[]const u8{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||
[]const u8{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||
[]const u8{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
|
||||
};
|
||||
|
||||
h: [8]u32,
|
||||
t: u64,
|
||||
// Streaming cache
|
||||
buf: [64]u8,
|
||||
buf_len: u8,
|
||||
h: [8]u32,
|
||||
t: u64,
|
||||
// Streaming cache
|
||||
buf: [64]u8,
|
||||
buf_len: u8,
|
||||
|
||||
pub fn init() Self {
|
||||
debug.assert(8 <= out_len and out_len <= 512);
|
||||
pub fn init() Self {
|
||||
debug.assert(8 <= out_len and out_len <= 512);
|
||||
|
||||
var s: Self = undefined;
|
||||
s.reset();
|
||||
return s;
|
||||
}
|
||||
var s: Self = undefined;
|
||||
s.reset();
|
||||
return s;
|
||||
}
|
||||
|
||||
pub fn reset(d: &Self) void {
|
||||
mem.copy(u32, d.h[0..], iv[0..]);
|
||||
pub fn reset(d: &Self) void {
|
||||
mem.copy(u32, d.h[0..], iv[0..]);
|
||||
|
||||
// No key plus default parameters
|
||||
d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
|
||||
d.t = 0;
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
|
||||
off += 64 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
d.t += 64;
|
||||
d.round(d.buf[0..], false);
|
||||
// No key plus default parameters
|
||||
d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
|
||||
d.t = 0;
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
// Full middle blocks.
|
||||
while (off + 64 <= b.len) : (off += 64) {
|
||||
d.t += 64;
|
||||
d.round(b[off..off + 64], false);
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
}
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
debug.assert(out.len >= out_len / 8);
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
|
||||
off += 64 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
d.t += 64;
|
||||
d.round(d.buf[0..], false);
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
d.t += d.buf_len;
|
||||
d.round(d.buf[0..], true);
|
||||
// Full middle blocks.
|
||||
while (off + 64 <= b.len) : (off += 64) {
|
||||
d.t += 64;
|
||||
d.round(b[off..off + 64], false);
|
||||
}
|
||||
|
||||
const rr = d.h[0 .. out_len / 32];
|
||||
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
|
||||
}
|
||||
}
|
||||
|
||||
fn round(d: &Self, b: []const u8, last: bool) void {
|
||||
debug.assert(b.len == 64);
|
||||
|
||||
var m: [16]u32 = undefined;
|
||||
var v: [16]u32 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
*r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
while (k < 8) : (k += 1) {
|
||||
v[k] = d.h[k];
|
||||
v[k+8] = iv[k];
|
||||
}
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
debug.assert(out.len >= out_len / 8);
|
||||
|
||||
v[12] ^= @truncate(u32, d.t);
|
||||
v[13] ^= u32(d.t >> 32);
|
||||
if (last) v[14] = ~v[14];
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
d.t += d.buf_len;
|
||||
d.round(d.buf[0..], true);
|
||||
|
||||
const rounds = comptime []RoundParam {
|
||||
Rp(0, 4, 8, 12, 0, 1),
|
||||
Rp(1, 5, 9, 13, 2, 3),
|
||||
Rp(2, 6, 10, 14, 4, 5),
|
||||
Rp(3, 7, 11, 15, 6, 7),
|
||||
Rp(0, 5, 10, 15, 8, 9),
|
||||
Rp(1, 6, 11, 12, 10, 11),
|
||||
Rp(2, 7, 8, 13, 12, 13),
|
||||
Rp(3, 4, 9, 14, 14, 15),
|
||||
};
|
||||
const rr = d.h[0..out_len / 32];
|
||||
|
||||
comptime var j: usize = 0;
|
||||
inline while (j < 10) : (j += 1) {
|
||||
inline for (rounds) |r| {
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
|
||||
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
|
||||
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Little);
|
||||
}
|
||||
}
|
||||
|
||||
for (d.h) |*r, i| {
|
||||
*r ^= v[i] ^ v[i + 8];
|
||||
fn round(d: &Self, b: []const u8, last: bool) void {
|
||||
debug.assert(b.len == 64);
|
||||
|
||||
var m: [16]u32 = undefined;
|
||||
var v: [16]u32 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
r.* = mem.readIntLE(u32, b[4 * i..4 * i + 4]);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
while (k < 8) : (k += 1) {
|
||||
v[k] = d.h[k];
|
||||
v[k + 8] = iv[k];
|
||||
}
|
||||
|
||||
v[12] ^= @truncate(u32, d.t);
|
||||
v[13] ^= u32(d.t >> 32);
|
||||
if (last) v[14] = ~v[14];
|
||||
|
||||
const rounds = comptime []RoundParam{
|
||||
Rp(0, 4, 8, 12, 0, 1),
|
||||
Rp(1, 5, 9, 13, 2, 3),
|
||||
Rp(2, 6, 10, 14, 4, 5),
|
||||
Rp(3, 7, 11, 15, 6, 7),
|
||||
Rp(0, 5, 10, 15, 8, 9),
|
||||
Rp(1, 6, 11, 12, 10, 11),
|
||||
Rp(2, 7, 8, 13, 12, 13),
|
||||
Rp(3, 4, 9, 14, 14, 15),
|
||||
};
|
||||
|
||||
comptime var j: usize = 0;
|
||||
inline while (j < 10) : (j += 1) {
|
||||
inline for (rounds) |r| {
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
|
||||
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
|
||||
v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
|
||||
}
|
||||
}
|
||||
|
||||
for (d.h) |*r, i| {
|
||||
r.* ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
}
|
||||
};}
|
||||
};
|
||||
}
|
||||
|
||||
test "blake2s224 single" {
|
||||
const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
|
||||
@ -230,7 +250,7 @@ test "blake2s256 streaming" {
|
||||
}
|
||||
|
||||
test "blake2s256 aligned final" {
|
||||
var block = []u8 {0} ** Blake2s256.block_size;
|
||||
var block = []u8{0} ** Blake2s256.block_size;
|
||||
var out: [Blake2s256.digest_size]u8 = undefined;
|
||||
|
||||
var h = Blake2s256.init();
|
||||
@ -238,154 +258,159 @@ test "blake2s256 aligned final" {
|
||||
h.final(out[0..]);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Blake2b
|
||||
|
||||
pub const Blake2b384 = Blake2b(384);
|
||||
pub const Blake2b512 = Blake2b(512);
|
||||
|
||||
fn Blake2b(comptime out_len: usize) type { return struct {
|
||||
const Self = this;
|
||||
const block_size = 128;
|
||||
const digest_size = out_len / 8;
|
||||
fn Blake2b(comptime out_len: usize) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const block_size = 128;
|
||||
const digest_size = out_len / 8;
|
||||
|
||||
const iv = [8]u64 {
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
|
||||
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
||||
};
|
||||
const iv = [8]u64{
|
||||
0x6a09e667f3bcc908,
|
||||
0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b,
|
||||
0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1,
|
||||
0x9b05688c2b3e6c1f,
|
||||
0x1f83d9abfb41bd6b,
|
||||
0x5be0cd19137e2179,
|
||||
};
|
||||
|
||||
const sigma = [12][16]u8 {
|
||||
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
[]const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||
[]const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||
[]const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||
[]const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||
[]const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||
[]const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||
[]const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||
[]const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
|
||||
[]const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
[]const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
};
|
||||
const sigma = [12][16]u8{
|
||||
[]const u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
[]const u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
[]const u8{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||
[]const u8{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||
[]const u8{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||
[]const u8{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||
[]const u8{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||
[]const u8{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||
[]const u8{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||
[]const u8{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
|
||||
[]const u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
[]const u8{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
};
|
||||
|
||||
h: [8]u64,
|
||||
t: u128,
|
||||
// Streaming cache
|
||||
buf: [128]u8,
|
||||
buf_len: u8,
|
||||
h: [8]u64,
|
||||
t: u128,
|
||||
// Streaming cache
|
||||
buf: [128]u8,
|
||||
buf_len: u8,
|
||||
|
||||
pub fn init() Self {
|
||||
debug.assert(8 <= out_len and out_len <= 512);
|
||||
pub fn init() Self {
|
||||
debug.assert(8 <= out_len and out_len <= 512);
|
||||
|
||||
var s: Self = undefined;
|
||||
s.reset();
|
||||
return s;
|
||||
}
|
||||
var s: Self = undefined;
|
||||
s.reset();
|
||||
return s;
|
||||
}
|
||||
|
||||
pub fn reset(d: &Self) void {
|
||||
mem.copy(u64, d.h[0..], iv[0..]);
|
||||
pub fn reset(d: &Self) void {
|
||||
mem.copy(u64, d.h[0..], iv[0..]);
|
||||
|
||||
// No key plus default parameters
|
||||
d.h[0] ^= 0x01010000 ^ (out_len >> 3);
|
||||
d.t = 0;
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
|
||||
off += 128 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
d.t += 128;
|
||||
d.round(d.buf[0..], false);
|
||||
// No key plus default parameters
|
||||
d.h[0] ^= 0x01010000 ^ (out_len >> 3);
|
||||
d.t = 0;
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
// Full middle blocks.
|
||||
while (off + 128 <= b.len) : (off += 128) {
|
||||
d.t += 128;
|
||||
d.round(b[off..off + 128], false);
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
}
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
d.t += d.buf_len;
|
||||
d.round(d.buf[0..], true);
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
|
||||
off += 128 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
d.t += 128;
|
||||
d.round(d.buf[0..], false);
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
const rr = d.h[0 .. out_len / 64];
|
||||
// Full middle blocks.
|
||||
while (off + 128 <= b.len) : (off += 128) {
|
||||
d.t += 128;
|
||||
d.round(b[off..off + 128], false);
|
||||
}
|
||||
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
|
||||
}
|
||||
}
|
||||
|
||||
fn round(d: &Self, b: []const u8, last: bool) void {
|
||||
debug.assert(b.len == 128);
|
||||
|
||||
var m: [16]u64 = undefined;
|
||||
var v: [16]u64 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
*r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
while (k < 8) : (k += 1) {
|
||||
v[k] = d.h[k];
|
||||
v[k+8] = iv[k];
|
||||
}
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
d.t += d.buf_len;
|
||||
d.round(d.buf[0..], true);
|
||||
|
||||
v[12] ^= @truncate(u64, d.t);
|
||||
v[13] ^= u64(d.t >> 64);
|
||||
if (last) v[14] = ~v[14];
|
||||
const rr = d.h[0..out_len / 64];
|
||||
|
||||
const rounds = comptime []RoundParam {
|
||||
Rp(0, 4, 8, 12, 0, 1),
|
||||
Rp(1, 5, 9, 13, 2, 3),
|
||||
Rp(2, 6, 10, 14, 4, 5),
|
||||
Rp(3, 7, 11, 15, 6, 7),
|
||||
Rp(0, 5, 10, 15, 8, 9),
|
||||
Rp(1, 6, 11, 12, 10, 11),
|
||||
Rp(2, 7, 8, 13, 12, 13),
|
||||
Rp(3, 4, 9, 14, 14, 15),
|
||||
};
|
||||
|
||||
comptime var j: usize = 0;
|
||||
inline while (j < 12) : (j += 1) {
|
||||
inline for (rounds) |r| {
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
|
||||
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
|
||||
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
|
||||
for (rr) |s, j| {
|
||||
mem.writeInt(out[8 * j..8 * j + 8], s, builtin.Endian.Little);
|
||||
}
|
||||
}
|
||||
|
||||
for (d.h) |*r, i| {
|
||||
*r ^= v[i] ^ v[i + 8];
|
||||
fn round(d: &Self, b: []const u8, last: bool) void {
|
||||
debug.assert(b.len == 128);
|
||||
|
||||
var m: [16]u64 = undefined;
|
||||
var v: [16]u64 = undefined;
|
||||
|
||||
for (m) |*r, i| {
|
||||
r.* = mem.readIntLE(u64, b[8 * i..8 * i + 8]);
|
||||
}
|
||||
|
||||
var k: usize = 0;
|
||||
while (k < 8) : (k += 1) {
|
||||
v[k] = d.h[k];
|
||||
v[k + 8] = iv[k];
|
||||
}
|
||||
|
||||
v[12] ^= @truncate(u64, d.t);
|
||||
v[13] ^= u64(d.t >> 64);
|
||||
if (last) v[14] = ~v[14];
|
||||
|
||||
const rounds = comptime []RoundParam{
|
||||
Rp(0, 4, 8, 12, 0, 1),
|
||||
Rp(1, 5, 9, 13, 2, 3),
|
||||
Rp(2, 6, 10, 14, 4, 5),
|
||||
Rp(3, 7, 11, 15, 6, 7),
|
||||
Rp(0, 5, 10, 15, 8, 9),
|
||||
Rp(1, 6, 11, 12, 10, 11),
|
||||
Rp(2, 7, 8, 13, 12, 13),
|
||||
Rp(3, 4, 9, 14, 14, 15),
|
||||
};
|
||||
|
||||
comptime var j: usize = 0;
|
||||
inline while (j < 12) : (j += 1) {
|
||||
inline for (rounds) |r| {
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
|
||||
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
|
||||
v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
|
||||
v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
|
||||
v[r.c] = v[r.c] +% v[r.d];
|
||||
v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
|
||||
}
|
||||
}
|
||||
|
||||
for (d.h) |*r, i| {
|
||||
r.* ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
}
|
||||
};}
|
||||
};
|
||||
}
|
||||
|
||||
test "blake2b384 single" {
|
||||
const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
|
||||
@ -458,7 +483,7 @@ test "blake2b512 streaming" {
|
||||
}
|
||||
|
||||
test "blake2b512 aligned final" {
|
||||
var block = []u8 {0} ** Blake2b512.block_size;
|
||||
var block = []u8{0} ** Blake2b512.block_size;
|
||||
var out: [Blake2b512.digest_size]u8 = undefined;
|
||||
|
||||
var h = Blake2b512.init();
|
||||
|
||||
@ -29,12 +29,12 @@ pub fn Hmac(comptime H: type) type {
|
||||
|
||||
var o_key_pad: [H.block_size]u8 = undefined;
|
||||
for (o_key_pad) |*b, i| {
|
||||
*b = scratch[i] ^ 0x5c;
|
||||
b.* = scratch[i] ^ 0x5c;
|
||||
}
|
||||
|
||||
var i_key_pad: [H.block_size]u8 = undefined;
|
||||
for (i_key_pad) |*b, i| {
|
||||
*b = scratch[i] ^ 0x36;
|
||||
b.* = scratch[i] ^ 0x36;
|
||||
}
|
||||
|
||||
// HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation
|
||||
|
||||
@ -6,12 +6,25 @@ const debug = @import("../debug/index.zig");
|
||||
const fmt = @import("../fmt/index.zig");
|
||||
|
||||
const RoundParam = struct {
|
||||
a: usize, b: usize, c: usize, d: usize,
|
||||
k: usize, s: u32, t: u32
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
k: usize,
|
||||
s: u32,
|
||||
t: u32,
|
||||
};
|
||||
|
||||
fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundParam {
|
||||
return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t };
|
||||
return RoundParam{
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c,
|
||||
.d = d,
|
||||
.k = k,
|
||||
.s = s,
|
||||
.t = t,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Md5 = struct {
|
||||
@ -99,7 +112,7 @@ 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);
|
||||
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Little);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,30 +125,33 @@ pub const Md5 = struct {
|
||||
while (i < 16) : (i += 1) {
|
||||
// NOTE: Performing or's separately improves perf by ~10%
|
||||
s[i] = 0;
|
||||
s[i] |= u32(b[i*4+0]);
|
||||
s[i] |= u32(b[i*4+1]) << 8;
|
||||
s[i] |= u32(b[i*4+2]) << 16;
|
||||
s[i] |= u32(b[i*4+3]) << 24;
|
||||
s[i] |= u32(b[i * 4 + 0]);
|
||||
s[i] |= u32(b[i * 4 + 1]) << 8;
|
||||
s[i] |= u32(b[i * 4 + 2]) << 16;
|
||||
s[i] |= u32(b[i * 4 + 3]) << 24;
|
||||
}
|
||||
|
||||
var v: [4]u32 = []u32 {
|
||||
d.s[0], d.s[1], d.s[2], d.s[3],
|
||||
var v: [4]u32 = []u32{
|
||||
d.s[0],
|
||||
d.s[1],
|
||||
d.s[2],
|
||||
d.s[3],
|
||||
};
|
||||
|
||||
const round0 = comptime []RoundParam {
|
||||
Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
|
||||
Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
|
||||
Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
|
||||
Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
|
||||
Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
|
||||
Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
|
||||
Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
|
||||
Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
|
||||
Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
|
||||
Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
|
||||
const round0 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
|
||||
Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
|
||||
Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
|
||||
Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
|
||||
Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
|
||||
Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
|
||||
Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
|
||||
Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
|
||||
Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
|
||||
Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
|
||||
Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
|
||||
Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
|
||||
Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
|
||||
Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
|
||||
Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
|
||||
Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
|
||||
Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
|
||||
@ -145,22 +161,22 @@ pub const Md5 = struct {
|
||||
v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
|
||||
}
|
||||
|
||||
const round1 = comptime []RoundParam {
|
||||
Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
|
||||
Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
|
||||
const round1 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
|
||||
Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
|
||||
Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
|
||||
Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
|
||||
Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
|
||||
Rp(3, 0, 1, 2, 10, 9, 0x02441453),
|
||||
Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
|
||||
Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
|
||||
Rp(3, 0, 1, 2, 10, 9, 0x02441453),
|
||||
Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
|
||||
Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
|
||||
Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
|
||||
Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
|
||||
Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
|
||||
Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
|
||||
Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
|
||||
Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
|
||||
Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
|
||||
Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
|
||||
Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
|
||||
Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
|
||||
Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
|
||||
Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
|
||||
Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
|
||||
Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
|
||||
Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
|
||||
Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
|
||||
};
|
||||
inline for (round1) |r| {
|
||||
@ -168,46 +184,46 @@ pub const Md5 = struct {
|
||||
v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
|
||||
}
|
||||
|
||||
const round2 = comptime []RoundParam {
|
||||
Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
|
||||
Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
|
||||
const round2 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
|
||||
Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
|
||||
Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
|
||||
Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
|
||||
Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
|
||||
Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
|
||||
Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
|
||||
Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
|
||||
Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
|
||||
Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
|
||||
Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
|
||||
Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
|
||||
Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
|
||||
Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
|
||||
Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
|
||||
Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
|
||||
Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
|
||||
Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
|
||||
Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
|
||||
Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
|
||||
Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
|
||||
Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
|
||||
Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
|
||||
Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
|
||||
Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
|
||||
};
|
||||
inline for (round2) |r| {
|
||||
v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
|
||||
v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
|
||||
}
|
||||
|
||||
const round3 = comptime []RoundParam {
|
||||
Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
|
||||
Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
|
||||
const round3 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
|
||||
Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
|
||||
Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
|
||||
Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
|
||||
Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
|
||||
Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
|
||||
Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
|
||||
Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
|
||||
Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
|
||||
Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
|
||||
Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
|
||||
Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
|
||||
Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
|
||||
Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
|
||||
Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
|
||||
Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
|
||||
Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
|
||||
Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
|
||||
Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
|
||||
Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
|
||||
Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
|
||||
Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
|
||||
Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
|
||||
Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
|
||||
Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
|
||||
};
|
||||
inline for (round3) |r| {
|
||||
v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];
|
||||
@ -255,7 +271,7 @@ test "md5 streaming" {
|
||||
}
|
||||
|
||||
test "md5 aligned final" {
|
||||
var block = []u8 {0} ** Md5.block_size;
|
||||
var block = []u8{0} ** Md5.block_size;
|
||||
var out: [Md5.digest_size]u8 = undefined;
|
||||
|
||||
var h = Md5.init();
|
||||
|
||||
@ -7,11 +7,23 @@ const builtin = @import("builtin");
|
||||
pub const u160 = @IntType(false, 160);
|
||||
|
||||
const RoundParam = struct {
|
||||
a: usize, b: usize, c: usize, d: usize, e: usize, i: u32,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
i: u32,
|
||||
};
|
||||
|
||||
fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
|
||||
return RoundParam { .a = a, .b = b, .c = c, .d = d, .e = e, .i = i };
|
||||
return RoundParam{
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c,
|
||||
.d = d,
|
||||
.e = e,
|
||||
.i = i,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Sha1 = struct {
|
||||
@ -99,7 +111,7 @@ 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);
|
||||
mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Big);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,21 +120,25 @@ pub const Sha1 = struct {
|
||||
|
||||
var s: [16]u32 = undefined;
|
||||
|
||||
var v: [5]u32 = []u32 {
|
||||
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4],
|
||||
var v: [5]u32 = []u32{
|
||||
d.s[0],
|
||||
d.s[1],
|
||||
d.s[2],
|
||||
d.s[3],
|
||||
d.s[4],
|
||||
};
|
||||
|
||||
const round0a = comptime []RoundParam {
|
||||
Rp(0, 1, 2, 3, 4, 0),
|
||||
Rp(4, 0, 1, 2, 3, 1),
|
||||
Rp(3, 4, 0, 1, 2, 2),
|
||||
Rp(2, 3, 4, 0, 1, 3),
|
||||
Rp(1, 2, 3, 4, 0, 4),
|
||||
Rp(0, 1, 2, 3, 4, 5),
|
||||
Rp(4, 0, 1, 2, 3, 6),
|
||||
Rp(3, 4, 0, 1, 2, 7),
|
||||
Rp(2, 3, 4, 0, 1, 8),
|
||||
Rp(1, 2, 3, 4, 0, 9),
|
||||
const round0a = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 4, 0),
|
||||
Rp(4, 0, 1, 2, 3, 1),
|
||||
Rp(3, 4, 0, 1, 2, 2),
|
||||
Rp(2, 3, 4, 0, 1, 3),
|
||||
Rp(1, 2, 3, 4, 0, 4),
|
||||
Rp(0, 1, 2, 3, 4, 5),
|
||||
Rp(4, 0, 1, 2, 3, 6),
|
||||
Rp(3, 4, 0, 1, 2, 7),
|
||||
Rp(2, 3, 4, 0, 1, 8),
|
||||
Rp(1, 2, 3, 4, 0, 9),
|
||||
Rp(0, 1, 2, 3, 4, 10),
|
||||
Rp(4, 0, 1, 2, 3, 11),
|
||||
Rp(3, 4, 0, 1, 2, 12),
|
||||
@ -131,32 +147,27 @@ pub const Sha1 = struct {
|
||||
Rp(0, 1, 2, 3, 4, 15),
|
||||
};
|
||||
inline for (round0a) |r| {
|
||||
s[r.i] = (u32(b[r.i * 4 + 0]) << 24) |
|
||||
(u32(b[r.i * 4 + 1]) << 16) |
|
||||
(u32(b[r.i * 4 + 2]) << 8) |
|
||||
(u32(b[r.i * 4 + 3]) << 0);
|
||||
s[r.i] = (u32(b[r.i * 4 + 0]) << 24) | (u32(b[r.i * 4 + 1]) << 16) | (u32(b[r.i * 4 + 2]) << 8) | (u32(b[r.i * 4 + 3]) << 0);
|
||||
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
|
||||
+% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
|
||||
v[r.b] = math.rotl(u32, v[r.b], u32(30));
|
||||
}
|
||||
|
||||
const round0b = comptime []RoundParam {
|
||||
const round0b = comptime []RoundParam{
|
||||
Rp(4, 0, 1, 2, 3, 16),
|
||||
Rp(3, 4, 0, 1, 2, 17),
|
||||
Rp(2, 3, 4, 0, 1, 18),
|
||||
Rp(1, 2, 3, 4, 0, 19),
|
||||
};
|
||||
inline for (round0b) |r| {
|
||||
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
|
||||
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
|
||||
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
|
||||
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
|
||||
+% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
|
||||
v[r.b] = math.rotl(u32, v[r.b], u32(30));
|
||||
}
|
||||
|
||||
const round1 = comptime []RoundParam {
|
||||
const round1 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 4, 20),
|
||||
Rp(4, 0, 1, 2, 3, 21),
|
||||
Rp(3, 4, 0, 1, 2, 22),
|
||||
@ -179,15 +190,14 @@ pub const Sha1 = struct {
|
||||
Rp(1, 2, 3, 4, 0, 39),
|
||||
};
|
||||
inline for (round1) |r| {
|
||||
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
|
||||
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
|
||||
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
|
||||
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf]
|
||||
+% (v[r.b] ^ v[r.c] ^ v[r.d]);
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
|
||||
v[r.b] = math.rotl(u32, v[r.b], u32(30));
|
||||
}
|
||||
|
||||
const round2 = comptime []RoundParam {
|
||||
const round2 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 4, 40),
|
||||
Rp(4, 0, 1, 2, 3, 41),
|
||||
Rp(3, 4, 0, 1, 2, 42),
|
||||
@ -210,15 +220,14 @@ pub const Sha1 = struct {
|
||||
Rp(1, 2, 3, 4, 0, 59),
|
||||
};
|
||||
inline for (round2) |r| {
|
||||
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
|
||||
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
|
||||
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
|
||||
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf]
|
||||
+% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
|
||||
v[r.b] = math.rotl(u32, v[r.b], u32(30));
|
||||
}
|
||||
|
||||
const round3 = comptime []RoundParam {
|
||||
const round3 = comptime []RoundParam{
|
||||
Rp(0, 1, 2, 3, 4, 60),
|
||||
Rp(4, 0, 1, 2, 3, 61),
|
||||
Rp(3, 4, 0, 1, 2, 62),
|
||||
@ -241,11 +250,10 @@ pub const Sha1 = struct {
|
||||
Rp(1, 2, 3, 4, 0, 79),
|
||||
};
|
||||
inline for (round3) |r| {
|
||||
const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
|
||||
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
|
||||
s[r.i & 0xf] = math.rotl(u32, t, u32(1));
|
||||
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf]
|
||||
+% (v[r.b] ^ v[r.c] ^ v[r.d]);
|
||||
v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
|
||||
v[r.b] = math.rotl(u32, v[r.b], u32(30));
|
||||
}
|
||||
|
||||
@ -286,7 +294,7 @@ test "sha1 streaming" {
|
||||
}
|
||||
|
||||
test "sha1 aligned final" {
|
||||
var block = []u8 {0} ** Sha1.block_size;
|
||||
var block = []u8{0} ** Sha1.block_size;
|
||||
var out: [Sha1.digest_size]u8 = undefined;
|
||||
|
||||
var h = Sha1.init();
|
||||
|
||||
@ -9,12 +9,31 @@ const htest = @import("test.zig");
|
||||
// Sha224 + Sha256
|
||||
|
||||
const RoundParam256 = struct {
|
||||
a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
|
||||
i: usize, k: u32,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
f: usize,
|
||||
g: usize,
|
||||
h: usize,
|
||||
i: usize,
|
||||
k: u32,
|
||||
};
|
||||
|
||||
fn Rp256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) RoundParam256 {
|
||||
return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
|
||||
return RoundParam256{
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c,
|
||||
.d = d,
|
||||
.e = e,
|
||||
.f = f,
|
||||
.g = g,
|
||||
.h = h,
|
||||
.i = i,
|
||||
.k = k,
|
||||
};
|
||||
}
|
||||
|
||||
const Sha2Params32 = struct {
|
||||
@ -29,7 +48,7 @@ const Sha2Params32 = struct {
|
||||
out_len: usize,
|
||||
};
|
||||
|
||||
const Sha224Params = Sha2Params32 {
|
||||
const Sha224Params = Sha2Params32{
|
||||
.iv0 = 0xC1059ED8,
|
||||
.iv1 = 0x367CD507,
|
||||
.iv2 = 0x3070DD17,
|
||||
@ -41,7 +60,7 @@ const Sha224Params = Sha2Params32 {
|
||||
.out_len = 224,
|
||||
};
|
||||
|
||||
const Sha256Params = Sha2Params32 {
|
||||
const Sha256Params = Sha2Params32{
|
||||
.iv0 = 0x6A09E667,
|
||||
.iv1 = 0xBB67AE85,
|
||||
.iv2 = 0x3C6EF372,
|
||||
@ -56,216 +75,215 @@ const Sha256Params = Sha2Params32 {
|
||||
pub const Sha224 = Sha2_32(Sha224Params);
|
||||
pub const Sha256 = Sha2_32(Sha256Params);
|
||||
|
||||
fn Sha2_32(comptime params: Sha2Params32) type { return struct {
|
||||
const Self = this;
|
||||
const block_size = 64;
|
||||
const digest_size = params.out_len / 8;
|
||||
fn Sha2_32(comptime params: Sha2Params32) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const block_size = 64;
|
||||
const digest_size = params.out_len / 8;
|
||||
|
||||
s: [8]u32,
|
||||
// Streaming Cache
|
||||
buf: [64]u8,
|
||||
buf_len: u8,
|
||||
total_len: u64,
|
||||
s: [8]u32,
|
||||
// Streaming Cache
|
||||
buf: [64]u8,
|
||||
buf_len: u8,
|
||||
total_len: u64,
|
||||
|
||||
pub fn init() Self {
|
||||
var d: Self = undefined;
|
||||
d.reset();
|
||||
return d;
|
||||
}
|
||||
pub fn init() Self {
|
||||
var d: Self = undefined;
|
||||
d.reset();
|
||||
return d;
|
||||
}
|
||||
|
||||
pub fn reset(d: &Self) void {
|
||||
d.s[0] = params.iv0;
|
||||
d.s[1] = params.iv1;
|
||||
d.s[2] = params.iv2;
|
||||
d.s[3] = params.iv3;
|
||||
d.s[4] = params.iv4;
|
||||
d.s[5] = params.iv5;
|
||||
d.s[6] = params.iv6;
|
||||
d.s[7] = params.iv7;
|
||||
d.buf_len = 0;
|
||||
d.total_len = 0;
|
||||
}
|
||||
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
|
||||
off += 64 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
|
||||
d.round(d.buf[0..]);
|
||||
pub fn reset(d: &Self) void {
|
||||
d.s[0] = params.iv0;
|
||||
d.s[1] = params.iv1;
|
||||
d.s[2] = params.iv2;
|
||||
d.s[3] = params.iv3;
|
||||
d.s[4] = params.iv4;
|
||||
d.s[5] = params.iv5;
|
||||
d.s[6] = params.iv6;
|
||||
d.s[7] = params.iv7;
|
||||
d.buf_len = 0;
|
||||
d.total_len = 0;
|
||||
}
|
||||
|
||||
// Full middle blocks.
|
||||
while (off + 64 <= b.len) : (off += 64) {
|
||||
d.round(b[off..off + 64]);
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
d.total_len += b.len;
|
||||
}
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 64) {
|
||||
off += 64 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
debug.assert(out.len >= params.out_len / 8);
|
||||
d.round(d.buf[0..]);
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
// The buffer here will never be completely full.
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
// Full middle blocks.
|
||||
while (off + 64 <= b.len) : (off += 64) {
|
||||
d.round(b[off..off + 64]);
|
||||
}
|
||||
|
||||
// Append padding bits.
|
||||
d.buf[d.buf_len] = 0x80;
|
||||
d.buf_len += 1;
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
|
||||
d.total_len += b.len;
|
||||
}
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
debug.assert(out.len >= params.out_len / 8);
|
||||
|
||||
// The buffer here will never be completely full.
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
|
||||
// Append padding bits.
|
||||
d.buf[d.buf_len] = 0x80;
|
||||
d.buf_len += 1;
|
||||
|
||||
// > 448 mod 512 so need to add an extra round to wrap around.
|
||||
if (64 - d.buf_len < 8) {
|
||||
d.round(d.buf[0..]);
|
||||
mem.set(u8, d.buf[0..], 0);
|
||||
}
|
||||
|
||||
// Append message length.
|
||||
var i: usize = 1;
|
||||
var len = d.total_len >> 5;
|
||||
d.buf[63] = u8(d.total_len & 0x1f) << 3;
|
||||
while (i < 8) : (i += 1) {
|
||||
d.buf[63 - i] = u8(len & 0xff);
|
||||
len >>= 8;
|
||||
}
|
||||
|
||||
// > 448 mod 512 so need to add an extra round to wrap around.
|
||||
if (64 - d.buf_len < 8) {
|
||||
d.round(d.buf[0..]);
|
||||
mem.set(u8, d.buf[0..], 0);
|
||||
|
||||
// May truncate for possible 224 output
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Append message length.
|
||||
var i: usize = 1;
|
||||
var len = d.total_len >> 5;
|
||||
d.buf[63] = u8(d.total_len & 0x1f) << 3;
|
||||
while (i < 8) : (i += 1) {
|
||||
d.buf[63 - i] = u8(len & 0xff);
|
||||
len >>= 8;
|
||||
fn round(d: &Self, b: []const u8) void {
|
||||
debug.assert(b.len == 64);
|
||||
|
||||
var s: [64]u32 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
s[i] = 0;
|
||||
s[i] |= u32(b[i * 4 + 0]) << 24;
|
||||
s[i] |= u32(b[i * 4 + 1]) << 16;
|
||||
s[i] |= u32(b[i * 4 + 2]) << 8;
|
||||
s[i] |= u32(b[i * 4 + 3]) << 0;
|
||||
}
|
||||
while (i < 64) : (i += 1) {
|
||||
s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u32, s[i - 15], u32(7)) ^ math.rotr(u32, s[i - 15], u32(18)) ^ (s[i - 15] >> 3)) +% (math.rotr(u32, s[i - 2], u32(17)) ^ math.rotr(u32, s[i - 2], u32(19)) ^ (s[i - 2] >> 10));
|
||||
}
|
||||
|
||||
var v: [8]u32 = []u32{
|
||||
d.s[0],
|
||||
d.s[1],
|
||||
d.s[2],
|
||||
d.s[3],
|
||||
d.s[4],
|
||||
d.s[5],
|
||||
d.s[6],
|
||||
d.s[7],
|
||||
};
|
||||
|
||||
const round0 = comptime []RoundParam256{
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
|
||||
};
|
||||
inline for (round0) |r| {
|
||||
v[r.h] = v[r.h] +% (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
|
||||
|
||||
v[r.d] = v[r.d] +% v[r.h];
|
||||
|
||||
v[r.h] = v[r.h] +% (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
|
||||
}
|
||||
|
||||
d.s[0] +%= v[0];
|
||||
d.s[1] +%= v[1];
|
||||
d.s[2] +%= v[2];
|
||||
d.s[3] +%= v[3];
|
||||
d.s[4] +%= v[4];
|
||||
d.s[5] +%= v[5];
|
||||
d.s[6] +%= v[6];
|
||||
d.s[7] +%= v[7];
|
||||
}
|
||||
|
||||
d.round(d.buf[0..]);
|
||||
|
||||
// May truncate for possible 224 output
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn round(d: &Self, b: []const u8) void {
|
||||
debug.assert(b.len == 64);
|
||||
|
||||
var s: [64]u32 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
s[i] = 0;
|
||||
s[i] |= u32(b[i*4+0]) << 24;
|
||||
s[i] |= u32(b[i*4+1]) << 16;
|
||||
s[i] |= u32(b[i*4+2]) << 8;
|
||||
s[i] |= u32(b[i*4+3]) << 0;
|
||||
}
|
||||
while (i < 64) : (i += 1) {
|
||||
s[i] =
|
||||
s[i-16] +% s[i-7] +%
|
||||
(math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +%
|
||||
(math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10));
|
||||
}
|
||||
|
||||
var v: [8]u32 = []u32 {
|
||||
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
|
||||
};
|
||||
|
||||
const round0 = comptime []RoundParam256 {
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
|
||||
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
|
||||
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
|
||||
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
|
||||
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
|
||||
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
|
||||
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
|
||||
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
|
||||
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
|
||||
};
|
||||
inline for (round0) |r| {
|
||||
v[r.h] =
|
||||
v[r.h] +%
|
||||
(math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +%
|
||||
(v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
|
||||
r.k +% s[r.i];
|
||||
|
||||
v[r.d] = v[r.d] +% v[r.h];
|
||||
|
||||
v[r.h] =
|
||||
v[r.h] +%
|
||||
(math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +%
|
||||
((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
|
||||
}
|
||||
|
||||
d.s[0] +%= v[0];
|
||||
d.s[1] +%= v[1];
|
||||
d.s[2] +%= v[2];
|
||||
d.s[3] +%= v[3];
|
||||
d.s[4] +%= v[4];
|
||||
d.s[5] +%= v[5];
|
||||
d.s[6] +%= v[6];
|
||||
d.s[7] +%= v[7];
|
||||
}
|
||||
};}
|
||||
};
|
||||
}
|
||||
|
||||
test "sha224 single" {
|
||||
htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
|
||||
@ -320,7 +338,7 @@ test "sha256 streaming" {
|
||||
}
|
||||
|
||||
test "sha256 aligned final" {
|
||||
var block = []u8 {0} ** Sha256.block_size;
|
||||
var block = []u8{0} ** Sha256.block_size;
|
||||
var out: [Sha256.digest_size]u8 = undefined;
|
||||
|
||||
var h = Sha256.init();
|
||||
@ -328,17 +346,35 @@ test "sha256 aligned final" {
|
||||
h.final(out[0..]);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Sha384 + Sha512
|
||||
|
||||
const RoundParam512 = struct {
|
||||
a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
|
||||
i: usize, k: u64,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
f: usize,
|
||||
g: usize,
|
||||
h: usize,
|
||||
i: usize,
|
||||
k: u64,
|
||||
};
|
||||
|
||||
fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
|
||||
return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
|
||||
return RoundParam512{
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c,
|
||||
.d = d,
|
||||
.e = e,
|
||||
.f = f,
|
||||
.g = g,
|
||||
.h = h,
|
||||
.i = i,
|
||||
.k = k,
|
||||
};
|
||||
}
|
||||
|
||||
const Sha2Params64 = struct {
|
||||
@ -353,7 +389,7 @@ const Sha2Params64 = struct {
|
||||
out_len: usize,
|
||||
};
|
||||
|
||||
const Sha384Params = Sha2Params64 {
|
||||
const Sha384Params = Sha2Params64{
|
||||
.iv0 = 0xCBBB9D5DC1059ED8,
|
||||
.iv1 = 0x629A292A367CD507,
|
||||
.iv2 = 0x9159015A3070DD17,
|
||||
@ -365,7 +401,7 @@ const Sha384Params = Sha2Params64 {
|
||||
.out_len = 384,
|
||||
};
|
||||
|
||||
const Sha512Params = Sha2Params64 {
|
||||
const Sha512Params = Sha2Params64{
|
||||
.iv0 = 0x6A09E667F3BCC908,
|
||||
.iv1 = 0xBB67AE8584CAA73B,
|
||||
.iv2 = 0x3C6EF372FE94F82B,
|
||||
@ -374,242 +410,241 @@ const Sha512Params = Sha2Params64 {
|
||||
.iv5 = 0x9B05688C2B3E6C1F,
|
||||
.iv6 = 0x1F83D9ABFB41BD6B,
|
||||
.iv7 = 0x5BE0CD19137E2179,
|
||||
.out_len = 512
|
||||
.out_len = 512,
|
||||
};
|
||||
|
||||
pub const Sha384 = Sha2_64(Sha384Params);
|
||||
pub const Sha512 = Sha2_64(Sha512Params);
|
||||
|
||||
fn Sha2_64(comptime params: Sha2Params64) type { return struct {
|
||||
const Self = this;
|
||||
const block_size = 128;
|
||||
const digest_size = params.out_len / 8;
|
||||
fn Sha2_64(comptime params: Sha2Params64) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const block_size = 128;
|
||||
const digest_size = params.out_len / 8;
|
||||
|
||||
s: [8]u64,
|
||||
// Streaming Cache
|
||||
buf: [128]u8,
|
||||
buf_len: u8,
|
||||
total_len: u128,
|
||||
s: [8]u64,
|
||||
// Streaming Cache
|
||||
buf: [128]u8,
|
||||
buf_len: u8,
|
||||
total_len: u128,
|
||||
|
||||
pub fn init() Self {
|
||||
var d: Self = undefined;
|
||||
d.reset();
|
||||
return d;
|
||||
}
|
||||
pub fn init() Self {
|
||||
var d: Self = undefined;
|
||||
d.reset();
|
||||
return d;
|
||||
}
|
||||
|
||||
pub fn reset(d: &Self) void {
|
||||
d.s[0] = params.iv0;
|
||||
d.s[1] = params.iv1;
|
||||
d.s[2] = params.iv2;
|
||||
d.s[3] = params.iv3;
|
||||
d.s[4] = params.iv4;
|
||||
d.s[5] = params.iv5;
|
||||
d.s[6] = params.iv6;
|
||||
d.s[7] = params.iv7;
|
||||
d.buf_len = 0;
|
||||
d.total_len = 0;
|
||||
}
|
||||
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
|
||||
off += 128 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
|
||||
d.round(d.buf[0..]);
|
||||
pub fn reset(d: &Self) void {
|
||||
d.s[0] = params.iv0;
|
||||
d.s[1] = params.iv1;
|
||||
d.s[2] = params.iv2;
|
||||
d.s[3] = params.iv3;
|
||||
d.s[4] = params.iv4;
|
||||
d.s[5] = params.iv5;
|
||||
d.s[6] = params.iv6;
|
||||
d.s[7] = params.iv7;
|
||||
d.buf_len = 0;
|
||||
d.total_len = 0;
|
||||
}
|
||||
|
||||
// Full middle blocks.
|
||||
while (off + 128 <= b.len) : (off += 128) {
|
||||
d.round(b[off..off + 128]);
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var off: usize = 0;
|
||||
|
||||
d.total_len += b.len;
|
||||
}
|
||||
// Partial buffer exists from previous update. Copy into buffer then hash.
|
||||
if (d.buf_len != 0 and d.buf_len + b.len > 128) {
|
||||
off += 128 - d.buf_len;
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
debug.assert(out.len >= params.out_len / 8);
|
||||
d.round(d.buf[0..]);
|
||||
d.buf_len = 0;
|
||||
}
|
||||
|
||||
// The buffer here will never be completely full.
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
// Full middle blocks.
|
||||
while (off + 128 <= b.len) : (off += 128) {
|
||||
d.round(b[off..off + 128]);
|
||||
}
|
||||
|
||||
// Append padding bits.
|
||||
d.buf[d.buf_len] = 0x80;
|
||||
d.buf_len += 1;
|
||||
// Copy any remainder for next pass.
|
||||
mem.copy(u8, d.buf[d.buf_len..], b[off..]);
|
||||
d.buf_len += u8(b[off..].len);
|
||||
|
||||
d.total_len += b.len;
|
||||
}
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
debug.assert(out.len >= params.out_len / 8);
|
||||
|
||||
// The buffer here will never be completely full.
|
||||
mem.set(u8, d.buf[d.buf_len..], 0);
|
||||
|
||||
// Append padding bits.
|
||||
d.buf[d.buf_len] = 0x80;
|
||||
d.buf_len += 1;
|
||||
|
||||
// > 896 mod 1024 so need to add an extra round to wrap around.
|
||||
if (128 - d.buf_len < 16) {
|
||||
d.round(d.buf[0..]);
|
||||
mem.set(u8, d.buf[0..], 0);
|
||||
}
|
||||
|
||||
// Append message length.
|
||||
var i: usize = 1;
|
||||
var len = d.total_len >> 5;
|
||||
d.buf[127] = u8(d.total_len & 0x1f) << 3;
|
||||
while (i < 16) : (i += 1) {
|
||||
d.buf[127 - i] = u8(len & 0xff);
|
||||
len >>= 8;
|
||||
}
|
||||
|
||||
// > 896 mod 1024 so need to add an extra round to wrap around.
|
||||
if (128 - d.buf_len < 16) {
|
||||
d.round(d.buf[0..]);
|
||||
mem.set(u8, d.buf[0..], 0);
|
||||
|
||||
// May truncate for possible 384 output
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Append message length.
|
||||
var i: usize = 1;
|
||||
var len = d.total_len >> 5;
|
||||
d.buf[127] = u8(d.total_len & 0x1f) << 3;
|
||||
while (i < 16) : (i += 1) {
|
||||
d.buf[127 - i] = u8(len & 0xff);
|
||||
len >>= 8;
|
||||
fn round(d: &Self, b: []const u8) void {
|
||||
debug.assert(b.len == 128);
|
||||
|
||||
var s: [80]u64 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
s[i] = 0;
|
||||
s[i] |= u64(b[i * 8 + 0]) << 56;
|
||||
s[i] |= u64(b[i * 8 + 1]) << 48;
|
||||
s[i] |= u64(b[i * 8 + 2]) << 40;
|
||||
s[i] |= u64(b[i * 8 + 3]) << 32;
|
||||
s[i] |= u64(b[i * 8 + 4]) << 24;
|
||||
s[i] |= u64(b[i * 8 + 5]) << 16;
|
||||
s[i] |= u64(b[i * 8 + 6]) << 8;
|
||||
s[i] |= u64(b[i * 8 + 7]) << 0;
|
||||
}
|
||||
while (i < 80) : (i += 1) {
|
||||
s[i] = s[i - 16] +% s[i - 7] +% (math.rotr(u64, s[i - 15], u64(1)) ^ math.rotr(u64, s[i - 15], u64(8)) ^ (s[i - 15] >> 7)) +% (math.rotr(u64, s[i - 2], u64(19)) ^ math.rotr(u64, s[i - 2], u64(61)) ^ (s[i - 2] >> 6));
|
||||
}
|
||||
|
||||
var v: [8]u64 = []u64{
|
||||
d.s[0],
|
||||
d.s[1],
|
||||
d.s[2],
|
||||
d.s[3],
|
||||
d.s[4],
|
||||
d.s[5],
|
||||
d.s[6],
|
||||
d.s[7],
|
||||
};
|
||||
|
||||
const round0 = comptime []RoundParam512{
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
|
||||
};
|
||||
inline for (round0) |r| {
|
||||
v[r.h] = v[r.h] +% (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
|
||||
|
||||
v[r.d] = v[r.d] +% v[r.h];
|
||||
|
||||
v[r.h] = v[r.h] +% (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +% ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
|
||||
}
|
||||
|
||||
d.s[0] +%= v[0];
|
||||
d.s[1] +%= v[1];
|
||||
d.s[2] +%= v[2];
|
||||
d.s[3] +%= v[3];
|
||||
d.s[4] +%= v[4];
|
||||
d.s[5] +%= v[5];
|
||||
d.s[6] +%= v[6];
|
||||
d.s[7] +%= v[7];
|
||||
}
|
||||
|
||||
d.round(d.buf[0..]);
|
||||
|
||||
// May truncate for possible 384 output
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn round(d: &Self, b: []const u8) void {
|
||||
debug.assert(b.len == 128);
|
||||
|
||||
var s: [80]u64 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
s[i] = 0;
|
||||
s[i] |= u64(b[i*8+0]) << 56;
|
||||
s[i] |= u64(b[i*8+1]) << 48;
|
||||
s[i] |= u64(b[i*8+2]) << 40;
|
||||
s[i] |= u64(b[i*8+3]) << 32;
|
||||
s[i] |= u64(b[i*8+4]) << 24;
|
||||
s[i] |= u64(b[i*8+5]) << 16;
|
||||
s[i] |= u64(b[i*8+6]) << 8;
|
||||
s[i] |= u64(b[i*8+7]) << 0;
|
||||
}
|
||||
while (i < 80) : (i += 1) {
|
||||
s[i] =
|
||||
s[i-16] +% s[i-7] +%
|
||||
(math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +%
|
||||
(math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6));
|
||||
}
|
||||
|
||||
var v: [8]u64 = []u64 {
|
||||
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
|
||||
};
|
||||
|
||||
const round0 = comptime []RoundParam512 {
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
|
||||
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
|
||||
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
|
||||
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
|
||||
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
|
||||
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
|
||||
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
|
||||
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
|
||||
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
|
||||
};
|
||||
inline for (round0) |r| {
|
||||
v[r.h] =
|
||||
v[r.h] +%
|
||||
(math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +%
|
||||
(v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
|
||||
r.k +% s[r.i];
|
||||
|
||||
v[r.d] = v[r.d] +% v[r.h];
|
||||
|
||||
v[r.h] =
|
||||
v[r.h] +%
|
||||
(math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +%
|
||||
((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
|
||||
}
|
||||
|
||||
d.s[0] +%= v[0];
|
||||
d.s[1] +%= v[1];
|
||||
d.s[2] +%= v[2];
|
||||
d.s[3] +%= v[3];
|
||||
d.s[4] +%= v[4];
|
||||
d.s[5] +%= v[5];
|
||||
d.s[6] +%= v[6];
|
||||
d.s[7] +%= v[7];
|
||||
}
|
||||
};}
|
||||
};
|
||||
}
|
||||
|
||||
test "sha384 single" {
|
||||
const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
|
||||
@ -680,7 +715,7 @@ test "sha512 streaming" {
|
||||
}
|
||||
|
||||
test "sha512 aligned final" {
|
||||
var block = []u8 {0} ** Sha512.block_size;
|
||||
var block = []u8{0} ** Sha512.block_size;
|
||||
var out: [Sha512.digest_size]u8 = undefined;
|
||||
|
||||
var h = Sha512.init();
|
||||
|
||||
@ -10,148 +10,228 @@ pub const Sha3_256 = Keccak(256, 0x06);
|
||||
pub const Sha3_384 = Keccak(384, 0x06);
|
||||
pub const Sha3_512 = Keccak(512, 0x06);
|
||||
|
||||
fn Keccak(comptime bits: usize, comptime delim: u8) type { return struct {
|
||||
const Self = this;
|
||||
const block_size = 200;
|
||||
const digest_size = bits / 8;
|
||||
fn Keccak(comptime bits: usize, comptime delim: u8) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const block_size = 200;
|
||||
const digest_size = bits / 8;
|
||||
|
||||
s: [200]u8,
|
||||
offset: usize,
|
||||
rate: usize,
|
||||
s: [200]u8,
|
||||
offset: usize,
|
||||
rate: usize,
|
||||
|
||||
pub fn init() Self {
|
||||
var d: Self = undefined;
|
||||
d.reset();
|
||||
return d;
|
||||
}
|
||||
pub fn init() Self {
|
||||
var d: Self = undefined;
|
||||
d.reset();
|
||||
return d;
|
||||
}
|
||||
|
||||
pub fn reset(d: &Self) void {
|
||||
mem.set(u8, d.s[0..], 0);
|
||||
d.offset = 0;
|
||||
d.rate = 200 - (bits / 4);
|
||||
}
|
||||
pub fn reset(d: &Self) void {
|
||||
mem.set(u8, d.s[0..], 0);
|
||||
d.offset = 0;
|
||||
d.rate = 200 - (bits / 4);
|
||||
}
|
||||
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
pub fn hash(b: []const u8, out: []u8) void {
|
||||
var d = Self.init();
|
||||
d.update(b);
|
||||
d.final(out);
|
||||
}
|
||||
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var ip: usize = 0;
|
||||
var len = b.len;
|
||||
var rate = d.rate - d.offset;
|
||||
var offset = d.offset;
|
||||
pub fn update(d: &Self, b: []const u8) void {
|
||||
var ip: usize = 0;
|
||||
var len = b.len;
|
||||
var rate = d.rate - d.offset;
|
||||
var offset = d.offset;
|
||||
|
||||
// absorb
|
||||
while (len >= rate) {
|
||||
for (d.s[offset .. offset + rate]) |*r, i|
|
||||
*r ^= b[ip..][i];
|
||||
// absorb
|
||||
while (len >= rate) {
|
||||
for (d.s[offset..offset + rate]) |*r, i|
|
||||
r.* ^= b[ip..][i];
|
||||
|
||||
keccak_f(1600, d.s[0..]);
|
||||
|
||||
ip += rate;
|
||||
len -= rate;
|
||||
rate = d.rate;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
for (d.s[offset..offset + len]) |*r, i|
|
||||
r.* ^= b[ip..][i];
|
||||
|
||||
d.offset = offset + len;
|
||||
}
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
// padding
|
||||
d.s[d.offset] ^= delim;
|
||||
d.s[d.rate - 1] ^= 0x80;
|
||||
|
||||
keccak_f(1600, d.s[0..]);
|
||||
|
||||
ip += rate;
|
||||
len -= rate;
|
||||
rate = d.rate;
|
||||
offset = 0;
|
||||
// squeeze
|
||||
var op: usize = 0;
|
||||
var len: usize = bits / 8;
|
||||
|
||||
while (len >= d.rate) {
|
||||
mem.copy(u8, out[op..], d.s[0..d.rate]);
|
||||
keccak_f(1600, d.s[0..]);
|
||||
op += d.rate;
|
||||
len -= d.rate;
|
||||
}
|
||||
|
||||
mem.copy(u8, out[op..], d.s[0..len]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (d.s[offset .. offset + len]) |*r, i|
|
||||
*r ^= b[ip..][i];
|
||||
|
||||
d.offset = offset + len;
|
||||
}
|
||||
|
||||
pub fn final(d: &Self, out: []u8) void {
|
||||
// padding
|
||||
d.s[d.offset] ^= delim;
|
||||
d.s[d.rate - 1] ^= 0x80;
|
||||
|
||||
keccak_f(1600, d.s[0..]);
|
||||
|
||||
// squeeze
|
||||
var op: usize = 0;
|
||||
var len: usize = bits / 8;
|
||||
|
||||
while (len >= d.rate) {
|
||||
mem.copy(u8, out[op..], d.s[0..d.rate]);
|
||||
keccak_f(1600, d.s[0..]);
|
||||
op += d.rate;
|
||||
len -= d.rate;
|
||||
}
|
||||
|
||||
mem.copy(u8, out[op..], d.s[0..len]);
|
||||
}
|
||||
};}
|
||||
|
||||
const RC = []const u64 {
|
||||
0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
|
||||
0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
|
||||
0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
||||
0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
|
||||
0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
|
||||
0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
|
||||
const RC = []const u64{
|
||||
0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808a,
|
||||
0x8000000080008000,
|
||||
0x000000000000808b,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008a,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000a,
|
||||
0x000000008000808b,
|
||||
0x800000000000008b,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800a,
|
||||
0x800000008000000a,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008,
|
||||
};
|
||||
|
||||
const ROTC = []const usize {
|
||||
1, 3, 6, 10, 15, 21, 28, 36,
|
||||
45, 55, 2, 14, 27, 41, 56, 8,
|
||||
25, 43, 62, 18, 39, 61, 20, 44
|
||||
const ROTC = []const usize{
|
||||
1,
|
||||
3,
|
||||
6,
|
||||
10,
|
||||
15,
|
||||
21,
|
||||
28,
|
||||
36,
|
||||
45,
|
||||
55,
|
||||
2,
|
||||
14,
|
||||
27,
|
||||
41,
|
||||
56,
|
||||
8,
|
||||
25,
|
||||
43,
|
||||
62,
|
||||
18,
|
||||
39,
|
||||
61,
|
||||
20,
|
||||
44,
|
||||
};
|
||||
|
||||
const PIL = []const usize {
|
||||
10, 7, 11, 17, 18, 3, 5, 16,
|
||||
8, 21, 24, 4, 15, 23, 19, 13,
|
||||
12, 2, 20, 14, 22, 9, 6, 1
|
||||
const PIL = []const usize{
|
||||
10,
|
||||
7,
|
||||
11,
|
||||
17,
|
||||
18,
|
||||
3,
|
||||
5,
|
||||
16,
|
||||
8,
|
||||
21,
|
||||
24,
|
||||
4,
|
||||
15,
|
||||
23,
|
||||
19,
|
||||
13,
|
||||
12,
|
||||
2,
|
||||
20,
|
||||
14,
|
||||
22,
|
||||
9,
|
||||
6,
|
||||
1,
|
||||
};
|
||||
|
||||
const M5 = []const usize {
|
||||
0, 1, 2, 3, 4, 0, 1, 2, 3, 4
|
||||
const M5 = []const usize{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
};
|
||||
|
||||
fn keccak_f(comptime F: usize, d: []u8) void {
|
||||
debug.assert(d.len == F / 8);
|
||||
|
||||
const B = F / 25;
|
||||
const no_rounds = comptime x: { break :x 12 + 2 * math.log2(B); };
|
||||
const no_rounds = comptime x: {
|
||||
break :x 12 + 2 * math.log2(B);
|
||||
};
|
||||
|
||||
var s = []const u64 {0} ** 25;
|
||||
var t = []const u64 {0} ** 1;
|
||||
var c = []const u64 {0} ** 5;
|
||||
var s = []const u64{0} ** 25;
|
||||
var t = []const u64{0} ** 1;
|
||||
var c = []const u64{0} ** 5;
|
||||
|
||||
for (s) |*r, i| {
|
||||
*r = mem.readIntLE(u64, d[8*i .. 8*i + 8]);
|
||||
r.* = mem.readIntLE(u64, d[8 * i..8 * i + 8]);
|
||||
}
|
||||
|
||||
comptime var x: usize = 0;
|
||||
comptime var y: usize = 0;
|
||||
for (RC[0..no_rounds]) |round| {
|
||||
// theta
|
||||
x = 0; inline while (x < 5) : (x += 1) {
|
||||
c[x] = s[x] ^ s[x+5] ^ s[x+10] ^ s[x+15] ^ s[x+20];
|
||||
x = 0;
|
||||
inline while (x < 5) : (x += 1) {
|
||||
c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20];
|
||||
}
|
||||
x = 0; inline while (x < 5) : (x += 1) {
|
||||
t[0] = c[M5[x+4]] ^ math.rotl(u64, c[M5[x+1]], usize(1));
|
||||
y = 0; inline while (y < 5) : (y += 1) {
|
||||
s[x + y*5] ^= t[0];
|
||||
x = 0;
|
||||
inline while (x < 5) : (x += 1) {
|
||||
t[0] = c[M5[x + 4]] ^ math.rotl(u64, c[M5[x + 1]], usize(1));
|
||||
y = 0;
|
||||
inline while (y < 5) : (y += 1) {
|
||||
s[x + y * 5] ^= t[0];
|
||||
}
|
||||
}
|
||||
|
||||
// rho+pi
|
||||
t[0] = s[1];
|
||||
x = 0; inline while (x < 24) : (x += 1) {
|
||||
x = 0;
|
||||
inline while (x < 24) : (x += 1) {
|
||||
c[0] = s[PIL[x]];
|
||||
s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);
|
||||
t[0] = c[0];
|
||||
}
|
||||
|
||||
// chi
|
||||
y = 0; inline while (y < 5) : (y += 1) {
|
||||
x = 0; inline while (x < 5) : (x += 1) {
|
||||
c[x] = s[x + y*5];
|
||||
y = 0;
|
||||
inline while (y < 5) : (y += 1) {
|
||||
x = 0;
|
||||
inline while (x < 5) : (x += 1) {
|
||||
c[x] = s[x + y * 5];
|
||||
}
|
||||
x = 0; inline while (x < 5) : (x += 1) {
|
||||
s[x + y*5] = c[x] ^ (~c[M5[x+1]] & c[M5[x+2]]);
|
||||
x = 0;
|
||||
inline while (x < 5) : (x += 1) {
|
||||
s[x + y * 5] = c[x] ^ (~c[M5[x + 1]] & c[M5[x + 2]]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,11 +240,10 @@ 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);
|
||||
mem.writeInt(d[8 * i..8 * i + 8], r, builtin.Endian.Little);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
test "sha3-224 single" {
|
||||
htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");
|
||||
htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");
|
||||
@ -192,7 +271,7 @@ test "sha3-224 streaming" {
|
||||
}
|
||||
|
||||
test "sha3-256 single" {
|
||||
htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" , "");
|
||||
htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", "");
|
||||
htest.assertEqualHash(Sha3_256, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc");
|
||||
htest.assertEqualHash(Sha3_256, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
|
||||
}
|
||||
@ -218,7 +297,7 @@ test "sha3-256 streaming" {
|
||||
}
|
||||
|
||||
test "sha3-256 aligned final" {
|
||||
var block = []u8 {0} ** Sha3_256.block_size;
|
||||
var block = []u8{0} ** Sha3_256.block_size;
|
||||
var out: [Sha3_256.digest_size]u8 = undefined;
|
||||
|
||||
var h = Sha3_256.init();
|
||||
@ -228,7 +307,7 @@ test "sha3-256 aligned final" {
|
||||
|
||||
test "sha3-384 single" {
|
||||
const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
|
||||
htest.assertEqualHash(Sha3_384, h1 , "");
|
||||
htest.assertEqualHash(Sha3_384, h1, "");
|
||||
const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
|
||||
htest.assertEqualHash(Sha3_384, h2, "abc");
|
||||
const h3 = "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7";
|
||||
@ -259,7 +338,7 @@ test "sha3-384 streaming" {
|
||||
|
||||
test "sha3-512 single" {
|
||||
const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
|
||||
htest.assertEqualHash(Sha3_512, h1 , "");
|
||||
htest.assertEqualHash(Sha3_512, h1, "");
|
||||
const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
|
||||
htest.assertEqualHash(Sha3_512, h2, "abc");
|
||||
const h3 = "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185";
|
||||
@ -289,7 +368,7 @@ test "sha3-512 streaming" {
|
||||
}
|
||||
|
||||
test "sha3-512 aligned final" {
|
||||
var block = []u8 {0} ** Sha3_512.block_size;
|
||||
var block = []u8{0} ** Sha3_512.block_size;
|
||||
var out: [Sha3_512.digest_size]u8 = undefined;
|
||||
|
||||
var h = Sha3_512.init();
|
||||
|
||||
@ -14,9 +14,8 @@ pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, inpu
|
||||
pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
|
||||
var expected_bytes: [expected.len / 2]u8 = undefined;
|
||||
for (expected_bytes) |*r, i| {
|
||||
*r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;
|
||||
r.* = fmt.parseInt(u8, expected[2 * i..2 * i + 2], 16) catch unreachable;
|
||||
}
|
||||
|
||||
debug.assert(mem.eql(u8, expected_bytes, input));
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ const Timer = time.Timer;
|
||||
const HashFunction = @import("md5.zig").Md5;
|
||||
|
||||
const MiB = 1024 * 1024;
|
||||
const BytesToHash = 1024 * MiB;
|
||||
const BytesToHash = 1024 * MiB;
|
||||
|
||||
pub fn main() !void {
|
||||
var stdout_file = try std.io.getStdOut();
|
||||
|
||||
@ -9,7 +9,6 @@ pub const line_sep = switch (builtin.os) {
|
||||
else => "\n",
|
||||
};
|
||||
|
||||
|
||||
pub fn len(ptr: &const u8) usize {
|
||||
var count: usize = 0;
|
||||
while (ptr[count] != 0) : (count += 1) {}
|
||||
@ -95,7 +94,7 @@ pub const NullTerminated2DArray = struct {
|
||||
}
|
||||
index_buf[i] = null;
|
||||
|
||||
return NullTerminated2DArray {
|
||||
return NullTerminated2DArray{
|
||||
.allocator = allocator,
|
||||
.byte_count = byte_count,
|
||||
.ptr = @ptrCast(?&?&u8, buf.ptr),
|
||||
@ -107,4 +106,3 @@ pub const NullTerminated2DArray = struct {
|
||||
self.allocator.free(buf[0..self.byte_count]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -13,14 +13,14 @@ pub const FailingAllocator = struct {
|
||||
deallocations: usize,
|
||||
|
||||
pub fn init(allocator: &mem.Allocator, fail_index: usize) FailingAllocator {
|
||||
return FailingAllocator {
|
||||
return FailingAllocator{
|
||||
.internal_allocator = allocator,
|
||||
.fail_index = fail_index,
|
||||
.index = 0,
|
||||
.allocated_bytes = 0,
|
||||
.freed_bytes = 0,
|
||||
.deallocations = 0,
|
||||
.allocator = mem.Allocator {
|
||||
.allocator = mem.Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
|
||||
@ -104,9 +104,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
|
||||
|
||||
var panicking: u8 = 0; // TODO make this a bool
|
||||
|
||||
pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize,
|
||||
comptime format: []const u8, args: ...) noreturn
|
||||
{
|
||||
pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
|
||||
@setCold(true);
|
||||
|
||||
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
|
||||
@ -132,9 +130,7 @@ const WHITE = "\x1b[37;1m";
|
||||
const DIM = "\x1b[2m";
|
||||
const RESET = "\x1b[0m";
|
||||
|
||||
pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
|
||||
debug_info: &ElfStackTrace, tty_color: bool) !void
|
||||
{
|
||||
pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool) !void {
|
||||
var frame_index: usize = undefined;
|
||||
var frames_left: usize = undefined;
|
||||
if (stack_trace.index < stack_trace.instruction_addresses.len) {
|
||||
@ -154,9 +150,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
|
||||
debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void
|
||||
{
|
||||
pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void {
|
||||
const AddressState = union(enum) {
|
||||
NotLookingForStartAddress,
|
||||
LookingForStartAddress: usize,
|
||||
@ -166,14 +160,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
|
||||
// else AddressState.NotLookingForStartAddress;
|
||||
var addr_state: AddressState = undefined;
|
||||
if (start_addr) |addr| {
|
||||
addr_state = AddressState { .LookingForStartAddress = addr };
|
||||
addr_state = AddressState{ .LookingForStartAddress = addr };
|
||||
} else {
|
||||
addr_state = AddressState.NotLookingForStartAddress;
|
||||
}
|
||||
|
||||
var fp = @ptrToInt(@frameAddress());
|
||||
while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
|
||||
const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
|
||||
while (fp != 0) : (fp = @intToPtr(&const usize, fp).*) {
|
||||
const return_address = @intToPtr(&const usize, fp + @sizeOf(usize)).*;
|
||||
|
||||
switch (addr_state) {
|
||||
AddressState.NotLookingForStartAddress => {},
|
||||
@ -200,32 +194,32 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
|
||||
// in practice because the compiler dumps everything in a single
|
||||
// object file. Future improvement: use external dSYM data when
|
||||
// available.
|
||||
const unknown = macho.Symbol { .name = "???", .address = address };
|
||||
const unknown = macho.Symbol{
|
||||
.name = "???",
|
||||
.address = address,
|
||||
};
|
||||
const symbol = debug_info.symbol_table.search(address) ?? &unknown;
|
||||
try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++
|
||||
DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n",
|
||||
symbol.name, address);
|
||||
try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address);
|
||||
},
|
||||
else => {
|
||||
const compile_unit = findCompileUnit(debug_info, address) catch {
|
||||
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
|
||||
address);
|
||||
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", address);
|
||||
return;
|
||||
};
|
||||
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
|
||||
if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
|
||||
defer line_info.deinit();
|
||||
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
|
||||
DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
|
||||
line_info.file_name, line_info.line, line_info.column,
|
||||
address, compile_unit_name);
|
||||
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", line_info.file_name, line_info.line, line_info.column, address, compile_unit_name);
|
||||
if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
|
||||
if (line_info.column == 0) {
|
||||
try out_stream.write("\n");
|
||||
} else {
|
||||
{var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
|
||||
try out_stream.writeByte(' ');
|
||||
}}
|
||||
{
|
||||
var col_i: usize = 1;
|
||||
while (col_i < line_info.column) : (col_i += 1) {
|
||||
try out_stream.writeByte(' ');
|
||||
}
|
||||
}
|
||||
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
|
||||
}
|
||||
} else |err| switch (err) {
|
||||
@ -247,7 +241,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
|
||||
builtin.ObjectFormat.elf => {
|
||||
const st = try allocator.create(ElfStackTrace);
|
||||
errdefer allocator.destroy(st);
|
||||
*st = ElfStackTrace {
|
||||
st.* = ElfStackTrace{
|
||||
.self_exe_file = undefined,
|
||||
.elf = undefined,
|
||||
.debug_info = undefined,
|
||||
@ -279,9 +273,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
|
||||
const st = try allocator.create(ElfStackTrace);
|
||||
errdefer allocator.destroy(st);
|
||||
|
||||
*st = ElfStackTrace {
|
||||
.symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)),
|
||||
};
|
||||
st.* = ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) };
|
||||
|
||||
return st;
|
||||
},
|
||||
@ -325,8 +317,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &con
|
||||
}
|
||||
}
|
||||
|
||||
if (amt_read < buf.len)
|
||||
return error.EndOfFile;
|
||||
if (amt_read < buf.len) return error.EndOfFile;
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,10 +409,8 @@ const Constant = struct {
|
||||
signed: bool,
|
||||
|
||||
fn asUnsignedLe(self: &const Constant) !u64 {
|
||||
if (self.payload.len > @sizeOf(u64))
|
||||
return error.InvalidDebugInfo;
|
||||
if (self.signed)
|
||||
return error.InvalidDebugInfo;
|
||||
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
|
||||
if (self.signed) return error.InvalidDebugInfo;
|
||||
return mem.readInt(self.payload, u64, builtin.Endian.Little);
|
||||
}
|
||||
};
|
||||
@ -438,15 +427,14 @@ const Die = struct {
|
||||
|
||||
fn getAttr(self: &const Die, id: u64) ?&const FormValue {
|
||||
for (self.attrs.toSliceConst()) |*attr| {
|
||||
if (attr.id == id)
|
||||
return &attr.value;
|
||||
if (attr.id == id) return &attr.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn getAttrAddr(self: &const Die, id: u64) !u64 {
|
||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||
return switch (*form_value) {
|
||||
return switch (form_value.*) {
|
||||
FormValue.Address => |value| value,
|
||||
else => error.InvalidDebugInfo,
|
||||
};
|
||||
@ -454,7 +442,7 @@ const Die = struct {
|
||||
|
||||
fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
|
||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||
return switch (*form_value) {
|
||||
return switch (form_value.*) {
|
||||
FormValue.Const => |value| value.asUnsignedLe(),
|
||||
FormValue.SecOffset => |value| value,
|
||||
else => error.InvalidDebugInfo,
|
||||
@ -463,7 +451,7 @@ const Die = struct {
|
||||
|
||||
fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
|
||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||
return switch (*form_value) {
|
||||
return switch (form_value.*) {
|
||||
FormValue.Const => |value| value.asUnsignedLe(),
|
||||
else => error.InvalidDebugInfo,
|
||||
};
|
||||
@ -471,7 +459,7 @@ const Die = struct {
|
||||
|
||||
fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
|
||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
||||
return switch (*form_value) {
|
||||
return switch (form_value.*) {
|
||||
FormValue.String => |value| value,
|
||||
FormValue.StrPtr => |offset| getString(st, offset),
|
||||
else => error.InvalidDebugInfo,
|
||||
@ -518,10 +506,8 @@ const LineNumberProgram = struct {
|
||||
prev_basic_block: bool,
|
||||
prev_end_sequence: bool,
|
||||
|
||||
pub fn init(is_stmt: bool, include_dirs: []const []const u8,
|
||||
file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram
|
||||
{
|
||||
return LineNumberProgram {
|
||||
pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram {
|
||||
return LineNumberProgram{
|
||||
.address = 0,
|
||||
.file = 1,
|
||||
.line = 1,
|
||||
@ -548,14 +534,16 @@ const LineNumberProgram = struct {
|
||||
return error.MissingDebugInfo;
|
||||
} else if (self.prev_file - 1 >= self.file_entries.len) {
|
||||
return error.InvalidDebugInfo;
|
||||
} else &self.file_entries.items[self.prev_file - 1];
|
||||
} else
|
||||
&self.file_entries.items[self.prev_file - 1];
|
||||
|
||||
const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
|
||||
return error.InvalidDebugInfo;
|
||||
} else self.include_dirs[file_entry.dir_index];
|
||||
} 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);
|
||||
errdefer self.file_entries.allocator.free(file_name);
|
||||
return LineInfo {
|
||||
return LineInfo{
|
||||
.line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
|
||||
.column = self.prev_column,
|
||||
.file_name = file_name,
|
||||
@ -578,8 +566,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
|
||||
var buf = ArrayList(u8).init(allocator);
|
||||
while (true) {
|
||||
const byte = try in_stream.readByte();
|
||||
if (byte == 0)
|
||||
break;
|
||||
if (byte == 0) break;
|
||||
try buf.append(byte);
|
||||
}
|
||||
return buf.toSlice();
|
||||
@ -600,7 +587,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8
|
||||
|
||||
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue { .Block = buf };
|
||||
return FormValue{ .Block = buf };
|
||||
}
|
||||
|
||||
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||
@ -609,26 +596,25 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !
|
||||
}
|
||||
|
||||
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
|
||||
return FormValue { .Const = Constant {
|
||||
.signed = signed,
|
||||
.payload = try readAllocBytes(allocator, in_stream, size),
|
||||
}};
|
||||
return FormValue{
|
||||
.Const = Constant{
|
||||
.signed = signed,
|
||||
.payload = try readAllocBytes(allocator, in_stream, size),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
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.readIntLe(u64) else u64(try in_stream.readIntLe(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.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
|
||||
}
|
||||
|
||||
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue { .Ref = buf };
|
||||
return FormValue{ .Ref = buf };
|
||||
}
|
||||
|
||||
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
|
||||
@ -636,7 +622,7 @@ fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type
|
||||
return parseFormValueRefLen(allocator, in_stream, block_len);
|
||||
}
|
||||
|
||||
const ParseFormValueError = error {
|
||||
const ParseFormValueError = error{
|
||||
EndOfStream,
|
||||
Io,
|
||||
BadFd,
|
||||
@ -646,11 +632,9 @@ const ParseFormValueError = error {
|
||||
OutOfMemory,
|
||||
};
|
||||
|
||||
fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)
|
||||
ParseFormValueError!FormValue
|
||||
{
|
||||
fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
|
||||
return switch (form_id) {
|
||||
DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },
|
||||
DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
|
||||
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
|
||||
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
|
||||
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
|
||||
@ -670,11 +654,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
|
||||
DW.FORM_exprloc => {
|
||||
const size = try readULeb128(in_stream);
|
||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue { .ExprLoc = buf };
|
||||
return FormValue{ .ExprLoc = buf };
|
||||
},
|
||||
DW.FORM_flag => FormValue { .Flag = (try in_stream.readByte()) != 0 },
|
||||
DW.FORM_flag_present => FormValue { .Flag = true },
|
||||
DW.FORM_sec_offset => FormValue { .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
|
||||
DW.FORM_flag_present => FormValue{ .Flag = true },
|
||||
DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
|
||||
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
|
||||
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
|
||||
@ -685,11 +669,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
|
||||
return parseFormValueRefLen(allocator, in_stream, ref_len);
|
||||
},
|
||||
|
||||
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_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
|
||||
|
||||
DW.FORM_string => FormValue { .String = try readStringRaw(allocator, in_stream) },
|
||||
DW.FORM_strp => FormValue { .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
|
||||
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_indirect => {
|
||||
const child_form_id = try readULeb128(in_stream);
|
||||
return parseFormValue(allocator, in_stream, child_form_id, is_64);
|
||||
@ -705,9 +689,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
|
||||
var result = AbbrevTable.init(st.allocator());
|
||||
while (true) {
|
||||
const abbrev_code = try readULeb128(in_stream);
|
||||
if (abbrev_code == 0)
|
||||
return result;
|
||||
try result.append(AbbrevTableEntry {
|
||||
if (abbrev_code == 0) return result;
|
||||
try result.append(AbbrevTableEntry{
|
||||
.abbrev_code = abbrev_code,
|
||||
.tag_id = try readULeb128(in_stream),
|
||||
.has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
|
||||
@ -718,9 +701,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
|
||||
while (true) {
|
||||
const attr_id = try readULeb128(in_stream);
|
||||
const form_id = try readULeb128(in_stream);
|
||||
if (attr_id == 0 and form_id == 0)
|
||||
break;
|
||||
try attrs.append(AbbrevAttr {
|
||||
if (attr_id == 0 and form_id == 0) break;
|
||||
try attrs.append(AbbrevAttr{
|
||||
.attr_id = attr_id,
|
||||
.form_id = form_id,
|
||||
});
|
||||
@ -737,7 +719,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
|
||||
}
|
||||
}
|
||||
try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
|
||||
try st.abbrev_table_list.append(AbbrevTableHeader {
|
||||
try st.abbrev_table_list.append(AbbrevTableHeader{
|
||||
.offset = abbrev_offset,
|
||||
.table = try parseAbbrevTable(st),
|
||||
});
|
||||
@ -746,8 +728,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
|
||||
|
||||
fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {
|
||||
for (abbrev_table.toSliceConst()) |*table_entry| {
|
||||
if (table_entry.abbrev_code == abbrev_code)
|
||||
return table_entry;
|
||||
if (table_entry.abbrev_code == abbrev_code) return table_entry;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -759,14 +740,14 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !
|
||||
const abbrev_code = try readULeb128(in_stream);
|
||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
|
||||
|
||||
var result = Die {
|
||||
var result = Die{
|
||||
.tag_id = table_entry.tag_id,
|
||||
.has_children = table_entry.has_children,
|
||||
.attrs = ArrayList(Die.Attr).init(st.allocator()),
|
||||
};
|
||||
try result.attrs.resize(table_entry.attrs.len);
|
||||
for (table_entry.attrs.toSliceConst()) |attr, i| {
|
||||
result.attrs.items[i] = Die.Attr {
|
||||
result.attrs.items[i] = Die.Attr{
|
||||
.id = attr.attr_id,
|
||||
.value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
|
||||
};
|
||||
@ -790,8 +771,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
||||
if (unit_length == 0)
|
||||
return error.MissingDebugInfo;
|
||||
if (unit_length == 0) return error.MissingDebugInfo;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
||||
if (compile_unit.index != this_index) {
|
||||
@ -803,8 +783,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
||||
// TODO support 3 and 5
|
||||
if (version != 2 and version != 4) return error.InvalidDebugInfo;
|
||||
|
||||
const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64)
|
||||
else try in_stream.readInt(st.elf.endian, u32);
|
||||
const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
|
||||
const prog_start_offset = (try in_file.getPos()) + prologue_length;
|
||||
|
||||
const minimum_instruction_length = try in_stream.readByte();
|
||||
@ -819,38 +798,37 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
||||
const line_base = try in_stream.readByteSigned();
|
||||
|
||||
const line_range = try in_stream.readByte();
|
||||
if (line_range == 0)
|
||||
return error.InvalidDebugInfo;
|
||||
if (line_range == 0) return error.InvalidDebugInfo;
|
||||
|
||||
const opcode_base = try in_stream.readByte();
|
||||
|
||||
const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);
|
||||
|
||||
{var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
|
||||
standard_opcode_lengths[i] = try in_stream.readByte();
|
||||
}}
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < opcode_base - 1) : (i += 1) {
|
||||
standard_opcode_lengths[i] = try in_stream.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
var include_directories = ArrayList([]u8).init(st.allocator());
|
||||
try include_directories.append(compile_unit_cwd);
|
||||
while (true) {
|
||||
const dir = try st.readString();
|
||||
if (dir.len == 0)
|
||||
break;
|
||||
if (dir.len == 0) break;
|
||||
try include_directories.append(dir);
|
||||
}
|
||||
|
||||
var file_entries = ArrayList(FileEntry).init(st.allocator());
|
||||
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
|
||||
&file_entries, target_address);
|
||||
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
|
||||
|
||||
while (true) {
|
||||
const file_name = try st.readString();
|
||||
if (file_name.len == 0)
|
||||
break;
|
||||
if (file_name.len == 0) break;
|
||||
const dir_index = try readULeb128(in_stream);
|
||||
const mtime = try readULeb128(in_stream);
|
||||
const len_bytes = try readULeb128(in_stream);
|
||||
try file_entries.append(FileEntry {
|
||||
try file_entries.append(FileEntry{
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
.mtime = mtime,
|
||||
@ -866,8 +844,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
||||
var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
|
||||
if (opcode == DW.LNS_extended_op) {
|
||||
const op_size = try readULeb128(in_stream);
|
||||
if (op_size < 1)
|
||||
return error.InvalidDebugInfo;
|
||||
if (op_size < 1) return error.InvalidDebugInfo;
|
||||
sub_op = try in_stream.readByte();
|
||||
switch (sub_op) {
|
||||
DW.LNE_end_sequence => {
|
||||
@ -884,7 +861,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
||||
const dir_index = try readULeb128(in_stream);
|
||||
const mtime = try readULeb128(in_stream);
|
||||
const len_bytes = try readULeb128(in_stream);
|
||||
try file_entries.append(FileEntry {
|
||||
try file_entries.append(FileEntry{
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
.mtime = mtime,
|
||||
@ -941,11 +918,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
|
||||
const arg = try in_stream.readInt(st.elf.endian, u16);
|
||||
prog.address += arg;
|
||||
},
|
||||
DW.LNS_set_prologue_end => {
|
||||
},
|
||||
DW.LNS_set_prologue_end => {},
|
||||
else => {
|
||||
if (opcode - 1 >= standard_opcode_lengths.len)
|
||||
return error.InvalidDebugInfo;
|
||||
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
|
||||
const len_bytes = standard_opcode_lengths[opcode - 1];
|
||||
try in_file.seekForward(len_bytes);
|
||||
},
|
||||
@ -972,16 +947,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
||||
if (unit_length == 0)
|
||||
return;
|
||||
if (unit_length == 0) return;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
||||
const version = try in_stream.readInt(st.elf.endian, u16);
|
||||
if (version < 2 or version > 5) return error.InvalidDebugInfo;
|
||||
|
||||
const debug_abbrev_offset =
|
||||
if (is_64) try in_stream.readInt(st.elf.endian, u64)
|
||||
else try in_stream.readInt(st.elf.endian, u32);
|
||||
const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
|
||||
|
||||
const address_size = try in_stream.readByte();
|
||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||
@ -992,15 +964,14 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
||||
try st.self_exe_file.seekTo(compile_unit_pos);
|
||||
|
||||
const compile_unit_die = try st.allocator().create(Die);
|
||||
*compile_unit_die = try parseDie(st, abbrev_table, is_64);
|
||||
compile_unit_die.* = try parseDie(st, abbrev_table, is_64);
|
||||
|
||||
if (compile_unit_die.tag_id != DW.TAG_compile_unit)
|
||||
return error.InvalidDebugInfo;
|
||||
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
|
||||
|
||||
const pc_range = x: {
|
||||
if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
|
||||
if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
|
||||
const pc_end = switch (*high_pc_value) {
|
||||
const pc_end = switch (high_pc_value.*) {
|
||||
FormValue.Address => |value| value,
|
||||
FormValue.Const => |value| b: {
|
||||
const offset = try value.asUnsignedLe();
|
||||
@ -1008,7 +979,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
||||
},
|
||||
else => return error.InvalidDebugInfo,
|
||||
};
|
||||
break :x PcRange {
|
||||
break :x PcRange{
|
||||
.start = low_pc,
|
||||
.end = pc_end,
|
||||
};
|
||||
@ -1016,13 +987,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
|
||||
break :x null;
|
||||
}
|
||||
} else |err| {
|
||||
if (err != error.MissingDebugInfo)
|
||||
return err;
|
||||
if (err != error.MissingDebugInfo) return err;
|
||||
break :x null;
|
||||
}
|
||||
};
|
||||
|
||||
try st.compile_unit_list.append(CompileUnit {
|
||||
try st.compile_unit_list.append(CompileUnit{
|
||||
.version = version,
|
||||
.is_64 = is_64,
|
||||
.pc_range = pc_range,
|
||||
@ -1040,8 +1010,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
|
||||
const in_stream = &in_file_stream.stream;
|
||||
for (st.compile_unit_list.toSlice()) |*compile_unit| {
|
||||
if (compile_unit.pc_range) |range| {
|
||||
if (target_address >= range.start and target_address < range.end)
|
||||
return compile_unit;
|
||||
if (target_address >= range.start and target_address < range.end) return compile_unit;
|
||||
}
|
||||
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
|
||||
var base_address: usize = 0;
|
||||
@ -1063,8 +1032,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
|
||||
}
|
||||
}
|
||||
} else |err| {
|
||||
if (err != error.MissingDebugInfo)
|
||||
return err;
|
||||
if (err != error.MissingDebugInfo) return err;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -1073,8 +1041,8 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
|
||||
|
||||
fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
|
||||
const first_32_bits = try in_stream.readIntLe(u32);
|
||||
*is_64 = (first_32_bits == 0xffffffff);
|
||||
if (*is_64) {
|
||||
is_64.* = (first_32_bits == 0xffffffff);
|
||||
if (is_64.*) {
|
||||
return in_stream.readIntLe(u64);
|
||||
} else {
|
||||
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
||||
@ -1091,13 +1059,11 @@ fn readULeb128(in_stream: var) !u64 {
|
||||
|
||||
var operand: u64 = undefined;
|
||||
|
||||
if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
|
||||
return error.InvalidDebugInfo;
|
||||
if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
|
||||
|
||||
result |= operand;
|
||||
|
||||
if ((byte & 0b10000000) == 0)
|
||||
return result;
|
||||
if ((byte & 0b10000000) == 0) return result;
|
||||
|
||||
shift += 7;
|
||||
}
|
||||
@ -1112,15 +1078,13 @@ fn readILeb128(in_stream: var) !i64 {
|
||||
|
||||
var operand: i64 = undefined;
|
||||
|
||||
if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
|
||||
return error.InvalidDebugInfo;
|
||||
if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
|
||||
|
||||
result |= operand;
|
||||
shift += 7;
|
||||
|
||||
if ((byte & 0b10000000) == 0) {
|
||||
if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
|
||||
result |= -(i64(1) << u6(shift));
|
||||
if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << u6(shift));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1131,7 +1095,6 @@ pub const global_allocator = &global_fixed_allocator.allocator;
|
||||
var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
|
||||
var global_allocator_mem: [100 * 1024]u8 = undefined;
|
||||
|
||||
|
||||
// TODO make thread safe
|
||||
var debug_info_allocator: ?&mem.Allocator = null;
|
||||
var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
|
||||
|
||||
@ -337,7 +337,6 @@ pub const AT_PGI_lbase = 0x3a00;
|
||||
pub const AT_PGI_soffset = 0x3a01;
|
||||
pub const AT_PGI_lstride = 0x3a02;
|
||||
|
||||
|
||||
pub const OP_addr = 0x03;
|
||||
pub const OP_deref = 0x06;
|
||||
pub const OP_const1u = 0x08;
|
||||
@ -577,7 +576,6 @@ pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.
|
||||
pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.
|
||||
pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.
|
||||
|
||||
|
||||
pub const CFA_advance_loc = 0x40;
|
||||
pub const CFA_offset = 0x80;
|
||||
pub const CFA_restore = 0xc0;
|
||||
|
||||
42
std/elf.zig
42
std/elf.zig
@ -123,13 +123,11 @@ pub const DT_SYMINFO = 0x6ffffeff;
|
||||
pub const DT_ADDRRNGHI = 0x6ffffeff;
|
||||
pub const DT_ADDRNUM = 11;
|
||||
|
||||
|
||||
pub const DT_VERSYM = 0x6ffffff0;
|
||||
|
||||
pub const DT_RELACOUNT = 0x6ffffff9;
|
||||
pub const DT_RELCOUNT = 0x6ffffffa;
|
||||
|
||||
|
||||
pub const DT_FLAGS_1 = 0x6ffffffb;
|
||||
pub const DT_VERDEF = 0x6ffffffc;
|
||||
|
||||
@ -139,13 +137,10 @@ pub const DT_VERNEED = 0x6ffffffe;
|
||||
pub const DT_VERNEEDNUM = 0x6fffffff;
|
||||
pub const DT_VERSIONTAGNUM = 16;
|
||||
|
||||
|
||||
|
||||
pub const DT_AUXILIARY = 0x7ffffffd;
|
||||
pub const DT_FILTER = 0x7fffffff;
|
||||
pub const DT_EXTRANUM = 3;
|
||||
|
||||
|
||||
pub const DT_SPARC_REGISTER = 0x70000001;
|
||||
pub const DT_SPARC_NUM = 2;
|
||||
|
||||
@ -434,9 +429,7 @@ pub const Elf = struct {
|
||||
try elf.in_file.seekForward(4);
|
||||
|
||||
const header_size = try in.readInt(elf.endian, u16);
|
||||
if ((elf.is_64 and header_size != 64) or
|
||||
(!elf.is_64 and header_size != 52))
|
||||
{
|
||||
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
@ -467,16 +460,16 @@ 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(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);
|
||||
}
|
||||
} else {
|
||||
if (sh_entry_size != 40) return error.InvalidFormat;
|
||||
@ -513,8 +506,7 @@ pub const Elf = struct {
|
||||
pub fn close(elf: &Elf) void {
|
||||
elf.allocator.free(elf.section_headers);
|
||||
|
||||
if (elf.auto_close_stream)
|
||||
elf.in_file.close();
|
||||
if (elf.auto_close_stream) elf.in_file.close();
|
||||
}
|
||||
|
||||
pub fn findSection(elf: &Elf, name: []const u8) !?&SectionHeader {
|
||||
@ -852,27 +844,27 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
|
||||
flags2: Elf32_Word,
|
||||
};
|
||||
|
||||
pub const Ehdr = switch(@sizeOf(usize)) {
|
||||
pub const Ehdr = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Ehdr,
|
||||
8 => Elf64_Ehdr,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Phdr = switch(@sizeOf(usize)) {
|
||||
pub const Phdr = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Phdr,
|
||||
8 => Elf64_Phdr,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Sym = switch(@sizeOf(usize)) {
|
||||
pub const Sym = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Sym,
|
||||
8 => Elf64_Sym,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Verdef = switch(@sizeOf(usize)) {
|
||||
pub const Verdef = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Verdef,
|
||||
8 => Elf64_Verdef,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Verdaux = switch(@sizeOf(usize)) {
|
||||
pub const Verdaux = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Verdaux,
|
||||
8 => Elf64_Verdaux,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
|
||||
@ -6,7 +6,7 @@ const mem = std.mem;
|
||||
const posix = std.os.posix;
|
||||
|
||||
pub const TcpServer = struct {
|
||||
handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
|
||||
handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void,
|
||||
|
||||
loop: &Loop,
|
||||
sockfd: i32,
|
||||
@ -18,13 +18,11 @@ pub const TcpServer = struct {
|
||||
const PromiseNode = std.LinkedList(promise).Node;
|
||||
|
||||
pub fn init(loop: &Loop) !TcpServer {
|
||||
const sockfd = try std.os.posixSocket(posix.AF_INET,
|
||||
posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
|
||||
posix.PROTO_tcp);
|
||||
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
|
||||
errdefer std.os.close(sockfd);
|
||||
|
||||
// TODO can't initialize handler coroutine here because we need well defined copy elision
|
||||
return TcpServer {
|
||||
return TcpServer{
|
||||
.loop = loop,
|
||||
.sockfd = sockfd,
|
||||
.accept_coro = null,
|
||||
@ -34,9 +32,7 @@ pub const TcpServer = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn listen(self: &TcpServer, address: &const std.net.Address,
|
||||
handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
|
||||
{
|
||||
pub fn listen(self: &TcpServer, address: &const std.net.Address, handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void) !void {
|
||||
self.handleRequestFn = handleRequestFn;
|
||||
|
||||
try std.os.posixBind(self.sockfd, &address.os_addr);
|
||||
@ -48,7 +44,6 @@ pub const TcpServer = struct {
|
||||
|
||||
try self.loop.addFd(self.sockfd, ??self.accept_coro);
|
||||
errdefer self.loop.removeFd(self.sockfd);
|
||||
|
||||
}
|
||||
|
||||
pub fn deinit(self: &TcpServer) void {
|
||||
@ -60,9 +55,7 @@ pub const TcpServer = struct {
|
||||
pub async fn handler(self: &TcpServer) void {
|
||||
while (true) {
|
||||
var accepted_addr: std.net.Address = undefined;
|
||||
if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
|
||||
posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
|
||||
{
|
||||
if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {
|
||||
var socket = std.os.File.openHandle(accepted_fd);
|
||||
_ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
|
||||
error.OutOfMemory => {
|
||||
@ -83,19 +76,14 @@ pub const TcpServer = struct {
|
||||
}
|
||||
continue;
|
||||
},
|
||||
error.ConnectionAborted,
|
||||
error.FileDescriptorClosed => continue,
|
||||
error.ConnectionAborted, error.FileDescriptorClosed => continue,
|
||||
|
||||
error.PageFault => unreachable,
|
||||
error.InvalidSyscall => unreachable,
|
||||
error.FileDescriptorNotASocket => unreachable,
|
||||
error.OperationNotSupported => unreachable,
|
||||
|
||||
error.SystemFdQuotaExceeded,
|
||||
error.SystemResources,
|
||||
error.ProtocolFailure,
|
||||
error.BlockedByFirewall,
|
||||
error.Unexpected => {
|
||||
error.SystemFdQuotaExceeded, error.SystemResources, error.ProtocolFailure, error.BlockedByFirewall, error.Unexpected => {
|
||||
@panic("TODO handle this error");
|
||||
},
|
||||
}
|
||||
@ -110,7 +98,7 @@ pub const Loop = struct {
|
||||
|
||||
fn init(allocator: &mem.Allocator) !Loop {
|
||||
const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
|
||||
return Loop {
|
||||
return Loop{
|
||||
.keep_running = true,
|
||||
.allocator = allocator,
|
||||
.epollfd = epollfd,
|
||||
@ -118,11 +106,9 @@ pub const Loop = struct {
|
||||
}
|
||||
|
||||
pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
|
||||
var ev = std.os.linux.epoll_event {
|
||||
.events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,
|
||||
.data = std.os.linux.epoll_data {
|
||||
.ptr = @ptrToInt(prom),
|
||||
},
|
||||
var ev = std.os.linux.epoll_event{
|
||||
.events = std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,
|
||||
.data = std.os.linux.epoll_data{ .ptr = @ptrToInt(prom) },
|
||||
};
|
||||
try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
|
||||
}
|
||||
@ -130,7 +116,6 @@ pub const Loop = struct {
|
||||
pub fn removeFd(self: &Loop, fd: i32) void {
|
||||
std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
|
||||
}
|
||||
|
||||
async fn waitFd(self: &Loop, fd: i32) !void {
|
||||
defer self.removeFd(fd);
|
||||
suspend |p| {
|
||||
@ -157,9 +142,9 @@ pub const Loop = struct {
|
||||
};
|
||||
|
||||
pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
|
||||
var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733
|
||||
var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733
|
||||
|
||||
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);
|
||||
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
|
||||
errdefer std.os.close(sockfd);
|
||||
|
||||
try std.os.posixConnectAsync(sockfd, &address.os_addr);
|
||||
@ -178,12 +163,9 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
tcp_server: TcpServer,
|
||||
|
||||
const Self = this;
|
||||
|
||||
async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,
|
||||
_socket: &const std.os.File) void
|
||||
{
|
||||
async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address, _socket: &const std.os.File) void {
|
||||
const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
|
||||
var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
|
||||
var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
|
||||
defer socket.close();
|
||||
const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("unable to handle connection: out of memory"),
|
||||
@ -191,14 +173,13 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
(await next_handler) catch |err| {
|
||||
std.debug.panic("unable to handle connection: {}\n", err);
|
||||
};
|
||||
suspend |p| { cancel p; }
|
||||
suspend |p| {
|
||||
cancel p;
|
||||
}
|
||||
}
|
||||
|
||||
async fn errorableHandler(self: &Self, _addr: &const std.net.Address,
|
||||
_socket: &const std.os.File) !void
|
||||
{
|
||||
const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
|
||||
var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
|
||||
async fn errorableHandler(self: &Self, _addr: &const std.net.Address, _socket: &const std.os.File) !void {
|
||||
const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
|
||||
var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
|
||||
|
||||
var adapter = std.io.FileOutStream.init(&socket);
|
||||
var stream = &adapter.stream;
|
||||
@ -210,9 +191,7 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
const addr = std.net.Address.initIp4(ip4addr, 0);
|
||||
|
||||
var loop = try Loop.init(std.debug.global_allocator);
|
||||
var server = MyServer {
|
||||
.tcp_server = try TcpServer.init(&loop),
|
||||
};
|
||||
var server = MyServer{ .tcp_server = try TcpServer.init(&loop) };
|
||||
defer server.tcp_server.deinit();
|
||||
try server.tcp_server.listen(addr, MyServer.handler);
|
||||
|
||||
@ -220,7 +199,6 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
defer cancel p;
|
||||
loop.run();
|
||||
}
|
||||
|
||||
async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void {
|
||||
errdefer @panic("test failure");
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pub const enum3 = []u64 {
|
||||
pub const enum3 = []u64{
|
||||
0x4e2e2785c3a2a20b,
|
||||
0x240a28877a09a4e1,
|
||||
0x728fca36c06cf106,
|
||||
@ -439,13 +439,13 @@ const Slab = struct {
|
||||
};
|
||||
|
||||
fn slab(str: []const u8, exp: i32) Slab {
|
||||
return Slab {
|
||||
return Slab{
|
||||
.str = str,
|
||||
.exp = exp,
|
||||
};
|
||||
}
|
||||
|
||||
pub const enum3_data = []Slab {
|
||||
pub const enum3_data = []Slab{
|
||||
slab("40648030339495312", 69),
|
||||
slab("4498645355592131", -134),
|
||||
slab("678321594594593", 244),
|
||||
@ -879,4 +879,3 @@ pub const enum3_data = []Slab {
|
||||
slab("32216657306260762", 218),
|
||||
slab("30423431424080128", 219),
|
||||
};
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
|
||||
const data = enum3_data[i];
|
||||
const digits = buffer[1..data.str.len + 1];
|
||||
mem.copy(u8, digits, data.str);
|
||||
return FloatDecimal {
|
||||
return FloatDecimal{
|
||||
.digits = digits,
|
||||
.exp = data.exp,
|
||||
};
|
||||
@ -98,14 +98,12 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
|
||||
/// Uncorrected Errol3 double to ASCII conversion.
|
||||
fn errol3u(val: f64, buffer: []u8) FloatDecimal {
|
||||
// check if in integer or fixed range
|
||||
|
||||
if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
|
||||
return errolInt(val, buffer);
|
||||
} else if (val >= 16.0 and val < 9.007199254740992e15) {
|
||||
return errolFixed(val, buffer);
|
||||
}
|
||||
|
||||
|
||||
// normalize the midpoint
|
||||
|
||||
const e = math.frexp(val).exponent;
|
||||
@ -137,11 +135,11 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
|
||||
}
|
||||
|
||||
// compute boundaries
|
||||
var high = HP {
|
||||
var high = HP{
|
||||
.val = mid.val,
|
||||
.off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
|
||||
};
|
||||
var low = HP {
|
||||
var low = HP{
|
||||
.val = mid.val,
|
||||
.off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
|
||||
};
|
||||
@ -171,15 +169,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
|
||||
var buf_index: usize = 1;
|
||||
while (true) {
|
||||
var hdig = u8(math.floor(high.val));
|
||||
if ((high.val == f64(hdig)) and (high.off < 0))
|
||||
hdig -= 1;
|
||||
if ((high.val == f64(hdig)) and (high.off < 0)) hdig -= 1;
|
||||
|
||||
var ldig = u8(math.floor(low.val));
|
||||
if ((low.val == f64(ldig)) and (low.off < 0))
|
||||
ldig -= 1;
|
||||
if ((low.val == f64(ldig)) and (low.off < 0)) ldig -= 1;
|
||||
|
||||
if (ldig != hdig)
|
||||
break;
|
||||
if (ldig != hdig) break;
|
||||
|
||||
buffer[buf_index] = hdig + '0';
|
||||
buf_index += 1;
|
||||
@ -191,13 +186,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
|
||||
|
||||
const tmp = (high.val + low.val) / 2.0;
|
||||
var mdig = u8(math.floor(tmp + 0.5));
|
||||
if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0)
|
||||
mdig -= 1;
|
||||
if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
|
||||
|
||||
buffer[buf_index] = mdig + '0';
|
||||
buf_index += 1;
|
||||
|
||||
return FloatDecimal {
|
||||
return FloatDecimal{
|
||||
.digits = buffer[1..buf_index],
|
||||
.exp = exp,
|
||||
};
|
||||
@ -235,7 +229,7 @@ fn hpProd(in: &const HP, val: f64) HP {
|
||||
const p = in.val * val;
|
||||
const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
|
||||
|
||||
return HP {
|
||||
return HP{
|
||||
.val = p,
|
||||
.off = in.off * val + e,
|
||||
};
|
||||
@ -246,8 +240,8 @@ fn hpProd(in: &const HP, val: f64) HP {
|
||||
/// @hi: The high bits.
|
||||
/// @lo: The low bits.
|
||||
fn split(val: f64, hi: &f64, lo: &f64) void {
|
||||
*hi = gethi(val);
|
||||
*lo = val - *hi;
|
||||
hi.* = gethi(val);
|
||||
lo.* = val - hi.*;
|
||||
}
|
||||
|
||||
fn gethi(in: f64) f64 {
|
||||
@ -301,7 +295,6 @@ fn hpMul10(hp: &HP) void {
|
||||
hpNormalize(hp);
|
||||
}
|
||||
|
||||
|
||||
/// Integer conversion algorithm, guaranteed correct, optimal, and best.
|
||||
/// @val: The val.
|
||||
/// @buf: The output buffer.
|
||||
@ -343,8 +336,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
|
||||
}
|
||||
const m64 = @truncate(u64, @divTrunc(mid, x));
|
||||
|
||||
if (lf != hf)
|
||||
mi += 19;
|
||||
if (lf != hf) mi += 19;
|
||||
|
||||
var buf_index = u64toa(m64, buffer) - 1;
|
||||
|
||||
@ -354,7 +346,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
|
||||
buf_index += 1;
|
||||
}
|
||||
|
||||
return FloatDecimal {
|
||||
return FloatDecimal{
|
||||
.digits = buffer[0..buf_index],
|
||||
.exp = i32(buf_index) + mi,
|
||||
};
|
||||
@ -396,25 +388,24 @@ fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
|
||||
buffer[j] = u8(mdig + '0');
|
||||
j += 1;
|
||||
|
||||
if(hdig != ldig or j > 50)
|
||||
break;
|
||||
if (hdig != ldig or j > 50) break;
|
||||
}
|
||||
|
||||
if (mid > 0.5) {
|
||||
buffer[j-1] += 1;
|
||||
} else if ((mid == 0.5) and (buffer[j-1] & 0x1) != 0) {
|
||||
buffer[j-1] += 1;
|
||||
buffer[j - 1] += 1;
|
||||
} else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
|
||||
buffer[j - 1] += 1;
|
||||
}
|
||||
} else {
|
||||
while (buffer[j-1] == '0') {
|
||||
buffer[j-1] = 0;
|
||||
while (buffer[j - 1] == '0') {
|
||||
buffer[j - 1] = 0;
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[j] = 0;
|
||||
|
||||
return FloatDecimal {
|
||||
return FloatDecimal{
|
||||
.digits = buffer[0..j],
|
||||
.exp = exp,
|
||||
};
|
||||
@ -428,7 +419,7 @@ fn fpprev(val: f64) f64 {
|
||||
return @bitCast(f64, @bitCast(u64, val) -% 1);
|
||||
}
|
||||
|
||||
pub const c_digits_lut = []u8 {
|
||||
pub const c_digits_lut = []u8{
|
||||
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
|
||||
'0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
|
||||
'1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
|
||||
@ -587,7 +578,7 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
|
||||
buffer[buf_index] = c_digits_lut[d8 + 1];
|
||||
buf_index += 1;
|
||||
} else {
|
||||
const a = u32(value / kTen16); // 1 to 1844
|
||||
const a = u32(value / kTen16); // 1 to 1844
|
||||
value %= kTen16;
|
||||
|
||||
if (a < 10) {
|
||||
@ -686,7 +677,6 @@ fn fpeint(from: f64) u128 {
|
||||
return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
|
||||
}
|
||||
|
||||
|
||||
/// Given two different integers with the same length in terms of the number
|
||||
/// of decimal digits, index the digits from the right-most position starting
|
||||
/// from zero, find the first index where the digits in the two integers
|
||||
@ -713,7 +703,6 @@ fn mismatch10(a: u64, b: u64) i32 {
|
||||
a_copy /= 10;
|
||||
b_copy /= 10;
|
||||
|
||||
if (a_copy == b_copy)
|
||||
return i;
|
||||
if (a_copy == b_copy) return i;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -11,9 +11,7 @@ const max_int_digits = 65;
|
||||
/// Renders fmt string with args, calling output with slices of bytes.
|
||||
/// If `output` returns an error, the error is returned from `format` and
|
||||
/// `output` is not called again.
|
||||
pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
|
||||
comptime fmt: []const u8, args: ...) Errors!void
|
||||
{
|
||||
pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
|
||||
const State = enum {
|
||||
Start,
|
||||
OpenBrace,
|
||||
@ -27,6 +25,9 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
Character,
|
||||
Buf,
|
||||
BufWidth,
|
||||
Bytes,
|
||||
BytesBase,
|
||||
BytesWidth,
|
||||
};
|
||||
|
||||
comptime var start_index = 0;
|
||||
@ -95,13 +96,18 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
'.' => {
|
||||
state = State.Float;
|
||||
},
|
||||
'B' => {
|
||||
width = 0;
|
||||
radix = 1000;
|
||||
state = State.Bytes;
|
||||
},
|
||||
else => @compileError("Unknown format character: " ++ []u8{c}),
|
||||
},
|
||||
State.Buf => switch (c) {
|
||||
'}' => {
|
||||
return output(context, args[next_arg]);
|
||||
},
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
width_start = i;
|
||||
state = State.BufWidth;
|
||||
},
|
||||
@ -121,7 +127,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
width_start = i;
|
||||
state = State.IntegerWidth;
|
||||
},
|
||||
@ -135,7 +141,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {},
|
||||
'0'...'9' => {},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.FloatScientific => switch (c) {
|
||||
@ -145,7 +151,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
width_start = i;
|
||||
state = State.FloatScientificWidth;
|
||||
},
|
||||
@ -159,7 +165,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {},
|
||||
'0'...'9' => {},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.Float => switch (c) {
|
||||
@ -169,7 +175,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
width_start = i;
|
||||
state = State.FloatWidth;
|
||||
},
|
||||
@ -183,7 +189,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {},
|
||||
'0'...'9' => {},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.BufWidth => switch (c) {
|
||||
@ -194,7 +200,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0' ... '9' => {},
|
||||
'0'...'9' => {},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.Character => switch (c) {
|
||||
@ -206,6 +212,47 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.Bytes => switch (c) {
|
||||
'}' => {
|
||||
try formatBytes(args[next_arg], 0, radix, context, Errors, output);
|
||||
next_arg += 1;
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'i' => {
|
||||
radix = 1024;
|
||||
state = State.BytesBase;
|
||||
},
|
||||
'0'...'9' => {
|
||||
width_start = i;
|
||||
state = State.BytesWidth;
|
||||
},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.BytesBase => switch (c) {
|
||||
'}' => {
|
||||
try formatBytes(args[next_arg], 0, radix, context, Errors, output);
|
||||
next_arg += 1;
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0'...'9' => {
|
||||
width_start = i;
|
||||
state = State.BytesWidth;
|
||||
},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
State.BytesWidth => switch (c) {
|
||||
'}' => {
|
||||
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
|
||||
try formatBytes(args[next_arg], width, radix, context, Errors, output);
|
||||
next_arg += 1;
|
||||
state = State.Start;
|
||||
start_index = i + 1;
|
||||
},
|
||||
'0'...'9' => {},
|
||||
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
|
||||
},
|
||||
}
|
||||
}
|
||||
comptime {
|
||||
@ -221,7 +268,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
|
||||
pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
const T = @typeOf(value);
|
||||
switch (@typeId(T)) {
|
||||
builtin.TypeId.Int => {
|
||||
@ -256,7 +303,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
|
||||
},
|
||||
builtin.TypeId.Pointer => {
|
||||
if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
|
||||
return output(context, (*value)[0..]);
|
||||
return output(context, (value.*)[0..]);
|
||||
} else {
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||
}
|
||||
@ -270,13 +317,11 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
|
||||
pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
return output(context, (&c)[0..1]);
|
||||
}
|
||||
|
||||
pub fn formatBuf(buf: []const u8, width: usize,
|
||||
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
|
||||
{
|
||||
pub fn formatBuf(buf: []const u8, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
try output(context, buf);
|
||||
|
||||
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
|
||||
@ -289,7 +334,7 @@ pub fn formatBuf(buf: []const u8, width: usize,
|
||||
// Print a float in scientific notation to the specified precision. Null uses full precision.
|
||||
// It should be the case that every full precision, printed value can be re-parsed back to the
|
||||
// same type unambiguously.
|
||||
pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
|
||||
pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
var x = f64(value);
|
||||
|
||||
// Errol doesn't handle these special cases.
|
||||
@ -338,7 +383,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
|
||||
var printed: usize = 0;
|
||||
if (float_decimal.digits.len > 1) {
|
||||
const num_digits = math.min(float_decimal.digits.len, precision + 1);
|
||||
try output(context, float_decimal.digits[1 .. num_digits]);
|
||||
try output(context, float_decimal.digits[1..num_digits]);
|
||||
printed += num_digits - 1;
|
||||
}
|
||||
|
||||
@ -350,12 +395,9 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
|
||||
try output(context, float_decimal.digits[0..1]);
|
||||
try output(context, ".");
|
||||
if (float_decimal.digits.len > 1) {
|
||||
const num_digits = if (@typeOf(value) == f32)
|
||||
math.min(usize(9), float_decimal.digits.len)
|
||||
else
|
||||
float_decimal.digits.len;
|
||||
const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
|
||||
|
||||
try output(context, float_decimal.digits[1 .. num_digits]);
|
||||
try output(context, float_decimal.digits[1..num_digits]);
|
||||
} else {
|
||||
try output(context, "0");
|
||||
}
|
||||
@ -381,7 +423,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
|
||||
|
||||
// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
|
||||
// By default floats are printed at full precision (no rounding).
|
||||
pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {
|
||||
pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
var x = f64(value);
|
||||
|
||||
// Errol doesn't handle these special cases.
|
||||
@ -431,14 +473,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
|
||||
|
||||
if (num_digits_whole > 0) {
|
||||
// We may have to zero pad, for instance 1e4 requires zero padding.
|
||||
try output(context, float_decimal.digits[0 .. num_digits_whole_no_pad]);
|
||||
try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
|
||||
var i = num_digits_whole_no_pad;
|
||||
while (i < num_digits_whole) : (i += 1) {
|
||||
try output(context, "0");
|
||||
}
|
||||
} else {
|
||||
try output(context , "0");
|
||||
try output(context, "0");
|
||||
}
|
||||
|
||||
// {.0} special case doesn't want a trailing '.'
|
||||
@ -470,10 +512,10 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
|
||||
// Remaining fractional portion, zero-padding if insufficient.
|
||||
debug.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]);
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad..num_digits_whole_no_pad + precision - printed]);
|
||||
return;
|
||||
} else {
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad ..]);
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
printed += float_decimal.digits.len - num_digits_whole_no_pad;
|
||||
|
||||
while (printed < precision) : (printed += 1) {
|
||||
@ -489,14 +531,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
|
||||
|
||||
if (num_digits_whole > 0) {
|
||||
// We may have to zero pad, for instance 1e4 requires zero padding.
|
||||
try output(context, float_decimal.digits[0 .. num_digits_whole_no_pad]);
|
||||
try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
|
||||
var i = num_digits_whole_no_pad;
|
||||
while (i < num_digits_whole) : (i += 1) {
|
||||
try output(context, "0");
|
||||
}
|
||||
} else {
|
||||
try output(context , "0");
|
||||
try output(context, "0");
|
||||
}
|
||||
|
||||
// Omit `.` if no fractional portion
|
||||
@ -516,14 +558,54 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
|
||||
}
|
||||
}
|
||||
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad ..]);
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatBytes(
|
||||
value: var,
|
||||
width: ?usize,
|
||||
comptime radix: usize,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
output: fn(@typeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
if (value == 0) {
|
||||
return output(context, "0B");
|
||||
}
|
||||
|
||||
pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
|
||||
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
|
||||
{
|
||||
const mags = " KMGTPEZY";
|
||||
const magnitude = switch (radix) {
|
||||
1000 => math.min(math.log2(value) / comptime math.log2(1000), mags.len - 1),
|
||||
1024 => math.min(math.log2(value) / 10, mags.len - 1),
|
||||
else => unreachable,
|
||||
};
|
||||
const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
|
||||
const suffix = mags[magnitude];
|
||||
|
||||
try formatFloatDecimal(new_value, width, context, Errors, output);
|
||||
|
||||
if (suffix == ' ') {
|
||||
return output(context, "B");
|
||||
}
|
||||
|
||||
const buf = switch (radix) {
|
||||
1000 => []u8{ suffix, 'B' },
|
||||
1024 => []u8{ suffix, 'i', 'B' },
|
||||
else => unreachable,
|
||||
};
|
||||
return output(context, buf);
|
||||
}
|
||||
|
||||
pub fn formatInt(
|
||||
value: var,
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
width: usize,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
output: fn(@typeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
if (@typeOf(value).is_signed) {
|
||||
return formatIntSigned(value, base, uppercase, width, context, Errors, output);
|
||||
} else {
|
||||
@ -531,9 +613,7 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
|
||||
{
|
||||
fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
const uint = @IntType(false, @typeOf(value).bit_count);
|
||||
if (value < 0) {
|
||||
const minus_sign: u8 = '-';
|
||||
@ -552,9 +632,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
|
||||
{
|
||||
fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
|
||||
// max_int_digits accounts for the minus sign. when printing an unsigned
|
||||
// number we don't need to do that.
|
||||
var buf: [max_int_digits - 1]u8 = undefined;
|
||||
@ -566,8 +644,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
index -= 1;
|
||||
buf[index] = digitToChar(u8(digit), uppercase);
|
||||
a /= base;
|
||||
if (a == 0)
|
||||
break;
|
||||
if (a == 0) break;
|
||||
}
|
||||
|
||||
const digits_buf = buf[index..];
|
||||
@ -579,8 +656,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
while (true) {
|
||||
try output(context, (&zero_byte)[0..1]);
|
||||
leftover_padding -= 1;
|
||||
if (leftover_padding == 0)
|
||||
break;
|
||||
if (leftover_padding == 0) break;
|
||||
}
|
||||
mem.set(u8, buf[0..index], '0');
|
||||
return output(context, buf);
|
||||
@ -592,7 +668,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
}
|
||||
|
||||
pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
|
||||
var context = FormatIntBuf {
|
||||
var context = FormatIntBuf{
|
||||
.out_buf = out_buf,
|
||||
.index = 0,
|
||||
};
|
||||
@ -609,10 +685,8 @@ fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
|
||||
}
|
||||
|
||||
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
|
||||
if (!T.is_signed)
|
||||
return parseUnsigned(T, buf, radix);
|
||||
if (buf.len == 0)
|
||||
return T(0);
|
||||
if (!T.is_signed) return parseUnsigned(T, buf, radix);
|
||||
if (buf.len == 0) return T(0);
|
||||
if (buf[0] == '-') {
|
||||
return math.negate(try parseUnsigned(T, buf[1..], radix));
|
||||
} else if (buf[0] == '+') {
|
||||
@ -632,9 +706,10 @@ test "fmt.parseInt" {
|
||||
assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
|
||||
}
|
||||
|
||||
const ParseUnsignedError = error {
|
||||
const ParseUnsignedError = error{
|
||||
/// The result cannot fit in the type specified
|
||||
Overflow,
|
||||
|
||||
/// The input had a byte that was not a digit
|
||||
InvalidCharacter,
|
||||
};
|
||||
@ -653,22 +728,21 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
|
||||
|
||||
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
|
||||
const value = switch (c) {
|
||||
'0' ... '9' => c - '0',
|
||||
'A' ... 'Z' => c - 'A' + 10,
|
||||
'a' ... 'z' => c - 'a' + 10,
|
||||
'0'...'9' => c - '0',
|
||||
'A'...'Z' => c - 'A' + 10,
|
||||
'a'...'z' => c - 'a' + 10,
|
||||
else => return error.InvalidCharacter,
|
||||
};
|
||||
|
||||
if (value >= radix)
|
||||
return error.InvalidCharacter;
|
||||
if (value >= radix) return error.InvalidCharacter;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
fn digitToChar(digit: u8, uppercase: bool) u8 {
|
||||
return switch (digit) {
|
||||
0 ... 9 => digit + '0',
|
||||
10 ... 35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
|
||||
0...9 => digit + '0',
|
||||
10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
@ -684,7 +758,7 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
|
||||
}
|
||||
|
||||
pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
|
||||
var context = BufPrintContext { .remaining = buf, };
|
||||
var context = BufPrintContext{ .remaining = buf };
|
||||
try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
|
||||
return buf[0..buf.len - context.remaining.len];
|
||||
}
|
||||
@ -697,7 +771,7 @@ pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...
|
||||
}
|
||||
|
||||
fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
|
||||
*size += bytes.len;
|
||||
size.* += bytes.len;
|
||||
}
|
||||
|
||||
test "buf print int" {
|
||||
@ -738,44 +812,34 @@ test "parse unsigned comptime" {
|
||||
|
||||
test "fmt.format" {
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: ?i32 = 1234;
|
||||
const result = try bufPrint(buf1[0..], "nullable: {}\n", value);
|
||||
assert(mem.eql(u8, result, "nullable: 1234\n"));
|
||||
try testFmt("nullable: 1234\n", "nullable: {}\n", value);
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: ?i32 = null;
|
||||
const result = try bufPrint(buf1[0..], "nullable: {}\n", value);
|
||||
assert(mem.eql(u8, result, "nullable: null\n"));
|
||||
try testFmt("nullable: null\n", "nullable: {}\n", value);
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: error!i32 = 1234;
|
||||
const result = try bufPrint(buf1[0..], "error union: {}\n", value);
|
||||
assert(mem.eql(u8, result, "error union: 1234\n"));
|
||||
try testFmt("error union: 1234\n", "error union: {}\n", value);
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: error!i32 = error.InvalidChar;
|
||||
const result = try bufPrint(buf1[0..], "error union: {}\n", value);
|
||||
assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
|
||||
try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
|
||||
}
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value: u3 = 0b101;
|
||||
const result = try bufPrint(buf1[0..], "u3: {}\n", value);
|
||||
assert(mem.eql(u8, result, "u3: 5\n"));
|
||||
try testFmt("u3: 5\n", "u3: {}\n", value);
|
||||
}
|
||||
try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
|
||||
try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
|
||||
{
|
||||
// Dummy field because of https://github.com/zig-lang/zig/issues/557.
|
||||
// Dummy field because of https://github.com/ziglang/zig/issues/557.
|
||||
const Struct = struct {
|
||||
unused: u8,
|
||||
};
|
||||
var buf1: [32]u8 = undefined;
|
||||
const value = Struct {
|
||||
.unused = 42,
|
||||
};
|
||||
const value = Struct{ .unused = 42 };
|
||||
const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);
|
||||
assert(mem.startsWith(u8, result, "pointer: Struct@"));
|
||||
}
|
||||
@ -986,9 +1050,22 @@ test "fmt.format" {
|
||||
}
|
||||
}
|
||||
|
||||
fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
|
||||
var buf: [100]u8 = undefined;
|
||||
const result = try bufPrint(buf[0..], template, args);
|
||||
if (mem.eql(u8, result, expected)) return;
|
||||
|
||||
std.debug.warn("\n====== expected this output: =========\n");
|
||||
std.debug.warn("{}", expected);
|
||||
std.debug.warn("\n======== instead found this: =========\n");
|
||||
std.debug.warn("{}", result);
|
||||
std.debug.warn("\n======================================\n");
|
||||
return error.TestFailed;
|
||||
}
|
||||
|
||||
pub fn trim(buf: []const u8) []const u8 {
|
||||
var start: usize = 0;
|
||||
while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) { }
|
||||
while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
|
||||
|
||||
var end: usize = buf.len;
|
||||
while (true) {
|
||||
@ -1000,7 +1077,6 @@ pub fn trim(buf: []const u8) []const u8 {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
return buf[start..end];
|
||||
}
|
||||
|
||||
@ -13,9 +13,7 @@ pub const Adler32 = struct {
|
||||
adler: u32,
|
||||
|
||||
pub fn init() Adler32 {
|
||||
return Adler32 {
|
||||
.adler = 1,
|
||||
};
|
||||
return Adler32{ .adler = 1 };
|
||||
}
|
||||
|
||||
// This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
|
||||
@ -33,8 +31,7 @@ pub const Adler32 = struct {
|
||||
if (s2 >= base) {
|
||||
s2 -= base;
|
||||
}
|
||||
}
|
||||
else if (input.len < 16) {
|
||||
} else if (input.len < 16) {
|
||||
for (input) |b| {
|
||||
s1 +%= b;
|
||||
s2 +%= s1;
|
||||
@ -44,8 +41,7 @@ pub const Adler32 = struct {
|
||||
}
|
||||
|
||||
s2 %= base;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
var i: usize = 0;
|
||||
while (i + nmax <= input.len) : (i += nmax) {
|
||||
const n = nmax / 16; // note: 16 | nmax
|
||||
@ -98,15 +94,14 @@ test "adler32 sanity" {
|
||||
}
|
||||
|
||||
test "adler32 long" {
|
||||
const long1 = []u8 {1} ** 1024;
|
||||
const long1 = []u8{1} ** 1024;
|
||||
debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
|
||||
|
||||
const long2 = []u8 {1} ** 1025;
|
||||
const long2 = []u8{1} ** 1025;
|
||||
debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
|
||||
}
|
||||
|
||||
test "adler32 very long" {
|
||||
const long = []u8 {1} ** 5553;
|
||||
const long = []u8{1} ** 5553;
|
||||
debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
|
||||
}
|
||||
|
||||
|
||||
@ -9,9 +9,9 @@ const std = @import("../index.zig");
|
||||
const debug = std.debug;
|
||||
|
||||
pub const Polynomial = struct {
|
||||
const IEEE = 0xedb88320;
|
||||
const IEEE = 0xedb88320;
|
||||
const Castagnoli = 0x82f63b78;
|
||||
const Koopman = 0xeb31d82e;
|
||||
const Koopman = 0xeb31d82e;
|
||||
};
|
||||
|
||||
// IEEE is by far the most common CRC and so is aliased by default.
|
||||
@ -27,20 +27,22 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
|
||||
|
||||
for (tables[0]) |*e, i| {
|
||||
var crc = u32(i);
|
||||
var j: usize = 0; while (j < 8) : (j += 1) {
|
||||
var j: usize = 0;
|
||||
while (j < 8) : (j += 1) {
|
||||
if (crc & 1 == 1) {
|
||||
crc = (crc >> 1) ^ poly;
|
||||
} else {
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
*e = crc;
|
||||
e.* = crc;
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 256) : (i += 1) {
|
||||
var crc = tables[0][i];
|
||||
var j: usize = 1; while (j < 8) : (j += 1) {
|
||||
var j: usize = 1;
|
||||
while (j < 8) : (j += 1) {
|
||||
const index = @truncate(u8, crc);
|
||||
crc = tables[0][index] ^ (crc >> 8);
|
||||
tables[j][i] = crc;
|
||||
@ -53,19 +55,17 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
|
||||
crc: u32,
|
||||
|
||||
pub fn init() Self {
|
||||
return Self {
|
||||
.crc = 0xffffffff,
|
||||
};
|
||||
return Self{ .crc = 0xffffffff };
|
||||
}
|
||||
|
||||
pub fn update(self: &Self, input: []const u8) void {
|
||||
var i: usize = 0;
|
||||
while (i + 8 <= input.len) : (i += 8) {
|
||||
const p = input[i..i+8];
|
||||
const p = input[i..i + 8];
|
||||
|
||||
// Unrolling this way gives ~50Mb/s increase
|
||||
self.crc ^= (u32(p[0]) << 0);
|
||||
self.crc ^= (u32(p[1]) << 8);
|
||||
self.crc ^= (u32(p[0]) << 0);
|
||||
self.crc ^= (u32(p[1]) << 8);
|
||||
self.crc ^= (u32(p[2]) << 16);
|
||||
self.crc ^= (u32(p[3]) << 24);
|
||||
|
||||
@ -76,8 +76,8 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
|
||||
lookup_tables[3][p[4]] ^
|
||||
lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
|
||||
lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
|
||||
lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
|
||||
lookup_tables[7][@truncate(u8, self.crc >> 0)];
|
||||
lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
|
||||
lookup_tables[7][@truncate(u8, self.crc >> 0)];
|
||||
}
|
||||
|
||||
while (i < input.len) : (i += 1) {
|
||||
@ -123,14 +123,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
|
||||
|
||||
for (table) |*e, i| {
|
||||
var crc = u32(i * 16);
|
||||
var j: usize = 0; while (j < 8) : (j += 1) {
|
||||
var j: usize = 0;
|
||||
while (j < 8) : (j += 1) {
|
||||
if (crc & 1 == 1) {
|
||||
crc = (crc >> 1) ^ poly;
|
||||
} else {
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
*e = crc;
|
||||
e.* = crc;
|
||||
}
|
||||
|
||||
break :block table;
|
||||
@ -139,9 +140,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
|
||||
crc: u32,
|
||||
|
||||
pub fn init() Self {
|
||||
return Self {
|
||||
.crc = 0xffffffff,
|
||||
};
|
||||
return Self{ .crc = 0xffffffff };
|
||||
}
|
||||
|
||||
pub fn update(self: &Self, input: []const u8) void {
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
const std = @import("../index.zig");
|
||||
const debug = std.debug;
|
||||
|
||||
pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5);
|
||||
pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);
|
||||
pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
|
||||
pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d);
|
||||
|
||||
@ -18,9 +18,7 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
|
||||
value: T,
|
||||
|
||||
pub fn init() Self {
|
||||
return Self {
|
||||
.value = offset,
|
||||
};
|
||||
return Self{ .value = offset };
|
||||
}
|
||||
|
||||
pub fn update(self: &Self, input: []const u8) void {
|
||||
|
||||
@ -45,7 +45,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
|
||||
const k0 = mem.readInt(key[0..8], u64, Endian.Little);
|
||||
const k1 = mem.readInt(key[8..16], u64, Endian.Little);
|
||||
|
||||
var d = Self {
|
||||
var d = Self{
|
||||
.v0 = k0 ^ 0x736f6d6570736575,
|
||||
.v1 = k1 ^ 0x646f72616e646f6d,
|
||||
.v2 = k0 ^ 0x6c7967656e657261,
|
||||
@ -162,7 +162,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 = [][]const 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
|
||||
@ -241,7 +241,7 @@ test "siphash64-2-4 sanity" {
|
||||
}
|
||||
|
||||
test "siphash128-2-4 sanity" {
|
||||
const vectors = [][]const u8 {
|
||||
const vectors = [][]const 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",
|
||||
|
||||
@ -9,10 +9,7 @@ const builtin = @import("builtin");
|
||||
const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;
|
||||
const debug_u32 = if (want_modification_safety) u32 else void;
|
||||
|
||||
pub fn HashMap(comptime K: type, comptime V: type,
|
||||
comptime hash: fn(key: K)u32,
|
||||
comptime eql: fn(a: K, b: K)bool) type
|
||||
{
|
||||
pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn(key: K) u32, comptime eql: fn(a: K, b: K) bool) type {
|
||||
return struct {
|
||||
entries: []Entry,
|
||||
size: usize,
|
||||
@ -65,7 +62,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
||||
};
|
||||
|
||||
pub fn init(allocator: &Allocator) Self {
|
||||
return Self {
|
||||
return Self{
|
||||
.entries = []Entry{},
|
||||
.allocator = allocator,
|
||||
.size = 0,
|
||||
@ -129,34 +126,36 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
||||
if (hm.entries.len == 0) return null;
|
||||
hm.incrementModificationCount();
|
||||
const start_index = hm.keyToIndex(key);
|
||||
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
var entry = &hm.entries[index];
|
||||
{
|
||||
var roll_over: usize = 0;
|
||||
while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
var entry = &hm.entries[index];
|
||||
|
||||
if (!entry.used)
|
||||
return null;
|
||||
if (!entry.used) return null;
|
||||
|
||||
if (!eql(entry.key, key)) continue;
|
||||
if (!eql(entry.key, key)) continue;
|
||||
|
||||
while (roll_over < hm.entries.len) : (roll_over += 1) {
|
||||
const next_index = (start_index + roll_over + 1) % hm.entries.len;
|
||||
const next_entry = &hm.entries[next_index];
|
||||
if (!next_entry.used or next_entry.distance_from_start_index == 0) {
|
||||
entry.used = false;
|
||||
hm.size -= 1;
|
||||
return entry;
|
||||
while (roll_over < hm.entries.len) : (roll_over += 1) {
|
||||
const next_index = (start_index + roll_over + 1) % hm.entries.len;
|
||||
const next_entry = &hm.entries[next_index];
|
||||
if (!next_entry.used or next_entry.distance_from_start_index == 0) {
|
||||
entry.used = false;
|
||||
hm.size -= 1;
|
||||
return entry;
|
||||
}
|
||||
entry.* = next_entry.*;
|
||||
entry.distance_from_start_index -= 1;
|
||||
entry = next_entry;
|
||||
}
|
||||
*entry = *next_entry;
|
||||
entry.distance_from_start_index -= 1;
|
||||
entry = next_entry;
|
||||
unreachable; // shifting everything in the table
|
||||
}
|
||||
unreachable; // shifting everything in the table
|
||||
}}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn iterator(hm: &const Self) Iterator {
|
||||
return Iterator {
|
||||
return Iterator{
|
||||
.hm = hm,
|
||||
.count = 0,
|
||||
.index = 0,
|
||||
@ -182,21 +181,23 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
||||
/// Returns the value that was already there.
|
||||
fn internalPut(hm: &Self, orig_key: K, orig_value: &const V) ?V {
|
||||
var key = orig_key;
|
||||
var value = *orig_value;
|
||||
var value = orig_value.*;
|
||||
const start_index = hm.keyToIndex(key);
|
||||
var roll_over: usize = 0;
|
||||
var distance_from_start_index: usize = 0;
|
||||
while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) {
|
||||
while (roll_over < hm.entries.len) : ({
|
||||
roll_over += 1;
|
||||
distance_from_start_index += 1;
|
||||
}) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
const entry = &hm.entries[index];
|
||||
|
||||
if (entry.used and !eql(entry.key, key)) {
|
||||
if (entry.distance_from_start_index < distance_from_start_index) {
|
||||
// robin hood to the rescue
|
||||
const tmp = *entry;
|
||||
hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,
|
||||
distance_from_start_index);
|
||||
*entry = Entry {
|
||||
const tmp = entry.*;
|
||||
hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index, distance_from_start_index);
|
||||
entry.* = Entry{
|
||||
.used = true,
|
||||
.distance_from_start_index = distance_from_start_index,
|
||||
.key = key,
|
||||
@ -219,7 +220,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
||||
}
|
||||
|
||||
hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);
|
||||
*entry = Entry {
|
||||
entry.* = Entry{
|
||||
.used = true,
|
||||
.distance_from_start_index = distance_from_start_index,
|
||||
.key = key,
|
||||
@ -232,13 +233,16 @@ pub fn HashMap(comptime K: type, comptime V: type,
|
||||
|
||||
fn internalGet(hm: &const Self, key: K) ?&Entry {
|
||||
const start_index = hm.keyToIndex(key);
|
||||
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
const entry = &hm.entries[index];
|
||||
{
|
||||
var roll_over: usize = 0;
|
||||
while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
|
||||
const index = (start_index + roll_over) % hm.entries.len;
|
||||
const entry = &hm.entries[index];
|
||||
|
||||
if (!entry.used) return null;
|
||||
if (eql(entry.key, key)) return entry;
|
||||
}}
|
||||
if (!entry.used) return null;
|
||||
if (eql(entry.key, key)) return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -282,11 +286,19 @@ test "iterator hash map" {
|
||||
assert((reset_map.put(2, 22) catch unreachable) == null);
|
||||
assert((reset_map.put(3, 33) catch unreachable) == null);
|
||||
|
||||
var keys = []i32 { 1, 2, 3 };
|
||||
var values = []i32 { 11, 22, 33 };
|
||||
var keys = []i32{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
var values = []i32{
|
||||
11,
|
||||
22,
|
||||
33,
|
||||
};
|
||||
|
||||
var it = reset_map.iterator();
|
||||
var count : usize = 0;
|
||||
var count: usize = 0;
|
||||
while (it.next()) |next| {
|
||||
assert(next.key == keys[count]);
|
||||
assert(next.value == values[count]);
|
||||
@ -305,7 +317,7 @@ test "iterator hash map" {
|
||||
}
|
||||
|
||||
it.reset();
|
||||
var entry = ?? it.next();
|
||||
var entry = ??it.next();
|
||||
assert(entry.key == keys[0]);
|
||||
assert(entry.value == values[0]);
|
||||
}
|
||||
|
||||
96
std/heap.zig
96
std/heap.zig
@ -10,7 +10,7 @@ const c = std.c;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub const c_allocator = &c_allocator_state;
|
||||
var c_allocator_state = Allocator {
|
||||
var c_allocator_state = Allocator{
|
||||
.allocFn = cAlloc,
|
||||
.reallocFn = cRealloc,
|
||||
.freeFn = cFree,
|
||||
@ -18,10 +18,7 @@ var c_allocator_state = Allocator {
|
||||
|
||||
fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
|
||||
assert(alignment <= @alignOf(c_longdouble));
|
||||
return if (c.malloc(n)) |buf|
|
||||
@ptrCast(&u8, buf)[0..n]
|
||||
else
|
||||
error.OutOfMemory;
|
||||
return if (c.malloc(n)) |buf| @ptrCast(&u8, buf)[0..n] else error.OutOfMemory;
|
||||
}
|
||||
|
||||
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
|
||||
@ -48,8 +45,8 @@ pub const DirectAllocator = struct {
|
||||
const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
|
||||
|
||||
pub fn init() DirectAllocator {
|
||||
return DirectAllocator {
|
||||
.allocator = Allocator {
|
||||
return DirectAllocator{
|
||||
.allocator = Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
@ -73,37 +70,35 @@ pub const DirectAllocator = struct {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios => {
|
||||
const p = os.posix;
|
||||
const alloc_size = if(alignment <= os.page_size) n else n + alignment;
|
||||
const addr = p.mmap(null, alloc_size, p.PROT_READ|p.PROT_WRITE,
|
||||
p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
|
||||
if(addr == p.MAP_FAILED) return error.OutOfMemory;
|
||||
|
||||
if(alloc_size == n) return @intToPtr(&u8, addr)[0..n];
|
||||
|
||||
const alloc_size = if (alignment <= os.page_size) n else n + alignment;
|
||||
const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
|
||||
if (addr == p.MAP_FAILED) return error.OutOfMemory;
|
||||
|
||||
if (alloc_size == n) return @intToPtr(&u8, addr)[0..n];
|
||||
|
||||
var aligned_addr = addr & ~usize(alignment - 1);
|
||||
aligned_addr += alignment;
|
||||
|
||||
|
||||
//We can unmap the unused portions of our mmap, but we must only
|
||||
// pass munmap bytes that exist outside our allocated pages or it
|
||||
// will happily eat us too
|
||||
|
||||
|
||||
//Since alignment > page_size, we are by definition on a page boundry
|
||||
const unused_start = addr;
|
||||
const unused_len = aligned_addr - 1 - unused_start;
|
||||
|
||||
var err = p.munmap(unused_start, unused_len);
|
||||
debug.assert(p.getErrno(err) == 0);
|
||||
|
||||
|
||||
//It is impossible that there is an unoccupied page at the top of our
|
||||
// mmap.
|
||||
|
||||
|
||||
return @intToPtr(&u8, aligned_addr)[0..n];
|
||||
},
|
||||
Os.windows => {
|
||||
const amt = n + alignment + @sizeOf(usize);
|
||||
const heap_handle = self.heap_handle ?? blk: {
|
||||
const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0)
|
||||
?? return error.OutOfMemory;
|
||||
const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
|
||||
self.heap_handle = hh;
|
||||
break :blk hh;
|
||||
};
|
||||
@ -113,7 +108,7 @@ pub const DirectAllocator = struct {
|
||||
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
||||
const adjusted_addr = root_addr + march_forward_bytes;
|
||||
const record_addr = adjusted_addr + n;
|
||||
*@intToPtr(&align(1) usize, record_addr) = root_addr;
|
||||
@intToPtr(&align(1) usize, record_addr).* = root_addr;
|
||||
return @intToPtr(&u8, adjusted_addr)[0..n];
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
@ -144,13 +139,13 @@ pub const DirectAllocator = struct {
|
||||
Os.windows => {
|
||||
const old_adjusted_addr = @ptrToInt(old_mem.ptr);
|
||||
const old_record_addr = old_adjusted_addr + old_mem.len;
|
||||
const root_addr = *@intToPtr(&align(1) usize, old_record_addr);
|
||||
const root_addr = @intToPtr(&align(1) usize, old_record_addr).*;
|
||||
const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);
|
||||
const amt = new_size + alignment + @sizeOf(usize);
|
||||
const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
|
||||
if (new_size > old_mem.len) return error.OutOfMemory;
|
||||
const new_record_addr = old_record_addr - new_size + old_mem.len;
|
||||
*@intToPtr(&align(1) usize, new_record_addr) = root_addr;
|
||||
@intToPtr(&align(1) usize, new_record_addr).* = root_addr;
|
||||
return old_mem[0..new_size];
|
||||
};
|
||||
const offset = old_adjusted_addr - root_addr;
|
||||
@ -158,7 +153,7 @@ pub const DirectAllocator = struct {
|
||||
const new_adjusted_addr = new_root_addr + offset;
|
||||
assert(new_adjusted_addr % alignment == 0);
|
||||
const new_record_addr = new_adjusted_addr + new_size;
|
||||
*@intToPtr(&align(1) usize, new_record_addr) = new_root_addr;
|
||||
@intToPtr(&align(1) usize, new_record_addr).* = new_root_addr;
|
||||
return @intToPtr(&u8, new_adjusted_addr)[0..new_size];
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
@ -174,7 +169,7 @@ pub const DirectAllocator = struct {
|
||||
},
|
||||
Os.windows => {
|
||||
const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
|
||||
const root_addr = *@intToPtr(&align(1) usize, record_addr);
|
||||
const root_addr = @intToPtr(&align(1) usize, record_addr).*;
|
||||
const ptr = @intToPtr(os.windows.LPVOID, root_addr);
|
||||
_ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
|
||||
},
|
||||
@ -195,8 +190,8 @@ pub const ArenaAllocator = struct {
|
||||
const BufNode = std.LinkedList([]u8).Node;
|
||||
|
||||
pub fn init(child_allocator: &Allocator) ArenaAllocator {
|
||||
return ArenaAllocator {
|
||||
.allocator = Allocator {
|
||||
return ArenaAllocator{
|
||||
.allocator = Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
@ -228,7 +223,7 @@ pub const ArenaAllocator = struct {
|
||||
const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
|
||||
const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
|
||||
const buf_node = &buf_node_slice[0];
|
||||
*buf_node = BufNode {
|
||||
buf_node.* = BufNode{
|
||||
.data = buf,
|
||||
.prev = null,
|
||||
.next = null,
|
||||
@ -253,7 +248,7 @@ pub const ArenaAllocator = struct {
|
||||
cur_node = try self.createNode(cur_buf.len, n + alignment);
|
||||
continue;
|
||||
}
|
||||
const result = cur_buf[adjusted_index .. new_end_index];
|
||||
const result = cur_buf[adjusted_index..new_end_index];
|
||||
self.end_index = new_end_index;
|
||||
return result;
|
||||
}
|
||||
@ -269,7 +264,7 @@ pub const ArenaAllocator = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn free(allocator: &Allocator, bytes: []u8) void { }
|
||||
fn free(allocator: &Allocator, bytes: []u8) void {}
|
||||
};
|
||||
|
||||
pub const FixedBufferAllocator = struct {
|
||||
@ -278,8 +273,8 @@ pub const FixedBufferAllocator = struct {
|
||||
buffer: []u8,
|
||||
|
||||
pub fn init(buffer: []u8) FixedBufferAllocator {
|
||||
return FixedBufferAllocator {
|
||||
.allocator = Allocator {
|
||||
return FixedBufferAllocator{
|
||||
.allocator = Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
@ -299,7 +294,7 @@ pub const FixedBufferAllocator = struct {
|
||||
if (new_end_index > self.buffer.len) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
const result = self.buffer[adjusted_index .. new_end_index];
|
||||
const result = self.buffer[adjusted_index..new_end_index];
|
||||
self.end_index = new_end_index;
|
||||
|
||||
return result;
|
||||
@ -315,7 +310,7 @@ pub const FixedBufferAllocator = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn free(allocator: &Allocator, bytes: []u8) void { }
|
||||
fn free(allocator: &Allocator, bytes: []u8) void {}
|
||||
};
|
||||
|
||||
/// lock free
|
||||
@ -325,8 +320,8 @@ pub const ThreadSafeFixedBufferAllocator = struct {
|
||||
buffer: []u8,
|
||||
|
||||
pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {
|
||||
return ThreadSafeFixedBufferAllocator {
|
||||
.allocator = Allocator {
|
||||
return ThreadSafeFixedBufferAllocator{
|
||||
.allocator = Allocator{
|
||||
.allocFn = alloc,
|
||||
.reallocFn = realloc,
|
||||
.freeFn = free,
|
||||
@ -348,8 +343,7 @@ pub const ThreadSafeFixedBufferAllocator = struct {
|
||||
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) ?? return self.buffer[adjusted_index .. new_end_index];
|
||||
end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) ?? return self.buffer[adjusted_index..new_end_index];
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,11 +357,9 @@ pub const ThreadSafeFixedBufferAllocator = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn free(allocator: &Allocator, bytes: []u8) void { }
|
||||
fn free(allocator: &Allocator, bytes: []u8) void {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
test "c_allocator" {
|
||||
if (builtin.link_libc) {
|
||||
var slice = c_allocator.alloc(u8, 50) catch return;
|
||||
@ -415,8 +407,8 @@ fn testAllocator(allocator: &mem.Allocator) !void {
|
||||
var slice = try allocator.alloc(&i32, 100);
|
||||
|
||||
for (slice) |*item, i| {
|
||||
*item = try allocator.create(i32);
|
||||
**item = i32(i);
|
||||
item.* = try allocator.create(i32);
|
||||
item.*.* = i32(i);
|
||||
}
|
||||
|
||||
for (slice) |item, i| {
|
||||
@ -432,28 +424,28 @@ fn testAllocator(allocator: &mem.Allocator) !void {
|
||||
}
|
||||
|
||||
fn testAllocatorLargeAlignment(allocator: &mem.Allocator) mem.Allocator.Error!void {
|
||||
//Maybe a platform's page_size is actually the same as or
|
||||
//Maybe a platform's page_size is actually the same as or
|
||||
// very near usize?
|
||||
if(os.page_size << 2 > @maxValue(usize)) return;
|
||||
|
||||
if (os.page_size << 2 > @maxValue(usize)) return;
|
||||
|
||||
const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
|
||||
const large_align = u29(os.page_size << 2);
|
||||
|
||||
|
||||
var align_mask: usize = undefined;
|
||||
_ = @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));
|
||||
|
||||
|
||||
slice = try allocator.reallocFn(allocator, slice, 100, large_align);
|
||||
debug.assert(@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));
|
||||
|
||||
|
||||
slice = try allocator.reallocFn(allocator, slice, 10, large_align);
|
||||
debug.assert(@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));
|
||||
|
||||
|
||||
65
std/io.zig
65
std/io.zig
@ -18,32 +18,17 @@ const is_windows = builtin.os == builtin.Os.windows;
|
||||
const GetStdIoErrs = os.WindowsGetStdHandleErrs;
|
||||
|
||||
pub fn getStdErr() GetStdIoErrs!File {
|
||||
const handle = if (is_windows)
|
||||
try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE)
|
||||
else if (is_posix)
|
||||
os.posix.STDERR_FILENO
|
||||
else
|
||||
unreachable;
|
||||
const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
|
||||
return File.openHandle(handle);
|
||||
}
|
||||
|
||||
pub fn getStdOut() GetStdIoErrs!File {
|
||||
const handle = if (is_windows)
|
||||
try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE)
|
||||
else if (is_posix)
|
||||
os.posix.STDOUT_FILENO
|
||||
else
|
||||
unreachable;
|
||||
const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
|
||||
return File.openHandle(handle);
|
||||
}
|
||||
|
||||
pub fn getStdIn() GetStdIoErrs!File {
|
||||
const handle = if (is_windows)
|
||||
try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE)
|
||||
else if (is_posix)
|
||||
os.posix.STDIN_FILENO
|
||||
else
|
||||
unreachable;
|
||||
const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
|
||||
return File.openHandle(handle);
|
||||
}
|
||||
|
||||
@ -56,11 +41,9 @@ pub const FileInStream = struct {
|
||||
pub const Stream = InStream(Error);
|
||||
|
||||
pub fn init(file: &File) FileInStream {
|
||||
return FileInStream {
|
||||
return FileInStream{
|
||||
.file = file,
|
||||
.stream = Stream {
|
||||
.readFn = readFn,
|
||||
},
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
}
|
||||
|
||||
@ -79,11 +62,9 @@ pub const FileOutStream = struct {
|
||||
pub const Stream = OutStream(Error);
|
||||
|
||||
pub fn init(file: &File) FileOutStream {
|
||||
return FileOutStream {
|
||||
return FileOutStream{
|
||||
.file = file,
|
||||
.stream = Stream {
|
||||
.writeFn = writeFn,
|
||||
},
|
||||
.stream = Stream{ .writeFn = writeFn },
|
||||
};
|
||||
}
|
||||
|
||||
@ -121,8 +102,7 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
}
|
||||
|
||||
const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
|
||||
if (new_buf_size == actual_buf_len)
|
||||
return error.StreamTooLong;
|
||||
if (new_buf_size == actual_buf_len) return error.StreamTooLong;
|
||||
try buffer.resize(new_buf_size);
|
||||
}
|
||||
}
|
||||
@ -165,9 +145,7 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
|
||||
/// Caller owns returned memory.
|
||||
/// If this function returns an error, the contents from the stream read so far are lost.
|
||||
pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator,
|
||||
delimiter: u8, max_size: usize) ![]u8
|
||||
{
|
||||
pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator, delimiter: u8, max_size: usize) ![]u8 {
|
||||
var buf = Buffer.initNull(allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
@ -283,7 +261,7 @@ pub fn BufferedInStream(comptime Error: type) type {
|
||||
pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Stream = InStream(Error);
|
||||
const Stream = InStream(Error);
|
||||
|
||||
pub stream: Stream,
|
||||
|
||||
@ -294,7 +272,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
||||
end_index: usize,
|
||||
|
||||
pub fn init(unbuffered_in_stream: &Stream) Self {
|
||||
return Self {
|
||||
return Self{
|
||||
.unbuffered_in_stream = unbuffered_in_stream,
|
||||
.buffer = undefined,
|
||||
|
||||
@ -305,9 +283,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
||||
.start_index = buffer_size,
|
||||
.end_index = buffer_size,
|
||||
|
||||
.stream = Stream {
|
||||
.readFn = readFn,
|
||||
},
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
}
|
||||
|
||||
@ -368,13 +344,11 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
|
||||
index: usize,
|
||||
|
||||
pub fn init(unbuffered_out_stream: &Stream) Self {
|
||||
return Self {
|
||||
return Self{
|
||||
.unbuffered_out_stream = unbuffered_out_stream,
|
||||
.buffer = undefined,
|
||||
.index = 0,
|
||||
.stream = Stream {
|
||||
.writeFn = writeFn,
|
||||
},
|
||||
.stream = Stream{ .writeFn = writeFn },
|
||||
};
|
||||
}
|
||||
|
||||
@ -416,11 +390,9 @@ pub const BufferOutStream = struct {
|
||||
pub const Stream = OutStream(Error);
|
||||
|
||||
pub fn init(buffer: &Buffer) BufferOutStream {
|
||||
return BufferOutStream {
|
||||
return BufferOutStream{
|
||||
.buffer = buffer,
|
||||
.stream = Stream {
|
||||
.writeFn = writeFn,
|
||||
},
|
||||
.stream = Stream{ .writeFn = writeFn },
|
||||
};
|
||||
}
|
||||
|
||||
@ -430,7 +402,6 @@ pub const BufferOutStream = struct {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
pub const BufferedAtomicFile = struct {
|
||||
atomic_file: os.AtomicFile,
|
||||
file_stream: FileOutStream,
|
||||
@ -441,7 +412,7 @@ pub const BufferedAtomicFile = struct {
|
||||
var self = try allocator.create(BufferedAtomicFile);
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
*self = BufferedAtomicFile {
|
||||
self.* = BufferedAtomicFile{
|
||||
.atomic_file = undefined,
|
||||
.file_stream = undefined,
|
||||
.buffered_stream = undefined,
|
||||
@ -489,7 +460,7 @@ pub fn readLine(buf: []u8) !usize {
|
||||
'\r' => {
|
||||
// trash the following \n
|
||||
_ = stream.readByte() catch return error.EndOfFile;
|
||||
return index;
|
||||
return index;
|
||||
},
|
||||
'\n' => return index,
|
||||
else => {
|
||||
|
||||
@ -42,7 +42,7 @@ test "write a file, read it, then delete it" {
|
||||
|
||||
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"));
|
||||
assert(mem.eql(u8, contents[contents.len - "end".len..], "end"));
|
||||
}
|
||||
try os.deleteFile(allocator, tmp_file_name);
|
||||
}
|
||||
|
||||
173
std/json.zig
173
std/json.zig
@ -35,7 +35,7 @@ pub const Token = struct {
|
||||
};
|
||||
|
||||
pub fn init(id: Id, count: usize, offset: u1) Token {
|
||||
return Token {
|
||||
return Token{
|
||||
.id = id,
|
||||
.offset = offset,
|
||||
.string_has_escape = false,
|
||||
@ -45,7 +45,7 @@ pub const Token = struct {
|
||||
}
|
||||
|
||||
pub fn initString(count: usize, has_unicode_escape: bool) Token {
|
||||
return Token {
|
||||
return Token{
|
||||
.id = Id.String,
|
||||
.offset = 0,
|
||||
.string_has_escape = has_unicode_escape,
|
||||
@ -55,7 +55,7 @@ pub const Token = struct {
|
||||
}
|
||||
|
||||
pub fn initNumber(count: usize, number_is_integer: bool) Token {
|
||||
return Token {
|
||||
return Token{
|
||||
.id = Id.Number,
|
||||
.offset = 0,
|
||||
.string_has_escape = false,
|
||||
@ -66,7 +66,7 @@ pub const Token = struct {
|
||||
|
||||
// A marker token is a zero-length
|
||||
pub fn initMarker(id: Id) Token {
|
||||
return Token {
|
||||
return Token{
|
||||
.id = id,
|
||||
.offset = 0,
|
||||
.string_has_escape = false,
|
||||
@ -77,7 +77,7 @@ pub const Token = struct {
|
||||
|
||||
// Slice into the underlying input string.
|
||||
pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {
|
||||
return input[i + self.offset - self.count .. i + self.offset];
|
||||
return input[i + self.offset - self.count..i + self.offset];
|
||||
}
|
||||
};
|
||||
|
||||
@ -86,7 +86,7 @@ pub const Token = struct {
|
||||
// parsing state requires ~40-50 bytes of stack space.
|
||||
//
|
||||
// Conforms strictly to RFC8529.
|
||||
const StreamingJsonParser = struct {
|
||||
pub const StreamingJsonParser = struct {
|
||||
// Current state
|
||||
state: State,
|
||||
// How many bytes we have counted for the current token
|
||||
@ -105,8 +105,8 @@ const StreamingJsonParser = struct {
|
||||
stack: u256,
|
||||
stack_used: u8,
|
||||
|
||||
const object_bit = 0;
|
||||
const array_bit = 1;
|
||||
const object_bit = 0;
|
||||
const array_bit = 1;
|
||||
const max_stack_size = @maxValue(u8);
|
||||
|
||||
pub fn init() StreamingJsonParser {
|
||||
@ -120,7 +120,7 @@ const StreamingJsonParser = struct {
|
||||
p.count = 0;
|
||||
// Set before ever read in main transition function
|
||||
p.after_string_state = undefined;
|
||||
p.after_value_state = State.ValueEnd; // handle end of values normally
|
||||
p.after_value_state = State.ValueEnd; // handle end of values normally
|
||||
p.stack = 0;
|
||||
p.stack_used = 0;
|
||||
p.complete = false;
|
||||
@ -181,7 +181,7 @@ const StreamingJsonParser = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Error = error {
|
||||
pub const Error = error{
|
||||
InvalidTopLevel,
|
||||
TooManyNestedItems,
|
||||
TooManyClosingItems,
|
||||
@ -206,8 +206,8 @@ const StreamingJsonParser = struct {
|
||||
//
|
||||
// There is currently no error recovery on a bad stream.
|
||||
pub fn feed(p: &StreamingJsonParser, c: u8, token1: &?Token, token2: &?Token) Error!void {
|
||||
*token1 = null;
|
||||
*token2 = null;
|
||||
token1.* = null;
|
||||
token2.* = null;
|
||||
p.count += 1;
|
||||
|
||||
// unlikely
|
||||
@ -228,7 +228,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.ValueBegin;
|
||||
p.after_string_state = State.ObjectSeparator;
|
||||
|
||||
*token = Token.initMarker(Token.Id.ObjectBegin);
|
||||
token.* = Token.initMarker(Token.Id.ObjectBegin);
|
||||
},
|
||||
'[' => {
|
||||
p.stack <<= 1;
|
||||
@ -238,7 +238,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.ValueBegin;
|
||||
p.after_string_state = State.ValueEnd;
|
||||
|
||||
*token = Token.initMarker(Token.Id.ArrayBegin);
|
||||
token.* = Token.initMarker(Token.Id.ArrayBegin);
|
||||
},
|
||||
'-' => {
|
||||
p.number_is_integer = true;
|
||||
@ -252,7 +252,7 @@ const StreamingJsonParser = struct {
|
||||
p.after_value_state = State.TopLevelEnd;
|
||||
p.count = 0;
|
||||
},
|
||||
'1' ... '9' => {
|
||||
'1'...'9' => {
|
||||
p.number_is_integer = true;
|
||||
p.state = State.NumberMaybeDigitOrDotOrExponent;
|
||||
p.after_value_state = State.TopLevelEnd;
|
||||
@ -324,7 +324,7 @@ const StreamingJsonParser = struct {
|
||||
else => {},
|
||||
}
|
||||
|
||||
*token = Token.initMarker(Token.Id.ObjectEnd);
|
||||
token.* = Token.initMarker(Token.Id.ObjectEnd);
|
||||
},
|
||||
']' => {
|
||||
if (p.stack & 1 != array_bit) {
|
||||
@ -348,7 +348,7 @@ const StreamingJsonParser = struct {
|
||||
else => {},
|
||||
}
|
||||
|
||||
*token = Token.initMarker(Token.Id.ArrayEnd);
|
||||
token.* = Token.initMarker(Token.Id.ArrayEnd);
|
||||
},
|
||||
'{' => {
|
||||
if (p.stack_used == max_stack_size) {
|
||||
@ -362,7 +362,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.ValueBegin;
|
||||
p.after_string_state = State.ObjectSeparator;
|
||||
|
||||
*token = Token.initMarker(Token.Id.ObjectBegin);
|
||||
token.* = Token.initMarker(Token.Id.ObjectBegin);
|
||||
},
|
||||
'[' => {
|
||||
if (p.stack_used == max_stack_size) {
|
||||
@ -376,7 +376,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.ValueBegin;
|
||||
p.after_string_state = State.ValueEnd;
|
||||
|
||||
*token = Token.initMarker(Token.Id.ArrayBegin);
|
||||
token.* = Token.initMarker(Token.Id.ArrayBegin);
|
||||
},
|
||||
'-' => {
|
||||
p.state = State.Number;
|
||||
@ -386,7 +386,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.NumberMaybeDotOrExponent;
|
||||
p.count = 0;
|
||||
},
|
||||
'1' ... '9' => {
|
||||
'1'...'9' => {
|
||||
p.state = State.NumberMaybeDigitOrDotOrExponent;
|
||||
p.count = 0;
|
||||
},
|
||||
@ -428,7 +428,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.ValueBegin;
|
||||
p.after_string_state = State.ObjectSeparator;
|
||||
|
||||
*token = Token.initMarker(Token.Id.ObjectBegin);
|
||||
token.* = Token.initMarker(Token.Id.ObjectBegin);
|
||||
},
|
||||
'[' => {
|
||||
if (p.stack_used == max_stack_size) {
|
||||
@ -442,7 +442,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.ValueBegin;
|
||||
p.after_string_state = State.ValueEnd;
|
||||
|
||||
*token = Token.initMarker(Token.Id.ArrayBegin);
|
||||
token.* = Token.initMarker(Token.Id.ArrayBegin);
|
||||
},
|
||||
'-' => {
|
||||
p.state = State.Number;
|
||||
@ -452,7 +452,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.NumberMaybeDotOrExponent;
|
||||
p.count = 0;
|
||||
},
|
||||
'1' ... '9' => {
|
||||
'1'...'9' => {
|
||||
p.state = State.NumberMaybeDigitOrDotOrExponent;
|
||||
p.count = 0;
|
||||
},
|
||||
@ -501,7 +501,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.TopLevelEnd;
|
||||
}
|
||||
|
||||
*token = Token.initMarker(Token.Id.ArrayEnd);
|
||||
token.* = Token.initMarker(Token.Id.ArrayEnd);
|
||||
},
|
||||
'}' => {
|
||||
if (p.stack_used == 0) {
|
||||
@ -519,7 +519,7 @@ const StreamingJsonParser = struct {
|
||||
p.state = State.TopLevelEnd;
|
||||
}
|
||||
|
||||
*token = Token.initMarker(Token.Id.ObjectEnd);
|
||||
token.* = Token.initMarker(Token.Id.ObjectEnd);
|
||||
},
|
||||
0x09, 0x0A, 0x0D, 0x20 => {
|
||||
// whitespace
|
||||
@ -543,7 +543,7 @@ const StreamingJsonParser = struct {
|
||||
},
|
||||
|
||||
State.String => switch (c) {
|
||||
0x00 ... 0x1F => {
|
||||
0x00...0x1F => {
|
||||
return error.InvalidControlCharacter;
|
||||
},
|
||||
'"' => {
|
||||
@ -553,21 +553,21 @@ const StreamingJsonParser = struct {
|
||||
p.complete = true;
|
||||
}
|
||||
|
||||
*token = Token.initString(p.count - 1, p.string_has_escape);
|
||||
token.* = Token.initString(p.count - 1, p.string_has_escape);
|
||||
},
|
||||
'\\' => {
|
||||
p.state = State.StringEscapeCharacter;
|
||||
},
|
||||
0x20, 0x21, 0x23 ... 0x5B, 0x5D ... 0x7F => {
|
||||
0x20, 0x21, 0x23...0x5B, 0x5D...0x7F => {
|
||||
// non-control ascii
|
||||
},
|
||||
0xC0 ... 0xDF => {
|
||||
0xC0...0xDF => {
|
||||
p.state = State.StringUtf8Byte1;
|
||||
},
|
||||
0xE0 ... 0xEF => {
|
||||
0xE0...0xEF => {
|
||||
p.state = State.StringUtf8Byte2;
|
||||
},
|
||||
0xF0 ... 0xFF => {
|
||||
0xF0...0xFF => {
|
||||
p.state = State.StringUtf8Byte3;
|
||||
},
|
||||
else => {
|
||||
@ -613,28 +613,28 @@ const StreamingJsonParser = struct {
|
||||
},
|
||||
|
||||
State.StringEscapeHexUnicode4 => switch (c) {
|
||||
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
|
||||
'0'...'9', 'A'...'F', 'a'...'f' => {
|
||||
p.state = State.StringEscapeHexUnicode3;
|
||||
},
|
||||
else => return error.InvalidUnicodeHexSymbol,
|
||||
},
|
||||
|
||||
State.StringEscapeHexUnicode3 => switch (c) {
|
||||
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
|
||||
'0'...'9', 'A'...'F', 'a'...'f' => {
|
||||
p.state = State.StringEscapeHexUnicode2;
|
||||
},
|
||||
else => return error.InvalidUnicodeHexSymbol,
|
||||
},
|
||||
|
||||
State.StringEscapeHexUnicode2 => switch (c) {
|
||||
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
|
||||
'0'...'9', 'A'...'F', 'a'...'f' => {
|
||||
p.state = State.StringEscapeHexUnicode1;
|
||||
},
|
||||
else => return error.InvalidUnicodeHexSymbol,
|
||||
},
|
||||
|
||||
State.StringEscapeHexUnicode1 => switch (c) {
|
||||
'0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
|
||||
'0'...'9', 'A'...'F', 'a'...'f' => {
|
||||
p.state = State.String;
|
||||
},
|
||||
else => return error.InvalidUnicodeHexSymbol,
|
||||
@ -646,7 +646,7 @@ const StreamingJsonParser = struct {
|
||||
'0' => {
|
||||
p.state = State.NumberMaybeDotOrExponent;
|
||||
},
|
||||
'1' ... '9' => {
|
||||
'1'...'9' => {
|
||||
p.state = State.NumberMaybeDigitOrDotOrExponent;
|
||||
},
|
||||
else => {
|
||||
@ -668,7 +668,7 @@ const StreamingJsonParser = struct {
|
||||
},
|
||||
else => {
|
||||
p.state = p.after_value_state;
|
||||
*token = Token.initNumber(p.count, p.number_is_integer);
|
||||
token.* = Token.initNumber(p.count, p.number_is_integer);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
@ -685,12 +685,12 @@ const StreamingJsonParser = struct {
|
||||
p.number_is_integer = false;
|
||||
p.state = State.NumberExponent;
|
||||
},
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
// another digit
|
||||
},
|
||||
else => {
|
||||
p.state = p.after_value_state;
|
||||
*token = Token.initNumber(p.count, p.number_is_integer);
|
||||
token.* = Token.initNumber(p.count, p.number_is_integer);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
@ -699,7 +699,7 @@ const StreamingJsonParser = struct {
|
||||
State.NumberFractionalRequired => {
|
||||
p.complete = p.after_value_state == State.TopLevelEnd;
|
||||
switch (c) {
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
p.state = State.NumberFractional;
|
||||
},
|
||||
else => {
|
||||
@ -711,7 +711,7 @@ const StreamingJsonParser = struct {
|
||||
State.NumberFractional => {
|
||||
p.complete = p.after_value_state == State.TopLevelEnd;
|
||||
switch (c) {
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
// another digit
|
||||
},
|
||||
'e', 'E' => {
|
||||
@ -720,7 +720,7 @@ const StreamingJsonParser = struct {
|
||||
},
|
||||
else => {
|
||||
p.state = p.after_value_state;
|
||||
*token = Token.initNumber(p.count, p.number_is_integer);
|
||||
token.* = Token.initNumber(p.count, p.number_is_integer);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
@ -735,18 +735,18 @@ const StreamingJsonParser = struct {
|
||||
},
|
||||
else => {
|
||||
p.state = p.after_value_state;
|
||||
*token = Token.initNumber(p.count, p.number_is_integer);
|
||||
token.* = Token.initNumber(p.count, p.number_is_integer);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
State.NumberExponent => switch (c) {
|
||||
'-', '+', => {
|
||||
'-', '+' => {
|
||||
p.complete = false;
|
||||
p.state = State.NumberExponentDigitsRequired;
|
||||
},
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
p.complete = p.after_value_state == State.TopLevelEnd;
|
||||
p.state = State.NumberExponentDigits;
|
||||
},
|
||||
@ -756,7 +756,7 @@ const StreamingJsonParser = struct {
|
||||
},
|
||||
|
||||
State.NumberExponentDigitsRequired => switch (c) {
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
p.complete = p.after_value_state == State.TopLevelEnd;
|
||||
p.state = State.NumberExponentDigits;
|
||||
},
|
||||
@ -768,12 +768,12 @@ const StreamingJsonParser = struct {
|
||||
State.NumberExponentDigits => {
|
||||
p.complete = p.after_value_state == State.TopLevelEnd;
|
||||
switch (c) {
|
||||
'0' ... '9' => {
|
||||
'0'...'9' => {
|
||||
// another digit
|
||||
},
|
||||
else => {
|
||||
p.state = p.after_value_state;
|
||||
*token = Token.initNumber(p.count, p.number_is_integer);
|
||||
token.* = Token.initNumber(p.count, p.number_is_integer);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
@ -793,7 +793,7 @@ const StreamingJsonParser = struct {
|
||||
'e' => {
|
||||
p.state = p.after_value_state;
|
||||
p.complete = p.state == State.TopLevelEnd;
|
||||
*token = Token.init(Token.Id.True, p.count + 1, 1);
|
||||
token.* = Token.init(Token.Id.True, p.count + 1, 1);
|
||||
},
|
||||
else => {
|
||||
return error.InvalidLiteral;
|
||||
@ -819,7 +819,7 @@ const StreamingJsonParser = struct {
|
||||
'e' => {
|
||||
p.state = p.after_value_state;
|
||||
p.complete = p.state == State.TopLevelEnd;
|
||||
*token = Token.init(Token.Id.False, p.count + 1, 1);
|
||||
token.* = Token.init(Token.Id.False, p.count + 1, 1);
|
||||
},
|
||||
else => {
|
||||
return error.InvalidLiteral;
|
||||
@ -840,7 +840,7 @@ const StreamingJsonParser = struct {
|
||||
'l' => {
|
||||
p.state = p.after_value_state;
|
||||
p.complete = p.state == State.TopLevelEnd;
|
||||
*token = Token.init(Token.Id.Null, p.count + 1, 1);
|
||||
token.* = Token.init(Token.Id.Null, p.count + 1, 1);
|
||||
},
|
||||
else => {
|
||||
return error.InvalidLiteral;
|
||||
@ -895,7 +895,7 @@ pub const Value = union(enum) {
|
||||
Object: ObjectMap,
|
||||
|
||||
pub fn dump(self: &const Value) void {
|
||||
switch (*self) {
|
||||
switch (self.*) {
|
||||
Value.Null => {
|
||||
std.debug.warn("null");
|
||||
},
|
||||
@ -950,7 +950,7 @@ pub const Value = union(enum) {
|
||||
}
|
||||
|
||||
fn dumpIndentLevel(self: &const Value, indent: usize, level: usize) void {
|
||||
switch (*self) {
|
||||
switch (self.*) {
|
||||
Value.Null => {
|
||||
std.debug.warn("null");
|
||||
},
|
||||
@ -1012,7 +1012,7 @@ pub const Value = union(enum) {
|
||||
};
|
||||
|
||||
// A non-stream JSON parser which constructs a tree of Value's.
|
||||
const JsonParser = struct {
|
||||
pub const JsonParser = struct {
|
||||
allocator: &Allocator,
|
||||
state: State,
|
||||
copy_strings: bool,
|
||||
@ -1027,7 +1027,7 @@ const JsonParser = struct {
|
||||
};
|
||||
|
||||
pub fn init(allocator: &Allocator, copy_strings: bool) JsonParser {
|
||||
return JsonParser {
|
||||
return JsonParser{
|
||||
.allocator = allocator,
|
||||
.state = State.Simple,
|
||||
.copy_strings = copy_strings,
|
||||
@ -1082,7 +1082,7 @@ const JsonParser = struct {
|
||||
|
||||
std.debug.assert(p.stack.len == 1);
|
||||
|
||||
return ValueTree {
|
||||
return ValueTree{
|
||||
.arena = arena,
|
||||
.root = p.stack.at(0),
|
||||
};
|
||||
@ -1115,11 +1115,11 @@ const JsonParser = struct {
|
||||
|
||||
switch (token.id) {
|
||||
Token.Id.ObjectBegin => {
|
||||
try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
|
||||
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
|
||||
p.state = State.ObjectKey;
|
||||
},
|
||||
Token.Id.ArrayBegin => {
|
||||
try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
|
||||
try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
|
||||
p.state = State.ArrayValue;
|
||||
},
|
||||
Token.Id.String => {
|
||||
@ -1133,12 +1133,12 @@ const JsonParser = struct {
|
||||
p.state = State.ObjectKey;
|
||||
},
|
||||
Token.Id.True => {
|
||||
_ = try object.put(key, Value { .Bool = true });
|
||||
_ = try object.put(key, Value{ .Bool = true });
|
||||
_ = p.stack.pop();
|
||||
p.state = State.ObjectKey;
|
||||
},
|
||||
Token.Id.False => {
|
||||
_ = try object.put(key, Value { .Bool = false });
|
||||
_ = try object.put(key, Value{ .Bool = false });
|
||||
_ = p.stack.pop();
|
||||
p.state = State.ObjectKey;
|
||||
},
|
||||
@ -1165,11 +1165,11 @@ const JsonParser = struct {
|
||||
try p.pushToParent(value);
|
||||
},
|
||||
Token.Id.ObjectBegin => {
|
||||
try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
|
||||
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
|
||||
p.state = State.ObjectKey;
|
||||
},
|
||||
Token.Id.ArrayBegin => {
|
||||
try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
|
||||
try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
|
||||
p.state = State.ArrayValue;
|
||||
},
|
||||
Token.Id.String => {
|
||||
@ -1179,10 +1179,10 @@ const JsonParser = struct {
|
||||
try array.append(try p.parseNumber(token, input, i));
|
||||
},
|
||||
Token.Id.True => {
|
||||
try array.append(Value { .Bool = true });
|
||||
try array.append(Value{ .Bool = true });
|
||||
},
|
||||
Token.Id.False => {
|
||||
try array.append(Value { .Bool = false });
|
||||
try array.append(Value{ .Bool = false });
|
||||
},
|
||||
Token.Id.Null => {
|
||||
try array.append(Value.Null);
|
||||
@ -1194,11 +1194,11 @@ const JsonParser = struct {
|
||||
},
|
||||
State.Simple => switch (token.id) {
|
||||
Token.Id.ObjectBegin => {
|
||||
try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
|
||||
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
|
||||
p.state = State.ObjectKey;
|
||||
},
|
||||
Token.Id.ArrayBegin => {
|
||||
try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
|
||||
try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
|
||||
p.state = State.ArrayValue;
|
||||
},
|
||||
Token.Id.String => {
|
||||
@ -1208,10 +1208,10 @@ const JsonParser = struct {
|
||||
try p.stack.append(try p.parseNumber(token, input, i));
|
||||
},
|
||||
Token.Id.True => {
|
||||
try p.stack.append(Value { .Bool = true });
|
||||
try p.stack.append(Value{ .Bool = true });
|
||||
},
|
||||
Token.Id.False => {
|
||||
try p.stack.append(Value { .Bool = false });
|
||||
try p.stack.append(Value{ .Bool = false });
|
||||
},
|
||||
Token.Id.Null => {
|
||||
try p.stack.append(Value.Null);
|
||||
@ -1248,15 +1248,14 @@ const JsonParser = struct {
|
||||
// TODO: We don't strictly have to copy values which do not contain any escape
|
||||
// characters if flagged with the option.
|
||||
const slice = token.slice(input, i);
|
||||
return Value { .String = try mem.dupe(p.allocator, u8, slice) };
|
||||
return Value{ .String = try mem.dupe(p.allocator, u8, slice) };
|
||||
}
|
||||
|
||||
fn parseNumber(p: &JsonParser, token: &const Token, input: []const u8, i: usize) !Value {
|
||||
return if (token.number_is_integer)
|
||||
Value { .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
|
||||
Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
|
||||
else
|
||||
@panic("TODO: fmt.parseFloat not yet implemented")
|
||||
;
|
||||
@panic("TODO: fmt.parseFloat not yet implemented");
|
||||
}
|
||||
};
|
||||
|
||||
@ -1267,21 +1266,21 @@ test "json parser dynamic" {
|
||||
defer p.deinit();
|
||||
|
||||
const s =
|
||||
\\{
|
||||
\\ "Image": {
|
||||
\\ "Width": 800,
|
||||
\\ "Height": 600,
|
||||
\\ "Title": "View from 15th Floor",
|
||||
\\ "Thumbnail": {
|
||||
\\ "Url": "http://www.example.com/image/481989943",
|
||||
\\ "Height": 125,
|
||||
\\ "Width": 100
|
||||
\\ },
|
||||
\\ "Animated" : false,
|
||||
\\ "IDs": [116, 943, 234, 38793]
|
||||
\\ }
|
||||
\\}
|
||||
;
|
||||
\\{
|
||||
\\ "Image": {
|
||||
\\ "Width": 800,
|
||||
\\ "Height": 600,
|
||||
\\ "Title": "View from 15th Floor",
|
||||
\\ "Thumbnail": {
|
||||
\\ "Url": "http://www.example.com/image/481989943",
|
||||
\\ "Height": 125,
|
||||
\\ "Width": 100
|
||||
\\ },
|
||||
\\ "Animated" : false,
|
||||
\\ "IDs": [116, 943, 234, 38793]
|
||||
\\ }
|
||||
\\}
|
||||
;
|
||||
|
||||
var tree = try p.parse(s);
|
||||
defer tree.deinit();
|
||||
|
||||
@ -81,9 +81,7 @@ test "y_array_with_several_null" {
|
||||
}
|
||||
|
||||
test "y_array_with_trailing_space" {
|
||||
ok(
|
||||
"[2] "
|
||||
);
|
||||
ok("[2] ");
|
||||
}
|
||||
|
||||
test "y_number_0e+1" {
|
||||
@ -431,15 +429,11 @@ test "y_string_two-byte-utf-8" {
|
||||
}
|
||||
|
||||
test "y_string_u+2028_line_sep" {
|
||||
ok(
|
||||
\\["
"]
|
||||
);
|
||||
ok("[\"\xe2\x80\xa8\"]");
|
||||
}
|
||||
|
||||
test "y_string_u+2029_par_sep" {
|
||||
ok(
|
||||
\\["
"]
|
||||
);
|
||||
ok("[\"\xe2\x80\xa9\"]");
|
||||
}
|
||||
|
||||
test "y_string_uescaped_newline" {
|
||||
@ -455,9 +449,7 @@ test "y_string_uEscape" {
|
||||
}
|
||||
|
||||
test "y_string_unescaped_char_delete" {
|
||||
ok(
|
||||
\\[""]
|
||||
);
|
||||
ok("[\"\x7f\"]");
|
||||
}
|
||||
|
||||
test "y_string_unicode_2" {
|
||||
@ -527,9 +519,7 @@ test "y_string_utf8" {
|
||||
}
|
||||
|
||||
test "y_string_with_del_character" {
|
||||
ok(
|
||||
\\["aa"]
|
||||
);
|
||||
ok("[\"a\x7fa\"]");
|
||||
}
|
||||
|
||||
test "y_structure_lonely_false" {
|
||||
@ -587,9 +577,7 @@ test "y_structure_true_in_array" {
|
||||
}
|
||||
|
||||
test "y_structure_whitespace_array" {
|
||||
ok(
|
||||
" [] "
|
||||
);
|
||||
ok(" [] ");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -704,7 +692,6 @@ test "n_array_newlines_unclosed" {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
test "n_array_number_and_comma" {
|
||||
err(
|
||||
\\[1,]
|
||||
@ -718,9 +705,7 @@ test "n_array_number_and_several_commas" {
|
||||
}
|
||||
|
||||
test "n_array_spaces_vertical_tab_formfeed" {
|
||||
err(
|
||||
\\["a"\f]
|
||||
);
|
||||
err("[\"\x0aa\"\\f]");
|
||||
}
|
||||
|
||||
test "n_array_star_inside" {
|
||||
@ -774,9 +759,7 @@ test "n_incomplete_true" {
|
||||
}
|
||||
|
||||
test "n_multidigit_number_then_00" {
|
||||
err(
|
||||
\\123 | ||||