mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 22:33:08 +00:00
Merge remote-tracking branch 'origin/master' into llvm7
This commit is contained in:
commit
32dd98b19f
@ -464,6 +464,7 @@ set(ZIG_STD_FILES
|
|||||||
"math/atan.zig"
|
"math/atan.zig"
|
||||||
"math/atan2.zig"
|
"math/atan2.zig"
|
||||||
"math/atanh.zig"
|
"math/atanh.zig"
|
||||||
|
"math/big/int.zig"
|
||||||
"math/cbrt.zig"
|
"math/cbrt.zig"
|
||||||
"math/ceil.zig"
|
"math/ceil.zig"
|
||||||
"math/complex/abs.zig"
|
"math/complex/abs.zig"
|
||||||
@ -555,6 +556,7 @@ set(ZIG_STD_FILES
|
|||||||
"special/compiler_rt/aulldiv.zig"
|
"special/compiler_rt/aulldiv.zig"
|
||||||
"special/compiler_rt/aullrem.zig"
|
"special/compiler_rt/aullrem.zig"
|
||||||
"special/compiler_rt/comparetf2.zig"
|
"special/compiler_rt/comparetf2.zig"
|
||||||
|
"special/compiler_rt/divti3.zig"
|
||||||
"special/compiler_rt/fixuint.zig"
|
"special/compiler_rt/fixuint.zig"
|
||||||
"special/compiler_rt/fixunsdfdi.zig"
|
"special/compiler_rt/fixunsdfdi.zig"
|
||||||
"special/compiler_rt/fixunsdfsi.zig"
|
"special/compiler_rt/fixunsdfsi.zig"
|
||||||
@ -565,6 +567,7 @@ set(ZIG_STD_FILES
|
|||||||
"special/compiler_rt/fixunstfdi.zig"
|
"special/compiler_rt/fixunstfdi.zig"
|
||||||
"special/compiler_rt/fixunstfsi.zig"
|
"special/compiler_rt/fixunstfsi.zig"
|
||||||
"special/compiler_rt/fixunstfti.zig"
|
"special/compiler_rt/fixunstfti.zig"
|
||||||
|
"special/compiler_rt/muloti4.zig"
|
||||||
"special/compiler_rt/index.zig"
|
"special/compiler_rt/index.zig"
|
||||||
"special/compiler_rt/udivmod.zig"
|
"special/compiler_rt/udivmod.zig"
|
||||||
"special/compiler_rt/udivmoddi4.zig"
|
"special/compiler_rt/udivmoddi4.zig"
|
||||||
|
|||||||
24
README.md
24
README.md
@ -55,18 +55,18 @@ that counts as "freestanding" for the purposes of this table.
|
|||||||
|i386 | OK | planned | OK | planned | planned |
|
|i386 | OK | planned | OK | planned | planned |
|
||||||
|x86_64 | OK | OK | OK | OK | planned |
|
|x86_64 | OK | OK | OK | OK | planned |
|
||||||
|arm | OK | planned | planned | N/A | planned |
|
|arm | OK | planned | planned | N/A | planned |
|
||||||
|aarch64 | OK | planned | planned | planned | planned |
|
|aarch64 | OK | planned | N/A | planned | planned |
|
||||||
|bpf | OK | planned | planned | N/A | planned |
|
|bpf | OK | planned | N/A | N/A | planned |
|
||||||
|hexagon | OK | planned | planned | N/A | planned |
|
|hexagon | OK | planned | N/A | N/A | planned |
|
||||||
|mips | OK | planned | planned | N/A | planned |
|
|mips | OK | planned | N/A | N/A | planned |
|
||||||
|powerpc | OK | planned | planned | N/A | planned |
|
|powerpc | OK | planned | N/A | N/A | planned |
|
||||||
|r600 | OK | planned | planned | N/A | planned |
|
|r600 | OK | planned | N/A | N/A | planned |
|
||||||
|amdgcn | OK | planned | planned | N/A | planned |
|
|amdgcn | OK | planned | N/A | N/A | planned |
|
||||||
|sparc | OK | planned | planned | N/A | planned |
|
|sparc | OK | planned | N/A | N/A | planned |
|
||||||
|s390x | OK | planned | planned | N/A | planned |
|
|s390x | OK | planned | N/A | N/A | planned |
|
||||||
|thumb | OK | planned | planned | N/A | planned |
|
|thumb | OK | planned | N/A | N/A | planned |
|
||||||
|spir | OK | planned | planned | N/A | planned |
|
|spir | OK | planned | N/A | N/A | planned |
|
||||||
|lanai | OK | planned | planned | N/A | planned |
|
|lanai | OK | planned | N/A | N/A | planned |
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
|
|||||||
@ -63,6 +63,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
exe.addObjectFile(lib);
|
exe.addObjectFile(lib);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_wasm");
|
||||||
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_elf");
|
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_elf");
|
||||||
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_coff");
|
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_coff");
|
||||||
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_lib");
|
addCppLib(b, exe, cmake_binary_dir, "embedded_lld_lib");
|
||||||
@ -74,7 +75,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
cxx_compiler,
|
cxx_compiler,
|
||||||
"-print-file-name=libstdc++.a",
|
"-print-file-name=libstdc++.a",
|
||||||
});
|
});
|
||||||
const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
|
const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?;
|
||||||
if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
|
if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
|
||||||
warn(
|
warn(
|
||||||
\\Unable to determine path to libstdc++.a
|
\\Unable to determine path to libstdc++.a
|
||||||
@ -101,11 +102,11 @@ pub fn build(b: *Builder) !void {
|
|||||||
|
|
||||||
b.default_step.dependOn(&exe.step);
|
b.default_step.dependOn(&exe.step);
|
||||||
|
|
||||||
const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") ?? false;
|
const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
|
||||||
if (!skip_self_hosted) {
|
if (!skip_self_hosted) {
|
||||||
test_step.dependOn(&exe.step);
|
test_step.dependOn(&exe.step);
|
||||||
}
|
}
|
||||||
const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") ?? false;
|
const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") orelse false;
|
||||||
exe.setVerboseLink(verbose_link_exe);
|
exe.setVerboseLink(verbose_link_exe);
|
||||||
|
|
||||||
b.installArtifact(exe);
|
b.installArtifact(exe);
|
||||||
@ -113,7 +114,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
installCHeaders(b, c_header_files);
|
installCHeaders(b, c_header_files);
|
||||||
|
|
||||||
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
|
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
|
||||||
const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") ?? false;
|
const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") orelse false;
|
||||||
|
|
||||||
test_step.dependOn(docs_step);
|
test_step.dependOn(docs_step);
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ Every type has a "handle". If a type is a simple primitive type such as i32 or
|
|||||||
f64, the handle is "by value", meaning that we pass around the value itself when
|
f64, the handle is "by value", meaning that we pass around the value itself when
|
||||||
we refer to a value of that type.
|
we refer to a value of that type.
|
||||||
|
|
||||||
If a type is a container, error union, maybe type, slice, or array, then its
|
If a type is a container, error union, optional type, slice, or array, then its
|
||||||
handle is a pointer, and everywhere we refer to a value of this type we refer to
|
handle is a pointer, and everywhere we refer to a value of this type we refer to
|
||||||
a pointer.
|
a pointer.
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ Error union types are represented as:
|
|||||||
payload: T,
|
payload: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe types are represented as:
|
Optional types are represented as:
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
payload: T,
|
payload: T,
|
||||||
@ -28,6 +28,6 @@ Maybe types are represented as:
|
|||||||
|
|
||||||
## Data Optimizations
|
## Data Optimizations
|
||||||
|
|
||||||
Maybe pointer types are special: the 0x0 pointer value is used to represent a
|
Optional pointer types are special: the 0x0 pointer value is used to represent a
|
||||||
null pointer. Thus, instead of the struct above, maybe pointer types are
|
null pointer. Thus, instead of the struct above, optional pointer types are
|
||||||
represented as a `usize` in codegen and the handle is by value.
|
represented as a `usize` in codegen and the handle is by value.
|
||||||
|
|||||||
@ -25,13 +25,13 @@ pub fn main() !void {
|
|||||||
|
|
||||||
if (!args_it.skip()) @panic("expected self arg");
|
if (!args_it.skip()) @panic("expected self arg");
|
||||||
|
|
||||||
const zig_exe = try (args_it.next(allocator) ?? @panic("expected zig exe arg"));
|
const zig_exe = try (args_it.next(allocator) orelse @panic("expected zig exe arg"));
|
||||||
defer allocator.free(zig_exe);
|
defer allocator.free(zig_exe);
|
||||||
|
|
||||||
const in_file_name = try (args_it.next(allocator) ?? @panic("expected input arg"));
|
const in_file_name = try (args_it.next(allocator) orelse @panic("expected input arg"));
|
||||||
defer allocator.free(in_file_name);
|
defer allocator.free(in_file_name);
|
||||||
|
|
||||||
const out_file_name = try (args_it.next(allocator) ?? @panic("expected output arg"));
|
const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));
|
||||||
defer allocator.free(out_file_name);
|
defer allocator.free(out_file_name);
|
||||||
|
|
||||||
var in_file = try os.File.openRead(allocator, in_file_name);
|
var in_file = try os.File.openRead(allocator, in_file_name);
|
||||||
@ -51,14 +51,8 @@ pub fn main() !void {
|
|||||||
var toc = try genToc(allocator, &tokenizer);
|
var toc = try genToc(allocator, &tokenizer);
|
||||||
|
|
||||||
try os.makePath(allocator, tmp_dir_name);
|
try os.makePath(allocator, tmp_dir_name);
|
||||||
defer {
|
defer os.deleteTree(allocator, tmp_dir_name) catch {};
|
||||||
// TODO issue #709
|
|
||||||
// disabled to pass CI tests, but obviously we want to implement this
|
|
||||||
// and then remove this workaround
|
|
||||||
if (builtin.os != builtin.Os.windows) {
|
|
||||||
os.deleteTree(allocator, tmp_dir_name) catch {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
|
try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
|
||||||
try buffered_out_stream.flush();
|
try buffered_out_stream.flush();
|
||||||
}
|
}
|
||||||
@ -300,6 +294,7 @@ const Link = struct {
|
|||||||
const Node = union(enum) {
|
const Node = union(enum) {
|
||||||
Content: []const u8,
|
Content: []const u8,
|
||||||
Nav,
|
Nav,
|
||||||
|
Builtin,
|
||||||
HeaderOpen: HeaderOpen,
|
HeaderOpen: HeaderOpen,
|
||||||
SeeAlso: []const SeeAlsoItem,
|
SeeAlso: []const SeeAlsoItem,
|
||||||
Code: Code,
|
Code: Code,
|
||||||
@ -356,6 +351,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
|
|||||||
_ = try eatToken(tokenizer, Token.Id.BracketClose);
|
_ = try eatToken(tokenizer, Token.Id.BracketClose);
|
||||||
|
|
||||||
try nodes.append(Node.Nav);
|
try nodes.append(Node.Nav);
|
||||||
|
} else if (mem.eql(u8, tag_name, "builtin")) {
|
||||||
|
_ = try eatToken(tokenizer, Token.Id.BracketClose);
|
||||||
|
try nodes.append(Node.Builtin);
|
||||||
} else if (mem.eql(u8, tag_name, "header_open")) {
|
} else if (mem.eql(u8, tag_name, "header_open")) {
|
||||||
_ = try eatToken(tokenizer, Token.Id.Separator);
|
_ = try eatToken(tokenizer, Token.Id.Separator);
|
||||||
const content_token = try eatToken(tokenizer, Token.Id.TagContent);
|
const content_token = try eatToken(tokenizer, Token.Id.TagContent);
|
||||||
@ -690,6 +688,9 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
|
|||||||
|
|
||||||
fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
|
fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
|
||||||
var code_progress_index: usize = 0;
|
var code_progress_index: usize = 0;
|
||||||
|
|
||||||
|
const builtin_code = try escapeHtml(allocator, try getBuiltinCode(allocator, zig_exe));
|
||||||
|
|
||||||
for (toc.nodes) |node| {
|
for (toc.nodes) |node| {
|
||||||
switch (node) {
|
switch (node) {
|
||||||
Node.Content => |data| {
|
Node.Content => |data| {
|
||||||
@ -704,6 +705,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||||||
Node.Nav => {
|
Node.Nav => {
|
||||||
try out.write(toc.toc);
|
try out.write(toc.toc);
|
||||||
},
|
},
|
||||||
|
Node.Builtin => {
|
||||||
|
try out.print("<pre><code class=\"zig\">{}</code></pre>", builtin_code);
|
||||||
|
},
|
||||||
Node.HeaderOpen => |info| {
|
Node.HeaderOpen => |info| {
|
||||||
try out.print("<h{} id=\"{}\">{}</h{}>\n", info.n, info.url, info.name, info.n);
|
try out.print("<h{} id=\"{}\">{}</h{}>\n", info.n, info.url, info.name, info.n);
|
||||||
},
|
},
|
||||||
@ -954,6 +958,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||||||
var build_args = std.ArrayList([]const u8).init(allocator);
|
var build_args = std.ArrayList([]const u8).init(allocator);
|
||||||
defer build_args.deinit();
|
defer build_args.deinit();
|
||||||
|
|
||||||
|
const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
|
||||||
|
const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext);
|
||||||
|
|
||||||
try build_args.appendSlice([][]const u8{
|
try build_args.appendSlice([][]const u8{
|
||||||
zig_exe,
|
zig_exe,
|
||||||
"build-obj",
|
"build-obj",
|
||||||
@ -962,6 +969,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
|||||||
"on",
|
"on",
|
||||||
"--output",
|
"--output",
|
||||||
tmp_obj_file_name,
|
tmp_obj_file_name,
|
||||||
|
"--output-h",
|
||||||
|
output_h_file_name,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!code.is_inline) {
|
if (!code.is_inline) {
|
||||||
@ -1060,3 +1069,11 @@ fn exec(allocator: *mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getBuiltinCode(allocator: *mem.Allocator, zig_exe: []const u8) ![]const u8 {
|
||||||
|
const result = try exec(allocator, []const []const u8{
|
||||||
|
zig_exe,
|
||||||
|
"builtin",
|
||||||
|
});
|
||||||
|
return result.stdout;
|
||||||
|
}
|
||||||
|
|||||||
1126
doc/langref.html.in
1126
doc/langref.html.in
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ const allocator = std.debug.global_allocator;
|
|||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var args_it = os.args();
|
var args_it = os.args();
|
||||||
const exe = try unwrapArg(??args_it.next(allocator));
|
const exe = try unwrapArg(args_it.next(allocator).?);
|
||||||
var catted_anything = false;
|
var catted_anything = false;
|
||||||
var stdout_file = try io.getStdOut();
|
var stdout_file = try io.getStdOut();
|
||||||
|
|
||||||
|
|||||||
@ -99,7 +99,7 @@ pub const Args = struct {
|
|||||||
error.ArgumentNotInAllowedSet => {
|
error.ArgumentNotInAllowedSet => {
|
||||||
std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
|
std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
|
||||||
std.debug.warn("allowed options are ");
|
std.debug.warn("allowed options are ");
|
||||||
for (??flag.allowed_set) |possible| {
|
for (flag.allowed_set.?) |possible| {
|
||||||
std.debug.warn("'{}' ", possible);
|
std.debug.warn("'{}' ", possible);
|
||||||
}
|
}
|
||||||
std.debug.warn("\n");
|
std.debug.warn("\n");
|
||||||
@ -276,14 +276,14 @@ test "parse arguments" {
|
|||||||
debug.assert(!args.present("help2"));
|
debug.assert(!args.present("help2"));
|
||||||
debug.assert(!args.present("init"));
|
debug.assert(!args.present("init"));
|
||||||
|
|
||||||
debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig"));
|
debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig"));
|
||||||
debug.assert(mem.eql(u8, ??args.single("color"), "on"));
|
debug.assert(mem.eql(u8, args.single("color").?, "on"));
|
||||||
|
|
||||||
const objects = ??args.many("object");
|
const objects = args.many("object").?;
|
||||||
debug.assert(mem.eql(u8, objects[0], "obj1"));
|
debug.assert(mem.eql(u8, objects[0], "obj1"));
|
||||||
debug.assert(mem.eql(u8, objects[1], "obj2"));
|
debug.assert(mem.eql(u8, objects[1], "obj2"));
|
||||||
|
|
||||||
debug.assert(mem.eql(u8, ??args.single("library"), "lib2"));
|
debug.assert(mem.eql(u8, args.single("library").?, "lib2"));
|
||||||
|
|
||||||
const pos = args.positionals.toSliceConst();
|
const pos = args.positionals.toSliceConst();
|
||||||
debug.assert(mem.eql(u8, pos[0], "build"));
|
debug.assert(mem.eql(u8, pos[0], "build"));
|
||||||
|
|||||||
@ -27,7 +27,7 @@ pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
|
|||||||
|
|
||||||
var cur_path: []const u8 = self_exe_path;
|
var cur_path: []const u8 = self_exe_path;
|
||||||
while (true) {
|
while (true) {
|
||||||
const test_dir = os.path.dirname(cur_path);
|
const test_dir = os.path.dirname(cur_path) orelse ".";
|
||||||
|
|
||||||
if (mem.eql(u8, test_dir, cur_path)) {
|
if (mem.eql(u8, test_dir, cur_path)) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -8,6 +8,6 @@ pub const ContextRef = removeNullability(c.LLVMContextRef);
|
|||||||
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
|
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
|
||||||
|
|
||||||
fn removeNullability(comptime T: type) type {
|
fn removeNullability(comptime T: type) type {
|
||||||
comptime assert(@typeId(T) == builtin.TypeId.Nullable);
|
comptime assert(@typeId(T) == builtin.TypeId.Optional);
|
||||||
return T.Child;
|
return T.Child;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -212,7 +212,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
|
|||||||
const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
|
const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
|
||||||
defer allocator.free(build_runner_path);
|
defer allocator.free(build_runner_path);
|
||||||
|
|
||||||
const build_file = flags.single("build-file") ?? "build.zig";
|
const build_file = flags.single("build-file") orelse "build.zig";
|
||||||
const build_file_abs = try os.path.resolve(allocator, ".", build_file);
|
const build_file_abs = try os.path.resolve(allocator, ".", build_file);
|
||||||
defer allocator.free(build_file_abs);
|
defer allocator.free(build_file_abs);
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
|
|||||||
defer build_args.deinit();
|
defer build_args.deinit();
|
||||||
|
|
||||||
const build_file_basename = os.path.basename(build_file_abs);
|
const build_file_basename = os.path.basename(build_file_abs);
|
||||||
const build_file_dirname = os.path.dirname(build_file_abs);
|
const build_file_dirname = os.path.dirname(build_file_abs) orelse ".";
|
||||||
|
|
||||||
var full_cache_dir: []u8 = undefined;
|
var full_cache_dir: []u8 = undefined;
|
||||||
if (flags.single("cache-dir")) |cache_dir| {
|
if (flags.single("cache-dir")) |cache_dir| {
|
||||||
@ -490,7 +490,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
|
|||||||
try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
|
try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
|
||||||
os.exit(1);
|
os.exit(1);
|
||||||
}
|
}
|
||||||
cur_pkg = ??cur_pkg.parent;
|
cur_pkg = cur_pkg.parent.?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,28 +514,28 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const basename = os.path.basename(??in_file);
|
const basename = os.path.basename(in_file.?);
|
||||||
var it = mem.split(basename, ".");
|
var it = mem.split(basename, ".");
|
||||||
const root_name = it.next() ?? {
|
const root_name = it.next() orelse {
|
||||||
try stderr.write("file name cannot be empty\n");
|
try stderr.write("file name cannot be empty\n");
|
||||||
os.exit(1);
|
os.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
const asm_a = flags.many("assembly");
|
const asm_a = flags.many("assembly");
|
||||||
const obj_a = flags.many("object");
|
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)) {
|
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");
|
try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
|
||||||
os.exit(1);
|
os.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) {
|
if (out_type == Module.Kind.Obj and (obj_a != null and obj_a.?.len != 0)) {
|
||||||
try stderr.write("When building an object file, --object arguments are invalid\n");
|
try stderr.write("When building an object file, --object arguments are invalid\n");
|
||||||
os.exit(1);
|
os.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const zig_root_source_file = in_file;
|
const zig_root_source_file = in_file;
|
||||||
|
|
||||||
const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch {
|
const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") orelse "zig-cache"[0..]) catch {
|
||||||
os.exit(1);
|
os.exit(1);
|
||||||
};
|
};
|
||||||
defer allocator.free(full_cache_dir);
|
defer allocator.free(full_cache_dir);
|
||||||
@ -555,9 +555,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
|
|||||||
);
|
);
|
||||||
defer module.destroy();
|
defer module.destroy();
|
||||||
|
|
||||||
module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
|
module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") orelse "0", 10);
|
||||||
module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10);
|
module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") orelse "0", 10);
|
||||||
module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10);
|
module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") orelse "0", 10);
|
||||||
|
|
||||||
module.is_test = false;
|
module.is_test = false;
|
||||||
|
|
||||||
@ -652,7 +652,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
|
|||||||
}
|
}
|
||||||
|
|
||||||
try module.build();
|
try module.build();
|
||||||
try module.link(flags.single("out-file") ?? null);
|
try module.link(flags.single("out-file") orelse null);
|
||||||
|
|
||||||
if (flags.present("print-timing-info")) {
|
if (flags.present("print-timing-info")) {
|
||||||
// codegen_print_timing_info(g, stderr);
|
// codegen_print_timing_info(g, stderr);
|
||||||
@ -734,7 +734,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
|
|||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
|
const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
|
||||||
try stderr.print("unable to open '{}': {}", file_path, err);
|
try stderr.print("unable to open '{}': {}\n", file_path, err);
|
||||||
fmt_errors = true;
|
fmt_errors = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -130,13 +130,13 @@ pub const Module = struct {
|
|||||||
var name_buffer = try Buffer.init(allocator, name);
|
var name_buffer = try Buffer.init(allocator, name);
|
||||||
errdefer name_buffer.deinit();
|
errdefer name_buffer.deinit();
|
||||||
|
|
||||||
const context = c.LLVMContextCreate() ?? return error.OutOfMemory;
|
const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
|
||||||
errdefer c.LLVMContextDispose(context);
|
errdefer c.LLVMContextDispose(context);
|
||||||
|
|
||||||
const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory;
|
const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) orelse return error.OutOfMemory;
|
||||||
errdefer c.LLVMDisposeModule(module);
|
errdefer c.LLVMDisposeModule(module);
|
||||||
|
|
||||||
const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory;
|
const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
|
||||||
errdefer c.LLVMDisposeBuilder(builder);
|
errdefer c.LLVMDisposeBuilder(builder);
|
||||||
|
|
||||||
const module_ptr = try allocator.create(Module);
|
const module_ptr = try allocator.create(Module);
|
||||||
@ -223,7 +223,7 @@ pub const Module = struct {
|
|||||||
c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
|
c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
|
const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");
|
||||||
const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
|
const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
|
||||||
try printError("unable to get real path '{}': {}", root_src_path, err);
|
try printError("unable to get real path '{}': {}", root_src_path, err);
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
@ -144,6 +144,9 @@ enum ConstPtrSpecial {
|
|||||||
// understand the value of pointee at compile time. However, we will still
|
// understand the value of pointee at compile time. However, we will still
|
||||||
// emit a binary with a compile time known address.
|
// emit a binary with a compile time known address.
|
||||||
// In this case index is the numeric address value.
|
// In this case index is the numeric address value.
|
||||||
|
// We also use this for null pointer. We need the data layout for ConstCastOnly == true
|
||||||
|
// types to be the same, so all optionals of pointer types use x_ptr
|
||||||
|
// instead of x_optional
|
||||||
ConstPtrSpecialHardCodedAddr,
|
ConstPtrSpecialHardCodedAddr,
|
||||||
// This means that the pointer represents memory of assigning to _.
|
// This means that the pointer represents memory of assigning to _.
|
||||||
// That is, storing discards the data, and loading is invalid.
|
// That is, storing discards the data, and loading is invalid.
|
||||||
@ -219,10 +222,10 @@ enum RuntimeHintErrorUnion {
|
|||||||
RuntimeHintErrorUnionNonError,
|
RuntimeHintErrorUnionNonError,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RuntimeHintMaybe {
|
enum RuntimeHintOptional {
|
||||||
RuntimeHintMaybeUnknown,
|
RuntimeHintOptionalUnknown,
|
||||||
RuntimeHintMaybeNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
|
RuntimeHintOptionalNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
|
||||||
RuntimeHintMaybeNonNull,
|
RuntimeHintOptionalNonNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RuntimeHintPtr {
|
enum RuntimeHintPtr {
|
||||||
@ -251,7 +254,7 @@ struct ConstExprValue {
|
|||||||
bool x_bool;
|
bool x_bool;
|
||||||
ConstBoundFnValue x_bound_fn;
|
ConstBoundFnValue x_bound_fn;
|
||||||
TypeTableEntry *x_type;
|
TypeTableEntry *x_type;
|
||||||
ConstExprValue *x_maybe;
|
ConstExprValue *x_optional;
|
||||||
ConstErrValue x_err_union;
|
ConstErrValue x_err_union;
|
||||||
ErrorTableEntry *x_err_set;
|
ErrorTableEntry *x_err_set;
|
||||||
BigInt x_enum_tag;
|
BigInt x_enum_tag;
|
||||||
@ -265,7 +268,7 @@ struct ConstExprValue {
|
|||||||
|
|
||||||
// populated if special == ConstValSpecialRuntime
|
// populated if special == ConstValSpecialRuntime
|
||||||
RuntimeHintErrorUnion rh_error_union;
|
RuntimeHintErrorUnion rh_error_union;
|
||||||
RuntimeHintMaybe rh_maybe;
|
RuntimeHintOptional rh_maybe;
|
||||||
RuntimeHintPtr rh_ptr;
|
RuntimeHintPtr rh_ptr;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
@ -384,6 +387,7 @@ enum NodeType {
|
|||||||
NodeTypeSliceExpr,
|
NodeTypeSliceExpr,
|
||||||
NodeTypeFieldAccessExpr,
|
NodeTypeFieldAccessExpr,
|
||||||
NodeTypePtrDeref,
|
NodeTypePtrDeref,
|
||||||
|
NodeTypeUnwrapOptional,
|
||||||
NodeTypeUse,
|
NodeTypeUse,
|
||||||
NodeTypeBoolLiteral,
|
NodeTypeBoolLiteral,
|
||||||
NodeTypeNullLiteral,
|
NodeTypeNullLiteral,
|
||||||
@ -553,7 +557,7 @@ enum BinOpType {
|
|||||||
BinOpTypeMultWrap,
|
BinOpTypeMultWrap,
|
||||||
BinOpTypeDiv,
|
BinOpTypeDiv,
|
||||||
BinOpTypeMod,
|
BinOpTypeMod,
|
||||||
BinOpTypeUnwrapMaybe,
|
BinOpTypeUnwrapOptional,
|
||||||
BinOpTypeArrayCat,
|
BinOpTypeArrayCat,
|
||||||
BinOpTypeArrayMult,
|
BinOpTypeArrayMult,
|
||||||
BinOpTypeErrorUnion,
|
BinOpTypeErrorUnion,
|
||||||
@ -572,6 +576,10 @@ struct AstNodeCatchExpr {
|
|||||||
AstNode *op2;
|
AstNode *op2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstNodeUnwrapOptional {
|
||||||
|
AstNode *expr;
|
||||||
|
};
|
||||||
|
|
||||||
enum CastOp {
|
enum CastOp {
|
||||||
CastOpNoCast, // signifies the function call expression is not a cast
|
CastOpNoCast, // signifies the function call expression is not a cast
|
||||||
CastOpNoop, // fn call expr is a cast, but does nothing
|
CastOpNoop, // fn call expr is a cast, but does nothing
|
||||||
@ -583,6 +591,7 @@ enum CastOp {
|
|||||||
CastOpNumLitToConcrete,
|
CastOpNumLitToConcrete,
|
||||||
CastOpErrSet,
|
CastOpErrSet,
|
||||||
CastOpBitCast,
|
CastOpBitCast,
|
||||||
|
CastOpPtrOfArrayToSlice,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeFnCallExpr {
|
struct AstNodeFnCallExpr {
|
||||||
@ -619,8 +628,7 @@ enum PrefixOp {
|
|||||||
PrefixOpBinNot,
|
PrefixOpBinNot,
|
||||||
PrefixOpNegation,
|
PrefixOpNegation,
|
||||||
PrefixOpNegationWrap,
|
PrefixOpNegationWrap,
|
||||||
PrefixOpMaybe,
|
PrefixOpOptional,
|
||||||
PrefixOpUnwrapMaybe,
|
|
||||||
PrefixOpAddrOf,
|
PrefixOpAddrOf,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -905,6 +913,7 @@ struct AstNode {
|
|||||||
AstNodeTestDecl test_decl;
|
AstNodeTestDecl test_decl;
|
||||||
AstNodeBinOpExpr bin_op_expr;
|
AstNodeBinOpExpr bin_op_expr;
|
||||||
AstNodeCatchExpr unwrap_err_expr;
|
AstNodeCatchExpr unwrap_err_expr;
|
||||||
|
AstNodeUnwrapOptional unwrap_optional;
|
||||||
AstNodePrefixOpExpr prefix_op_expr;
|
AstNodePrefixOpExpr prefix_op_expr;
|
||||||
AstNodePointerType pointer_type;
|
AstNodePointerType pointer_type;
|
||||||
AstNodeFnCallExpr fn_call_expr;
|
AstNodeFnCallExpr fn_call_expr;
|
||||||
@ -1037,6 +1046,10 @@ struct TypeTableEntryStruct {
|
|||||||
// whether we've finished resolving it
|
// whether we've finished resolving it
|
||||||
bool complete;
|
bool complete;
|
||||||
|
|
||||||
|
// whether any of the fields require comptime
|
||||||
|
// the value is not valid until zero_bits_known == true
|
||||||
|
bool requires_comptime;
|
||||||
|
|
||||||
bool zero_bits_loop_flag;
|
bool zero_bits_loop_flag;
|
||||||
bool zero_bits_known;
|
bool zero_bits_known;
|
||||||
uint32_t abi_alignment; // also figured out with zero_bits pass
|
uint32_t abi_alignment; // also figured out with zero_bits pass
|
||||||
@ -1044,7 +1057,7 @@ struct TypeTableEntryStruct {
|
|||||||
HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
|
HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeTableEntryMaybe {
|
struct TypeTableEntryOptional {
|
||||||
TypeTableEntry *child_type;
|
TypeTableEntry *child_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1078,8 +1091,7 @@ struct TypeTableEntryEnum {
|
|||||||
bool zero_bits_loop_flag;
|
bool zero_bits_loop_flag;
|
||||||
bool zero_bits_known;
|
bool zero_bits_known;
|
||||||
|
|
||||||
bool generate_name_table;
|
LLVMValueRef name_function;
|
||||||
LLVMValueRef name_table;
|
|
||||||
|
|
||||||
HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
|
HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
|
||||||
};
|
};
|
||||||
@ -1105,6 +1117,10 @@ struct TypeTableEntryUnion {
|
|||||||
// whether we've finished resolving it
|
// whether we've finished resolving it
|
||||||
bool complete;
|
bool complete;
|
||||||
|
|
||||||
|
// whether any of the fields require comptime
|
||||||
|
// the value is not valid until zero_bits_known == true
|
||||||
|
bool requires_comptime;
|
||||||
|
|
||||||
bool zero_bits_loop_flag;
|
bool zero_bits_loop_flag;
|
||||||
bool zero_bits_known;
|
bool zero_bits_known;
|
||||||
uint32_t abi_alignment; // also figured out with zero_bits pass
|
uint32_t abi_alignment; // also figured out with zero_bits pass
|
||||||
@ -1163,7 +1179,7 @@ enum TypeTableEntryId {
|
|||||||
TypeTableEntryIdComptimeInt,
|
TypeTableEntryIdComptimeInt,
|
||||||
TypeTableEntryIdUndefined,
|
TypeTableEntryIdUndefined,
|
||||||
TypeTableEntryIdNull,
|
TypeTableEntryIdNull,
|
||||||
TypeTableEntryIdMaybe,
|
TypeTableEntryIdOptional,
|
||||||
TypeTableEntryIdErrorUnion,
|
TypeTableEntryIdErrorUnion,
|
||||||
TypeTableEntryIdErrorSet,
|
TypeTableEntryIdErrorSet,
|
||||||
TypeTableEntryIdEnum,
|
TypeTableEntryIdEnum,
|
||||||
@ -1194,7 +1210,7 @@ struct TypeTableEntry {
|
|||||||
TypeTableEntryFloat floating;
|
TypeTableEntryFloat floating;
|
||||||
TypeTableEntryArray array;
|
TypeTableEntryArray array;
|
||||||
TypeTableEntryStruct structure;
|
TypeTableEntryStruct structure;
|
||||||
TypeTableEntryMaybe maybe;
|
TypeTableEntryOptional maybe;
|
||||||
TypeTableEntryErrorUnion error_union;
|
TypeTableEntryErrorUnion error_union;
|
||||||
TypeTableEntryErrorSet error_set;
|
TypeTableEntryErrorSet error_set;
|
||||||
TypeTableEntryEnum enumeration;
|
TypeTableEntryEnum enumeration;
|
||||||
@ -1346,7 +1362,6 @@ enum BuiltinFnId {
|
|||||||
BuiltinFnIdSetRuntimeSafety,
|
BuiltinFnIdSetRuntimeSafety,
|
||||||
BuiltinFnIdSetFloatMode,
|
BuiltinFnIdSetFloatMode,
|
||||||
BuiltinFnIdTypeName,
|
BuiltinFnIdTypeName,
|
||||||
BuiltinFnIdCanImplicitCast,
|
|
||||||
BuiltinFnIdPanic,
|
BuiltinFnIdPanic,
|
||||||
BuiltinFnIdPtrCast,
|
BuiltinFnIdPtrCast,
|
||||||
BuiltinFnIdBitCast,
|
BuiltinFnIdBitCast,
|
||||||
@ -1391,10 +1406,11 @@ enum PanicMsgId {
|
|||||||
PanicMsgIdRemainderDivisionByZero,
|
PanicMsgIdRemainderDivisionByZero,
|
||||||
PanicMsgIdExactDivisionRemainder,
|
PanicMsgIdExactDivisionRemainder,
|
||||||
PanicMsgIdSliceWidenRemainder,
|
PanicMsgIdSliceWidenRemainder,
|
||||||
PanicMsgIdUnwrapMaybeFail,
|
PanicMsgIdUnwrapOptionalFail,
|
||||||
PanicMsgIdInvalidErrorCode,
|
PanicMsgIdInvalidErrorCode,
|
||||||
PanicMsgIdIncorrectAlignment,
|
PanicMsgIdIncorrectAlignment,
|
||||||
PanicMsgIdBadUnionField,
|
PanicMsgIdBadUnionField,
|
||||||
|
PanicMsgIdBadEnumValue,
|
||||||
|
|
||||||
PanicMsgIdCount,
|
PanicMsgIdCount,
|
||||||
};
|
};
|
||||||
@ -1712,8 +1728,6 @@ struct CodeGen {
|
|||||||
ZigList<Buf *> link_objects;
|
ZigList<Buf *> link_objects;
|
||||||
ZigList<Buf *> assembly_files;
|
ZigList<Buf *> assembly_files;
|
||||||
|
|
||||||
ZigList<TypeTableEntry *> name_table_enums;
|
|
||||||
|
|
||||||
Buf *test_filter;
|
Buf *test_filter;
|
||||||
Buf *test_name_prefix;
|
Buf *test_name_prefix;
|
||||||
|
|
||||||
@ -2003,8 +2017,8 @@ enum IrInstructionId {
|
|||||||
IrInstructionIdAsm,
|
IrInstructionIdAsm,
|
||||||
IrInstructionIdSizeOf,
|
IrInstructionIdSizeOf,
|
||||||
IrInstructionIdTestNonNull,
|
IrInstructionIdTestNonNull,
|
||||||
IrInstructionIdUnwrapMaybe,
|
IrInstructionIdUnwrapOptional,
|
||||||
IrInstructionIdMaybeWrap,
|
IrInstructionIdOptionalWrap,
|
||||||
IrInstructionIdUnionTag,
|
IrInstructionIdUnionTag,
|
||||||
IrInstructionIdClz,
|
IrInstructionIdClz,
|
||||||
IrInstructionIdCtz,
|
IrInstructionIdCtz,
|
||||||
@ -2055,7 +2069,6 @@ enum IrInstructionId {
|
|||||||
IrInstructionIdCheckSwitchProngs,
|
IrInstructionIdCheckSwitchProngs,
|
||||||
IrInstructionIdCheckStatementIsVoid,
|
IrInstructionIdCheckStatementIsVoid,
|
||||||
IrInstructionIdTypeName,
|
IrInstructionIdTypeName,
|
||||||
IrInstructionIdCanImplicitCast,
|
|
||||||
IrInstructionIdDeclRef,
|
IrInstructionIdDeclRef,
|
||||||
IrInstructionIdPanic,
|
IrInstructionIdPanic,
|
||||||
IrInstructionIdTagName,
|
IrInstructionIdTagName,
|
||||||
@ -2172,7 +2185,7 @@ enum IrUnOp {
|
|||||||
IrUnOpNegation,
|
IrUnOpNegation,
|
||||||
IrUnOpNegationWrap,
|
IrUnOpNegationWrap,
|
||||||
IrUnOpDereference,
|
IrUnOpDereference,
|
||||||
IrUnOpMaybe,
|
IrUnOpOptional,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrInstructionUnOp {
|
struct IrInstructionUnOp {
|
||||||
@ -2475,7 +2488,7 @@ struct IrInstructionTestNonNull {
|
|||||||
IrInstruction *value;
|
IrInstruction *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrInstructionUnwrapMaybe {
|
struct IrInstructionUnwrapOptional {
|
||||||
IrInstruction base;
|
IrInstruction base;
|
||||||
|
|
||||||
IrInstruction *value;
|
IrInstruction *value;
|
||||||
@ -2733,7 +2746,7 @@ struct IrInstructionUnwrapErrPayload {
|
|||||||
bool safety_check_on;
|
bool safety_check_on;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrInstructionMaybeWrap {
|
struct IrInstructionOptionalWrap {
|
||||||
IrInstruction base;
|
IrInstruction base;
|
||||||
|
|
||||||
IrInstruction *value;
|
IrInstruction *value;
|
||||||
@ -2848,13 +2861,6 @@ struct IrInstructionTypeName {
|
|||||||
IrInstruction *type_value;
|
IrInstruction *type_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrInstructionCanImplicitCast {
|
|
||||||
IrInstruction base;
|
|
||||||
|
|
||||||
IrInstruction *type_value;
|
|
||||||
IrInstruction *target_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IrInstructionDeclRef {
|
struct IrInstructionDeclRef {
|
||||||
IrInstruction base;
|
IrInstruction base;
|
||||||
|
|
||||||
@ -2949,10 +2955,10 @@ struct IrInstructionExport {
|
|||||||
struct IrInstructionErrorReturnTrace {
|
struct IrInstructionErrorReturnTrace {
|
||||||
IrInstruction base;
|
IrInstruction base;
|
||||||
|
|
||||||
enum Nullable {
|
enum Optional {
|
||||||
Null,
|
Null,
|
||||||
NonNull,
|
NonNull,
|
||||||
} nullable;
|
} optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IrInstructionErrorUnion {
|
struct IrInstructionErrorUnion {
|
||||||
|
|||||||
376
src/analyze.cpp
376
src/analyze.cpp
@ -236,7 +236,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
|
|||||||
case TypeTableEntryIdComptimeInt:
|
case TypeTableEntryIdComptimeInt:
|
||||||
case TypeTableEntryIdUndefined:
|
case TypeTableEntryIdUndefined:
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
@ -272,7 +272,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
|
|||||||
case TypeTableEntryIdComptimeInt:
|
case TypeTableEntryIdComptimeInt:
|
||||||
case TypeTableEntryIdUndefined:
|
case TypeTableEntryIdUndefined:
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
@ -384,6 +384,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
|
|||||||
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
|
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
|
||||||
{
|
{
|
||||||
assert(!type_is_invalid(child_type));
|
assert(!type_is_invalid(child_type));
|
||||||
|
assert(ptr_len == PtrLenSingle || child_type->id != TypeTableEntryIdOpaque);
|
||||||
|
|
||||||
TypeId type_id = {};
|
TypeId type_id = {};
|
||||||
TypeTableEntry **parent_pointer = nullptr;
|
TypeTableEntry **parent_pointer = nullptr;
|
||||||
@ -519,9 +520,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
|
|||||||
} else {
|
} else {
|
||||||
ensure_complete_type(g, child_type);
|
ensure_complete_type(g, child_type);
|
||||||
|
|
||||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
|
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdOptional);
|
||||||
assert(child_type->type_ref || child_type->zero_bits);
|
assert(child_type->type_ref || child_type->zero_bits);
|
||||||
assert(child_type->di_type);
|
|
||||||
entry->is_copyable = type_is_copyable(g, child_type);
|
entry->is_copyable = type_is_copyable(g, child_type);
|
||||||
|
|
||||||
buf_resize(&entry->name, 0);
|
buf_resize(&entry->name, 0);
|
||||||
@ -531,12 +531,14 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
|
|||||||
entry->type_ref = LLVMInt1Type();
|
entry->type_ref = LLVMInt1Type();
|
||||||
entry->di_type = g->builtin_types.entry_bool->di_type;
|
entry->di_type = g->builtin_types.entry_bool->di_type;
|
||||||
} else if (type_is_codegen_pointer(child_type)) {
|
} else if (type_is_codegen_pointer(child_type)) {
|
||||||
|
assert(child_type->di_type);
|
||||||
// this is an optimization but also is necessary for calling C
|
// this is an optimization but also is necessary for calling C
|
||||||
// functions where all pointers are maybe pointers
|
// functions where all pointers are maybe pointers
|
||||||
// function types are technically pointers
|
// function types are technically pointers
|
||||||
entry->type_ref = child_type->type_ref;
|
entry->type_ref = child_type->type_ref;
|
||||||
entry->di_type = child_type->di_type;
|
entry->di_type = child_type->di_type;
|
||||||
} else {
|
} else {
|
||||||
|
assert(child_type->di_type);
|
||||||
// create a struct with a boolean whether this is the null value
|
// create a struct with a boolean whether this is the null value
|
||||||
LLVMTypeRef elem_types[] = {
|
LLVMTypeRef elem_types[] = {
|
||||||
child_type->type_ref,
|
child_type->type_ref,
|
||||||
@ -1360,7 +1362,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
|
|||||||
return type_entry->data.structure.layout == ContainerLayoutPacked;
|
return type_entry->data.structure.layout == ContainerLayoutPacked;
|
||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
return type_entry->data.unionation.layout == ContainerLayoutPacked;
|
return type_entry->data.unionation.layout == ContainerLayoutPacked;
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
{
|
{
|
||||||
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
||||||
return type_is_codegen_pointer(child_type);
|
return type_is_codegen_pointer(child_type);
|
||||||
@ -1414,7 +1416,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
|
|||||||
return type_allowed_in_extern(g, type_entry->data.pointer.child_type);
|
return type_allowed_in_extern(g, type_entry->data.pointer.child_type);
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked;
|
return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked;
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
{
|
{
|
||||||
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
||||||
return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
|
return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
|
||||||
@ -1537,7 +1539,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
|||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdEnum:
|
case TypeTableEntryIdEnum:
|
||||||
@ -1631,7 +1633,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
|||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdEnum:
|
case TypeTableEntryIdEnum:
|
||||||
@ -2532,6 +2534,10 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type_requires_comptime(field_type)) {
|
||||||
|
struct_type->data.structure.requires_comptime = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!type_has_bits(field_type))
|
if (!type_has_bits(field_type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2723,6 +2729,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
|||||||
}
|
}
|
||||||
union_field->type_entry = field_type;
|
union_field->type_entry = field_type;
|
||||||
|
|
||||||
|
if (type_requires_comptime(field_type)) {
|
||||||
|
union_type->data.unionation.requires_comptime = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
|
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
|
||||||
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
|
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
|
||||||
buf_sprintf("non-enum union field assignment"));
|
buf_sprintf("non-enum union field assignment"));
|
||||||
@ -2975,8 +2986,8 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
|
|||||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
|
TypeTableEntry *optional_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
|
||||||
if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) {
|
if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
|
||||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3298,6 +3309,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
|||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
case NodeTypePtrDeref:
|
case NodeTypePtrDeref:
|
||||||
|
case NodeTypeUnwrapOptional:
|
||||||
case NodeTypeStructField:
|
case NodeTypeStructField:
|
||||||
case NodeTypeContainerInitExpr:
|
case NodeTypeContainerInitExpr:
|
||||||
case NodeTypeStructValueField:
|
case NodeTypeStructValueField:
|
||||||
@ -3358,7 +3370,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
|
|||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdEnum:
|
case TypeTableEntryIdEnum:
|
||||||
@ -3736,7 +3748,7 @@ static bool is_container(TypeTableEntry *type_entry) {
|
|||||||
case TypeTableEntryIdComptimeInt:
|
case TypeTableEntryIdComptimeInt:
|
||||||
case TypeTableEntryIdUndefined:
|
case TypeTableEntryIdUndefined:
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
@ -3751,14 +3763,24 @@ static bool is_container(TypeTableEntry *type_entry) {
|
|||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_ref(TypeTableEntry *type_entry) {
|
||||||
|
return type_entry->id == TypeTableEntryIdPointer && type_entry->data.pointer.ptr_len == PtrLenSingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_array_ref(TypeTableEntry *type_entry) {
|
||||||
|
TypeTableEntry *array = is_ref(type_entry) ?
|
||||||
|
type_entry->data.pointer.child_type : type_entry;
|
||||||
|
return array->id == TypeTableEntryIdArray;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_container_ref(TypeTableEntry *type_entry) {
|
bool is_container_ref(TypeTableEntry *type_entry) {
|
||||||
return (type_entry->id == TypeTableEntryIdPointer) ?
|
return is_ref(type_entry) ?
|
||||||
is_container(type_entry->data.pointer.child_type) : is_container(type_entry);
|
is_container(type_entry->data.pointer.child_type) : is_container(type_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry) {
|
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry) {
|
||||||
assert(is_container_ref(type_entry));
|
assert(is_container_ref(type_entry));
|
||||||
return (type_entry->id == TypeTableEntryIdPointer) ?
|
return is_ref(type_entry) ?
|
||||||
type_entry->data.pointer.child_type : type_entry;
|
type_entry->data.pointer.child_type : type_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3785,7 +3807,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
|
|||||||
case TypeTableEntryIdComptimeInt:
|
case TypeTableEntryIdComptimeInt:
|
||||||
case TypeTableEntryIdUndefined:
|
case TypeTableEntryIdUndefined:
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
@ -3804,7 +3826,7 @@ TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) {
|
|||||||
if (type->id == TypeTableEntryIdPointer) return type;
|
if (type->id == TypeTableEntryIdPointer) return type;
|
||||||
if (type->id == TypeTableEntryIdFn) return type;
|
if (type->id == TypeTableEntryIdFn) return type;
|
||||||
if (type->id == TypeTableEntryIdPromise) return type;
|
if (type->id == TypeTableEntryIdPromise) return type;
|
||||||
if (type->id == TypeTableEntryIdMaybe) {
|
if (type->id == TypeTableEntryIdOptional) {
|
||||||
if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;
|
if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;
|
||||||
if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;
|
if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;
|
||||||
if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type;
|
if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type;
|
||||||
@ -4311,7 +4333,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
|||||||
return type_has_bits(type_entry);
|
return type_has_bits(type_entry);
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
return type_has_bits(type_entry->data.error_union.payload_type);
|
return type_has_bits(type_entry->data.error_union.payload_type);
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
return type_has_bits(type_entry->data.maybe.child_type) &&
|
return type_has_bits(type_entry->data.maybe.child_type) &&
|
||||||
!type_is_codegen_pointer(type_entry->data.maybe.child_type);
|
!type_is_codegen_pointer(type_entry->data.maybe.child_type);
|
||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
@ -4558,6 +4580,52 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
|
||||||
|
uint32_t hash_val = 0;
|
||||||
|
switch (const_val->data.x_ptr.mut) {
|
||||||
|
case ConstPtrMutRuntimeVar:
|
||||||
|
hash_val += (uint32_t)3500721036;
|
||||||
|
break;
|
||||||
|
case ConstPtrMutComptimeConst:
|
||||||
|
hash_val += (uint32_t)4214318515;
|
||||||
|
break;
|
||||||
|
case ConstPtrMutComptimeVar:
|
||||||
|
hash_val += (uint32_t)1103195694;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (const_val->data.x_ptr.special) {
|
||||||
|
case ConstPtrSpecialInvalid:
|
||||||
|
zig_unreachable();
|
||||||
|
case ConstPtrSpecialRef:
|
||||||
|
hash_val += (uint32_t)2478261866;
|
||||||
|
hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee);
|
||||||
|
return hash_val;
|
||||||
|
case ConstPtrSpecialBaseArray:
|
||||||
|
hash_val += (uint32_t)1764906839;
|
||||||
|
hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
|
||||||
|
hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
|
||||||
|
hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
|
||||||
|
return hash_val;
|
||||||
|
case ConstPtrSpecialBaseStruct:
|
||||||
|
hash_val += (uint32_t)3518317043;
|
||||||
|
hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
|
||||||
|
hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
|
||||||
|
return hash_val;
|
||||||
|
case ConstPtrSpecialHardCodedAddr:
|
||||||
|
hash_val += (uint32_t)4048518294;
|
||||||
|
hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
|
||||||
|
return hash_val;
|
||||||
|
case ConstPtrSpecialDiscard:
|
||||||
|
hash_val += 2010123162;
|
||||||
|
return hash_val;
|
||||||
|
case ConstPtrSpecialFunction:
|
||||||
|
hash_val += (uint32_t)2590901619;
|
||||||
|
hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
|
||||||
|
return hash_val;
|
||||||
|
}
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t hash_const_val(ConstExprValue *const_val) {
|
static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||||
assert(const_val->special == ConstValSpecialStatic);
|
assert(const_val->special == ConstValSpecialStatic);
|
||||||
switch (const_val->type->id) {
|
switch (const_val->type->id) {
|
||||||
@ -4626,51 +4694,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
|||||||
assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
|
assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
|
||||||
return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
|
return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
{
|
return hash_const_val_ptr(const_val);
|
||||||
uint32_t hash_val = 0;
|
|
||||||
switch (const_val->data.x_ptr.mut) {
|
|
||||||
case ConstPtrMutRuntimeVar:
|
|
||||||
hash_val += (uint32_t)3500721036;
|
|
||||||
break;
|
|
||||||
case ConstPtrMutComptimeConst:
|
|
||||||
hash_val += (uint32_t)4214318515;
|
|
||||||
break;
|
|
||||||
case ConstPtrMutComptimeVar:
|
|
||||||
hash_val += (uint32_t)1103195694;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (const_val->data.x_ptr.special) {
|
|
||||||
case ConstPtrSpecialInvalid:
|
|
||||||
zig_unreachable();
|
|
||||||
case ConstPtrSpecialRef:
|
|
||||||
hash_val += (uint32_t)2478261866;
|
|
||||||
hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee);
|
|
||||||
return hash_val;
|
|
||||||
case ConstPtrSpecialBaseArray:
|
|
||||||
hash_val += (uint32_t)1764906839;
|
|
||||||
hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
|
|
||||||
hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
|
|
||||||
hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
|
|
||||||
return hash_val;
|
|
||||||
case ConstPtrSpecialBaseStruct:
|
|
||||||
hash_val += (uint32_t)3518317043;
|
|
||||||
hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
|
|
||||||
hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
|
|
||||||
return hash_val;
|
|
||||||
case ConstPtrSpecialHardCodedAddr:
|
|
||||||
hash_val += (uint32_t)4048518294;
|
|
||||||
hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
|
|
||||||
return hash_val;
|
|
||||||
case ConstPtrSpecialDiscard:
|
|
||||||
hash_val += 2010123162;
|
|
||||||
return hash_val;
|
|
||||||
case ConstPtrSpecialFunction:
|
|
||||||
hash_val += (uint32_t)2590901619;
|
|
||||||
hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
|
|
||||||
return hash_val;
|
|
||||||
}
|
|
||||||
zig_unreachable();
|
|
||||||
}
|
|
||||||
case TypeTableEntryIdPromise:
|
case TypeTableEntryIdPromise:
|
||||||
// TODO better hashing algorithm
|
// TODO better hashing algorithm
|
||||||
return 223048345;
|
return 223048345;
|
||||||
@ -4687,11 +4711,15 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
|||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
// TODO better hashing algorithm
|
// TODO better hashing algorithm
|
||||||
return 2709806591;
|
return 2709806591;
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
if (const_val->data.x_maybe) {
|
if (get_codegen_ptr_type(const_val->type) != nullptr) {
|
||||||
return hash_const_val(const_val->data.x_maybe) * 1992916303;
|
return hash_const_val(const_val) * 1992916303;
|
||||||
} else {
|
} else {
|
||||||
return 4016830364;
|
if (const_val->data.x_optional) {
|
||||||
|
return hash_const_val(const_val->data.x_optional) * 1992916303;
|
||||||
|
} else {
|
||||||
|
return 4016830364;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
// TODO better hashing algorithm
|
// TODO better hashing algorithm
|
||||||
@ -4791,10 +4819,12 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
if (value->data.x_maybe == nullptr)
|
if (get_codegen_ptr_type(value->type) != nullptr)
|
||||||
|
return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
|
||||||
|
if (value->data.x_optional == nullptr)
|
||||||
return false;
|
return false;
|
||||||
return can_mutate_comptime_var_state(value->data.x_maybe);
|
return can_mutate_comptime_var_state(value->data.x_optional);
|
||||||
|
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
if (value->data.x_err_union.err != nullptr)
|
if (value->data.x_err_union.err != nullptr)
|
||||||
@ -4841,7 +4871,7 @@ static bool return_type_is_cacheable(TypeTableEntry *return_type) {
|
|||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
return return_type_is_cacheable(return_type->data.maybe.child_type);
|
return return_type_is_cacheable(return_type->data.maybe.child_type);
|
||||||
|
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
@ -4943,17 +4973,29 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
|
|||||||
case TypeTableEntryIdArgTuple:
|
case TypeTableEntryIdArgTuple:
|
||||||
return true;
|
return true;
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
|
return type_requires_comptime(type_entry->data.array.child_type);
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
|
assert(type_has_zero_bits_known(type_entry));
|
||||||
|
return type_entry->data.structure.requires_comptime;
|
||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
case TypeTableEntryIdMaybe:
|
assert(type_has_zero_bits_known(type_entry));
|
||||||
|
return type_entry->data.unionation.requires_comptime;
|
||||||
|
case TypeTableEntryIdOptional:
|
||||||
|
return type_requires_comptime(type_entry->data.maybe.child_type);
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
|
return type_requires_comptime(type_entry->data.error_union.payload_type);
|
||||||
|
case TypeTableEntryIdPointer:
|
||||||
|
if (type_entry->data.pointer.child_type->id == TypeTableEntryIdOpaque) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return type_requires_comptime(type_entry->data.pointer.child_type);
|
||||||
|
}
|
||||||
case TypeTableEntryIdEnum:
|
case TypeTableEntryIdEnum:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdBool:
|
case TypeTableEntryIdBool:
|
||||||
case TypeTableEntryIdInt:
|
case TypeTableEntryIdInt:
|
||||||
case TypeTableEntryIdFloat:
|
case TypeTableEntryIdFloat:
|
||||||
case TypeTableEntryIdPointer:
|
|
||||||
case TypeTableEntryIdVoid:
|
case TypeTableEntryIdVoid:
|
||||||
case TypeTableEntryIdUnreachable:
|
case TypeTableEntryIdUnreachable:
|
||||||
case TypeTableEntryIdPromise:
|
case TypeTableEntryIdPromise:
|
||||||
@ -5308,6 +5350,52 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) {
|
|||||||
return var->is_comptime->value.data.x_bool;
|
return var->is_comptime->value.data.x_bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
|
||||||
|
if (a->data.x_ptr.special != b->data.x_ptr.special)
|
||||||
|
return false;
|
||||||
|
if (a->data.x_ptr.mut != b->data.x_ptr.mut)
|
||||||
|
return false;
|
||||||
|
switch (a->data.x_ptr.special) {
|
||||||
|
case ConstPtrSpecialInvalid:
|
||||||
|
zig_unreachable();
|
||||||
|
case ConstPtrSpecialRef:
|
||||||
|
if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
case ConstPtrSpecialBaseArray:
|
||||||
|
if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
|
||||||
|
a->data.x_ptr.data.base_array.array_val->global_refs !=
|
||||||
|
b->data.x_ptr.data.base_array.array_val->global_refs)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
|
||||||
|
return false;
|
||||||
|
if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
case ConstPtrSpecialBaseStruct:
|
||||||
|
if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
|
||||||
|
a->data.x_ptr.data.base_struct.struct_val->global_refs !=
|
||||||
|
b->data.x_ptr.data.base_struct.struct_val->global_refs)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
case ConstPtrSpecialHardCodedAddr:
|
||||||
|
if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
case ConstPtrSpecialDiscard:
|
||||||
|
return true;
|
||||||
|
case ConstPtrSpecialFunction:
|
||||||
|
return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
|
||||||
|
}
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||||
assert(a->type->id == b->type->id);
|
assert(a->type->id == b->type->id);
|
||||||
assert(a->special == ConstValSpecialStatic);
|
assert(a->special == ConstValSpecialStatic);
|
||||||
@ -5359,49 +5447,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
|||||||
return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
|
return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
if (a->data.x_ptr.special != b->data.x_ptr.special)
|
return const_values_equal_ptr(a, b);
|
||||||
return false;
|
|
||||||
if (a->data.x_ptr.mut != b->data.x_ptr.mut)
|
|
||||||
return false;
|
|
||||||
switch (a->data.x_ptr.special) {
|
|
||||||
case ConstPtrSpecialInvalid:
|
|
||||||
zig_unreachable();
|
|
||||||
case ConstPtrSpecialRef:
|
|
||||||
if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
case ConstPtrSpecialBaseArray:
|
|
||||||
if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
|
|
||||||
a->data.x_ptr.data.base_array.array_val->global_refs !=
|
|
||||||
b->data.x_ptr.data.base_array.array_val->global_refs)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
|
|
||||||
return false;
|
|
||||||
if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
case ConstPtrSpecialBaseStruct:
|
|
||||||
if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
|
|
||||||
a->data.x_ptr.data.base_struct.struct_val->global_refs !=
|
|
||||||
b->data.x_ptr.data.base_struct.struct_val->global_refs)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
case ConstPtrSpecialHardCodedAddr:
|
|
||||||
if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
case ConstPtrSpecialDiscard:
|
|
||||||
return true;
|
|
||||||
case ConstPtrSpecialFunction:
|
|
||||||
return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
|
|
||||||
}
|
|
||||||
zig_unreachable();
|
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
@ -5416,11 +5462,13 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
|||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) {
|
if (get_codegen_ptr_type(a->type) != nullptr)
|
||||||
return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr);
|
return const_values_equal_ptr(a, b);
|
||||||
|
if (a->data.x_optional == nullptr || b->data.x_optional == nullptr) {
|
||||||
|
return (a->data.x_optional == nullptr && b->data.x_optional == nullptr);
|
||||||
} else {
|
} else {
|
||||||
return const_values_equal(a->data.x_maybe, b->data.x_maybe);
|
return const_values_equal(a->data.x_optional, b->data.x_optional);
|
||||||
}
|
}
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
@ -5493,6 +5541,41 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeTableEntry *type_entry) {
|
||||||
|
switch (const_val->data.x_ptr.special) {
|
||||||
|
case ConstPtrSpecialInvalid:
|
||||||
|
zig_unreachable();
|
||||||
|
case ConstPtrSpecialRef:
|
||||||
|
case ConstPtrSpecialBaseStruct:
|
||||||
|
buf_appendf(buf, "*");
|
||||||
|
render_const_value(g, buf, const_ptr_pointee(g, const_val));
|
||||||
|
return;
|
||||||
|
case ConstPtrSpecialBaseArray:
|
||||||
|
if (const_val->data.x_ptr.data.base_array.is_cstr) {
|
||||||
|
buf_appendf(buf, "*(c str lit)");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
buf_appendf(buf, "*");
|
||||||
|
render_const_value(g, buf, const_ptr_pointee(g, const_val));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case ConstPtrSpecialHardCodedAddr:
|
||||||
|
buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
|
||||||
|
const_val->data.x_ptr.data.hard_coded_addr.addr);
|
||||||
|
return;
|
||||||
|
case ConstPtrSpecialDiscard:
|
||||||
|
buf_append_str(buf, "*_");
|
||||||
|
return;
|
||||||
|
case ConstPtrSpecialFunction:
|
||||||
|
{
|
||||||
|
FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
|
||||||
|
buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||||
switch (const_val->special) {
|
switch (const_val->special) {
|
||||||
case ConstValSpecialRuntime:
|
case ConstValSpecialRuntime:
|
||||||
@ -5569,38 +5652,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
switch (const_val->data.x_ptr.special) {
|
return render_const_val_ptr(g, buf, const_val, type_entry);
|
||||||
case ConstPtrSpecialInvalid:
|
|
||||||
zig_unreachable();
|
|
||||||
case ConstPtrSpecialRef:
|
|
||||||
case ConstPtrSpecialBaseStruct:
|
|
||||||
buf_appendf(buf, "&");
|
|
||||||
render_const_value(g, buf, const_ptr_pointee(g, const_val));
|
|
||||||
return;
|
|
||||||
case ConstPtrSpecialBaseArray:
|
|
||||||
if (const_val->data.x_ptr.data.base_array.is_cstr) {
|
|
||||||
buf_appendf(buf, "&(c str lit)");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
buf_appendf(buf, "&");
|
|
||||||
render_const_value(g, buf, const_ptr_pointee(g, const_val));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case ConstPtrSpecialHardCodedAddr:
|
|
||||||
buf_appendf(buf, "(&%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
|
|
||||||
const_val->data.x_ptr.data.hard_coded_addr.addr);
|
|
||||||
return;
|
|
||||||
case ConstPtrSpecialDiscard:
|
|
||||||
buf_append_str(buf, "&_");
|
|
||||||
return;
|
|
||||||
case ConstPtrSpecialFunction:
|
|
||||||
{
|
|
||||||
FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
|
|
||||||
buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zig_unreachable();
|
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
{
|
{
|
||||||
AstNode *node = const_val->data.x_block->source_node;
|
AstNode *node = const_val->data.x_block->source_node;
|
||||||
@ -5658,10 +5710,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
|||||||
buf_appendf(buf, "undefined");
|
buf_appendf(buf, "undefined");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
{
|
{
|
||||||
if (const_val->data.x_maybe) {
|
if (get_codegen_ptr_type(const_val->type) != nullptr)
|
||||||
render_const_value(g, buf, const_val->data.x_maybe);
|
return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type);
|
||||||
|
if (const_val->data.x_optional) {
|
||||||
|
render_const_value(g, buf, const_val->data.x_optional);
|
||||||
} else {
|
} else {
|
||||||
buf_appendf(buf, "null");
|
buf_appendf(buf, "null");
|
||||||
}
|
}
|
||||||
@ -5767,7 +5821,7 @@ uint32_t type_id_hash(TypeId x) {
|
|||||||
case TypeTableEntryIdComptimeInt:
|
case TypeTableEntryIdComptimeInt:
|
||||||
case TypeTableEntryIdUndefined:
|
case TypeTableEntryIdUndefined:
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdEnum:
|
case TypeTableEntryIdEnum:
|
||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
@ -5813,7 +5867,7 @@ bool type_id_eql(TypeId a, TypeId b) {
|
|||||||
case TypeTableEntryIdComptimeInt:
|
case TypeTableEntryIdComptimeInt:
|
||||||
case TypeTableEntryIdUndefined:
|
case TypeTableEntryIdUndefined:
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdPromise:
|
case TypeTableEntryIdPromise:
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
case TypeTableEntryIdEnum:
|
case TypeTableEntryIdEnum:
|
||||||
@ -5935,7 +5989,7 @@ static const TypeTableEntryId all_type_ids[] = {
|
|||||||
TypeTableEntryIdComptimeInt,
|
TypeTableEntryIdComptimeInt,
|
||||||
TypeTableEntryIdUndefined,
|
TypeTableEntryIdUndefined,
|
||||||
TypeTableEntryIdNull,
|
TypeTableEntryIdNull,
|
||||||
TypeTableEntryIdMaybe,
|
TypeTableEntryIdOptional,
|
||||||
TypeTableEntryIdErrorUnion,
|
TypeTableEntryIdErrorUnion,
|
||||||
TypeTableEntryIdErrorSet,
|
TypeTableEntryIdErrorSet,
|
||||||
TypeTableEntryIdEnum,
|
TypeTableEntryIdEnum,
|
||||||
@ -5980,7 +6034,7 @@ size_t type_id_index(TypeTableEntry *entry) {
|
|||||||
return 7;
|
return 7;
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
if (entry->data.structure.is_slice)
|
if (entry->data.structure.is_slice)
|
||||||
return 25;
|
return 6;
|
||||||
return 8;
|
return 8;
|
||||||
case TypeTableEntryIdComptimeFloat:
|
case TypeTableEntryIdComptimeFloat:
|
||||||
return 9;
|
return 9;
|
||||||
@ -5990,7 +6044,7 @@ size_t type_id_index(TypeTableEntry *entry) {
|
|||||||
return 11;
|
return 11;
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
return 12;
|
return 12;
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
return 13;
|
return 13;
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
return 14;
|
return 14;
|
||||||
@ -6048,8 +6102,8 @@ const char *type_id_name(TypeTableEntryId id) {
|
|||||||
return "Undefined";
|
return "Undefined";
|
||||||
case TypeTableEntryIdNull:
|
case TypeTableEntryIdNull:
|
||||||
return "Null";
|
return "Null";
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
return "Nullable";
|
return "Optional";
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
return "ErrorUnion";
|
return "ErrorUnion";
|
||||||
case TypeTableEntryIdErrorSet:
|
case TypeTableEntryIdErrorSet:
|
||||||
|
|||||||
@ -70,6 +70,8 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
|
|||||||
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
|
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
|
||||||
TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
|
TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
|
||||||
|
|
||||||
|
bool is_ref(TypeTableEntry *type_entry);
|
||||||
|
bool is_array_ref(TypeTableEntry *type_entry);
|
||||||
bool is_container_ref(TypeTableEntry *type_entry);
|
bool is_container_ref(TypeTableEntry *type_entry);
|
||||||
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
||||||
void scan_import(CodeGen *g, ImportTableEntry *import);
|
void scan_import(CodeGen *g, ImportTableEntry *import);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ static const char *bin_op_str(BinOpType bin_op) {
|
|||||||
case BinOpTypeAssignBitXor: return "^=";
|
case BinOpTypeAssignBitXor: return "^=";
|
||||||
case BinOpTypeAssignBitOr: return "|=";
|
case BinOpTypeAssignBitOr: return "|=";
|
||||||
case BinOpTypeAssignMergeErrorSets: return "||=";
|
case BinOpTypeAssignMergeErrorSets: return "||=";
|
||||||
case BinOpTypeUnwrapMaybe: return "??";
|
case BinOpTypeUnwrapOptional: return "orelse";
|
||||||
case BinOpTypeArrayCat: return "++";
|
case BinOpTypeArrayCat: return "++";
|
||||||
case BinOpTypeArrayMult: return "**";
|
case BinOpTypeArrayMult: return "**";
|
||||||
case BinOpTypeErrorUnion: return "!";
|
case BinOpTypeErrorUnion: return "!";
|
||||||
@ -66,8 +66,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
|
|||||||
case PrefixOpNegationWrap: return "-%";
|
case PrefixOpNegationWrap: return "-%";
|
||||||
case PrefixOpBoolNot: return "!";
|
case PrefixOpBoolNot: return "!";
|
||||||
case PrefixOpBinNot: return "~";
|
case PrefixOpBinNot: return "~";
|
||||||
case PrefixOpMaybe: return "?";
|
case PrefixOpOptional: return "?";
|
||||||
case PrefixOpUnwrapMaybe: return "??";
|
|
||||||
case PrefixOpAddrOf: return "&";
|
case PrefixOpAddrOf: return "&";
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {
|
|||||||
return "FieldAccessExpr";
|
return "FieldAccessExpr";
|
||||||
case NodeTypePtrDeref:
|
case NodeTypePtrDeref:
|
||||||
return "PtrDerefExpr";
|
return "PtrDerefExpr";
|
||||||
|
case NodeTypeUnwrapOptional:
|
||||||
|
return "UnwrapOptional";
|
||||||
case NodeTypeContainerDecl:
|
case NodeTypeContainerDecl:
|
||||||
return "ContainerDecl";
|
return "ContainerDecl";
|
||||||
case NodeTypeStructField:
|
case NodeTypeStructField:
|
||||||
@ -711,6 +712,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||||||
fprintf(ar->f, ".*");
|
fprintf(ar->f, ".*");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case NodeTypeUnwrapOptional:
|
||||||
|
{
|
||||||
|
AstNode *lhs = node->data.unwrap_optional.expr;
|
||||||
|
render_node_ungrouped(ar, lhs);
|
||||||
|
fprintf(ar->f, ".?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case NodeTypeUndefinedLiteral:
|
case NodeTypeUndefinedLiteral:
|
||||||
fprintf(ar->f, "undefined");
|
fprintf(ar->f, "undefined");
|
||||||
break;
|
break;
|
||||||
|
|||||||
444
src/codegen.cpp
444
src/codegen.cpp
@ -869,7 +869,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
|
|||||||
return buf_create_from_str("exact division produced remainder");
|
return buf_create_from_str("exact division produced remainder");
|
||||||
case PanicMsgIdSliceWidenRemainder:
|
case PanicMsgIdSliceWidenRemainder:
|
||||||
return buf_create_from_str("slice widening size mismatch");
|
return buf_create_from_str("slice widening size mismatch");
|
||||||
case PanicMsgIdUnwrapMaybeFail:
|
case PanicMsgIdUnwrapOptionalFail:
|
||||||
return buf_create_from_str("attempt to unwrap null");
|
return buf_create_from_str("attempt to unwrap null");
|
||||||
case PanicMsgIdUnreachable:
|
case PanicMsgIdUnreachable:
|
||||||
return buf_create_from_str("reached unreachable code");
|
return buf_create_from_str("reached unreachable code");
|
||||||
@ -879,6 +879,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
|
|||||||
return buf_create_from_str("incorrect alignment");
|
return buf_create_from_str("incorrect alignment");
|
||||||
case PanicMsgIdBadUnionField:
|
case PanicMsgIdBadUnionField:
|
||||||
return buf_create_from_str("access of inactive union field");
|
return buf_create_from_str("access of inactive union field");
|
||||||
|
case PanicMsgIdBadEnumValue:
|
||||||
|
return buf_create_from_str("invalid enum value");
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -2497,7 +2499,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
|||||||
assert(wanted_type->data.structure.is_slice);
|
assert(wanted_type->data.structure.is_slice);
|
||||||
assert(actual_type->id == TypeTableEntryIdArray);
|
assert(actual_type->id == TypeTableEntryIdArray);
|
||||||
|
|
||||||
TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
|
TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||||
TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
|
TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
|
||||||
|
|
||||||
|
|
||||||
@ -2543,6 +2545,29 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
|||||||
return expr_val;
|
return expr_val;
|
||||||
case CastOpBitCast:
|
case CastOpBitCast:
|
||||||
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
|
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
|
||||||
|
case CastOpPtrOfArrayToSlice: {
|
||||||
|
assert(cast_instruction->tmp_ptr);
|
||||||
|
assert(actual_type->id == TypeTableEntryIdPointer);
|
||||||
|
TypeTableEntry *array_type = actual_type->data.pointer.child_type;
|
||||||
|
assert(array_type->id == TypeTableEntryIdArray);
|
||||||
|
|
||||||
|
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
|
||||||
|
slice_ptr_index, "");
|
||||||
|
LLVMValueRef indices[] = {
|
||||||
|
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
|
||||||
|
LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
|
||||||
|
};
|
||||||
|
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
|
||||||
|
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||||
|
|
||||||
|
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
|
||||||
|
slice_len_index, "");
|
||||||
|
LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
|
||||||
|
array_type->data.array.len, false);
|
||||||
|
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||||
|
|
||||||
|
return cast_instruction->tmp_ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -2678,7 +2703,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
|
|||||||
|
|
||||||
switch (op_id) {
|
switch (op_id) {
|
||||||
case IrUnOpInvalid:
|
case IrUnOpInvalid:
|
||||||
case IrUnOpMaybe:
|
case IrUnOpOptional:
|
||||||
case IrUnOpDereference:
|
case IrUnOpDereference:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
case IrUnOpNegation:
|
case IrUnOpNegation:
|
||||||
@ -3249,7 +3274,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
|
static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
|
||||||
assert(maybe_type->id == TypeTableEntryIdMaybe);
|
assert(maybe_type->id == TypeTableEntryIdOptional);
|
||||||
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
|
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
|
||||||
if (child_type->zero_bits) {
|
if (child_type->zero_bits) {
|
||||||
return maybe_handle;
|
return maybe_handle;
|
||||||
@ -3271,23 +3296,23 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
|
static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
|
||||||
IrInstructionUnwrapMaybe *instruction)
|
IrInstructionUnwrapOptional *instruction)
|
||||||
{
|
{
|
||||||
TypeTableEntry *ptr_type = instruction->value->value.type;
|
TypeTableEntry *ptr_type = instruction->value->value.type;
|
||||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||||
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
|
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
|
||||||
assert(maybe_type->id == TypeTableEntryIdMaybe);
|
assert(maybe_type->id == TypeTableEntryIdOptional);
|
||||||
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
|
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
|
||||||
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
|
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
|
||||||
LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
|
LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
|
||||||
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
|
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
|
||||||
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
|
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
|
||||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
|
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
|
||||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
|
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
|
||||||
LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
|
LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||||
gen_safety_crash(g, PanicMsgIdUnwrapMaybeFail);
|
gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||||
}
|
}
|
||||||
@ -3432,34 +3457,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
|
|||||||
return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
|
return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLVMValueRef get_enum_tag_name_function(CodeGen *g, TypeTableEntry *enum_type) {
|
||||||
|
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||||
|
if (enum_type->data.enumeration.name_function)
|
||||||
|
return enum_type->data.enumeration.name_function;
|
||||||
|
|
||||||
|
TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
|
||||||
|
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||||
|
TypeTableEntry *u8_slice_type = get_slice_type(g, u8_ptr_type);
|
||||||
|
TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
|
||||||
|
|
||||||
|
LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0),
|
||||||
|
&tag_int_type->type_ref, 1, false);
|
||||||
|
|
||||||
|
Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
|
||||||
|
LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
|
||||||
|
LLVMSetLinkage(fn_val, LLVMInternalLinkage);
|
||||||
|
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
|
||||||
|
addLLVMFnAttr(fn_val, "nounwind");
|
||||||
|
add_uwtable_attr(g, fn_val);
|
||||||
|
if (g->build_mode == BuildModeDebug) {
|
||||||
|
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
|
||||||
|
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
|
||||||
|
LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
|
||||||
|
FnTableEntry *prev_cur_fn = g->cur_fn;
|
||||||
|
LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
|
||||||
|
|
||||||
|
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
|
||||||
|
LLVMPositionBuilderAtEnd(g->builder, entry_block);
|
||||||
|
ZigLLVMClearCurrentDebugLocation(g->builder);
|
||||||
|
g->cur_fn = nullptr;
|
||||||
|
g->cur_fn_val = fn_val;
|
||||||
|
|
||||||
|
size_t field_count = enum_type->data.enumeration.src_field_count;
|
||||||
|
LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
|
||||||
|
LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0);
|
||||||
|
LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
|
||||||
|
|
||||||
|
|
||||||
|
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
||||||
|
LLVMValueRef array_ptr_indices[] = {
|
||||||
|
LLVMConstNull(usize->type_ref),
|
||||||
|
LLVMConstNull(usize->type_ref),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
|
||||||
|
Buf *name = enum_type->data.enumeration.fields[field_i].name;
|
||||||
|
LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
|
||||||
|
LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
|
||||||
|
LLVMSetInitializer(str_global, str_init);
|
||||||
|
LLVMSetLinkage(str_global, LLVMPrivateLinkage);
|
||||||
|
LLVMSetGlobalConstant(str_global, true);
|
||||||
|
LLVMSetUnnamedAddr(str_global, true);
|
||||||
|
LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
|
||||||
|
|
||||||
|
LLVMValueRef fields[] = {
|
||||||
|
LLVMConstGEP(str_global, array_ptr_indices, 2),
|
||||||
|
LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
|
||||||
|
};
|
||||||
|
LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2);
|
||||||
|
|
||||||
|
LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), "");
|
||||||
|
LLVMSetInitializer(slice_global, slice_init_value);
|
||||||
|
LLVMSetLinkage(slice_global, LLVMPrivateLinkage);
|
||||||
|
LLVMSetGlobalConstant(slice_global, true);
|
||||||
|
LLVMSetUnnamedAddr(slice_global, true);
|
||||||
|
LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value)));
|
||||||
|
|
||||||
|
LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name");
|
||||||
|
LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
|
||||||
|
&enum_type->data.enumeration.fields[field_i].value);
|
||||||
|
LLVMAddCase(switch_instr, this_tag_int_value, return_block);
|
||||||
|
|
||||||
|
LLVMPositionBuilderAtEnd(g->builder, return_block);
|
||||||
|
LLVMBuildRet(g->builder, slice_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
|
||||||
|
if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
|
||||||
|
gen_safety_crash(g, PanicMsgIdBadEnumValue);
|
||||||
|
} else {
|
||||||
|
LLVMBuildUnreachable(g->builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
g->cur_fn = prev_cur_fn;
|
||||||
|
g->cur_fn_val = prev_cur_fn_val;
|
||||||
|
LLVMPositionBuilderAtEnd(g->builder, prev_block);
|
||||||
|
LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
|
||||||
|
|
||||||
|
enum_type->data.enumeration.name_function = fn_val;
|
||||||
|
return fn_val;
|
||||||
|
}
|
||||||
|
|
||||||
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
|
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
|
||||||
IrInstructionTagName *instruction)
|
IrInstructionTagName *instruction)
|
||||||
{
|
{
|
||||||
TypeTableEntry *enum_type = instruction->target->value.type;
|
TypeTableEntry *enum_type = instruction->target->value.type;
|
||||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||||
assert(enum_type->data.enumeration.generate_name_table);
|
|
||||||
|
|
||||||
TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
|
LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
|
||||||
|
|
||||||
LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
|
LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
|
||||||
if (ir_want_runtime_safety(g, &instruction->base)) {
|
return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1,
|
||||||
size_t field_count = enum_type->data.enumeration.src_field_count;
|
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
|
||||||
|
|
||||||
// if the field_count can't fit in the bits of the enum_type, then it can't possibly
|
|
||||||
// be the wrong value
|
|
||||||
BigInt field_bi;
|
|
||||||
bigint_init_unsigned(&field_bi, field_count);
|
|
||||||
if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
|
|
||||||
LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
|
|
||||||
add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LLVMValueRef indices[] = {
|
|
||||||
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
|
|
||||||
gen_widen_or_shorten(g, false, tag_int_type,
|
|
||||||
g->builtin_types.entry_usize, enum_tag_value),
|
|
||||||
};
|
|
||||||
return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
|
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
|
||||||
@ -3509,17 +3612,17 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
|||||||
} else if (target_type->id == TypeTableEntryIdFn) {
|
} else if (target_type->id == TypeTableEntryIdFn) {
|
||||||
align_bytes = target_type->data.fn.fn_type_id.alignment;
|
align_bytes = target_type->data.fn.fn_type_id.alignment;
|
||||||
ptr_val = target_val;
|
ptr_val = target_val;
|
||||||
} else if (target_type->id == TypeTableEntryIdMaybe &&
|
} else if (target_type->id == TypeTableEntryIdOptional &&
|
||||||
target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
|
target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
|
||||||
{
|
{
|
||||||
align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
|
align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
|
||||||
ptr_val = target_val;
|
ptr_val = target_val;
|
||||||
} else if (target_type->id == TypeTableEntryIdMaybe &&
|
} else if (target_type->id == TypeTableEntryIdOptional &&
|
||||||
target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
|
target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
|
||||||
{
|
{
|
||||||
align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
|
align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
|
||||||
ptr_val = target_val;
|
ptr_val = target_val;
|
||||||
} else if (target_type->id == TypeTableEntryIdMaybe &&
|
} else if (target_type->id == TypeTableEntryIdOptional &&
|
||||||
target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
|
target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
|
||||||
{
|
{
|
||||||
zig_panic("TODO audit this function");
|
zig_panic("TODO audit this function");
|
||||||
@ -3621,7 +3724,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
|
|||||||
success_order, failure_order, instruction->is_weak);
|
success_order, failure_order, instruction->is_weak);
|
||||||
|
|
||||||
TypeTableEntry *maybe_type = instruction->base.value.type;
|
TypeTableEntry *maybe_type = instruction->base.value.type;
|
||||||
assert(maybe_type->id == TypeTableEntryIdMaybe);
|
assert(maybe_type->id == TypeTableEntryIdOptional);
|
||||||
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
|
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
|
||||||
|
|
||||||
if (type_is_codegen_pointer(child_type)) {
|
if (type_is_codegen_pointer(child_type)) {
|
||||||
@ -3730,7 +3833,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
|
|||||||
} else {
|
} else {
|
||||||
end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
|
end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (want_runtime_safety) {
|
if (want_runtime_safety) {
|
||||||
add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
|
add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
|
||||||
if (instruction->end) {
|
if (instruction->end) {
|
||||||
@ -4008,10 +4110,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
|
static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) {
|
||||||
TypeTableEntry *wanted_type = instruction->base.value.type;
|
TypeTableEntry *wanted_type = instruction->base.value.type;
|
||||||
|
|
||||||
assert(wanted_type->id == TypeTableEntryIdMaybe);
|
assert(wanted_type->id == TypeTableEntryIdOptional);
|
||||||
|
|
||||||
TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
|
TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
|
||||||
|
|
||||||
@ -4540,7 +4642,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||||||
case IrInstructionIdCheckSwitchProngs:
|
case IrInstructionIdCheckSwitchProngs:
|
||||||
case IrInstructionIdCheckStatementIsVoid:
|
case IrInstructionIdCheckStatementIsVoid:
|
||||||
case IrInstructionIdTypeName:
|
case IrInstructionIdTypeName:
|
||||||
case IrInstructionIdCanImplicitCast:
|
|
||||||
case IrInstructionIdDeclRef:
|
case IrInstructionIdDeclRef:
|
||||||
case IrInstructionIdSwitchVar:
|
case IrInstructionIdSwitchVar:
|
||||||
case IrInstructionIdOffsetOf:
|
case IrInstructionIdOffsetOf:
|
||||||
@ -4593,8 +4694,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||||||
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
|
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
|
||||||
case IrInstructionIdTestNonNull:
|
case IrInstructionIdTestNonNull:
|
||||||
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
|
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
|
||||||
case IrInstructionIdUnwrapMaybe:
|
case IrInstructionIdUnwrapOptional:
|
||||||
return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
|
return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
|
||||||
case IrInstructionIdClz:
|
case IrInstructionIdClz:
|
||||||
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
|
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
|
||||||
case IrInstructionIdCtz:
|
case IrInstructionIdCtz:
|
||||||
@ -4635,8 +4736,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||||||
return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
|
return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
|
||||||
case IrInstructionIdUnwrapErrPayload:
|
case IrInstructionIdUnwrapErrPayload:
|
||||||
return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction);
|
return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction);
|
||||||
case IrInstructionIdMaybeWrap:
|
case IrInstructionIdOptionalWrap:
|
||||||
return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction);
|
return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction);
|
||||||
case IrInstructionIdErrWrapCode:
|
case IrInstructionIdErrWrapCode:
|
||||||
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
|
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
|
||||||
case IrInstructionIdErrWrapPayload:
|
case IrInstructionIdErrWrapPayload:
|
||||||
@ -4866,7 +4967,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
|||||||
}
|
}
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdPromise:
|
case TypeTableEntryIdPromise:
|
||||||
{
|
{
|
||||||
LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
|
LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
|
||||||
@ -4914,6 +5015,79 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef
|
|||||||
return LLVMTypeOf(val) != type_entry->type_ref;
|
return LLVMTypeOf(val) != type_entry->type_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) {
|
||||||
|
render_const_val_global(g, const_val, name);
|
||||||
|
switch (const_val->data.x_ptr.special) {
|
||||||
|
case ConstPtrSpecialInvalid:
|
||||||
|
case ConstPtrSpecialDiscard:
|
||||||
|
zig_unreachable();
|
||||||
|
case ConstPtrSpecialRef:
|
||||||
|
{
|
||||||
|
ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
|
||||||
|
render_const_val(g, pointee, "");
|
||||||
|
render_const_val_global(g, pointee, "");
|
||||||
|
ConstExprValue *other_val = pointee;
|
||||||
|
const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
|
||||||
|
render_const_val_global(g, const_val, "");
|
||||||
|
return const_val->global_refs->llvm_value;
|
||||||
|
}
|
||||||
|
case ConstPtrSpecialBaseArray:
|
||||||
|
{
|
||||||
|
ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
|
||||||
|
size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
|
||||||
|
assert(array_const_val->type->id == TypeTableEntryIdArray);
|
||||||
|
if (array_const_val->type->zero_bits) {
|
||||||
|
// make this a null pointer
|
||||||
|
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
||||||
|
const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
|
||||||
|
const_val->type->type_ref);
|
||||||
|
render_const_val_global(g, const_val, "");
|
||||||
|
return const_val->global_refs->llvm_value;
|
||||||
|
}
|
||||||
|
LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
|
||||||
|
elem_index);
|
||||||
|
LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
|
||||||
|
const_val->global_refs->llvm_value = ptr_val;
|
||||||
|
render_const_val_global(g, const_val, "");
|
||||||
|
return ptr_val;
|
||||||
|
}
|
||||||
|
case ConstPtrSpecialBaseStruct:
|
||||||
|
{
|
||||||
|
ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
|
||||||
|
assert(struct_const_val->type->id == TypeTableEntryIdStruct);
|
||||||
|
if (struct_const_val->type->zero_bits) {
|
||||||
|
// make this a null pointer
|
||||||
|
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
||||||
|
const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
|
||||||
|
const_val->type->type_ref);
|
||||||
|
render_const_val_global(g, const_val, "");
|
||||||
|
return const_val->global_refs->llvm_value;
|
||||||
|
}
|
||||||
|
size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
|
||||||
|
size_t gen_field_index =
|
||||||
|
struct_const_val->type->data.structure.fields[src_field_index].gen_index;
|
||||||
|
LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
|
||||||
|
gen_field_index);
|
||||||
|
LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
|
||||||
|
const_val->global_refs->llvm_value = ptr_val;
|
||||||
|
render_const_val_global(g, const_val, "");
|
||||||
|
return ptr_val;
|
||||||
|
}
|
||||||
|
case ConstPtrSpecialHardCodedAddr:
|
||||||
|
{
|
||||||
|
uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
|
||||||
|
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
||||||
|
const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
|
||||||
|
const_val->type->type_ref);
|
||||||
|
render_const_val_global(g, const_val, "");
|
||||||
|
return const_val->global_refs->llvm_value;
|
||||||
|
}
|
||||||
|
case ConstPtrSpecialFunction:
|
||||||
|
return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
|
||||||
|
}
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
|
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
|
||||||
TypeTableEntry *type_entry = const_val->type;
|
TypeTableEntry *type_entry = const_val->type;
|
||||||
assert(!type_entry->zero_bits);
|
assert(!type_entry->zero_bits);
|
||||||
@ -4958,23 +5132,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
|||||||
} else {
|
} else {
|
||||||
return LLVMConstNull(LLVMInt1Type());
|
return LLVMConstNull(LLVMInt1Type());
|
||||||
}
|
}
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
{
|
{
|
||||||
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
||||||
if (child_type->zero_bits) {
|
if (child_type->zero_bits) {
|
||||||
return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
|
return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
|
||||||
} else if (type_is_codegen_pointer(child_type)) {
|
} else if (type_is_codegen_pointer(child_type)) {
|
||||||
if (const_val->data.x_maybe) {
|
return gen_const_val_ptr(g, const_val, name);
|
||||||
return gen_const_val(g, const_val->data.x_maybe, "");
|
|
||||||
} else {
|
|
||||||
return LLVMConstNull(child_type->type_ref);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LLVMValueRef child_val;
|
LLVMValueRef child_val;
|
||||||
LLVMValueRef maybe_val;
|
LLVMValueRef maybe_val;
|
||||||
bool make_unnamed_struct;
|
bool make_unnamed_struct;
|
||||||
if (const_val->data.x_maybe) {
|
if (const_val->data.x_optional) {
|
||||||
child_val = gen_const_val(g, const_val->data.x_maybe, "");
|
child_val = gen_const_val(g, const_val->data.x_optional, "");
|
||||||
maybe_val = LLVMConstAllOnes(LLVMInt1Type());
|
maybe_val = LLVMConstAllOnes(LLVMInt1Type());
|
||||||
|
|
||||||
make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
|
make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
|
||||||
@ -5164,78 +5334,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
|||||||
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
|
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
|
||||||
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
|
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
{
|
return gen_const_val_ptr(g, const_val, name);
|
||||||
render_const_val_global(g, const_val, name);
|
|
||||||
switch (const_val->data.x_ptr.special) {
|
|
||||||
case ConstPtrSpecialInvalid:
|
|
||||||
case ConstPtrSpecialDiscard:
|
|
||||||
zig_unreachable();
|
|
||||||
case ConstPtrSpecialRef:
|
|
||||||
{
|
|
||||||
ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
|
|
||||||
render_const_val(g, pointee, "");
|
|
||||||
render_const_val_global(g, pointee, "");
|
|
||||||
ConstExprValue *other_val = pointee;
|
|
||||||
const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
|
|
||||||
render_const_val_global(g, const_val, "");
|
|
||||||
return const_val->global_refs->llvm_value;
|
|
||||||
}
|
|
||||||
case ConstPtrSpecialBaseArray:
|
|
||||||
{
|
|
||||||
ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
|
|
||||||
size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
|
|
||||||
assert(array_const_val->type->id == TypeTableEntryIdArray);
|
|
||||||
if (array_const_val->type->zero_bits) {
|
|
||||||
// make this a null pointer
|
|
||||||
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
|
||||||
const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
|
|
||||||
const_val->type->type_ref);
|
|
||||||
render_const_val_global(g, const_val, "");
|
|
||||||
return const_val->global_refs->llvm_value;
|
|
||||||
}
|
|
||||||
LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
|
|
||||||
elem_index);
|
|
||||||
LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
|
|
||||||
const_val->global_refs->llvm_value = ptr_val;
|
|
||||||
render_const_val_global(g, const_val, "");
|
|
||||||
return ptr_val;
|
|
||||||
}
|
|
||||||
case ConstPtrSpecialBaseStruct:
|
|
||||||
{
|
|
||||||
ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val;
|
|
||||||
assert(struct_const_val->type->id == TypeTableEntryIdStruct);
|
|
||||||
if (struct_const_val->type->zero_bits) {
|
|
||||||
// make this a null pointer
|
|
||||||
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
|
||||||
const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
|
|
||||||
const_val->type->type_ref);
|
|
||||||
render_const_val_global(g, const_val, "");
|
|
||||||
return const_val->global_refs->llvm_value;
|
|
||||||
}
|
|
||||||
size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
|
|
||||||
size_t gen_field_index =
|
|
||||||
struct_const_val->type->data.structure.fields[src_field_index].gen_index;
|
|
||||||
LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
|
|
||||||
gen_field_index);
|
|
||||||
LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
|
|
||||||
const_val->global_refs->llvm_value = ptr_val;
|
|
||||||
render_const_val_global(g, const_val, "");
|
|
||||||
return ptr_val;
|
|
||||||
}
|
|
||||||
case ConstPtrSpecialHardCodedAddr:
|
|
||||||
{
|
|
||||||
uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
|
|
||||||
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
|
||||||
const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
|
|
||||||
const_val->type->type_ref);
|
|
||||||
render_const_val_global(g, const_val, "");
|
|
||||||
return const_val->global_refs->llvm_value;
|
|
||||||
}
|
|
||||||
case ConstPtrSpecialFunction:
|
|
||||||
return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zig_unreachable();
|
|
||||||
case TypeTableEntryIdErrorUnion:
|
case TypeTableEntryIdErrorUnion:
|
||||||
{
|
{
|
||||||
TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
|
TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
|
||||||
@ -5367,55 +5466,6 @@ static void generate_error_name_table(CodeGen *g) {
|
|||||||
LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init)));
|
LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_enum_name_tables(CodeGen *g) {
|
|
||||||
TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
|
||||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
|
||||||
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
|
|
||||||
|
|
||||||
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
|
||||||
LLVMValueRef array_ptr_indices[] = {
|
|
||||||
LLVMConstNull(usize->type_ref),
|
|
||||||
LLVMConstNull(usize->type_ref),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
|
|
||||||
TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
|
|
||||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
|
||||||
|
|
||||||
size_t field_count = enum_type->data.enumeration.src_field_count;
|
|
||||||
LLVMValueRef *values = allocate<LLVMValueRef>(field_count);
|
|
||||||
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
|
|
||||||
Buf *name = enum_type->data.enumeration.fields[field_i].name;
|
|
||||||
|
|
||||||
LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
|
|
||||||
LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
|
|
||||||
LLVMSetInitializer(str_global, str_init);
|
|
||||||
LLVMSetLinkage(str_global, LLVMPrivateLinkage);
|
|
||||||
LLVMSetGlobalConstant(str_global, true);
|
|
||||||
LLVMSetUnnamedAddr(str_global, true);
|
|
||||||
LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
|
|
||||||
|
|
||||||
LLVMValueRef fields[] = {
|
|
||||||
LLVMConstGEP(str_global, array_ptr_indices, 2),
|
|
||||||
LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
|
|
||||||
};
|
|
||||||
values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)field_count);
|
|
||||||
|
|
||||||
Buf *table_name = get_mangled_name(g, buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)), false);
|
|
||||||
LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name));
|
|
||||||
LLVMSetInitializer(name_table, name_table_init);
|
|
||||||
LLVMSetLinkage(name_table, LLVMPrivateLinkage);
|
|
||||||
LLVMSetGlobalConstant(name_table, true);
|
|
||||||
LLVMSetUnnamedAddr(name_table, true);
|
|
||||||
LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
|
|
||||||
enum_type->data.enumeration.name_table = name_table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
|
static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
|
||||||
IrExecutable *executable = &fn->analyzed_executable;
|
IrExecutable *executable = &fn->analyzed_executable;
|
||||||
assert(executable->basic_block_list.length > 0);
|
assert(executable->basic_block_list.length > 0);
|
||||||
@ -5512,7 +5562,6 @@ static void do_code_gen(CodeGen *g) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generate_error_name_table(g);
|
generate_error_name_table(g);
|
||||||
generate_enum_name_tables(g);
|
|
||||||
|
|
||||||
// Generate module level variables
|
// Generate module level variables
|
||||||
for (size_t i = 0; i < g->global_vars.length; i += 1) {
|
for (size_t i = 0; i < g->global_vars.length; i += 1) {
|
||||||
@ -5651,8 +5700,8 @@ static void do_code_gen(CodeGen *g) {
|
|||||||
} else if (instruction->id == IrInstructionIdSlice) {
|
} else if (instruction->id == IrInstructionIdSlice) {
|
||||||
IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
|
IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
|
||||||
slot = &slice_instruction->tmp_ptr;
|
slot = &slice_instruction->tmp_ptr;
|
||||||
} else if (instruction->id == IrInstructionIdMaybeWrap) {
|
} else if (instruction->id == IrInstructionIdOptionalWrap) {
|
||||||
IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction;
|
IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction;
|
||||||
slot = &maybe_wrap_instruction->tmp_ptr;
|
slot = &maybe_wrap_instruction->tmp_ptr;
|
||||||
} else if (instruction->id == IrInstructionIdErrWrapPayload) {
|
} else if (instruction->id == IrInstructionIdErrWrapPayload) {
|
||||||
IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
|
IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
|
||||||
@ -6192,7 +6241,6 @@ static void define_builtin_fns(CodeGen *g) {
|
|||||||
create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
|
create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
|
||||||
create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
|
create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
|
||||||
create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
|
create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
|
||||||
create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
|
|
||||||
create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
|
create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
|
||||||
create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
|
create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
|
||||||
create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
|
create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
|
||||||
@ -6250,13 +6298,7 @@ static const char *build_mode_to_str(BuildMode build_mode) {
|
|||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void define_builtin_compile_vars(CodeGen *g) {
|
Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||||
if (g->std_package == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const char *builtin_zig_basename = "builtin.zig";
|
|
||||||
Buf *builtin_zig_path = buf_alloc();
|
|
||||||
os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
|
||||||
Buf *contents = buf_alloc();
|
Buf *contents = buf_alloc();
|
||||||
|
|
||||||
// Modifications to this struct must be coordinated with code that does anything with
|
// Modifications to this struct must be coordinated with code that does anything with
|
||||||
@ -6396,7 +6438,6 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
|||||||
const TypeTableEntryId id = type_id_at_index(i);
|
const TypeTableEntryId id = type_id_at_index(i);
|
||||||
buf_appendf(contents, " %s,\n", type_id_name(id));
|
buf_appendf(contents, " %s,\n", type_id_name(id));
|
||||||
}
|
}
|
||||||
buf_appendf(contents, " Slice,\n");
|
|
||||||
buf_appendf(contents, "};\n\n");
|
buf_appendf(contents, "};\n\n");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -6409,14 +6450,13 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
|||||||
" Int: Int,\n"
|
" Int: Int,\n"
|
||||||
" Float: Float,\n"
|
" Float: Float,\n"
|
||||||
" Pointer: Pointer,\n"
|
" Pointer: Pointer,\n"
|
||||||
" Slice: Slice,\n"
|
|
||||||
" Array: Array,\n"
|
" Array: Array,\n"
|
||||||
" Struct: Struct,\n"
|
" Struct: Struct,\n"
|
||||||
" ComptimeFloat: void,\n"
|
" ComptimeFloat: void,\n"
|
||||||
" ComptimeInt: void,\n"
|
" ComptimeInt: void,\n"
|
||||||
" Undefined: void,\n"
|
" Undefined: void,\n"
|
||||||
" Null: void,\n"
|
" Null: void,\n"
|
||||||
" Nullable: Nullable,\n"
|
" Optional: Optional,\n"
|
||||||
" ErrorUnion: ErrorUnion,\n"
|
" ErrorUnion: ErrorUnion,\n"
|
||||||
" ErrorSet: ErrorSet,\n"
|
" ErrorSet: ErrorSet,\n"
|
||||||
" Enum: Enum,\n"
|
" Enum: Enum,\n"
|
||||||
@ -6439,13 +6479,18 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
|||||||
" };\n"
|
" };\n"
|
||||||
"\n"
|
"\n"
|
||||||
" pub const Pointer = struct {\n"
|
" pub const Pointer = struct {\n"
|
||||||
|
" size: Size,\n"
|
||||||
" is_const: bool,\n"
|
" is_const: bool,\n"
|
||||||
" is_volatile: bool,\n"
|
" is_volatile: bool,\n"
|
||||||
" alignment: u32,\n"
|
" alignment: u32,\n"
|
||||||
" child: type,\n"
|
" child: type,\n"
|
||||||
" };\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
" pub const Slice = Pointer;\n"
|
" pub const Size = enum {\n"
|
||||||
|
" One,\n"
|
||||||
|
" Many,\n"
|
||||||
|
" Slice,\n"
|
||||||
|
" };\n"
|
||||||
|
" };\n"
|
||||||
"\n"
|
"\n"
|
||||||
" pub const Array = struct {\n"
|
" pub const Array = struct {\n"
|
||||||
" len: usize,\n"
|
" len: usize,\n"
|
||||||
@ -6470,7 +6515,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
|||||||
" defs: []Definition,\n"
|
" defs: []Definition,\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"\n"
|
"\n"
|
||||||
" pub const Nullable = struct {\n"
|
" pub const Optional = struct {\n"
|
||||||
" child: type,\n"
|
" child: type,\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -6619,6 +6664,19 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
|||||||
|
|
||||||
buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
|
buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
|
||||||
|
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void define_builtin_compile_vars(CodeGen *g) {
|
||||||
|
if (g->std_package == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *builtin_zig_basename = "builtin.zig";
|
||||||
|
Buf *builtin_zig_path = buf_alloc();
|
||||||
|
os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||||
|
|
||||||
|
Buf *contents = codegen_generate_builtin_source(g);
|
||||||
ensure_cache_dir(g);
|
ensure_cache_dir(g);
|
||||||
os_write_file(builtin_zig_path, contents);
|
os_write_file(builtin_zig_path, contents);
|
||||||
|
|
||||||
@ -7032,7 +7090,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
|
|||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
|
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
|
||||||
return;
|
return;
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
|
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
|
||||||
return;
|
return;
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
@ -7121,7 +7179,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
|
|||||||
buf_appendf(out_buf, "%s%s *", const_str, buf_ptr(&child_buf));
|
buf_appendf(out_buf, "%s%s *", const_str, buf_ptr(&child_buf));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
{
|
{
|
||||||
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
|
||||||
if (child_type->zero_bits) {
|
if (child_type->zero_bits) {
|
||||||
@ -7335,7 +7393,7 @@ static void gen_h_file(CodeGen *g) {
|
|||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdArgTuple:
|
case TypeTableEntryIdArgTuple:
|
||||||
case TypeTableEntryIdMaybe:
|
case TypeTableEntryIdOptional:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdPromise:
|
case TypeTableEntryIdPromise:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
|||||||
@ -59,5 +59,7 @@ void codegen_add_object(CodeGen *g, Buf *object_path);
|
|||||||
|
|
||||||
void codegen_translate_c(CodeGen *g, Buf *path);
|
void codegen_translate_c(CodeGen *g, Buf *path);
|
||||||
|
|
||||||
|
Buf *codegen_generate_builtin_source(CodeGen *g);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1060
src/ir.cpp
1060
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -148,7 +148,7 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
|
|||||||
return "-%";
|
return "-%";
|
||||||
case IrUnOpDereference:
|
case IrUnOpDereference:
|
||||||
return "*";
|
return "*";
|
||||||
case IrUnOpMaybe:
|
case IrUnOpOptional:
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
@ -481,7 +481,7 @@ static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instructi
|
|||||||
fprintf(irp->f, " != null");
|
fprintf(irp->f, " != null");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) {
|
static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
|
||||||
fprintf(irp->f, "&??*");
|
fprintf(irp->f, "&??*");
|
||||||
ir_print_other_instruction(irp, instruction->value);
|
ir_print_other_instruction(irp, instruction->value);
|
||||||
if (!instruction->safety_check_on) {
|
if (!instruction->safety_check_on) {
|
||||||
@ -777,7 +777,7 @@ static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionMaybeWrap *instruction) {
|
static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) {
|
||||||
fprintf(irp->f, "@maybeWrap(");
|
fprintf(irp->f, "@maybeWrap(");
|
||||||
ir_print_other_instruction(irp, instruction->value);
|
ir_print_other_instruction(irp, instruction->value);
|
||||||
fprintf(irp->f, ")");
|
fprintf(irp->f, ")");
|
||||||
@ -913,14 +913,6 @@ static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) {
|
|||||||
ir_print_other_instruction(irp, instruction->target);
|
ir_print_other_instruction(irp, instruction->target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCast *instruction) {
|
|
||||||
fprintf(irp->f, "@canImplicitCast(");
|
|
||||||
ir_print_other_instruction(irp, instruction->type_value);
|
|
||||||
fprintf(irp->f, ",");
|
|
||||||
ir_print_other_instruction(irp, instruction->target_value);
|
|
||||||
fprintf(irp->f, ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
|
static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
|
||||||
fprintf(irp->f, "&");
|
fprintf(irp->f, "&");
|
||||||
if (instruction->align_value != nullptr) {
|
if (instruction->align_value != nullptr) {
|
||||||
@ -1040,7 +1032,7 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
|
|||||||
|
|
||||||
static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
|
static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
|
||||||
fprintf(irp->f, "@errorReturnTrace(");
|
fprintf(irp->f, "@errorReturnTrace(");
|
||||||
switch (instruction->nullable) {
|
switch (instruction->optional) {
|
||||||
case IrInstructionErrorReturnTrace::Null:
|
case IrInstructionErrorReturnTrace::Null:
|
||||||
fprintf(irp->f, "Null");
|
fprintf(irp->f, "Null");
|
||||||
break;
|
break;
|
||||||
@ -1356,8 +1348,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||||||
case IrInstructionIdTestNonNull:
|
case IrInstructionIdTestNonNull:
|
||||||
ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
|
ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
|
||||||
break;
|
break;
|
||||||
case IrInstructionIdUnwrapMaybe:
|
case IrInstructionIdUnwrapOptional:
|
||||||
ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);
|
ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
|
||||||
break;
|
break;
|
||||||
case IrInstructionIdCtz:
|
case IrInstructionIdCtz:
|
||||||
ir_print_ctz(irp, (IrInstructionCtz *)instruction);
|
ir_print_ctz(irp, (IrInstructionCtz *)instruction);
|
||||||
@ -1473,8 +1465,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||||||
case IrInstructionIdUnwrapErrPayload:
|
case IrInstructionIdUnwrapErrPayload:
|
||||||
ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction);
|
ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction);
|
||||||
break;
|
break;
|
||||||
case IrInstructionIdMaybeWrap:
|
case IrInstructionIdOptionalWrap:
|
||||||
ir_print_maybe_wrap(irp, (IrInstructionMaybeWrap *)instruction);
|
ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction);
|
||||||
break;
|
break;
|
||||||
case IrInstructionIdErrWrapCode:
|
case IrInstructionIdErrWrapCode:
|
||||||
ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction);
|
ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction);
|
||||||
@ -1524,9 +1516,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||||||
case IrInstructionIdTagName:
|
case IrInstructionIdTagName:
|
||||||
ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
|
ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
|
||||||
break;
|
break;
|
||||||
case IrInstructionIdCanImplicitCast:
|
|
||||||
ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
|
|
||||||
break;
|
|
||||||
case IrInstructionIdPtrType:
|
case IrInstructionIdPtrType:
|
||||||
ir_print_ptr_type(irp, (IrInstructionPtrType *)instruction);
|
ir_print_ptr_type(irp, (IrInstructionPtrType *)instruction);
|
||||||
break;
|
break;
|
||||||
|
|||||||
15
src/link.cpp
15
src/link.cpp
@ -391,6 +391,19 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void construct_linker_job_wasm(LinkJob *lj) {
|
||||||
|
CodeGen *g = lj->codegen;
|
||||||
|
|
||||||
|
lj->args.append("--relocatable"); // So lld doesn't look for _start.
|
||||||
|
lj->args.append("-o");
|
||||||
|
lj->args.append(buf_ptr(&lj->out_file));
|
||||||
|
|
||||||
|
// .o files
|
||||||
|
for (size_t i = 0; i < g->link_objects.length; i += 1) {
|
||||||
|
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//static bool is_target_cyg_mingw(const ZigTarget *target) {
|
//static bool is_target_cyg_mingw(const ZigTarget *target) {
|
||||||
// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) ||
|
// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) ||
|
||||||
// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU);
|
// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU);
|
||||||
@ -924,7 +937,7 @@ static void construct_linker_job(LinkJob *lj) {
|
|||||||
case ZigLLVM_MachO:
|
case ZigLLVM_MachO:
|
||||||
return construct_linker_job_macho(lj);
|
return construct_linker_job_macho(lj);
|
||||||
case ZigLLVM_Wasm:
|
case ZigLLVM_Wasm:
|
||||||
zig_panic("TODO link wasm");
|
return construct_linker_job_wasm(lj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
src/main.cpp
15
src/main.cpp
@ -23,6 +23,7 @@ static int usage(const char *arg0) {
|
|||||||
" build-exe [source] create executable from source or object files\n"
|
" build-exe [source] create executable from source or object files\n"
|
||||||
" build-lib [source] create library from source or object files\n"
|
" build-lib [source] create library from source or object files\n"
|
||||||
" build-obj [source] create object from source or assembly\n"
|
" build-obj [source] create object from source or assembly\n"
|
||||||
|
" builtin show the source code of that @import(\"builtin\")\n"
|
||||||
" run [source] create executable and run immediately\n"
|
" run [source] create executable and run immediately\n"
|
||||||
" translate-c [source] convert c code to zig code\n"
|
" translate-c [source] convert c code to zig code\n"
|
||||||
" targets list available compilation targets\n"
|
" targets list available compilation targets\n"
|
||||||
@ -214,6 +215,7 @@ static Buf *resolve_zig_lib_dir(void) {
|
|||||||
enum Cmd {
|
enum Cmd {
|
||||||
CmdInvalid,
|
CmdInvalid,
|
||||||
CmdBuild,
|
CmdBuild,
|
||||||
|
CmdBuiltin,
|
||||||
CmdRun,
|
CmdRun,
|
||||||
CmdTest,
|
CmdTest,
|
||||||
CmdVersion,
|
CmdVersion,
|
||||||
@ -664,6 +666,8 @@ int main(int argc, char **argv) {
|
|||||||
out_type = OutTypeExe;
|
out_type = OutTypeExe;
|
||||||
} else if (strcmp(arg, "targets") == 0) {
|
} else if (strcmp(arg, "targets") == 0) {
|
||||||
cmd = CmdTargets;
|
cmd = CmdTargets;
|
||||||
|
} else if (strcmp(arg, "builtin") == 0) {
|
||||||
|
cmd = CmdBuiltin;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unrecognized command: %s\n", arg);
|
fprintf(stderr, "Unrecognized command: %s\n", arg);
|
||||||
return usage(arg0);
|
return usage(arg0);
|
||||||
@ -681,6 +685,7 @@ int main(int argc, char **argv) {
|
|||||||
return usage(arg0);
|
return usage(arg0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CmdBuiltin:
|
||||||
case CmdVersion:
|
case CmdVersion:
|
||||||
case CmdZen:
|
case CmdZen:
|
||||||
case CmdTargets:
|
case CmdTargets:
|
||||||
@ -727,6 +732,16 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case CmdBuiltin: {
|
||||||
|
Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
|
||||||
|
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf);
|
||||||
|
Buf *builtin_source = codegen_generate_builtin_source(g);
|
||||||
|
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
|
||||||
|
fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
case CmdRun:
|
case CmdRun:
|
||||||
case CmdBuild:
|
case CmdBuild:
|
||||||
case CmdTranslateC:
|
case CmdTranslateC:
|
||||||
|
|||||||
@ -1046,12 +1046,11 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression)
|
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?")
|
||||||
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
|
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
|
||||||
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
|
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
|
||||||
SliceExpression = "[" Expression ".." option(Expression) "]"
|
SliceExpression = "[" Expression ".." option(Expression) "]"
|
||||||
FieldAccessExpression : token(Dot) token(Symbol)
|
FieldAccessExpression : token(Dot) token(Symbol)
|
||||||
PtrDerefExpression = ".*"
|
|
||||||
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
|
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
@ -1148,6 +1147,13 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
|
|||||||
AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
|
AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
|
||||||
node->data.ptr_deref_expr.target = primary_expr;
|
node->data.ptr_deref_expr.target = primary_expr;
|
||||||
|
|
||||||
|
primary_expr = node;
|
||||||
|
} else if (token->id == TokenIdQuestion) {
|
||||||
|
*token_index += 1;
|
||||||
|
|
||||||
|
AstNode *node = ast_create_node(pc, NodeTypeUnwrapOptional, first_token);
|
||||||
|
node->data.unwrap_optional.expr = primary_expr;
|
||||||
|
|
||||||
primary_expr = node;
|
primary_expr = node;
|
||||||
} else {
|
} else {
|
||||||
ast_invalid_token_error(pc, token);
|
ast_invalid_token_error(pc, token);
|
||||||
@ -1165,8 +1171,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
|
|||||||
case TokenIdDash: return PrefixOpNegation;
|
case TokenIdDash: return PrefixOpNegation;
|
||||||
case TokenIdMinusPercent: return PrefixOpNegationWrap;
|
case TokenIdMinusPercent: return PrefixOpNegationWrap;
|
||||||
case TokenIdTilde: return PrefixOpBinNot;
|
case TokenIdTilde: return PrefixOpBinNot;
|
||||||
case TokenIdMaybe: return PrefixOpMaybe;
|
case TokenIdQuestion: return PrefixOpOptional;
|
||||||
case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
|
|
||||||
case TokenIdAmpersand: return PrefixOpAddrOf;
|
case TokenIdAmpersand: return PrefixOpAddrOf;
|
||||||
default: return PrefixOpInvalid;
|
default: return PrefixOpInvalid;
|
||||||
}
|
}
|
||||||
@ -2304,8 +2309,8 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, size_t *token_index, bool ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
|
UnwrapExpression : BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
|
||||||
UnwrapMaybe : "??" BoolOrExpression
|
UnwrapOptional = "orelse" Expression
|
||||||
UnwrapError = "catch" option("|" Symbol "|") Expression
|
UnwrapError = "catch" option("|" Symbol "|") Expression
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
@ -2315,14 +2320,14 @@ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, boo
|
|||||||
|
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
|
|
||||||
if (token->id == TokenIdDoubleQuestion) {
|
if (token->id == TokenIdKeywordOrElse) {
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
|
|
||||||
AstNode *rhs = ast_parse_expression(pc, token_index, true);
|
AstNode *rhs = ast_parse_expression(pc, token_index, true);
|
||||||
|
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
||||||
node->data.bin_op_expr.op1 = lhs;
|
node->data.bin_op_expr.op1 = lhs;
|
||||||
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
|
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapOptional;
|
||||||
node->data.bin_op_expr.op2 = rhs;
|
node->data.bin_op_expr.op2 = rhs;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -3028,6 +3033,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
|||||||
case NodeTypePtrDeref:
|
case NodeTypePtrDeref:
|
||||||
visit_field(&node->data.ptr_deref_expr.target, visit, context);
|
visit_field(&node->data.ptr_deref_expr.target, visit, context);
|
||||||
break;
|
break;
|
||||||
|
case NodeTypeUnwrapOptional:
|
||||||
|
visit_field(&node->data.unwrap_optional.expr, visit, context);
|
||||||
|
break;
|
||||||
case NodeTypeUse:
|
case NodeTypeUse:
|
||||||
visit_field(&node->data.use.expr, visit, context);
|
visit_field(&node->data.use.expr, visit, context);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -596,12 +596,15 @@ void resolve_target_object_format(ZigTarget *target) {
|
|||||||
case ZigLLVM_tce:
|
case ZigLLVM_tce:
|
||||||
case ZigLLVM_tcele:
|
case ZigLLVM_tcele:
|
||||||
case ZigLLVM_thumbeb:
|
case ZigLLVM_thumbeb:
|
||||||
case ZigLLVM_wasm32:
|
|
||||||
case ZigLLVM_wasm64:
|
|
||||||
case ZigLLVM_xcore:
|
case ZigLLVM_xcore:
|
||||||
target->oformat= ZigLLVM_ELF;
|
target->oformat= ZigLLVM_ELF;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case ZigLLVM_wasm32:
|
||||||
|
case ZigLLVM_wasm64:
|
||||||
|
target->oformat = ZigLLVM_Wasm;
|
||||||
|
return;
|
||||||
|
|
||||||
case ZigLLVM_ppc:
|
case ZigLLVM_ppc:
|
||||||
case ZigLLVM_ppc64:
|
case ZigLLVM_ppc64:
|
||||||
if (is_os_darwin(target)) {
|
if (is_os_darwin(target)) {
|
||||||
|
|||||||
@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = {
|
|||||||
{"noalias", TokenIdKeywordNoAlias},
|
{"noalias", TokenIdKeywordNoAlias},
|
||||||
{"null", TokenIdKeywordNull},
|
{"null", TokenIdKeywordNull},
|
||||||
{"or", TokenIdKeywordOr},
|
{"or", TokenIdKeywordOr},
|
||||||
|
{"orelse", TokenIdKeywordOrElse},
|
||||||
{"packed", TokenIdKeywordPacked},
|
{"packed", TokenIdKeywordPacked},
|
||||||
{"promise", TokenIdKeywordPromise},
|
{"promise", TokenIdKeywordPromise},
|
||||||
{"pub", TokenIdKeywordPub},
|
{"pub", TokenIdKeywordPub},
|
||||||
@ -215,7 +216,6 @@ enum TokenizeState {
|
|||||||
TokenizeStateSawGreaterThanGreaterThan,
|
TokenizeStateSawGreaterThanGreaterThan,
|
||||||
TokenizeStateSawDot,
|
TokenizeStateSawDot,
|
||||||
TokenizeStateSawDotDot,
|
TokenizeStateSawDotDot,
|
||||||
TokenizeStateSawQuestionMark,
|
|
||||||
TokenizeStateSawAtSign,
|
TokenizeStateSawAtSign,
|
||||||
TokenizeStateCharCode,
|
TokenizeStateCharCode,
|
||||||
TokenizeStateError,
|
TokenizeStateError,
|
||||||
@ -532,6 +532,10 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
begin_token(&t, TokenIdComma);
|
begin_token(&t, TokenIdComma);
|
||||||
end_token(&t);
|
end_token(&t);
|
||||||
break;
|
break;
|
||||||
|
case '?':
|
||||||
|
begin_token(&t, TokenIdQuestion);
|
||||||
|
end_token(&t);
|
||||||
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
begin_token(&t, TokenIdLBrace);
|
begin_token(&t, TokenIdLBrace);
|
||||||
end_token(&t);
|
end_token(&t);
|
||||||
@ -624,33 +628,10 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
begin_token(&t, TokenIdDot);
|
begin_token(&t, TokenIdDot);
|
||||||
t.state = TokenizeStateSawDot;
|
t.state = TokenizeStateSawDot;
|
||||||
break;
|
break;
|
||||||
case '?':
|
|
||||||
begin_token(&t, TokenIdMaybe);
|
|
||||||
t.state = TokenizeStateSawQuestionMark;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
invalid_char_error(&t, c);
|
invalid_char_error(&t, c);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TokenizeStateSawQuestionMark:
|
|
||||||
switch (c) {
|
|
||||||
case '?':
|
|
||||||
set_token_id(&t, t.cur_tok, TokenIdDoubleQuestion);
|
|
||||||
end_token(&t);
|
|
||||||
t.state = TokenizeStateStart;
|
|
||||||
break;
|
|
||||||
case '=':
|
|
||||||
set_token_id(&t, t.cur_tok, TokenIdMaybeAssign);
|
|
||||||
end_token(&t);
|
|
||||||
t.state = TokenizeStateStart;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
t.pos -= 1;
|
|
||||||
end_token(&t);
|
|
||||||
t.state = TokenizeStateStart;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenizeStateSawDot:
|
case TokenizeStateSawDot:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '.':
|
case '.':
|
||||||
@ -1485,7 +1466,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
case TokenizeStateSawGreaterThan:
|
case TokenizeStateSawGreaterThan:
|
||||||
case TokenizeStateSawGreaterThanGreaterThan:
|
case TokenizeStateSawGreaterThanGreaterThan:
|
||||||
case TokenizeStateSawDot:
|
case TokenizeStateSawDot:
|
||||||
case TokenizeStateSawQuestionMark:
|
|
||||||
case TokenizeStateSawAtSign:
|
case TokenizeStateSawAtSign:
|
||||||
case TokenizeStateSawStarPercent:
|
case TokenizeStateSawStarPercent:
|
||||||
case TokenizeStateSawPlusPercent:
|
case TokenizeStateSawPlusPercent:
|
||||||
@ -1550,7 +1530,6 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdDash: return "-";
|
case TokenIdDash: return "-";
|
||||||
case TokenIdDivEq: return "/=";
|
case TokenIdDivEq: return "/=";
|
||||||
case TokenIdDot: return ".";
|
case TokenIdDot: return ".";
|
||||||
case TokenIdDoubleQuestion: return "??";
|
|
||||||
case TokenIdEllipsis2: return "..";
|
case TokenIdEllipsis2: return "..";
|
||||||
case TokenIdEllipsis3: return "...";
|
case TokenIdEllipsis3: return "...";
|
||||||
case TokenIdEof: return "EOF";
|
case TokenIdEof: return "EOF";
|
||||||
@ -1587,6 +1566,7 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdKeywordNoAlias: return "noalias";
|
case TokenIdKeywordNoAlias: return "noalias";
|
||||||
case TokenIdKeywordNull: return "null";
|
case TokenIdKeywordNull: return "null";
|
||||||
case TokenIdKeywordOr: return "or";
|
case TokenIdKeywordOr: return "or";
|
||||||
|
case TokenIdKeywordOrElse: return "orelse";
|
||||||
case TokenIdKeywordPacked: return "packed";
|
case TokenIdKeywordPacked: return "packed";
|
||||||
case TokenIdKeywordPromise: return "promise";
|
case TokenIdKeywordPromise: return "promise";
|
||||||
case TokenIdKeywordPub: return "pub";
|
case TokenIdKeywordPub: return "pub";
|
||||||
@ -1609,8 +1589,7 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdLBrace: return "{";
|
case TokenIdLBrace: return "{";
|
||||||
case TokenIdLBracket: return "[";
|
case TokenIdLBracket: return "[";
|
||||||
case TokenIdLParen: return "(";
|
case TokenIdLParen: return "(";
|
||||||
case TokenIdMaybe: return "?";
|
case TokenIdQuestion: return "?";
|
||||||
case TokenIdMaybeAssign: return "?=";
|
|
||||||
case TokenIdMinusEq: return "-=";
|
case TokenIdMinusEq: return "-=";
|
||||||
case TokenIdMinusPercent: return "-%";
|
case TokenIdMinusPercent: return "-%";
|
||||||
case TokenIdMinusPercentEq: return "-%=";
|
case TokenIdMinusPercentEq: return "-%=";
|
||||||
|
|||||||
@ -41,7 +41,6 @@ enum TokenId {
|
|||||||
TokenIdDash,
|
TokenIdDash,
|
||||||
TokenIdDivEq,
|
TokenIdDivEq,
|
||||||
TokenIdDot,
|
TokenIdDot,
|
||||||
TokenIdDoubleQuestion,
|
|
||||||
TokenIdEllipsis2,
|
TokenIdEllipsis2,
|
||||||
TokenIdEllipsis3,
|
TokenIdEllipsis3,
|
||||||
TokenIdEof,
|
TokenIdEof,
|
||||||
@ -76,6 +75,7 @@ enum TokenId {
|
|||||||
TokenIdKeywordNoAlias,
|
TokenIdKeywordNoAlias,
|
||||||
TokenIdKeywordNull,
|
TokenIdKeywordNull,
|
||||||
TokenIdKeywordOr,
|
TokenIdKeywordOr,
|
||||||
|
TokenIdKeywordOrElse,
|
||||||
TokenIdKeywordPacked,
|
TokenIdKeywordPacked,
|
||||||
TokenIdKeywordPromise,
|
TokenIdKeywordPromise,
|
||||||
TokenIdKeywordPub,
|
TokenIdKeywordPub,
|
||||||
@ -100,8 +100,7 @@ enum TokenId {
|
|||||||
TokenIdLBrace,
|
TokenIdLBrace,
|
||||||
TokenIdLBracket,
|
TokenIdLBracket,
|
||||||
TokenIdLParen,
|
TokenIdLParen,
|
||||||
TokenIdMaybe,
|
TokenIdQuestion,
|
||||||
TokenIdMaybeAssign,
|
|
||||||
TokenIdMinusEq,
|
TokenIdMinusEq,
|
||||||
TokenIdMinusPercent,
|
TokenIdMinusPercent,
|
||||||
TokenIdMinusPercentEq,
|
TokenIdMinusPercentEq,
|
||||||
@ -170,6 +169,8 @@ struct Token {
|
|||||||
TokenCharLit char_lit;
|
TokenCharLit char_lit;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
// work around conflicting name Token which is also found in libclang
|
||||||
|
typedef Token ZigToken;
|
||||||
|
|
||||||
struct Tokenization {
|
struct Tokenization {
|
||||||
ZigList<Token> *tokens;
|
ZigList<Token> *tokens;
|
||||||
|
|||||||
@ -260,6 +260,12 @@ static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *ch
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child_node) {
|
||||||
|
AstNode *node = trans_create_node(c, NodeTypeUnwrapOptional);
|
||||||
|
node->data.unwrap_optional.expr = child_node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) {
|
static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) {
|
||||||
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
|
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
|
||||||
node->data.bin_op_expr.op1 = lhs_node;
|
node->data.bin_op_expr.op1 = lhs_node;
|
||||||
@ -276,8 +282,11 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod
|
|||||||
node);
|
node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node) {
|
static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) {
|
||||||
AstNode *node = trans_create_node(c, NodeTypePointerType);
|
AstNode *node = trans_create_node(c, NodeTypePointerType);
|
||||||
|
node->data.pointer_type.star_token = allocate<ZigToken>(1);
|
||||||
|
node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket;
|
||||||
|
node->data.pointer_type.is_const = is_const;
|
||||||
node->data.pointer_type.is_const = is_const;
|
node->data.pointer_type.is_const = is_const;
|
||||||
node->data.pointer_type.is_volatile = is_volatile;
|
node->data.pointer_type.is_volatile = is_volatile;
|
||||||
node->data.pointer_type.op_expr = child_node;
|
node->data.pointer_type.op_expr = child_node;
|
||||||
@ -379,7 +388,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
|
|||||||
fn_def->data.fn_def.fn_proto = fn_proto;
|
fn_def->data.fn_def.fn_proto = fn_proto;
|
||||||
fn_proto->data.fn_proto.fn_def_node = fn_def;
|
fn_proto->data.fn_proto.fn_def_node = fn_def;
|
||||||
|
|
||||||
AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
|
AstNode *unwrap_node = trans_create_node_unwrap_null(c, ref_node);
|
||||||
AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
|
AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
|
||||||
fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
|
fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
|
||||||
|
|
||||||
@ -406,10 +415,6 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
|
|||||||
return fn_def;
|
return fn_def;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) {
|
|
||||||
return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
static AstNode *get_global(Context *c, Buf *name) {
|
static AstNode *get_global(Context *c, Buf *name) {
|
||||||
{
|
{
|
||||||
auto entry = c->global_table.maybe_get(name);
|
auto entry = c->global_table.maybe_get(name);
|
||||||
@ -731,6 +736,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) {
|
||||||
|
switch (ty->getTypeClass()) {
|
||||||
|
case Type::Builtin: {
|
||||||
|
const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
|
||||||
|
return builtin_ty->getKind() == BuiltinType::Void;
|
||||||
|
}
|
||||||
|
case Type::Record: {
|
||||||
|
const RecordType *record_ty = static_cast<const RecordType*>(ty);
|
||||||
|
return record_ty->getDecl()->getDefinition() == nullptr;
|
||||||
|
}
|
||||||
|
case Type::Elaborated: {
|
||||||
|
const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
|
||||||
|
return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc);
|
||||||
|
}
|
||||||
|
case Type::Typedef: {
|
||||||
|
const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
|
||||||
|
const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
|
||||||
|
return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) {
|
static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) {
|
||||||
switch (ty->getTypeClass()) {
|
switch (ty->getTypeClass()) {
|
||||||
case Type::Builtin:
|
case Type::Builtin:
|
||||||
@ -859,12 +888,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (qual_type_child_is_fn_proto(child_qt)) {
|
if (qual_type_child_is_fn_proto(child_qt)) {
|
||||||
return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node);
|
return trans_create_node_prefix_op(c, PrefixOpOptional, child_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown;
|
||||||
|
|
||||||
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
||||||
child_qt.isVolatileQualified(), child_node);
|
child_qt.isVolatileQualified(), child_node, ptr_len);
|
||||||
return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node);
|
return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
|
||||||
}
|
}
|
||||||
case Type::Typedef:
|
case Type::Typedef:
|
||||||
{
|
{
|
||||||
@ -1048,7 +1079,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
||||||
child_qt.isVolatileQualified(), child_type_node);
|
child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown);
|
||||||
return pointer_node;
|
return pointer_node;
|
||||||
}
|
}
|
||||||
case Type::BlockPointer:
|
case Type::BlockPointer:
|
||||||
@ -1941,7 +1972,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
|||||||
bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType());
|
bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType());
|
||||||
if (is_fn_ptr)
|
if (is_fn_ptr)
|
||||||
return value_node;
|
return value_node;
|
||||||
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
|
AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node);
|
||||||
return trans_create_node_ptr_deref(c, unwrapped);
|
return trans_create_node_ptr_deref(c, unwrapped);
|
||||||
}
|
}
|
||||||
case UO_Plus:
|
case UO_Plus:
|
||||||
@ -2572,7 +2603,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (callee_node == nullptr) {
|
if (callee_node == nullptr) {
|
||||||
callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
|
callee_node = trans_create_node_unwrap_null(c, callee_raw_node);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callee_node = callee_raw_node;
|
callee_node = callee_raw_node;
|
||||||
@ -4286,7 +4317,7 @@ static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
if (prefix_node->type != NodeTypePrefixOpExpr)
|
if (prefix_node->type != NodeTypePrefixOpExpr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
|
if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpOptional)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
|
AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
|
||||||
@ -4462,7 +4493,7 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
|
|||||||
} else if (first_tok->id == CTokIdAsterisk) {
|
} else if (first_tok->id == CTokIdAsterisk) {
|
||||||
*tok_i += 1;
|
*tok_i += 1;
|
||||||
|
|
||||||
node = trans_create_node_ptr_type(c, false, false, node);
|
node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown);
|
||||||
} else {
|
} else {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -853,7 +853,7 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
|
|||||||
return lld::mach_o::link(array_ref_args, diag);
|
return lld::mach_o::link(array_ref_args, diag);
|
||||||
|
|
||||||
case ZigLLVM_Wasm:
|
case ZigLLVM_Wasm:
|
||||||
assert(false); // TODO ZigLLDLink for Wasm
|
return lld::wasm::link(array_ref_args, false, diag);
|
||||||
}
|
}
|
||||||
assert(false); // unreachable
|
assert(false); // unreachable
|
||||||
abort();
|
abort();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
const std = @import("index.zig");
|
const std = @import("index.zig");
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const assert = debug.assert;
|
const assert = debug.assert;
|
||||||
|
const assertError = debug.assertError;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
@ -28,20 +29,33 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(l: *const Self) void {
|
pub fn deinit(self: *const Self) void {
|
||||||
l.allocator.free(l.items);
|
self.allocator.free(self.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toSlice(l: *const Self) []align(A) T {
|
pub fn toSlice(self: *const Self) []align(A) T {
|
||||||
return l.items[0..l.len];
|
return self.items[0..self.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toSliceConst(l: *const Self) []align(A) const T {
|
pub fn toSliceConst(self: *const Self) []align(A) const T {
|
||||||
return l.items[0..l.len];
|
return self.items[0..self.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at(l: *const Self, n: usize) T {
|
pub fn at(self: *const Self, n: usize) T {
|
||||||
return l.toSliceConst()[n];
|
return self.toSliceConst()[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value at index `i`, or returns `error.OutOfBounds` if
|
||||||
|
/// the index is not in range.
|
||||||
|
pub fn setOrError(self: *const Self, i: usize, item: *const T) !void {
|
||||||
|
if (i >= self.len) return error.OutOfBounds;
|
||||||
|
self.items[i] = item.*;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value at index `i`, asserting that the value is in range.
|
||||||
|
pub fn set(self: *const Self, i: usize, item: *const T) void {
|
||||||
|
assert(i < self.len);
|
||||||
|
self.items[i] = item.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(self: *const Self) usize {
|
pub fn count(self: *const Self) usize {
|
||||||
@ -67,58 +81,58 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(l: *Self, n: usize, item: *const T) !void {
|
pub fn insert(self: *Self, n: usize, item: *const T) !void {
|
||||||
try l.ensureCapacity(l.len + 1);
|
try self.ensureCapacity(self.len + 1);
|
||||||
l.len += 1;
|
self.len += 1;
|
||||||
|
|
||||||
mem.copy(T, l.items[n + 1 .. l.len], l.items[n .. l.len - 1]);
|
mem.copy(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
|
||||||
l.items[n] = item.*;
|
self.items[n] = item.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insertSlice(l: *Self, n: usize, items: []align(A) const T) !void {
|
pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
|
||||||
try l.ensureCapacity(l.len + items.len);
|
try self.ensureCapacity(self.len + items.len);
|
||||||
l.len += items.len;
|
self.len += items.len;
|
||||||
|
|
||||||
mem.copy(T, l.items[n + items.len .. l.len], l.items[n .. l.len - items.len]);
|
mem.copy(T, self.items[n + items.len .. self.len], self.items[n .. self.len - items.len]);
|
||||||
mem.copy(T, l.items[n .. n + items.len], items);
|
mem.copy(T, self.items[n .. n + items.len], items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(l: *Self, item: *const T) !void {
|
pub fn append(self: *Self, item: *const T) !void {
|
||||||
const new_item_ptr = try l.addOne();
|
const new_item_ptr = try self.addOne();
|
||||||
new_item_ptr.* = item.*;
|
new_item_ptr.* = item.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendSlice(l: *Self, items: []align(A) const T) !void {
|
pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
|
||||||
try l.ensureCapacity(l.len + items.len);
|
try self.ensureCapacity(self.len + items.len);
|
||||||
mem.copy(T, l.items[l.len..], items);
|
mem.copy(T, self.items[self.len..], items);
|
||||||
l.len += items.len;
|
self.len += items.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(l: *Self, new_len: usize) !void {
|
pub fn resize(self: *Self, new_len: usize) !void {
|
||||||
try l.ensureCapacity(new_len);
|
try self.ensureCapacity(new_len);
|
||||||
l.len = new_len;
|
self.len = new_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shrink(l: *Self, new_len: usize) void {
|
pub fn shrink(self: *Self, new_len: usize) void {
|
||||||
assert(new_len <= l.len);
|
assert(new_len <= self.len);
|
||||||
l.len = new_len;
|
self.len = new_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensureCapacity(l: *Self, new_capacity: usize) !void {
|
pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
|
||||||
var better_capacity = l.items.len;
|
var better_capacity = self.items.len;
|
||||||
if (better_capacity >= new_capacity) return;
|
if (better_capacity >= new_capacity) return;
|
||||||
while (true) {
|
while (true) {
|
||||||
better_capacity += better_capacity / 2 + 8;
|
better_capacity += better_capacity / 2 + 8;
|
||||||
if (better_capacity >= new_capacity) break;
|
if (better_capacity >= new_capacity) break;
|
||||||
}
|
}
|
||||||
l.items = try l.allocator.alignedRealloc(T, A, l.items, better_capacity);
|
self.items = try self.allocator.alignedRealloc(T, A, self.items, better_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addOne(l: *Self) !*T {
|
pub fn addOne(self: *Self) !*T {
|
||||||
const new_length = l.len + 1;
|
const new_length = self.len + 1;
|
||||||
try l.ensureCapacity(new_length);
|
try self.ensureCapacity(new_length);
|
||||||
const result = &l.items[l.len];
|
const result = &self.items[self.len];
|
||||||
l.len = new_length;
|
self.len = new_length;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +173,15 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "basic ArrayList test" {
|
test "basic ArrayList test" {
|
||||||
var list = ArrayList(i32).init(debug.global_allocator);
|
var bytes: [1024]u8 = undefined;
|
||||||
|
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
|
||||||
|
|
||||||
|
var list = ArrayList(i32).init(allocator);
|
||||||
defer list.deinit();
|
defer list.deinit();
|
||||||
|
|
||||||
|
// setting on empty list is out of bounds
|
||||||
|
assertError(list.setOrError(0, 1), error.OutOfBounds);
|
||||||
|
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < 10) : (i += 1) {
|
while (i < 10) : (i += 1) {
|
||||||
@ -200,6 +220,16 @@ test "basic ArrayList test" {
|
|||||||
|
|
||||||
list.appendSlice([]const i32{}) catch unreachable;
|
list.appendSlice([]const i32{}) catch unreachable;
|
||||||
assert(list.len == 9);
|
assert(list.len == 9);
|
||||||
|
|
||||||
|
// can only set on indices < self.len
|
||||||
|
list.set(7, 33);
|
||||||
|
list.set(8, 42);
|
||||||
|
|
||||||
|
assertError(list.setOrError(9, 99), error.OutOfBounds);
|
||||||
|
assertError(list.setOrError(10, 123), error.OutOfBounds);
|
||||||
|
|
||||||
|
assert(list.pop() == 42);
|
||||||
|
assert(list.pop() == 33);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "iterator ArrayList test" {
|
test "iterator ArrayList test" {
|
||||||
@ -228,7 +258,7 @@ test "iterator ArrayList test" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it.reset();
|
it.reset();
|
||||||
assert(??it.next() == 1);
|
assert(it.next().? == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "insert ArrayList test" {
|
test "insert ArrayList test" {
|
||||||
|
|||||||
@ -33,8 +33,8 @@ pub fn Queue(comptime T: type) type {
|
|||||||
pub fn get(self: *Self) ?*Node {
|
pub fn get(self: *Self) ?*Node {
|
||||||
var head = @atomicLoad(*Node, &self.head, AtomicOrder.SeqCst);
|
var head = @atomicLoad(*Node, &self.head, AtomicOrder.SeqCst);
|
||||||
while (true) {
|
while (true) {
|
||||||
const node = head.next ?? return null;
|
const node = head.next orelse return null;
|
||||||
head = @cmpxchgWeak(*Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return node;
|
head = @cmpxchgWeak(*Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -94,8 +94,18 @@ test "std.atomic.queue" {
|
|||||||
for (getters) |t|
|
for (getters) |t|
|
||||||
t.wait();
|
t.wait();
|
||||||
|
|
||||||
std.debug.assert(context.put_sum == context.get_sum);
|
if (context.put_sum != context.get_sum) {
|
||||||
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
|
std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.get_count != puts_per_thread * put_thread_count) {
|
||||||
|
std.debug.panic(
|
||||||
|
"failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
|
||||||
|
context.get_count,
|
||||||
|
u32(puts_per_thread),
|
||||||
|
u32(put_thread_count),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn startPuts(ctx: *Context) u8 {
|
fn startPuts(ctx: *Context) u8 {
|
||||||
@ -114,15 +124,14 @@ fn startPuts(ctx: *Context) u8 {
|
|||||||
|
|
||||||
fn startGets(ctx: *Context) u8 {
|
fn startGets(ctx: *Context) u8 {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
|
||||||
|
|
||||||
while (ctx.queue.get()) |node| {
|
while (ctx.queue.get()) |node| {
|
||||||
std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
|
std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
|
||||||
_ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
|
_ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
|
||||||
_ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
|
_ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1) {
|
if (last) return 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,14 +28,14 @@ pub fn Stack(comptime T: type) type {
|
|||||||
var root = @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst);
|
var root = @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst);
|
||||||
while (true) {
|
while (true) {
|
||||||
node.next = root;
|
node.next = root;
|
||||||
root = @cmpxchgWeak(?*Node, &self.root, root, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? break;
|
root = @cmpxchgWeak(?*Node, &self.root, root, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop(self: *Self) ?*Node {
|
pub fn pop(self: *Self) ?*Node {
|
||||||
var root = @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst);
|
var root = @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst);
|
||||||
while (true) {
|
while (true) {
|
||||||
root = @cmpxchgWeak(?*Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root;
|
root = @cmpxchgWeak(?*Node, &self.root, root, (root orelse return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,8 +97,18 @@ test "std.atomic.stack" {
|
|||||||
for (getters) |t|
|
for (getters) |t|
|
||||||
t.wait();
|
t.wait();
|
||||||
|
|
||||||
std.debug.assert(context.put_sum == context.get_sum);
|
if (context.put_sum != context.get_sum) {
|
||||||
std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
|
std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.get_count != puts_per_thread * put_thread_count) {
|
||||||
|
std.debug.panic(
|
||||||
|
"failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
|
||||||
|
context.get_count,
|
||||||
|
u32(puts_per_thread),
|
||||||
|
u32(put_thread_count),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn startPuts(ctx: *Context) u8 {
|
fn startPuts(ctx: *Context) u8 {
|
||||||
@ -117,15 +127,14 @@ fn startPuts(ctx: *Context) u8 {
|
|||||||
|
|
||||||
fn startGets(ctx: *Context) u8 {
|
fn startGets(ctx: *Context) u8 {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
|
||||||
|
|
||||||
while (ctx.stack.pop()) |node| {
|
while (ctx.stack.pop()) |node| {
|
||||||
std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
|
std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
|
||||||
_ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
|
_ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
|
||||||
_ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
|
_ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1) {
|
if (last) return 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pub const BufMap = struct {
|
|||||||
pub fn deinit(self: *const BufMap) void {
|
pub fn deinit(self: *const BufMap) void {
|
||||||
var it = self.hash_map.iterator();
|
var it = self.hash_map.iterator();
|
||||||
while (true) {
|
while (true) {
|
||||||
const entry = it.next() ?? break;
|
const entry = it.next() orelse break;
|
||||||
self.free(entry.key);
|
self.free(entry.key);
|
||||||
self.free(entry.value);
|
self.free(entry.value);
|
||||||
}
|
}
|
||||||
@ -37,12 +37,12 @@ pub const BufMap = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
|
pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
|
||||||
const entry = self.hash_map.get(key) ?? return null;
|
const entry = self.hash_map.get(key) orelse return null;
|
||||||
return entry.value;
|
return entry.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self: *BufMap, key: []const u8) void {
|
pub fn delete(self: *BufMap, key: []const u8) void {
|
||||||
const entry = self.hash_map.remove(key) ?? return;
|
const entry = self.hash_map.remove(key) orelse return;
|
||||||
self.free(entry.key);
|
self.free(entry.key);
|
||||||
self.free(entry.value);
|
self.free(entry.value);
|
||||||
}
|
}
|
||||||
@ -72,15 +72,15 @@ test "BufMap" {
|
|||||||
defer bufmap.deinit();
|
defer bufmap.deinit();
|
||||||
|
|
||||||
try bufmap.set("x", "1");
|
try bufmap.set("x", "1");
|
||||||
assert(mem.eql(u8, ??bufmap.get("x"), "1"));
|
assert(mem.eql(u8, bufmap.get("x").?, "1"));
|
||||||
assert(1 == bufmap.count());
|
assert(1 == bufmap.count());
|
||||||
|
|
||||||
try bufmap.set("x", "2");
|
try bufmap.set("x", "2");
|
||||||
assert(mem.eql(u8, ??bufmap.get("x"), "2"));
|
assert(mem.eql(u8, bufmap.get("x").?, "2"));
|
||||||
assert(1 == bufmap.count());
|
assert(1 == bufmap.count());
|
||||||
|
|
||||||
try bufmap.set("x", "3");
|
try bufmap.set("x", "3");
|
||||||
assert(mem.eql(u8, ??bufmap.get("x"), "3"));
|
assert(mem.eql(u8, bufmap.get("x").?, "3"));
|
||||||
assert(1 == bufmap.count());
|
assert(1 == bufmap.count());
|
||||||
|
|
||||||
bufmap.delete("x");
|
bufmap.delete("x");
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub const BufSet = struct {
|
|||||||
pub fn deinit(self: *const BufSet) void {
|
pub fn deinit(self: *const BufSet) void {
|
||||||
var it = self.hash_map.iterator();
|
var it = self.hash_map.iterator();
|
||||||
while (true) {
|
while (true) {
|
||||||
const entry = it.next() ?? break;
|
const entry = it.next() orelse break;
|
||||||
self.free(entry.key);
|
self.free(entry.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ pub const BufSet = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self: *BufSet, key: []const u8) void {
|
pub fn delete(self: *BufSet, key: []const u8) void {
|
||||||
const entry = self.hash_map.remove(key) ?? return;
|
const entry = self.hash_map.remove(key) orelse return;
|
||||||
self.free(entry.key);
|
self.free(entry.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,6 @@ pub const Buffer = struct {
|
|||||||
/// Must deinitialize with deinit.
|
/// Must deinitialize with deinit.
|
||||||
/// None of the other operations are valid until you do one of these:
|
/// None of the other operations are valid until you do one of these:
|
||||||
/// * ::replaceContents
|
/// * ::replaceContents
|
||||||
/// * ::replaceContentsBuffer
|
|
||||||
/// * ::resize
|
/// * ::resize
|
||||||
pub fn initNull(allocator: *Allocator) Buffer {
|
pub fn initNull(allocator: *Allocator) Buffer {
|
||||||
return Buffer{ .list = ArrayList(u8).init(allocator) };
|
return Buffer{ .list = ArrayList(u8).init(allocator) };
|
||||||
@ -42,9 +41,9 @@ pub const Buffer = struct {
|
|||||||
/// Buffer takes ownership of the passed in slice. The slice must have been
|
/// Buffer takes ownership of the passed in slice. The slice must have been
|
||||||
/// allocated with `allocator`.
|
/// allocated with `allocator`.
|
||||||
/// Must deinitialize with deinit.
|
/// Must deinitialize with deinit.
|
||||||
pub fn fromOwnedSlice(allocator: *Allocator, slice: []u8) Buffer {
|
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);
|
try self.list.append(0);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ pub const Buffer = struct {
|
|||||||
return mem.eql(u8, self.list.items[start..l], m);
|
return mem.eql(u8, self.list.items[start..l], m);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replaceContents(self: *const Buffer, m: []const u8) !void {
|
pub fn replaceContents(self: *Buffer, m: []const u8) !void {
|
||||||
try self.resize(m.len);
|
try self.resize(m.len);
|
||||||
mem.copy(u8, self.list.toSlice(), m);
|
mem.copy(u8, self.list.toSlice(), m);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -136,7 +136,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
|
pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
|
||||||
self.prefix = maybe_prefix ?? "/usr/local"; // TODO better default
|
self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
|
||||||
self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
|
self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable;
|
||||||
self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
|
self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable;
|
||||||
}
|
}
|
||||||
@ -312,9 +312,9 @@ pub const Builder = struct {
|
|||||||
if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
|
if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
|
||||||
var it = mem.split(nix_cflags_compile, " ");
|
var it = mem.split(nix_cflags_compile, " ");
|
||||||
while (true) {
|
while (true) {
|
||||||
const word = it.next() ?? break;
|
const word = it.next() orelse break;
|
||||||
if (mem.eql(u8, word, "-isystem")) {
|
if (mem.eql(u8, word, "-isystem")) {
|
||||||
const include_path = it.next() ?? {
|
const include_path = it.next() orelse {
|
||||||
warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
|
warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
@ -330,9 +330,9 @@ pub const Builder = struct {
|
|||||||
if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
|
if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
|
||||||
var it = mem.split(nix_ldflags, " ");
|
var it = mem.split(nix_ldflags, " ");
|
||||||
while (true) {
|
while (true) {
|
||||||
const word = it.next() ?? break;
|
const word = it.next() orelse break;
|
||||||
if (mem.eql(u8, word, "-rpath")) {
|
if (mem.eql(u8, word, "-rpath")) {
|
||||||
const rpath = it.next() ?? {
|
const rpath = it.next() orelse {
|
||||||
warn("Expected argument after -rpath in NIX_LDFLAGS\n");
|
warn("Expected argument after -rpath in NIX_LDFLAGS\n");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
@ -362,7 +362,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
self.available_options_list.append(available_option) catch unreachable;
|
self.available_options_list.append(available_option) catch unreachable;
|
||||||
|
|
||||||
const entry = self.user_input_options.get(name) ?? return null;
|
const entry = self.user_input_options.get(name) orelse return null;
|
||||||
entry.value.used = true;
|
entry.value.used = true;
|
||||||
switch (type_id) {
|
switch (type_id) {
|
||||||
TypeId.Bool => switch (entry.value.value) {
|
TypeId.Bool => switch (entry.value.value) {
|
||||||
@ -416,9 +416,9 @@ pub const Builder = struct {
|
|||||||
pub fn standardReleaseOptions(self: *Builder) builtin.Mode {
|
pub fn standardReleaseOptions(self: *Builder) builtin.Mode {
|
||||||
if (self.release_mode) |mode| return mode;
|
if (self.release_mode) |mode| return mode;
|
||||||
|
|
||||||
const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
|
const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") orelse false;
|
||||||
const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
|
const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") orelse false;
|
||||||
const release_small = self.option(bool, "release-small", "size optimizations on and safety off") ?? false;
|
const release_small = self.option(bool, "release-small", "size optimizations on and safety off") orelse 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)");
|
warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)");
|
||||||
@ -518,7 +518,7 @@ pub const Builder = struct {
|
|||||||
// make sure all args are used
|
// make sure all args are used
|
||||||
var it = self.user_input_options.iterator();
|
var it = self.user_input_options.iterator();
|
||||||
while (true) {
|
while (true) {
|
||||||
const entry = it.next() ?? break;
|
const entry = it.next() orelse break;
|
||||||
if (!entry.value.used) {
|
if (!entry.value.used) {
|
||||||
warn("Invalid option: -D{}\n\n", entry.key);
|
warn("Invalid option: -D{}\n\n", entry.key);
|
||||||
self.markInvalidUserInput();
|
self.markInvalidUserInput();
|
||||||
@ -617,7 +617,7 @@ pub const Builder = struct {
|
|||||||
warn("cp {} {}\n", source_path, dest_path);
|
warn("cp {} {}\n", source_path, dest_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirname = os.path.dirname(dest_path);
|
const dirname = os.path.dirname(dest_path) orelse ".";
|
||||||
const abs_source_path = self.pathFromRoot(source_path);
|
const abs_source_path = self.pathFromRoot(source_path);
|
||||||
os.makePath(self.allocator, dirname) catch |err| {
|
os.makePath(self.allocator, dirname) catch |err| {
|
||||||
warn("Unable to create path {}: {}\n", dirname, @errorName(err));
|
warn("Unable to create path {}: {}\n", dirname, @errorName(err));
|
||||||
@ -1246,7 +1246,7 @@ pub const LibExeObjStep = struct {
|
|||||||
{
|
{
|
||||||
var it = self.link_libs.iterator();
|
var it = self.link_libs.iterator();
|
||||||
while (true) {
|
while (true) {
|
||||||
const entry = it.next() ?? break;
|
const entry = it.next() orelse break;
|
||||||
zig_args.append("--library") catch unreachable;
|
zig_args.append("--library") catch unreachable;
|
||||||
zig_args.append(entry.key) catch unreachable;
|
zig_args.append(entry.key) catch unreachable;
|
||||||
}
|
}
|
||||||
@ -1395,8 +1395,9 @@ pub const LibExeObjStep = struct {
|
|||||||
cc_args.append(abs_source_file) catch unreachable;
|
cc_args.append(abs_source_file) catch unreachable;
|
||||||
|
|
||||||
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
||||||
const cache_o_dir = os.path.dirname(cache_o_src);
|
if (os.path.dirname(cache_o_src)) |cache_o_dir| {
|
||||||
try builder.makePath(cache_o_dir);
|
try builder.makePath(cache_o_dir);
|
||||||
|
}
|
||||||
const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
|
const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
|
||||||
cc_args.append("-o") catch unreachable;
|
cc_args.append("-o") catch unreachable;
|
||||||
cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
|
cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
|
||||||
@ -1509,8 +1510,9 @@ pub const LibExeObjStep = struct {
|
|||||||
cc_args.append(abs_source_file) catch unreachable;
|
cc_args.append(abs_source_file) catch unreachable;
|
||||||
|
|
||||||
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
|
||||||
const cache_o_dir = os.path.dirname(cache_o_src);
|
if (os.path.dirname(cache_o_src)) |cache_o_dir| {
|
||||||
try builder.makePath(cache_o_dir);
|
try builder.makePath(cache_o_dir);
|
||||||
|
}
|
||||||
const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
|
const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
|
||||||
cc_args.append("-o") catch unreachable;
|
cc_args.append("-o") catch unreachable;
|
||||||
cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
|
cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
|
||||||
@ -1696,7 +1698,7 @@ pub const TestStep = struct {
|
|||||||
{
|
{
|
||||||
var it = self.link_libs.iterator();
|
var it = self.link_libs.iterator();
|
||||||
while (true) {
|
while (true) {
|
||||||
const entry = it.next() ?? break;
|
const entry = it.next() orelse break;
|
||||||
try zig_args.append("--library");
|
try zig_args.append("--library");
|
||||||
try zig_args.append(entry.key);
|
try zig_args.append(entry.key);
|
||||||
}
|
}
|
||||||
@ -1855,7 +1857,7 @@ pub const WriteFileStep = struct {
|
|||||||
fn make(step: *Step) !void {
|
fn make(step: *Step) !void {
|
||||||
const self = @fieldParentPtr(WriteFileStep, "step", step);
|
const self = @fieldParentPtr(WriteFileStep, "step", step);
|
||||||
const full_path = self.builder.pathFromRoot(self.file_path);
|
const full_path = self.builder.pathFromRoot(self.file_path);
|
||||||
const full_path_dir = os.path.dirname(full_path);
|
const full_path_dir = os.path.dirname(full_path) orelse ".";
|
||||||
os.makePath(self.builder.allocator, full_path_dir) catch |err| {
|
os.makePath(self.builder.allocator, full_path_dir) catch |err| {
|
||||||
warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
|
warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
|
||||||
return err;
|
return err;
|
||||||
@ -1945,7 +1947,7 @@ pub const Step = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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_dir = os.path.dirname(output_path) orelse ".";
|
||||||
const out_basename = os.path.basename(output_path);
|
const out_basename = os.path.basename(output_path);
|
||||||
// sym link for libfoo.so.1 to libfoo.so.1.2.3
|
// sym link for libfoo.so.1 to libfoo.so.1.2.3
|
||||||
const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
|
const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
|
||||||
|
|||||||
@ -20,11 +20,11 @@ pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
|
|||||||
pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
|
pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
|
||||||
pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
|
pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
|
||||||
pub extern "c" fn raise(sig: c_int) c_int;
|
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 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 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 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 munmap(addr: *c_void, len: usize) c_int;
|
||||||
pub extern "c" fn unlink(path: [*]const u8) c_int;
|
pub extern "c" fn unlink(path: [*]const u8) c_int;
|
||||||
pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
|
pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
|
||||||
pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
|
pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
|
||||||
@ -48,15 +48,15 @@ pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
|
|||||||
pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
|
pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
|
||||||
pub extern "c" fn rmdir(path: [*]const u8) c_int;
|
pub extern "c" fn rmdir(path: [*]const u8) c_int;
|
||||||
|
|
||||||
pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?[*]c_void;
|
pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
|
||||||
pub extern "c" fn malloc(usize) ?[*]c_void;
|
pub extern "c" fn malloc(usize) ?*c_void;
|
||||||
pub extern "c" fn realloc([*]c_void, usize) ?[*]c_void;
|
pub extern "c" fn realloc(*c_void, usize) ?*c_void;
|
||||||
pub extern "c" fn free([*]c_void) 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 "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_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_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;
|
pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
|
||||||
pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
|
pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
|
||||||
|
|
||||||
|
|||||||
@ -88,6 +88,16 @@ pub fn assert(ok: bool) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: add `==` operator for `error_union == error_set`, and then
|
||||||
|
/// remove this function
|
||||||
|
pub fn assertError(value: var, expected_error: error) void {
|
||||||
|
if (value) {
|
||||||
|
@panic("expected error");
|
||||||
|
} else |actual_error| {
|
||||||
|
assert(actual_error == expected_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Call this function when you want to panic if the condition is not true.
|
/// Call this function when you want to panic if the condition is not true.
|
||||||
/// If `ok` is `false`, this function will panic in every release mode.
|
/// If `ok` is `false`, this function will panic in every release mode.
|
||||||
pub fn assertOrPanic(ok: bool) void {
|
pub fn assertOrPanic(ok: bool) void {
|
||||||
@ -198,7 +208,7 @@ fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: us
|
|||||||
.name = "???",
|
.name = "???",
|
||||||
.address = address,
|
.address = address,
|
||||||
};
|
};
|
||||||
const symbol = debug_info.symbol_table.search(address) ?? &unknown;
|
const symbol = debug_info.symbol_table.search(address) orelse &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 => {
|
else => {
|
||||||
@ -258,10 +268,10 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
|
|||||||
try st.elf.openFile(allocator, &st.self_exe_file);
|
try st.elf.openFile(allocator, &st.self_exe_file);
|
||||||
errdefer st.elf.close();
|
errdefer st.elf.close();
|
||||||
|
|
||||||
st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
|
st.debug_info = (try st.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
|
||||||
st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
|
st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo;
|
||||||
st.debug_str = (try st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
|
st.debug_str = (try st.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo;
|
||||||
st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
|
st.debug_line = (try st.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo;
|
||||||
st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
|
st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
|
||||||
try scanAllCompileUnits(st);
|
try scanAllCompileUnits(st);
|
||||||
return st;
|
return st;
|
||||||
@ -433,7 +443,7 @@ const Die = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getAttrAddr(self: *const Die, id: u64) !u64 {
|
fn getAttrAddr(self: *const Die, id: u64) !u64 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||||
return switch (form_value.*) {
|
return switch (form_value.*) {
|
||||||
FormValue.Address => |value| value,
|
FormValue.Address => |value| value,
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
@ -441,7 +451,7 @@ const Die = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
|
fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||||
return switch (form_value.*) {
|
return switch (form_value.*) {
|
||||||
FormValue.Const => |value| value.asUnsignedLe(),
|
FormValue.Const => |value| value.asUnsignedLe(),
|
||||||
FormValue.SecOffset => |value| value,
|
FormValue.SecOffset => |value| value,
|
||||||
@ -450,7 +460,7 @@ const Die = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
|
fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||||
return switch (form_value.*) {
|
return switch (form_value.*) {
|
||||||
FormValue.Const => |value| value.asUnsignedLe(),
|
FormValue.Const => |value| value.asUnsignedLe(),
|
||||||
else => error.InvalidDebugInfo,
|
else => error.InvalidDebugInfo,
|
||||||
@ -458,7 +468,7 @@ const Die = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getAttrString(self: *const Die, st: *ElfStackTrace, id: u64) ![]u8 {
|
fn getAttrString(self: *const Die, st: *ElfStackTrace, id: u64) ![]u8 {
|
||||||
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
|
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||||
return switch (form_value.*) {
|
return switch (form_value.*) {
|
||||||
FormValue.String => |value| value,
|
FormValue.String => |value| value,
|
||||||
FormValue.StrPtr => |offset| getString(st, offset),
|
FormValue.StrPtr => |offset| getString(st, offset),
|
||||||
@ -738,7 +748,7 @@ fn parseDie(st: *ElfStackTrace, abbrev_table: *const AbbrevTable, is_64: bool) !
|
|||||||
var in_file_stream = io.FileInStream.init(in_file);
|
var in_file_stream = io.FileInStream.init(in_file);
|
||||||
const in_stream = &in_file_stream.stream;
|
const in_stream = &in_file_stream.stream;
|
||||||
const abbrev_code = try readULeb128(in_stream);
|
const abbrev_code = try readULeb128(in_stream);
|
||||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
|
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
|
||||||
|
|
||||||
var result = Die{
|
var result = Die{
|
||||||
.tag_id = table_entry.tag_id,
|
.tag_id = table_entry.tag_id,
|
||||||
|
|||||||
@ -40,9 +40,9 @@ pub const TcpServer = struct {
|
|||||||
self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
|
self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
|
||||||
|
|
||||||
self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self);
|
self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self);
|
||||||
errdefer cancel ??self.accept_coro;
|
errdefer cancel self.accept_coro.?;
|
||||||
|
|
||||||
try self.loop.addFd(self.sockfd, ??self.accept_coro);
|
try self.loop.addFd(self.sockfd, self.accept_coro.?);
|
||||||
errdefer self.loop.removeFd(self.sockfd);
|
errdefer self.loop.removeFd(self.sockfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,11 @@ pub fn formatType(
|
|||||||
output: fn (@typeOf(context), []const u8) Errors!void,
|
output: fn (@typeOf(context), []const u8) Errors!void,
|
||||||
) Errors!void {
|
) Errors!void {
|
||||||
const T = @typeOf(value);
|
const T = @typeOf(value);
|
||||||
switch (@typeId(T)) {
|
if (T == error) {
|
||||||
|
try output(context, "error.");
|
||||||
|
return output(context, @errorName(value));
|
||||||
|
}
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
builtin.TypeId.Int, builtin.TypeId.Float => {
|
builtin.TypeId.Int, builtin.TypeId.Float => {
|
||||||
return formatValue(value, fmt, context, Errors, output);
|
return formatValue(value, fmt, context, Errors, output);
|
||||||
},
|
},
|
||||||
@ -107,7 +111,7 @@ pub fn formatType(
|
|||||||
builtin.TypeId.Bool => {
|
builtin.TypeId.Bool => {
|
||||||
return output(context, if (value) "true" else "false");
|
return output(context, if (value) "true" else "false");
|
||||||
},
|
},
|
||||||
builtin.TypeId.Nullable => {
|
builtin.TypeId.Optional => {
|
||||||
if (value) |payload| {
|
if (value) |payload| {
|
||||||
return formatType(payload, fmt, context, Errors, output);
|
return formatType(payload, fmt, context, Errors, output);
|
||||||
} else {
|
} else {
|
||||||
@ -125,12 +129,13 @@ pub fn formatType(
|
|||||||
try output(context, "error.");
|
try output(context, "error.");
|
||||||
return output(context, @errorName(value));
|
return output(context, @errorName(value));
|
||||||
},
|
},
|
||||||
builtin.TypeId.Pointer => {
|
builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||||
switch (@typeId(T.Child)) {
|
builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
|
||||||
builtin.TypeId.Array => {
|
builtin.TypeId.Array => |info| {
|
||||||
if (T.Child.Child == u8) {
|
if (info.child == u8) {
|
||||||
return formatText(value, fmt, context, Errors, output);
|
return formatText(value, fmt, context, Errors, output);
|
||||||
}
|
}
|
||||||
|
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||||
},
|
},
|
||||||
builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
|
builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
|
||||||
const has_cust_fmt = comptime cf: {
|
const has_cust_fmt = comptime cf: {
|
||||||
@ -154,14 +159,24 @@ pub fn formatType(
|
|||||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||||
},
|
},
|
||||||
else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
|
else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
|
||||||
}
|
},
|
||||||
},
|
builtin.TypeInfo.Pointer.Size.Many => {
|
||||||
else => if (@canImplicitCast([]const u8, value)) {
|
if (ptr_info.child == u8) {
|
||||||
const casted_value = ([]const u8)(value);
|
//This is a bit of a hack, but it made more sense to
|
||||||
return output(context, casted_value);
|
// do this check here than have formatText do it
|
||||||
} else {
|
if (fmt[0] == 's') {
|
||||||
@compileError("Unable to format type '" ++ @typeName(T) ++ "'");
|
const len = std.cstr.len(value);
|
||||||
|
return formatText(value[0..len], fmt, context, Errors, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||||
|
},
|
||||||
|
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||||
|
const casted_value = ([]const u8)(value);
|
||||||
|
return output(context, casted_value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +308,7 @@ pub fn formatBuf(
|
|||||||
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
|
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
|
||||||
const pad_byte: u8 = ' ';
|
const pad_byte: u8 = ' ';
|
||||||
while (leftover_padding > 0) : (leftover_padding -= 1) {
|
while (leftover_padding > 0) : (leftover_padding -= 1) {
|
||||||
try output(context, (&pad_byte)[0..1]);
|
try output(context, (*[1]u8)(&pad_byte)[0..1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,14 +567,19 @@ pub fn formatBytes(
|
|||||||
return output(context, "0B");
|
return output(context, "0B");
|
||||||
}
|
}
|
||||||
|
|
||||||
const mags = " KMGTPEZY";
|
const mags_si = " kMGTPEZY";
|
||||||
|
const mags_iec = " KMGTPEZY";
|
||||||
const magnitude = switch (radix) {
|
const magnitude = switch (radix) {
|
||||||
1000 => math.min(math.log2(value) / comptime math.log2(1000), mags.len - 1),
|
1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
|
||||||
1024 => math.min(math.log2(value) / 10, mags.len - 1),
|
1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
|
const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
|
||||||
const suffix = mags[magnitude];
|
const suffix = switch (radix) {
|
||||||
|
1000 => mags_si[magnitude],
|
||||||
|
1024 => mags_iec[magnitude],
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
try formatFloatDecimal(new_value, width, context, Errors, output);
|
try formatFloatDecimal(new_value, width, context, Errors, output);
|
||||||
|
|
||||||
@ -807,11 +827,11 @@ test "parse unsigned comptime" {
|
|||||||
test "fmt.format" {
|
test "fmt.format" {
|
||||||
{
|
{
|
||||||
const value: ?i32 = 1234;
|
const value: ?i32 = 1234;
|
||||||
try testFmt("nullable: 1234\n", "nullable: {}\n", value);
|
try testFmt("optional: 1234\n", "optional: {}\n", value);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const value: ?i32 = null;
|
const value: ?i32 = null;
|
||||||
try testFmt("nullable: null\n", "nullable: {}\n", value);
|
try testFmt("optional: null\n", "optional: {}\n", value);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const value: error!i32 = 1234;
|
const value: error!i32 = 1234;
|
||||||
@ -829,6 +849,10 @@ test "fmt.format" {
|
|||||||
const value: u8 = 'a';
|
const value: u8 = 'a';
|
||||||
try testFmt("u8: a\n", "u8: {c}\n", value);
|
try testFmt("u8: a\n", "u8: {c}\n", value);
|
||||||
}
|
}
|
||||||
|
try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
|
||||||
|
try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
|
||||||
|
try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
|
||||||
|
try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
|
||||||
try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
|
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));
|
try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
|
||||||
{
|
{
|
||||||
|
|||||||
@ -265,11 +265,11 @@ test "basic hash map usage" {
|
|||||||
assert((map.put(4, 44) catch unreachable) == null);
|
assert((map.put(4, 44) catch unreachable) == null);
|
||||||
assert((map.put(5, 55) catch unreachable) == null);
|
assert((map.put(5, 55) catch unreachable) == null);
|
||||||
|
|
||||||
assert(??(map.put(5, 66) catch unreachable) == 55);
|
assert((map.put(5, 66) catch unreachable).? == 55);
|
||||||
assert(??(map.put(5, 55) catch unreachable) == 66);
|
assert((map.put(5, 55) catch unreachable).? == 66);
|
||||||
|
|
||||||
assert(map.contains(2));
|
assert(map.contains(2));
|
||||||
assert((??map.get(2)).value == 22);
|
assert(map.get(2).?.value == 22);
|
||||||
_ = map.remove(2);
|
_ = map.remove(2);
|
||||||
assert(map.remove(2) == null);
|
assert(map.remove(2) == null);
|
||||||
assert(map.get(2) == null);
|
assert(map.get(2) == null);
|
||||||
@ -317,7 +317,7 @@ test "iterator hash map" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it.reset();
|
it.reset();
|
||||||
var entry = ??it.next();
|
var entry = it.next().?;
|
||||||
assert(entry.key == keys[0]);
|
assert(entry.key == keys[0]);
|
||||||
assert(entry.value == values[0]);
|
assert(entry.value == values[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
20
std/heap.zig
20
std/heap.zig
@ -22,7 +22,7 @@ fn cAlloc(self: *Allocator, n: usize, alignment: u29) ![]u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
|
fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
|
||||||
const old_ptr = @ptrCast([*]c_void, old_mem.ptr);
|
const old_ptr = @ptrCast(*c_void, old_mem.ptr);
|
||||||
if (c.realloc(old_ptr, new_size)) |buf| {
|
if (c.realloc(old_ptr, new_size)) |buf| {
|
||||||
return @ptrCast([*]u8, buf)[0..new_size];
|
return @ptrCast([*]u8, buf)[0..new_size];
|
||||||
} else if (new_size <= old_mem.len) {
|
} else if (new_size <= old_mem.len) {
|
||||||
@ -33,7 +33,7 @@ fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cFree(self: *Allocator, old_mem: []u8) void {
|
fn cFree(self: *Allocator, old_mem: []u8) void {
|
||||||
const old_ptr = @ptrCast([*]c_void, old_mem.ptr);
|
const old_ptr = @ptrCast(*c_void, old_mem.ptr);
|
||||||
c.free(old_ptr);
|
c.free(old_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,12 +97,12 @@ pub const DirectAllocator = struct {
|
|||||||
},
|
},
|
||||||
Os.windows => {
|
Os.windows => {
|
||||||
const amt = n + alignment + @sizeOf(usize);
|
const amt = n + alignment + @sizeOf(usize);
|
||||||
const heap_handle = self.heap_handle ?? blk: {
|
const heap_handle = self.heap_handle orelse 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) orelse return error.OutOfMemory;
|
||||||
self.heap_handle = hh;
|
self.heap_handle = hh;
|
||||||
break :blk hh;
|
break :blk hh;
|
||||||
};
|
};
|
||||||
const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) ?? return error.OutOfMemory;
|
const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
|
||||||
const root_addr = @ptrToInt(ptr);
|
const root_addr = @ptrToInt(ptr);
|
||||||
const rem = @rem(root_addr, alignment);
|
const rem = @rem(root_addr, alignment);
|
||||||
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
|
||||||
@ -140,9 +140,9 @@ pub const DirectAllocator = struct {
|
|||||||
const old_adjusted_addr = @ptrToInt(old_mem.ptr);
|
const old_adjusted_addr = @ptrToInt(old_mem.ptr);
|
||||||
const old_record_addr = old_adjusted_addr + old_mem.len;
|
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([*]c_void, root_addr);
|
const old_ptr = @intToPtr(*c_void, root_addr);
|
||||||
const amt = new_size + alignment + @sizeOf(usize);
|
const amt = new_size + alignment + @sizeOf(usize);
|
||||||
const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
|
const new_ptr = os.windows.HeapReAlloc(self.heap_handle.?, 0, old_ptr, amt) orelse blk: {
|
||||||
if (new_size > old_mem.len) return error.OutOfMemory;
|
if (new_size > old_mem.len) return error.OutOfMemory;
|
||||||
const new_record_addr = old_record_addr - new_size + old_mem.len;
|
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;
|
||||||
@ -170,8 +170,8 @@ pub const DirectAllocator = struct {
|
|||||||
Os.windows => {
|
Os.windows => {
|
||||||
const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
|
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([*]c_void, root_addr);
|
const ptr = @intToPtr(*c_void, root_addr);
|
||||||
_ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
|
_ = os.windows.HeapFree(self.heap_handle.?, 0, ptr);
|
||||||
},
|
},
|
||||||
else => @compileError("Unsupported OS"),
|
else => @compileError("Unsupported OS"),
|
||||||
}
|
}
|
||||||
@ -343,7 +343,7 @@ pub const ThreadSafeFixedBufferAllocator = struct {
|
|||||||
if (new_end_index > self.buffer.len) {
|
if (new_end_index > self.buffer.len) {
|
||||||
return error.OutOfMemory;
|
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) orelse return self.buffer[adjusted_index..new_end_index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
265
std/json.zig
265
std/json.zig
@ -3,6 +3,7 @@
|
|||||||
// https://tools.ietf.org/html/rfc8259
|
// https://tools.ietf.org/html/rfc8259
|
||||||
|
|
||||||
const std = @import("index.zig");
|
const std = @import("index.zig");
|
||||||
|
const debug = std.debug;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
const u1 = @IntType(false, 1);
|
const u1 = @IntType(false, 1);
|
||||||
@ -86,7 +87,9 @@ pub const Token = struct {
|
|||||||
// parsing state requires ~40-50 bytes of stack space.
|
// parsing state requires ~40-50 bytes of stack space.
|
||||||
//
|
//
|
||||||
// Conforms strictly to RFC8529.
|
// Conforms strictly to RFC8529.
|
||||||
pub const StreamingJsonParser = struct {
|
//
|
||||||
|
// For a non-byte based wrapper, consider using TokenStream instead.
|
||||||
|
pub const StreamingParser = struct {
|
||||||
// Current state
|
// Current state
|
||||||
state: State,
|
state: State,
|
||||||
// How many bytes we have counted for the current token
|
// How many bytes we have counted for the current token
|
||||||
@ -109,13 +112,13 @@ pub const StreamingJsonParser = struct {
|
|||||||
const array_bit = 1;
|
const array_bit = 1;
|
||||||
const max_stack_size = @maxValue(u8);
|
const max_stack_size = @maxValue(u8);
|
||||||
|
|
||||||
pub fn init() StreamingJsonParser {
|
pub fn init() StreamingParser {
|
||||||
var p: StreamingJsonParser = undefined;
|
var p: StreamingParser = undefined;
|
||||||
p.reset();
|
p.reset();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(p: *StreamingJsonParser) void {
|
pub fn reset(p: *StreamingParser) void {
|
||||||
p.state = State.TopLevelBegin;
|
p.state = State.TopLevelBegin;
|
||||||
p.count = 0;
|
p.count = 0;
|
||||||
// Set before ever read in main transition function
|
// Set before ever read in main transition function
|
||||||
@ -175,7 +178,7 @@ pub const StreamingJsonParser = struct {
|
|||||||
|
|
||||||
// Only call this function to generate array/object final state.
|
// Only call this function to generate array/object final state.
|
||||||
pub fn fromInt(x: var) State {
|
pub fn fromInt(x: var) State {
|
||||||
std.debug.assert(x == 0 or x == 1);
|
debug.assert(x == 0 or x == 1);
|
||||||
const T = @TagType(State);
|
const T = @TagType(State);
|
||||||
return State(T(x));
|
return State(T(x));
|
||||||
}
|
}
|
||||||
@ -205,7 +208,7 @@ pub const StreamingJsonParser = struct {
|
|||||||
// tokens. token2 is always null if token1 is null.
|
// tokens. token2 is always null if token1 is null.
|
||||||
//
|
//
|
||||||
// There is currently no error recovery on a bad stream.
|
// There is currently no error recovery on a bad stream.
|
||||||
pub fn feed(p: *StreamingJsonParser, c: u8, token1: *?Token, token2: *?Token) Error!void {
|
pub fn feed(p: *StreamingParser, c: u8, token1: *?Token, token2: *?Token) Error!void {
|
||||||
token1.* = null;
|
token1.* = null;
|
||||||
token2.* = null;
|
token2.* = null;
|
||||||
p.count += 1;
|
p.count += 1;
|
||||||
@ -217,7 +220,7 @@ pub const StreamingJsonParser = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform a single transition on the state machine and return any possible token.
|
// Perform a single transition on the state machine and return any possible token.
|
||||||
fn transition(p: *StreamingJsonParser, c: u8, token: *?Token) Error!bool {
|
fn transition(p: *StreamingParser, c: u8, token: *?Token) Error!bool {
|
||||||
switch (p.state) {
|
switch (p.state) {
|
||||||
State.TopLevelBegin => switch (c) {
|
State.TopLevelBegin => switch (c) {
|
||||||
'{' => {
|
'{' => {
|
||||||
@ -321,7 +324,9 @@ pub const StreamingJsonParser = struct {
|
|||||||
p.complete = true;
|
p.complete = true;
|
||||||
p.state = State.TopLevelEnd;
|
p.state = State.TopLevelEnd;
|
||||||
},
|
},
|
||||||
else => {},
|
else => {
|
||||||
|
p.state = State.ValueEnd;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
token.* = Token.initMarker(Token.Id.ObjectEnd);
|
token.* = Token.initMarker(Token.Id.ObjectEnd);
|
||||||
@ -345,7 +350,9 @@ pub const StreamingJsonParser = struct {
|
|||||||
p.complete = true;
|
p.complete = true;
|
||||||
p.state = State.TopLevelEnd;
|
p.state = State.TopLevelEnd;
|
||||||
},
|
},
|
||||||
else => {},
|
else => {
|
||||||
|
p.state = State.ValueEnd;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
token.* = Token.initMarker(Token.Id.ArrayEnd);
|
token.* = Token.initMarker(Token.Id.ArrayEnd);
|
||||||
@ -852,16 +859,122 @@ pub const StreamingJsonParser = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A small wrapper over a StreamingParser for full slices. Returns a stream of json Tokens.
|
||||||
|
pub const TokenStream = struct {
|
||||||
|
i: usize,
|
||||||
|
slice: []const u8,
|
||||||
|
parser: StreamingParser,
|
||||||
|
token: ?Token,
|
||||||
|
|
||||||
|
pub fn init(slice: []const u8) TokenStream {
|
||||||
|
return TokenStream{
|
||||||
|
.i = 0,
|
||||||
|
.slice = slice,
|
||||||
|
.parser = StreamingParser.init(),
|
||||||
|
.token = null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: *TokenStream) !?Token {
|
||||||
|
if (self.token) |token| {
|
||||||
|
self.token = null;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
var t1: ?Token = undefined;
|
||||||
|
var t2: ?Token = undefined;
|
||||||
|
|
||||||
|
while (self.i < self.slice.len) {
|
||||||
|
try self.parser.feed(self.slice[self.i], &t1, &t2);
|
||||||
|
self.i += 1;
|
||||||
|
|
||||||
|
if (t1) |token| {
|
||||||
|
self.token = t2;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.i > self.slice.len) {
|
||||||
|
try self.parser.feed(' ', &t1, &t2);
|
||||||
|
self.i += 1;
|
||||||
|
|
||||||
|
if (t1) |token| {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn checkNext(p: *TokenStream, id: Token.Id) void {
|
||||||
|
const token = (p.next() catch unreachable).?;
|
||||||
|
debug.assert(token.id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "token" {
|
||||||
|
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]
|
||||||
|
\\ }
|
||||||
|
\\}
|
||||||
|
;
|
||||||
|
|
||||||
|
var p = TokenStream.init(s);
|
||||||
|
|
||||||
|
checkNext(&p, Token.Id.ObjectBegin);
|
||||||
|
checkNext(&p, Token.Id.String); // Image
|
||||||
|
checkNext(&p, Token.Id.ObjectBegin);
|
||||||
|
checkNext(&p, Token.Id.String); // Width
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.String); // Height
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.String); // Title
|
||||||
|
checkNext(&p, Token.Id.String);
|
||||||
|
checkNext(&p, Token.Id.String); // Thumbnail
|
||||||
|
checkNext(&p, Token.Id.ObjectBegin);
|
||||||
|
checkNext(&p, Token.Id.String); // Url
|
||||||
|
checkNext(&p, Token.Id.String);
|
||||||
|
checkNext(&p, Token.Id.String); // Height
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.String); // Width
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.ObjectEnd);
|
||||||
|
checkNext(&p, Token.Id.String); // Animated
|
||||||
|
checkNext(&p, Token.Id.False);
|
||||||
|
checkNext(&p, Token.Id.String); // IDs
|
||||||
|
checkNext(&p, Token.Id.ArrayBegin);
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.Number);
|
||||||
|
checkNext(&p, Token.Id.ArrayEnd);
|
||||||
|
checkNext(&p, Token.Id.ObjectEnd);
|
||||||
|
checkNext(&p, Token.Id.ObjectEnd);
|
||||||
|
|
||||||
|
debug.assert((try p.next()) == null);
|
||||||
|
}
|
||||||
|
|
||||||
// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
|
// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
|
||||||
// be able to decode the string even if this returns true.
|
// be able to decode the string even if this returns true.
|
||||||
pub fn validate(s: []const u8) bool {
|
pub fn validate(s: []const u8) bool {
|
||||||
var p = StreamingJsonParser.init();
|
var p = StreamingParser.init();
|
||||||
|
|
||||||
for (s) |c, i| {
|
for (s) |c, i| {
|
||||||
var token1: ?Token = undefined;
|
var token1: ?Token = undefined;
|
||||||
var token2: ?Token = undefined;
|
var token2: ?Token = undefined;
|
||||||
|
|
||||||
p.feed(c, *token1, *token2) catch |err| {
|
p.feed(c, &token1, &token2) catch |err| {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -869,6 +982,10 @@ pub fn validate(s: []const u8) bool {
|
|||||||
return p.complete;
|
return p.complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "json validate" {
|
||||||
|
debug.assert(validate("{}"));
|
||||||
|
}
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
@ -897,46 +1014,46 @@ pub const Value = union(enum) {
|
|||||||
pub fn dump(self: *const Value) void {
|
pub fn dump(self: *const Value) void {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
Value.Null => {
|
Value.Null => {
|
||||||
std.debug.warn("null");
|
debug.warn("null");
|
||||||
},
|
},
|
||||||
Value.Bool => |inner| {
|
Value.Bool => |inner| {
|
||||||
std.debug.warn("{}", inner);
|
debug.warn("{}", inner);
|
||||||
},
|
},
|
||||||
Value.Integer => |inner| {
|
Value.Integer => |inner| {
|
||||||
std.debug.warn("{}", inner);
|
debug.warn("{}", inner);
|
||||||
},
|
},
|
||||||
Value.Float => |inner| {
|
Value.Float => |inner| {
|
||||||
std.debug.warn("{.5}", inner);
|
debug.warn("{.5}", inner);
|
||||||
},
|
},
|
||||||
Value.String => |inner| {
|
Value.String => |inner| {
|
||||||
std.debug.warn("\"{}\"", inner);
|
debug.warn("\"{}\"", inner);
|
||||||
},
|
},
|
||||||
Value.Array => |inner| {
|
Value.Array => |inner| {
|
||||||
var not_first = false;
|
var not_first = false;
|
||||||
std.debug.warn("[");
|
debug.warn("[");
|
||||||
for (inner.toSliceConst()) |value| {
|
for (inner.toSliceConst()) |value| {
|
||||||
if (not_first) {
|
if (not_first) {
|
||||||
std.debug.warn(",");
|
debug.warn(",");
|
||||||
}
|
}
|
||||||
not_first = true;
|
not_first = true;
|
||||||
value.dump();
|
value.dump();
|
||||||
}
|
}
|
||||||
std.debug.warn("]");
|
debug.warn("]");
|
||||||
},
|
},
|
||||||
Value.Object => |inner| {
|
Value.Object => |inner| {
|
||||||
var not_first = false;
|
var not_first = false;
|
||||||
std.debug.warn("{{");
|
debug.warn("{{");
|
||||||
var it = inner.iterator();
|
var it = inner.iterator();
|
||||||
|
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
if (not_first) {
|
if (not_first) {
|
||||||
std.debug.warn(",");
|
debug.warn(",");
|
||||||
}
|
}
|
||||||
not_first = true;
|
not_first = true;
|
||||||
std.debug.warn("\"{}\":", entry.key);
|
debug.warn("\"{}\":", entry.key);
|
||||||
entry.value.dump();
|
entry.value.dump();
|
||||||
}
|
}
|
||||||
std.debug.warn("}}");
|
debug.warn("}}");
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -952,53 +1069,53 @@ pub const Value = union(enum) {
|
|||||||
fn dumpIndentLevel(self: *const Value, indent: usize, level: usize) void {
|
fn dumpIndentLevel(self: *const Value, indent: usize, level: usize) void {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
Value.Null => {
|
Value.Null => {
|
||||||
std.debug.warn("null");
|
debug.warn("null");
|
||||||
},
|
},
|
||||||
Value.Bool => |inner| {
|
Value.Bool => |inner| {
|
||||||
std.debug.warn("{}", inner);
|
debug.warn("{}", inner);
|
||||||
},
|
},
|
||||||
Value.Integer => |inner| {
|
Value.Integer => |inner| {
|
||||||
std.debug.warn("{}", inner);
|
debug.warn("{}", inner);
|
||||||
},
|
},
|
||||||
Value.Float => |inner| {
|
Value.Float => |inner| {
|
||||||
std.debug.warn("{.5}", inner);
|
debug.warn("{.5}", inner);
|
||||||
},
|
},
|
||||||
Value.String => |inner| {
|
Value.String => |inner| {
|
||||||
std.debug.warn("\"{}\"", inner);
|
debug.warn("\"{}\"", inner);
|
||||||
},
|
},
|
||||||
Value.Array => |inner| {
|
Value.Array => |inner| {
|
||||||
var not_first = false;
|
var not_first = false;
|
||||||
std.debug.warn("[\n");
|
debug.warn("[\n");
|
||||||
|
|
||||||
for (inner.toSliceConst()) |value| {
|
for (inner.toSliceConst()) |value| {
|
||||||
if (not_first) {
|
if (not_first) {
|
||||||
std.debug.warn(",\n");
|
debug.warn(",\n");
|
||||||
}
|
}
|
||||||
not_first = true;
|
not_first = true;
|
||||||
padSpace(level + indent);
|
padSpace(level + indent);
|
||||||
value.dumpIndentLevel(indent, level + indent);
|
value.dumpIndentLevel(indent, level + indent);
|
||||||
}
|
}
|
||||||
std.debug.warn("\n");
|
debug.warn("\n");
|
||||||
padSpace(level);
|
padSpace(level);
|
||||||
std.debug.warn("]");
|
debug.warn("]");
|
||||||
},
|
},
|
||||||
Value.Object => |inner| {
|
Value.Object => |inner| {
|
||||||
var not_first = false;
|
var not_first = false;
|
||||||
std.debug.warn("{{\n");
|
debug.warn("{{\n");
|
||||||
var it = inner.iterator();
|
var it = inner.iterator();
|
||||||
|
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
if (not_first) {
|
if (not_first) {
|
||||||
std.debug.warn(",\n");
|
debug.warn(",\n");
|
||||||
}
|
}
|
||||||
not_first = true;
|
not_first = true;
|
||||||
padSpace(level + indent);
|
padSpace(level + indent);
|
||||||
std.debug.warn("\"{}\": ", entry.key);
|
debug.warn("\"{}\": ", entry.key);
|
||||||
entry.value.dumpIndentLevel(indent, level + indent);
|
entry.value.dumpIndentLevel(indent, level + indent);
|
||||||
}
|
}
|
||||||
std.debug.warn("\n");
|
debug.warn("\n");
|
||||||
padSpace(level);
|
padSpace(level);
|
||||||
std.debug.warn("}}");
|
debug.warn("}}");
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1006,13 +1123,13 @@ pub const Value = union(enum) {
|
|||||||
fn padSpace(indent: usize) void {
|
fn padSpace(indent: usize) void {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < indent) : (i += 1) {
|
while (i < indent) : (i += 1) {
|
||||||
std.debug.warn(" ");
|
debug.warn(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A non-stream JSON parser which constructs a tree of Value's.
|
// A non-stream JSON parser which constructs a tree of Value's.
|
||||||
pub const JsonParser = struct {
|
pub const Parser = struct {
|
||||||
allocator: *Allocator,
|
allocator: *Allocator,
|
||||||
state: State,
|
state: State,
|
||||||
copy_strings: bool,
|
copy_strings: bool,
|
||||||
@ -1026,8 +1143,8 @@ pub const JsonParser = struct {
|
|||||||
Simple,
|
Simple,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: *Allocator, copy_strings: bool) JsonParser {
|
pub fn init(allocator: *Allocator, copy_strings: bool) Parser {
|
||||||
return JsonParser{
|
return Parser{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.state = State.Simple,
|
.state = State.Simple,
|
||||||
.copy_strings = copy_strings,
|
.copy_strings = copy_strings,
|
||||||
@ -1035,52 +1152,26 @@ pub const JsonParser = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(p: *JsonParser) void {
|
pub fn deinit(p: *Parser) void {
|
||||||
p.stack.deinit();
|
p.stack.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(p: *JsonParser) void {
|
pub fn reset(p: *Parser) void {
|
||||||
p.state = State.Simple;
|
p.state = State.Simple;
|
||||||
p.stack.shrink(0);
|
p.stack.shrink(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(p: *JsonParser, input: []const u8) !ValueTree {
|
pub fn parse(p: *Parser, input: []const u8) !ValueTree {
|
||||||
var mp = StreamingJsonParser.init();
|
var s = TokenStream.init(input);
|
||||||
|
|
||||||
var arena = ArenaAllocator.init(p.allocator);
|
var arena = ArenaAllocator.init(p.allocator);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
|
|
||||||
for (input) |c, i| {
|
while (try s.next()) |token| {
|
||||||
var mt1: ?Token = undefined;
|
try p.transition(&arena.allocator, input, s.i - 1, token);
|
||||||
var mt2: ?Token = undefined;
|
|
||||||
|
|
||||||
try mp.feed(c, &mt1, &mt2);
|
|
||||||
if (mt1) |t1| {
|
|
||||||
try p.transition(&arena.allocator, input, i, t1);
|
|
||||||
|
|
||||||
if (mt2) |t2| {
|
|
||||||
try p.transition(&arena.allocator, input, i, t2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle top-level lonely number values.
|
debug.assert(p.stack.len == 1);
|
||||||
{
|
|
||||||
const i = input.len;
|
|
||||||
var mt1: ?Token = undefined;
|
|
||||||
var mt2: ?Token = undefined;
|
|
||||||
|
|
||||||
try mp.feed(' ', &mt1, &mt2);
|
|
||||||
if (mt1) |t1| {
|
|
||||||
try p.transition(&arena.allocator, input, i, t1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mp.complete) {
|
|
||||||
return error.IncompleteJsonInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
std.debug.assert(p.stack.len == 1);
|
|
||||||
|
|
||||||
return ValueTree{
|
return ValueTree{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
@ -1090,7 +1181,7 @@ pub const JsonParser = struct {
|
|||||||
|
|
||||||
// Even though p.allocator exists, we take an explicit allocator so that allocation state
|
// Even though p.allocator exists, we take an explicit allocator so that allocation state
|
||||||
// can be cleaned up on error correctly during a `parse` on call.
|
// can be cleaned up on error correctly during a `parse` on call.
|
||||||
fn transition(p: *JsonParser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void {
|
fn transition(p: *Parser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void {
|
||||||
switch (p.state) {
|
switch (p.state) {
|
||||||
State.ObjectKey => switch (token.id) {
|
State.ObjectKey => switch (token.id) {
|
||||||
Token.Id.ObjectEnd => {
|
Token.Id.ObjectEnd => {
|
||||||
@ -1147,7 +1238,7 @@ pub const JsonParser = struct {
|
|||||||
_ = p.stack.pop();
|
_ = p.stack.pop();
|
||||||
p.state = State.ObjectKey;
|
p.state = State.ObjectKey;
|
||||||
},
|
},
|
||||||
else => {
|
Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
|
||||||
unreachable;
|
unreachable;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1187,7 +1278,7 @@ pub const JsonParser = struct {
|
|||||||
Token.Id.Null => {
|
Token.Id.Null => {
|
||||||
try array.append(Value.Null);
|
try array.append(Value.Null);
|
||||||
},
|
},
|
||||||
else => {
|
Token.Id.ObjectEnd => {
|
||||||
unreachable;
|
unreachable;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1223,7 +1314,7 @@ pub const JsonParser = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pushToParent(p: *JsonParser, value: *const Value) !void {
|
fn pushToParent(p: *Parser, value: *const Value) !void {
|
||||||
switch (p.stack.at(p.stack.len - 1)) {
|
switch (p.stack.at(p.stack.len - 1)) {
|
||||||
// Object Parent -> [ ..., object, <key>, value ]
|
// Object Parent -> [ ..., object, <key>, value ]
|
||||||
Value.String => |key| {
|
Value.String => |key| {
|
||||||
@ -1244,14 +1335,14 @@ pub const JsonParser = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseString(p: *JsonParser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value {
|
fn parseString(p: *Parser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value {
|
||||||
// TODO: We don't strictly have to copy values which do not contain any escape
|
// TODO: We don't strictly have to copy values which do not contain any escape
|
||||||
// characters if flagged with the option.
|
// characters if flagged with the option.
|
||||||
const slice = token.slice(input, i);
|
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 {
|
fn parseNumber(p: *Parser, token: *const Token, input: []const u8, i: usize) !Value {
|
||||||
return if (token.number_is_integer)
|
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
|
else
|
||||||
@ -1259,10 +1350,8 @@ pub const JsonParser = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const debug = std.debug;
|
|
||||||
|
|
||||||
test "json parser dynamic" {
|
test "json parser dynamic" {
|
||||||
var p = JsonParser.init(std.debug.global_allocator, false);
|
var p = Parser.init(debug.global_allocator, false);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const s =
|
const s =
|
||||||
@ -1287,17 +1376,17 @@ test "json parser dynamic" {
|
|||||||
|
|
||||||
var root = tree.root;
|
var root = tree.root;
|
||||||
|
|
||||||
var image = (??root.Object.get("Image")).value;
|
var image = root.Object.get("Image").?.value;
|
||||||
|
|
||||||
const width = (??image.Object.get("Width")).value;
|
const width = image.Object.get("Width").?.value;
|
||||||
debug.assert(width.Integer == 800);
|
debug.assert(width.Integer == 800);
|
||||||
|
|
||||||
const height = (??image.Object.get("Height")).value;
|
const height = image.Object.get("Height").?.value;
|
||||||
debug.assert(height.Integer == 600);
|
debug.assert(height.Integer == 600);
|
||||||
|
|
||||||
const title = (??image.Object.get("Title")).value;
|
const title = image.Object.get("Title").?.value;
|
||||||
debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
|
debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
|
||||||
|
|
||||||
const animated = (??image.Object.get("Animated")).value;
|
const animated = image.Object.get("Animated").?.value;
|
||||||
debug.assert(animated.Bool == false);
|
debug.assert(animated.Bool == false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,16 @@ fn any(comptime s: []const u8) void {
|
|||||||
std.debug.assert(true);
|
std.debug.assert(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Additional tests not part of test JSONTestSuite.
|
||||||
|
|
||||||
|
test "y_trailing_comma_after_empty" {
|
||||||
|
ok(
|
||||||
|
\\{"1":[],"2":{},"3":"4"}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
test "y_array_arraysWithSpaces" {
|
test "y_array_arraysWithSpaces" {
|
||||||
|
|||||||
@ -169,7 +169,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
|
|||||||
/// Returns:
|
/// Returns:
|
||||||
/// A pointer to the last node in the list.
|
/// A pointer to the last node in the list.
|
||||||
pub fn pop(list: *Self) ?*Node {
|
pub fn pop(list: *Self) ?*Node {
|
||||||
const last = list.last ?? return null;
|
const last = list.last orelse return null;
|
||||||
list.remove(last);
|
list.remove(last);
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
|
|||||||
/// Returns:
|
/// Returns:
|
||||||
/// A pointer to the first node in the list.
|
/// A pointer to the first node in the list.
|
||||||
pub fn popFirst(list: *Self) ?*Node {
|
pub fn popFirst(list: *Self) ?*Node {
|
||||||
const first = list.first ?? return null;
|
const first = list.first orelse return null;
|
||||||
list.remove(first);
|
list.remove(first);
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@ -270,8 +270,8 @@ test "basic linked list test" {
|
|||||||
var last = list.pop(); // {2, 3, 4}
|
var last = list.pop(); // {2, 3, 4}
|
||||||
list.remove(three); // {2, 4}
|
list.remove(three); // {2, 4}
|
||||||
|
|
||||||
assert((??list.first).data == 2);
|
assert(list.first.?.data == 2);
|
||||||
assert((??list.last).data == 4);
|
assert(list.last.?.data == 4);
|
||||||
assert(list.len == 2);
|
assert(list.len == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ test "basic intrusive linked list test" {
|
|||||||
var last = list.pop(); // {2, 3, 4}
|
var last = list.pop(); // {2, 3, 4}
|
||||||
list.remove(&three.link); // {2, 4}
|
list.remove(&three.link); // {2, 4}
|
||||||
|
|
||||||
assert((??list.first).toData().value == 2);
|
assert(list.first.?.toData().value == 2);
|
||||||
assert((??list.last).toData().value == 4);
|
assert(list.last.?.toData().value == 4);
|
||||||
assert(list.len == 2);
|
assert(list.len == 2);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -130,7 +130,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
|
|||||||
for (syms) |sym| {
|
for (syms) |sym| {
|
||||||
if (!isSymbol(sym)) continue;
|
if (!isSymbol(sym)) continue;
|
||||||
const start = sym.n_strx;
|
const start = sym.n_strx;
|
||||||
const end = ??mem.indexOfScalarPos(u8, strings, start, 0);
|
const end = mem.indexOfScalarPos(u8, strings, start, 0).?;
|
||||||
const name = strings[start..end];
|
const name = strings[start..end];
|
||||||
const address = sym.n_value;
|
const address = sym.n_value;
|
||||||
symbols[nsym] = Symbol{ .name = name, .address = address };
|
symbols[nsym] = Symbol{ .name = name, .address = address };
|
||||||
|
|||||||
5
std/math/big/index.zig
Normal file
5
std/math/big/index.zig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub use @import("int.zig");
|
||||||
|
|
||||||
|
test "math.big" {
|
||||||
|
_ = @import("int.zig");
|
||||||
|
}
|
||||||
2023
std/math/big/int.zig
Normal file
2023
std/math/big/int.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -132,6 +132,8 @@ pub const tan = @import("tan.zig").tan;
|
|||||||
pub const complex = @import("complex/index.zig");
|
pub const complex = @import("complex/index.zig");
|
||||||
pub const Complex = complex.Complex;
|
pub const Complex = complex.Complex;
|
||||||
|
|
||||||
|
pub const big = @import("big/index.zig");
|
||||||
|
|
||||||
test "math" {
|
test "math" {
|
||||||
_ = @import("nan.zig");
|
_ = @import("nan.zig");
|
||||||
_ = @import("isnan.zig");
|
_ = @import("isnan.zig");
|
||||||
@ -177,6 +179,8 @@ test "math" {
|
|||||||
_ = @import("tan.zig");
|
_ = @import("tan.zig");
|
||||||
|
|
||||||
_ = @import("complex/index.zig");
|
_ = @import("complex/index.zig");
|
||||||
|
|
||||||
|
_ = @import("big/index.zig");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min(x: var, y: var) @typeOf(x + y) {
|
pub fn min(x: var, y: var) @typeOf(x + y) {
|
||||||
@ -306,7 +310,14 @@ test "math.rotl" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn Log2Int(comptime T: type) type {
|
pub fn Log2Int(comptime T: type) type {
|
||||||
return @IntType(false, log2(T.bit_count));
|
// comptime ceil log2
|
||||||
|
comptime var count: usize = 0;
|
||||||
|
comptime var s = T.bit_count - 1;
|
||||||
|
inline while (s != 0) : (s >>= 1) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return @IntType(false, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math overflow functions" {
|
test "math overflow functions" {
|
||||||
|
|||||||
22
std/mem.zig
22
std/mem.zig
@ -304,20 +304,20 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "mem.indexOf" {
|
test "mem.indexOf" {
|
||||||
assert(??indexOf(u8, "one two three four", "four") == 14);
|
assert(indexOf(u8, "one two three four", "four").? == 14);
|
||||||
assert(??lastIndexOf(u8, "one two three two four", "two") == 14);
|
assert(lastIndexOf(u8, "one two three two four", "two").? == 14);
|
||||||
assert(indexOf(u8, "one two three four", "gour") == null);
|
assert(indexOf(u8, "one two three four", "gour") == null);
|
||||||
assert(lastIndexOf(u8, "one two three four", "gour") == null);
|
assert(lastIndexOf(u8, "one two three four", "gour") == null);
|
||||||
assert(??indexOf(u8, "foo", "foo") == 0);
|
assert(indexOf(u8, "foo", "foo").? == 0);
|
||||||
assert(??lastIndexOf(u8, "foo", "foo") == 0);
|
assert(lastIndexOf(u8, "foo", "foo").? == 0);
|
||||||
assert(indexOf(u8, "foo", "fool") == null);
|
assert(indexOf(u8, "foo", "fool") == null);
|
||||||
assert(lastIndexOf(u8, "foo", "lfoo") == null);
|
assert(lastIndexOf(u8, "foo", "lfoo") == null);
|
||||||
assert(lastIndexOf(u8, "foo", "fool") == null);
|
assert(lastIndexOf(u8, "foo", "fool") == null);
|
||||||
|
|
||||||
assert(??indexOf(u8, "foo foo", "foo") == 0);
|
assert(indexOf(u8, "foo foo", "foo").? == 0);
|
||||||
assert(??lastIndexOf(u8, "foo foo", "foo") == 4);
|
assert(lastIndexOf(u8, "foo foo", "foo").? == 4);
|
||||||
assert(??lastIndexOfAny(u8, "boo, cat", "abo") == 6);
|
assert(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
|
||||||
assert(??lastIndexOfScalar(u8, "boo", 'o') == 2);
|
assert(lastIndexOfScalar(u8, "boo", 'o').? == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an integer from memory with size equal to bytes.len.
|
/// Reads an integer from memory with size equal to bytes.len.
|
||||||
@ -432,9 +432,9 @@ pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
|
|||||||
|
|
||||||
test "mem.split" {
|
test "mem.split" {
|
||||||
var it = split(" abc def ghi ", " ");
|
var it = split(" abc def ghi ", " ");
|
||||||
assert(eql(u8, ??it.next(), "abc"));
|
assert(eql(u8, it.next().?, "abc"));
|
||||||
assert(eql(u8, ??it.next(), "def"));
|
assert(eql(u8, it.next().?, "def"));
|
||||||
assert(eql(u8, ??it.next(), "ghi"));
|
assert(eql(u8, it.next().?, "ghi"));
|
||||||
assert(it.next() == null);
|
assert(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -156,7 +156,7 @@ pub const ChildProcess = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
try self.waitUnwrappedWindows();
|
try self.waitUnwrappedWindows();
|
||||||
return ??self.term;
|
return self.term.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn killPosix(self: *ChildProcess) !Term {
|
pub fn killPosix(self: *ChildProcess) !Term {
|
||||||
@ -175,7 +175,7 @@ pub const ChildProcess = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.waitUnwrapped();
|
self.waitUnwrapped();
|
||||||
return ??self.term;
|
return self.term.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blocks until child process terminates and then cleans up all resources.
|
/// Blocks until child process terminates and then cleans up all resources.
|
||||||
@ -212,8 +212,8 @@ pub const ChildProcess = struct {
|
|||||||
defer Buffer.deinit(&stdout);
|
defer Buffer.deinit(&stdout);
|
||||||
defer Buffer.deinit(&stderr);
|
defer Buffer.deinit(&stderr);
|
||||||
|
|
||||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
|
||||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
|
||||||
|
|
||||||
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
|
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
|
||||||
try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
|
try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
|
||||||
@ -232,7 +232,7 @@ pub const ChildProcess = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try self.waitUnwrappedWindows();
|
try self.waitUnwrappedWindows();
|
||||||
return ??self.term;
|
return self.term.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn waitPosix(self: *ChildProcess) !Term {
|
fn waitPosix(self: *ChildProcess) !Term {
|
||||||
@ -242,7 +242,7 @@ pub const ChildProcess = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.waitUnwrapped();
|
self.waitUnwrapped();
|
||||||
return ??self.term;
|
return self.term.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *ChildProcess) void {
|
pub fn deinit(self: *ChildProcess) void {
|
||||||
@ -619,13 +619,13 @@ pub const ChildProcess = struct {
|
|||||||
self.term = null;
|
self.term = null;
|
||||||
|
|
||||||
if (self.stdin_behavior == StdIo.Pipe) {
|
if (self.stdin_behavior == StdIo.Pipe) {
|
||||||
os.close(??g_hChildStd_IN_Rd);
|
os.close(g_hChildStd_IN_Rd.?);
|
||||||
}
|
}
|
||||||
if (self.stderr_behavior == StdIo.Pipe) {
|
if (self.stderr_behavior == StdIo.Pipe) {
|
||||||
os.close(??g_hChildStd_ERR_Wr);
|
os.close(g_hChildStd_ERR_Wr.?);
|
||||||
}
|
}
|
||||||
if (self.stdout_behavior == StdIo.Pipe) {
|
if (self.stdout_behavior == StdIo.Pipe) {
|
||||||
os.close(??g_hChildStd_OUT_Wr);
|
os.close(g_hChildStd_OUT_Wr.?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -327,7 +327,7 @@ pub fn raise(sig: i32) usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
|
pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
|
||||||
return errnoWrap(c.read(fd, @ptrCast([*]c_void, buf), nbyte));
|
return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
|
pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
|
||||||
@ -335,17 +335,17 @@ pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
|
pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
|
||||||
return errnoWrap(c.write(fd, @ptrCast([*]const c_void, buf), nbyte));
|
return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
|
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
|
||||||
const ptr_result = c.mmap(@ptrCast([*]c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
|
const ptr_result = c.mmap(@ptrCast(*c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
|
||||||
const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
|
const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
|
||||||
return errnoWrap(isize_result);
|
return errnoWrap(isize_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn munmap(address: usize, length: usize) usize {
|
pub fn munmap(address: usize, length: usize) usize {
|
||||||
return errnoWrap(c.munmap(@intToPtr([*]c_void, address), length));
|
return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlink(path: [*]const u8) usize {
|
pub fn unlink(path: [*]const u8) usize {
|
||||||
|
|||||||
@ -96,7 +96,20 @@ pub const File = struct {
|
|||||||
return File{ .handle = handle };
|
return File{ .handle = handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool {
|
pub const AccessError = error{
|
||||||
|
PermissionDenied,
|
||||||
|
NotFound,
|
||||||
|
NameTooLong,
|
||||||
|
BadMode,
|
||||||
|
BadPathName,
|
||||||
|
Io,
|
||||||
|
SystemResources,
|
||||||
|
OutOfMemory,
|
||||||
|
|
||||||
|
Unexpected,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) AccessError!bool {
|
||||||
const path_with_null = try std.cstr.addNullByte(allocator, path);
|
const path_with_null = try std.cstr.addNullByte(allocator, path);
|
||||||
defer allocator.free(path_with_null);
|
defer allocator.free(path_with_null);
|
||||||
|
|
||||||
@ -123,7 +136,7 @@ pub const File = struct {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (is_windows) {
|
} else if (is_windows) {
|
||||||
if (os.windows.PathFileExists(path_with_null.ptr) == os.windows.TRUE) {
|
if (os.windows.GetFileAttributesA(path_with_null.ptr) != os.windows.INVALID_FILE_ATTRIBUTES) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +347,7 @@ pub const File = struct {
|
|||||||
while (index < buffer.len) {
|
while (index < buffer.len) {
|
||||||
const want_read_count = windows.DWORD(math.min(windows.DWORD(@maxValue(windows.DWORD)), buffer.len - index));
|
const want_read_count = windows.DWORD(math.min(windows.DWORD(@maxValue(windows.DWORD)), buffer.len - index));
|
||||||
var amt_read: windows.DWORD = undefined;
|
var amt_read: windows.DWORD = undefined;
|
||||||
if (windows.ReadFile(self.handle, @ptrCast([*]c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) {
|
if (windows.ReadFile(self.handle, @ptrCast(*c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) {
|
||||||
const err = windows.GetLastError();
|
const err = windows.GetLastError();
|
||||||
return switch (err) {
|
return switch (err) {
|
||||||
windows.ERROR.OPERATION_ABORTED => continue,
|
windows.ERROR.OPERATION_ABORTED => continue,
|
||||||
|
|||||||
306
std/os/index.zig
306
std/os/index.zig
@ -422,10 +422,10 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:
|
|||||||
|
|
||||||
const exe_path = argv[0];
|
const exe_path = argv[0];
|
||||||
if (mem.indexOfScalar(u8, exe_path, '/') != null) {
|
if (mem.indexOfScalar(u8, exe_path, '/') != null) {
|
||||||
return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
|
return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
|
const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
|
||||||
// PATH.len because it is >= the largest search_path
|
// PATH.len because it is >= the largest search_path
|
||||||
// +1 for the / to join the search path and exe_path
|
// +1 for the / to join the search path and exe_path
|
||||||
// +1 for the null terminating byte
|
// +1 for the null terminating byte
|
||||||
@ -490,7 +490,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
|
|||||||
errdefer result.deinit();
|
errdefer result.deinit();
|
||||||
|
|
||||||
if (is_windows) {
|
if (is_windows) {
|
||||||
const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
|
const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory;
|
||||||
defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
|
defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
@ -573,7 +573,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) ![]u8 {
|
|||||||
return allocator.shrink(u8, buf, result);
|
return allocator.shrink(u8, buf, result);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound;
|
const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
|
||||||
return mem.dupe(allocator, u8, result);
|
return mem.dupe(allocator, u8, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +714,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
|
|||||||
else => return err, // TODO zig should know this set does not include PathAlreadyExists
|
else => return err, // TODO zig should know this set does not include PathAlreadyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirname = os.path.dirname(new_path);
|
const dirname = os.path.dirname(new_path) orelse ".";
|
||||||
|
|
||||||
var rand_buf: [12]u8 = undefined;
|
var rand_buf: [12]u8 = undefined;
|
||||||
const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
|
const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
|
||||||
@ -734,7 +734,23 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deleteFile(allocator: *Allocator, file_path: []const u8) !void {
|
pub const DeleteFileError = error{
|
||||||
|
FileNotFound,
|
||||||
|
AccessDenied,
|
||||||
|
FileBusy,
|
||||||
|
FileSystem,
|
||||||
|
IsDir,
|
||||||
|
SymLinkLoop,
|
||||||
|
NameTooLong,
|
||||||
|
NotDir,
|
||||||
|
SystemResources,
|
||||||
|
ReadOnlyFileSystem,
|
||||||
|
OutOfMemory,
|
||||||
|
|
||||||
|
Unexpected,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn deleteFile(allocator: *Allocator, file_path: []const u8) DeleteFileError!void {
|
||||||
if (builtin.os == Os.windows) {
|
if (builtin.os == Os.windows) {
|
||||||
return deleteFileWindows(allocator, file_path);
|
return deleteFileWindows(allocator, file_path);
|
||||||
} else {
|
} else {
|
||||||
@ -844,14 +860,14 @@ pub const AtomicFile = struct {
|
|||||||
|
|
||||||
var rand_buf: [12]u8 = undefined;
|
var rand_buf: [12]u8 = undefined;
|
||||||
|
|
||||||
const dirname_component_len = if (dirname.len == 0) 0 else dirname.len + 1;
|
const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
|
||||||
const tmp_path = try allocator.alloc(u8, dirname_component_len +
|
const tmp_path = try allocator.alloc(u8, dirname_component_len +
|
||||||
base64.Base64Encoder.calcSize(rand_buf.len));
|
base64.Base64Encoder.calcSize(rand_buf.len));
|
||||||
errdefer allocator.free(tmp_path);
|
errdefer allocator.free(tmp_path);
|
||||||
|
|
||||||
if (dirname.len != 0) {
|
if (dirname) |dir| {
|
||||||
mem.copy(u8, tmp_path[0..], dirname);
|
mem.copy(u8, tmp_path[0..], dir);
|
||||||
tmp_path[dirname.len] = os.path.sep;
|
tmp_path[dir.len] = os.path.sep;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -1019,37 +1035,66 @@ pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const DeleteDirError = error{
|
||||||
|
AccessDenied,
|
||||||
|
FileBusy,
|
||||||
|
SymLinkLoop,
|
||||||
|
NameTooLong,
|
||||||
|
FileNotFound,
|
||||||
|
SystemResources,
|
||||||
|
NotDir,
|
||||||
|
DirNotEmpty,
|
||||||
|
ReadOnlyFileSystem,
|
||||||
|
OutOfMemory,
|
||||||
|
|
||||||
|
Unexpected,
|
||||||
|
};
|
||||||
|
|
||||||
/// Returns ::error.DirNotEmpty if the directory is not empty.
|
/// Returns ::error.DirNotEmpty if the directory is not empty.
|
||||||
/// To delete a directory recursively, see ::deleteTree
|
/// To delete a directory recursively, see ::deleteTree
|
||||||
pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) !void {
|
pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) DeleteDirError!void {
|
||||||
const path_buf = try allocator.alloc(u8, dir_path.len + 1);
|
const path_buf = try allocator.alloc(u8, dir_path.len + 1);
|
||||||
defer allocator.free(path_buf);
|
defer allocator.free(path_buf);
|
||||||
|
|
||||||
mem.copy(u8, path_buf, dir_path);
|
mem.copy(u8, path_buf, dir_path);
|
||||||
path_buf[dir_path.len] = 0;
|
path_buf[dir_path.len] = 0;
|
||||||
|
|
||||||
const err = posix.getErrno(posix.rmdir(path_buf.ptr));
|
switch (builtin.os) {
|
||||||
if (err > 0) {
|
Os.windows => {
|
||||||
return switch (err) {
|
if (windows.RemoveDirectoryA(path_buf.ptr) == 0) {
|
||||||
posix.EACCES, posix.EPERM => error.AccessDenied,
|
const err = windows.GetLastError();
|
||||||
posix.EBUSY => error.FileBusy,
|
return switch (err) {
|
||||||
posix.EFAULT, posix.EINVAL => unreachable,
|
windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
|
||||||
posix.ELOOP => error.SymLinkLoop,
|
windows.ERROR.DIR_NOT_EMPTY => error.DirNotEmpty,
|
||||||
posix.ENAMETOOLONG => error.NameTooLong,
|
else => unexpectedErrorWindows(err),
|
||||||
posix.ENOENT => error.FileNotFound,
|
};
|
||||||
posix.ENOMEM => error.SystemResources,
|
}
|
||||||
posix.ENOTDIR => error.NotDir,
|
},
|
||||||
posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
|
Os.linux, Os.macosx, Os.ios => {
|
||||||
posix.EROFS => error.ReadOnlyFileSystem,
|
const err = posix.getErrno(posix.rmdir(path_buf.ptr));
|
||||||
else => unexpectedErrorPosix(err),
|
if (err > 0) {
|
||||||
};
|
return switch (err) {
|
||||||
|
posix.EACCES, posix.EPERM => error.AccessDenied,
|
||||||
|
posix.EBUSY => error.FileBusy,
|
||||||
|
posix.EFAULT, posix.EINVAL => unreachable,
|
||||||
|
posix.ELOOP => error.SymLinkLoop,
|
||||||
|
posix.ENAMETOOLONG => error.NameTooLong,
|
||||||
|
posix.ENOENT => error.FileNotFound,
|
||||||
|
posix.ENOMEM => error.SystemResources,
|
||||||
|
posix.ENOTDIR => error.NotDir,
|
||||||
|
posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty,
|
||||||
|
posix.EROFS => error.ReadOnlyFileSystem,
|
||||||
|
else => unexpectedErrorPosix(err),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => @compileError("unimplemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether ::full_path describes a symlink, file, or directory, this function
|
/// Whether ::full_path describes a symlink, file, or directory, this function
|
||||||
/// removes it. If it cannot be removed because it is a non-empty directory,
|
/// removes it. If it cannot be removed because it is a non-empty directory,
|
||||||
/// this function recursively removes its entries and then tries again.
|
/// this function recursively removes its entries and then tries again.
|
||||||
/// TODO non-recursive implementation
|
|
||||||
const DeleteTreeError = error{
|
const DeleteTreeError = error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
@ -1128,7 +1173,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
|
|||||||
try full_entry_buf.resize(full_path.len + entry.name.len + 1);
|
try full_entry_buf.resize(full_path.len + entry.name.len + 1);
|
||||||
const full_entry_path = full_entry_buf.toSlice();
|
const full_entry_path = full_entry_buf.toSlice();
|
||||||
mem.copy(u8, full_entry_path, full_path);
|
mem.copy(u8, full_entry_path, full_path);
|
||||||
full_entry_path[full_path.len] = '/';
|
full_entry_path[full_path.len] = path.sep;
|
||||||
mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
|
mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
|
||||||
|
|
||||||
try deleteTree(allocator, full_entry_path);
|
try deleteTree(allocator, full_entry_path);
|
||||||
@ -1139,16 +1184,29 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const Dir = struct {
|
pub const Dir = struct {
|
||||||
fd: i32,
|
handle: Handle,
|
||||||
darwin_seek: darwin_seek_t,
|
|
||||||
allocator: *Allocator,
|
allocator: *Allocator,
|
||||||
buf: []u8,
|
|
||||||
index: usize,
|
|
||||||
end_index: usize,
|
|
||||||
|
|
||||||
const darwin_seek_t = switch (builtin.os) {
|
pub const Handle = switch (builtin.os) {
|
||||||
Os.macosx, Os.ios => i64,
|
Os.macosx, Os.ios => struct {
|
||||||
else => void,
|
fd: i32,
|
||||||
|
seek: i64,
|
||||||
|
buf: []u8,
|
||||||
|
index: usize,
|
||||||
|
end_index: usize,
|
||||||
|
},
|
||||||
|
Os.linux => struct {
|
||||||
|
fd: i32,
|
||||||
|
buf: []u8,
|
||||||
|
index: usize,
|
||||||
|
end_index: usize,
|
||||||
|
},
|
||||||
|
Os.windows => struct {
|
||||||
|
handle: windows.HANDLE,
|
||||||
|
find_file_data: windows.WIN32_FIND_DATAA,
|
||||||
|
first: bool,
|
||||||
|
},
|
||||||
|
else => @compileError("unimplemented"),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Entry = struct {
|
pub const Entry = struct {
|
||||||
@ -1168,81 +1226,122 @@ pub const Dir = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn open(allocator: *Allocator, dir_path: []const u8) !Dir {
|
pub const OpenError = error{
|
||||||
const fd = switch (builtin.os) {
|
PathNotFound,
|
||||||
Os.windows => @compileError("TODO support Dir.open for windows"),
|
NotDir,
|
||||||
Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, 0),
|
AccessDenied,
|
||||||
Os.macosx, Os.ios => try posixOpen(
|
FileTooBig,
|
||||||
allocator,
|
IsDir,
|
||||||
dir_path,
|
SymLinkLoop,
|
||||||
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
|
ProcessFdQuotaExceeded,
|
||||||
0,
|
NameTooLong,
|
||||||
),
|
SystemFdQuotaExceeded,
|
||||||
else => @compileError("Dir.open is not supported for this platform"),
|
NoDevice,
|
||||||
};
|
SystemResources,
|
||||||
const darwin_seek_init = switch (builtin.os) {
|
NoSpaceLeft,
|
||||||
Os.macosx, Os.ios => 0,
|
PathAlreadyExists,
|
||||||
else => {},
|
OutOfMemory,
|
||||||
};
|
|
||||||
|
Unexpected,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
|
||||||
return Dir{
|
return Dir{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.fd = fd,
|
.handle = switch (builtin.os) {
|
||||||
.darwin_seek = darwin_seek_init,
|
Os.windows => blk: {
|
||||||
.index = 0,
|
var find_file_data: windows.WIN32_FIND_DATAA = undefined;
|
||||||
.end_index = 0,
|
const handle = try windows_util.windowsFindFirstFile(allocator, dir_path, &find_file_data);
|
||||||
.buf = []u8{},
|
break :blk Handle{
|
||||||
|
.handle = handle,
|
||||||
|
.find_file_data = find_file_data, // TODO guaranteed copy elision
|
||||||
|
.first = true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Os.macosx, Os.ios => Handle{
|
||||||
|
.fd = try posixOpen(
|
||||||
|
allocator,
|
||||||
|
dir_path,
|
||||||
|
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
.seek = 0,
|
||||||
|
.index = 0,
|
||||||
|
.end_index = 0,
|
||||||
|
.buf = []u8{},
|
||||||
|
},
|
||||||
|
Os.linux => Handle{
|
||||||
|
.fd = try posixOpen(
|
||||||
|
allocator,
|
||||||
|
dir_path,
|
||||||
|
posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
.index = 0,
|
||||||
|
.end_index = 0,
|
||||||
|
.buf = []u8{},
|
||||||
|
},
|
||||||
|
else => @compileError("unimplemented"),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: *Dir) void {
|
pub fn close(self: *Dir) void {
|
||||||
self.allocator.free(self.buf);
|
switch (builtin.os) {
|
||||||
os.close(self.fd);
|
Os.windows => {
|
||||||
|
_ = windows.FindClose(self.handle.handle);
|
||||||
|
},
|
||||||
|
Os.macosx, Os.ios, Os.linux => {
|
||||||
|
self.allocator.free(self.handle.buf);
|
||||||
|
os.close(self.handle.fd);
|
||||||
|
},
|
||||||
|
else => @compileError("unimplemented"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||||
/// with subsequent calls to next, as well as when this ::Dir is deinitialized.
|
/// with subsequent calls to next, as well as when this `Dir` is deinitialized.
|
||||||
pub fn next(self: *Dir) !?Entry {
|
pub fn next(self: *Dir) !?Entry {
|
||||||
switch (builtin.os) {
|
switch (builtin.os) {
|
||||||
Os.linux => return self.nextLinux(),
|
Os.linux => return self.nextLinux(),
|
||||||
Os.macosx, Os.ios => return self.nextDarwin(),
|
Os.macosx, Os.ios => return self.nextDarwin(),
|
||||||
Os.windows => return self.nextWindows(),
|
Os.windows => return self.nextWindows(),
|
||||||
else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
|
else => @compileError("unimplemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nextDarwin(self: *Dir) !?Entry {
|
fn nextDarwin(self: *Dir) !?Entry {
|
||||||
start_over: while (true) {
|
start_over: while (true) {
|
||||||
if (self.index >= self.end_index) {
|
if (self.handle.index >= self.handle.end_index) {
|
||||||
if (self.buf.len == 0) {
|
if (self.handle.buf.len == 0) {
|
||||||
self.buf = try self.allocator.alloc(u8, page_size);
|
self.handle.buf = try self.allocator.alloc(u8, page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len, &self.darwin_seek);
|
const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
|
||||||
const err = posix.getErrno(result);
|
const err = posix.getErrno(result);
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
|
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
|
||||||
posix.EINVAL => {
|
posix.EINVAL => {
|
||||||
self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
|
self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
else => return unexpectedErrorPosix(err),
|
else => return unexpectedErrorPosix(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result == 0) return null;
|
if (result == 0) return null;
|
||||||
self.index = 0;
|
self.handle.index = 0;
|
||||||
self.end_index = result;
|
self.handle.end_index = result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.buf[self.index]);
|
const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
|
||||||
const next_index = self.index + darwin_entry.d_reclen;
|
const next_index = self.handle.index + darwin_entry.d_reclen;
|
||||||
self.index = next_index;
|
self.handle.index = next_index;
|
||||||
|
|
||||||
const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
|
const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
|
||||||
|
|
||||||
// skip . and .. entries
|
|
||||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
|
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
|
||||||
continue :start_over;
|
continue :start_over;
|
||||||
}
|
}
|
||||||
@ -1266,38 +1365,59 @@ pub const Dir = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn nextWindows(self: *Dir) !?Entry {
|
fn nextWindows(self: *Dir) !?Entry {
|
||||||
@compileError("TODO support Dir.next for windows");
|
while (true) {
|
||||||
|
if (self.handle.first) {
|
||||||
|
self.handle.first = false;
|
||||||
|
} else {
|
||||||
|
if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const name = std.cstr.toSlice(self.handle.find_file_data.cFileName[0..].ptr);
|
||||||
|
if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
|
||||||
|
continue;
|
||||||
|
const kind = blk: {
|
||||||
|
const attrs = self.handle.find_file_data.dwFileAttributes;
|
||||||
|
if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
|
||||||
|
if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
|
||||||
|
if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
|
||||||
|
break :blk Entry.Kind.Unknown;
|
||||||
|
};
|
||||||
|
return Entry{
|
||||||
|
.name = name,
|
||||||
|
.kind = kind,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nextLinux(self: *Dir) !?Entry {
|
fn nextLinux(self: *Dir) !?Entry {
|
||||||
start_over: while (true) {
|
start_over: while (true) {
|
||||||
if (self.index >= self.end_index) {
|
if (self.handle.index >= self.handle.end_index) {
|
||||||
if (self.buf.len == 0) {
|
if (self.handle.buf.len == 0) {
|
||||||
self.buf = try self.allocator.alloc(u8, page_size);
|
self.handle.buf = try self.allocator.alloc(u8, page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
|
const result = posix.getdents(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
|
||||||
const err = posix.getErrno(result);
|
const err = posix.getErrno(result);
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
|
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
|
||||||
posix.EINVAL => {
|
posix.EINVAL => {
|
||||||
self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
|
self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
else => return unexpectedErrorPosix(err),
|
else => return unexpectedErrorPosix(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result == 0) return null;
|
if (result == 0) return null;
|
||||||
self.index = 0;
|
self.handle.index = 0;
|
||||||
self.end_index = result;
|
self.handle.end_index = result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const linux_entry = @ptrCast(*align(1) posix.dirent, &self.buf[self.index]);
|
const linux_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
|
||||||
const next_index = self.index + linux_entry.d_reclen;
|
const next_index = self.handle.index + linux_entry.d_reclen;
|
||||||
self.index = next_index;
|
self.handle.index = next_index;
|
||||||
|
|
||||||
const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
|
const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
|
||||||
|
|
||||||
@ -1306,7 +1426,7 @@ pub const Dir = struct {
|
|||||||
continue :start_over;
|
continue :start_over;
|
||||||
}
|
}
|
||||||
|
|
||||||
const type_char = self.buf[next_index - 1];
|
const type_char = self.handle.buf[next_index - 1];
|
||||||
const entry_kind = switch (type_char) {
|
const entry_kind = switch (type_char) {
|
||||||
posix.DT_BLK => Entry.Kind.BlockDevice,
|
posix.DT_BLK => Entry.Kind.BlockDevice,
|
||||||
posix.DT_CHR => Entry.Kind.CharacterDevice,
|
posix.DT_CHR => Entry.Kind.CharacterDevice,
|
||||||
@ -1641,7 +1761,7 @@ pub const ArgIterator = struct {
|
|||||||
if (builtin.os == Os.windows) {
|
if (builtin.os == Os.windows) {
|
||||||
return self.inner.next(allocator);
|
return self.inner.next(allocator);
|
||||||
} else {
|
} else {
|
||||||
return mem.dupe(allocator, u8, self.inner.next() ?? return null);
|
return mem.dupe(allocator, u8, self.inner.next() orelse return null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1729,7 +1849,7 @@ test "windows arg parsing" {
|
|||||||
fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
|
fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
|
||||||
var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
|
var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
|
||||||
for (expected_args) |expected_arg| {
|
for (expected_args) |expected_arg| {
|
||||||
const arg = ??it.next(debug.global_allocator) catch unreachable;
|
const arg = it.next(debug.global_allocator).? catch unreachable;
|
||||||
assert(mem.eql(u8, arg, expected_arg));
|
assert(mem.eql(u8, arg, expected_arg));
|
||||||
}
|
}
|
||||||
assert(it.next(debug.global_allocator) == null);
|
assert(it.next(debug.global_allocator) == null);
|
||||||
@ -1845,13 +1965,13 @@ pub fn selfExeDirPath(allocator: *mem.Allocator) ![]u8 {
|
|||||||
// the executable was in when it was run.
|
// the executable was in when it was run.
|
||||||
const full_exe_path = try readLink(allocator, "/proc/self/exe");
|
const full_exe_path = try readLink(allocator, "/proc/self/exe");
|
||||||
errdefer allocator.free(full_exe_path);
|
errdefer allocator.free(full_exe_path);
|
||||||
const dir = path.dirname(full_exe_path);
|
const dir = path.dirname(full_exe_path) orelse ".";
|
||||||
return allocator.shrink(u8, full_exe_path, dir.len);
|
return allocator.shrink(u8, full_exe_path, dir.len);
|
||||||
},
|
},
|
||||||
Os.windows, Os.macosx, Os.ios => {
|
Os.windows, Os.macosx, Os.ios => {
|
||||||
const self_exe_path = try selfExePath(allocator);
|
const self_exe_path = try selfExePath(allocator);
|
||||||
errdefer allocator.free(self_exe_path);
|
errdefer allocator.free(self_exe_path);
|
||||||
const dirname = os.path.dirname(self_exe_path);
|
const dirname = os.path.dirname(self_exe_path) orelse ".";
|
||||||
return allocator.shrink(u8, self_exe_path, dirname.len);
|
return allocator.shrink(u8, self_exe_path, dirname.len);
|
||||||
},
|
},
|
||||||
else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)),
|
else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)),
|
||||||
@ -2362,7 +2482,7 @@ pub const Thread = struct {
|
|||||||
},
|
},
|
||||||
builtin.Os.windows => struct {
|
builtin.Os.windows => struct {
|
||||||
handle: windows.HANDLE,
|
handle: windows.HANDLE,
|
||||||
alloc_start: [*]c_void,
|
alloc_start: *c_void,
|
||||||
heap_handle: windows.HANDLE,
|
heap_handle: windows.HANDLE,
|
||||||
},
|
},
|
||||||
else => @compileError("Unsupported OS"),
|
else => @compileError("Unsupported OS"),
|
||||||
@ -2457,9 +2577,9 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const heap_handle = windows.GetProcessHeap() ?? return SpawnThreadError.OutOfMemory;
|
const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
|
||||||
const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
|
const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
|
||||||
const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) ?? return SpawnThreadError.OutOfMemory;
|
const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
|
||||||
errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
|
errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
|
||||||
const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
|
const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
|
||||||
const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
|
const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
|
||||||
@ -2468,7 +2588,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
|
|||||||
outer_context.thread.data.alloc_start = bytes_ptr;
|
outer_context.thread.data.alloc_start = bytes_ptr;
|
||||||
|
|
||||||
const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
|
const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
|
||||||
outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) ?? {
|
outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
|
||||||
const err = windows.GetLastError();
|
const err = windows.GetLastError();
|
||||||
return switch (err) {
|
return switch (err) {
|
||||||
else => os.unexpectedErrorWindows(err),
|
else => os.unexpectedErrorWindows(err),
|
||||||
@ -2533,7 +2653,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
|
|||||||
|
|
||||||
// align to page
|
// align to page
|
||||||
stack_end -= stack_end % os.page_size;
|
stack_end -= stack_end % os.page_size;
|
||||||
assert(c.pthread_attr_setstack(&attr, @intToPtr([*]c_void, stack_addr), stack_end - stack_addr) == 0);
|
assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 0);
|
||||||
|
|
||||||
const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
|
const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
|
||||||
switch (err) {
|
switch (err) {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const dynv = maybe_dynv ?? return 0;
|
const dynv = maybe_dynv orelse return 0;
|
||||||
if (base == @maxValue(usize)) return 0;
|
if (base == @maxValue(usize)) return 0;
|
||||||
|
|
||||||
var maybe_strings: ?[*]u8 = null;
|
var maybe_strings: ?[*]u8 = null;
|
||||||
@ -52,9 +52,9 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const strings = maybe_strings ?? return 0;
|
const strings = maybe_strings orelse return 0;
|
||||||
const syms = maybe_syms ?? return 0;
|
const syms = maybe_syms orelse return 0;
|
||||||
const hashtab = maybe_hashtab ?? return 0;
|
const hashtab = maybe_hashtab orelse return 0;
|
||||||
if (maybe_verdef == null) maybe_versym = null;
|
if (maybe_verdef == null) maybe_versym = null;
|
||||||
|
|
||||||
const OK_TYPES = (1 << elf.STT_NOTYPE | 1 << elf.STT_OBJECT | 1 << elf.STT_FUNC | 1 << elf.STT_COMMON);
|
const OK_TYPES = (1 << elf.STT_NOTYPE | 1 << elf.STT_OBJECT | 1 << elf.STT_FUNC | 1 << elf.STT_COMMON);
|
||||||
@ -67,7 +67,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
|
|||||||
if (0 == syms[i].st_shndx) continue;
|
if (0 == syms[i].st_shndx) continue;
|
||||||
if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue;
|
if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue;
|
||||||
if (maybe_versym) |versym| {
|
if (maybe_versym) |versym| {
|
||||||
if (!checkver(??maybe_verdef, versym[i], vername, strings))
|
if (!checkver(maybe_verdef.?, versym[i], vername, strings))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return base + syms[i].st_value;
|
return base + syms[i].st_value;
|
||||||
|
|||||||
@ -182,8 +182,8 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var it = mem.split(path, []u8{this_sep});
|
var it = mem.split(path, []u8{this_sep});
|
||||||
_ = (it.next() ?? return relative_path);
|
_ = (it.next() orelse return relative_path);
|
||||||
_ = (it.next() ?? return relative_path);
|
_ = (it.next() orelse return relative_path);
|
||||||
return WindowsPath{
|
return WindowsPath{
|
||||||
.is_abs = isAbsoluteWindows(path),
|
.is_abs = isAbsoluteWindows(path),
|
||||||
.kind = WindowsPath.Kind.NetworkShare,
|
.kind = WindowsPath.Kind.NetworkShare,
|
||||||
@ -200,8 +200,8 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var it = mem.split(path, []u8{this_sep});
|
var it = mem.split(path, []u8{this_sep});
|
||||||
_ = (it.next() ?? return relative_path);
|
_ = (it.next() orelse return relative_path);
|
||||||
_ = (it.next() ?? return relative_path);
|
_ = (it.next() orelse return relative_path);
|
||||||
return WindowsPath{
|
return WindowsPath{
|
||||||
.is_abs = isAbsoluteWindows(path),
|
.is_abs = isAbsoluteWindows(path),
|
||||||
.kind = WindowsPath.Kind.NetworkShare,
|
.kind = WindowsPath.Kind.NetworkShare,
|
||||||
@ -265,7 +265,7 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
|
|||||||
var it2 = mem.split(ns2, []u8{sep2});
|
var it2 = mem.split(ns2, []u8{sep2});
|
||||||
|
|
||||||
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
|
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
|
||||||
return asciiEqlIgnoreCase(??it1.next(), ??it2.next());
|
return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool {
|
fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool {
|
||||||
@ -286,7 +286,7 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8
|
|||||||
var it2 = mem.split(p2, []u8{sep2});
|
var it2 = mem.split(p2, []u8{sep2});
|
||||||
|
|
||||||
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
|
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
|
||||||
return asciiEqlIgnoreCase(??it1.next(), ??it2.next()) and asciiEqlIgnoreCase(??it1.next(), ??it2.next());
|
return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,8 +414,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
|||||||
WindowsPath.Kind.NetworkShare => {
|
WindowsPath.Kind.NetworkShare => {
|
||||||
result = try allocator.alloc(u8, max_size);
|
result = try allocator.alloc(u8, max_size);
|
||||||
var it = mem.split(paths[first_index], "/\\");
|
var it = mem.split(paths[first_index], "/\\");
|
||||||
const server_name = ??it.next();
|
const server_name = it.next().?;
|
||||||
const other_name = ??it.next();
|
const other_name = it.next().?;
|
||||||
|
|
||||||
result[result_index] = '\\';
|
result[result_index] = '\\';
|
||||||
result_index += 1;
|
result_index += 1;
|
||||||
@ -648,8 +648,8 @@ fn testResolvePosix(paths: []const []const u8) []u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If the path is a file in the current directory (no directory component)
|
/// If the path is a file in the current directory (no directory component)
|
||||||
/// then the returned slice has .len = 0.
|
/// then returns null
|
||||||
pub fn dirname(path: []const u8) []const u8 {
|
pub fn dirname(path: []const u8) ?[]const u8 {
|
||||||
if (is_windows) {
|
if (is_windows) {
|
||||||
return dirnameWindows(path);
|
return dirnameWindows(path);
|
||||||
} else {
|
} else {
|
||||||
@ -657,9 +657,9 @@ pub fn dirname(path: []const u8) []const u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dirnameWindows(path: []const u8) []const u8 {
|
pub fn dirnameWindows(path: []const u8) ?[]const u8 {
|
||||||
if (path.len == 0)
|
if (path.len == 0)
|
||||||
return path[0..0];
|
return null;
|
||||||
|
|
||||||
const root_slice = diskDesignatorWindows(path);
|
const root_slice = diskDesignatorWindows(path);
|
||||||
if (path.len == root_slice.len)
|
if (path.len == root_slice.len)
|
||||||
@ -671,13 +671,13 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
|
|||||||
|
|
||||||
while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
|
while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
|
||||||
if (end_index == 0)
|
if (end_index == 0)
|
||||||
return path[0..0];
|
return null;
|
||||||
end_index -= 1;
|
end_index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
|
while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
|
||||||
if (end_index == 0)
|
if (end_index == 0)
|
||||||
return path[0..0];
|
return null;
|
||||||
end_index -= 1;
|
end_index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,12 +685,15 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
|
|||||||
end_index += 1;
|
end_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (end_index == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
return path[0..end_index];
|
return path[0..end_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dirnamePosix(path: []const u8) []const u8 {
|
pub fn dirnamePosix(path: []const u8) ?[]const u8 {
|
||||||
if (path.len == 0)
|
if (path.len == 0)
|
||||||
return path[0..0];
|
return null;
|
||||||
|
|
||||||
var end_index: usize = path.len - 1;
|
var end_index: usize = path.len - 1;
|
||||||
while (path[end_index] == '/') {
|
while (path[end_index] == '/') {
|
||||||
@ -701,13 +704,16 @@ pub fn dirnamePosix(path: []const u8) []const u8 {
|
|||||||
|
|
||||||
while (path[end_index] != '/') {
|
while (path[end_index] != '/') {
|
||||||
if (end_index == 0)
|
if (end_index == 0)
|
||||||
return path[0..0];
|
return null;
|
||||||
end_index -= 1;
|
end_index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_index == 0 and path[end_index] == '/')
|
if (end_index == 0 and path[end_index] == '/')
|
||||||
return path[0..1];
|
return path[0..1];
|
||||||
|
|
||||||
|
if (end_index == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
return path[0..end_index];
|
return path[0..end_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,10 +723,10 @@ test "os.path.dirnamePosix" {
|
|||||||
testDirnamePosix("/a", "/");
|
testDirnamePosix("/a", "/");
|
||||||
testDirnamePosix("/", "/");
|
testDirnamePosix("/", "/");
|
||||||
testDirnamePosix("////", "/");
|
testDirnamePosix("////", "/");
|
||||||
testDirnamePosix("", "");
|
testDirnamePosix("", null);
|
||||||
testDirnamePosix("a", "");
|
testDirnamePosix("a", null);
|
||||||
testDirnamePosix("a/", "");
|
testDirnamePosix("a/", null);
|
||||||
testDirnamePosix("a//", "");
|
testDirnamePosix("a//", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "os.path.dirnameWindows" {
|
test "os.path.dirnameWindows" {
|
||||||
@ -742,7 +748,7 @@ test "os.path.dirnameWindows" {
|
|||||||
testDirnameWindows("c:foo\\bar", "c:foo");
|
testDirnameWindows("c:foo\\bar", "c:foo");
|
||||||
testDirnameWindows("c:foo\\bar\\", "c:foo");
|
testDirnameWindows("c:foo\\bar\\", "c:foo");
|
||||||
testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
|
testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
|
||||||
testDirnameWindows("file:stream", "");
|
testDirnameWindows("file:stream", null);
|
||||||
testDirnameWindows("dir\\file:stream", "dir");
|
testDirnameWindows("dir\\file:stream", "dir");
|
||||||
testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
|
testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
|
||||||
testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
|
testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
|
||||||
@ -753,18 +759,26 @@ test "os.path.dirnameWindows" {
|
|||||||
testDirnameWindows("/a/b/", "/a");
|
testDirnameWindows("/a/b/", "/a");
|
||||||
testDirnameWindows("/a/b", "/a");
|
testDirnameWindows("/a/b", "/a");
|
||||||
testDirnameWindows("/a", "/");
|
testDirnameWindows("/a", "/");
|
||||||
testDirnameWindows("", "");
|
testDirnameWindows("", null);
|
||||||
testDirnameWindows("/", "/");
|
testDirnameWindows("/", "/");
|
||||||
testDirnameWindows("////", "/");
|
testDirnameWindows("////", "/");
|
||||||
testDirnameWindows("foo", "");
|
testDirnameWindows("foo", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testDirnamePosix(input: []const u8, expected_output: []const u8) void {
|
fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void {
|
||||||
assert(mem.eql(u8, dirnamePosix(input), expected_output));
|
if (dirnamePosix(input)) |output| {
|
||||||
|
assert(mem.eql(u8, output, expected_output.?));
|
||||||
|
} else {
|
||||||
|
assert(expected_output == null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testDirnameWindows(input: []const u8, expected_output: []const u8) void {
|
fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
|
||||||
assert(mem.eql(u8, dirnameWindows(input), expected_output));
|
if (dirnameWindows(input)) |output| {
|
||||||
|
assert(mem.eql(u8, output, expected_output.?));
|
||||||
|
} else {
|
||||||
|
assert(expected_output == null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn basename(path: []const u8) []const u8 {
|
pub fn basename(path: []const u8) []const u8 {
|
||||||
@ -923,7 +937,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
|
|||||||
var from_it = mem.split(resolved_from, "/\\");
|
var from_it = mem.split(resolved_from, "/\\");
|
||||||
var to_it = mem.split(resolved_to, "/\\");
|
var to_it = mem.split(resolved_to, "/\\");
|
||||||
while (true) {
|
while (true) {
|
||||||
const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest());
|
const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
|
||||||
const to_rest = to_it.rest();
|
const to_rest = to_it.rest();
|
||||||
if (to_it.next()) |to_component| {
|
if (to_it.next()) |to_component| {
|
||||||
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
|
// TODO ASCII is wrong, we actually need full unicode support to compare paths.
|
||||||
@ -974,7 +988,7 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![
|
|||||||
var from_it = mem.split(resolved_from, "/");
|
var from_it = mem.split(resolved_from, "/");
|
||||||
var to_it = mem.split(resolved_to, "/");
|
var to_it = mem.split(resolved_to, "/");
|
||||||
while (true) {
|
while (true) {
|
||||||
const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest());
|
const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
|
||||||
const to_rest = to_it.rest();
|
const to_rest = to_it.rest();
|
||||||
if (to_it.next()) |to_component| {
|
if (to_it.next()) |to_component| {
|
||||||
if (mem.eql(u8, from_component, to_component))
|
if (mem.eql(u8, from_component, to_component))
|
||||||
|
|||||||
@ -10,11 +10,6 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
|
|||||||
const AtomicOrder = builtin.AtomicOrder;
|
const AtomicOrder = builtin.AtomicOrder;
|
||||||
|
|
||||||
test "makePath, put some files in it, deleteTree" {
|
test "makePath, put some files in it, deleteTree" {
|
||||||
if (builtin.os == builtin.Os.windows) {
|
|
||||||
// TODO implement os.Dir for windows
|
|
||||||
// https://github.com/ziglang/zig/issues/709
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try os.makePath(a, "os_test_tmp/b/c");
|
try os.makePath(a, "os_test_tmp/b/c");
|
||||||
try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
|
try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
|
||||||
try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
|
try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
|
||||||
@ -27,10 +22,6 @@ test "makePath, put some files in it, deleteTree" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "access file" {
|
test "access file" {
|
||||||
if (builtin.os == builtin.Os.windows) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try os.makePath(a, "os_test_tmp");
|
try os.makePath(a, "os_test_tmp");
|
||||||
if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
|
if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
|
||||||
unreachable;
|
unreachable;
|
||||||
|
|||||||
@ -68,11 +68,13 @@ pub const milliTimestamp = switch (builtin.os) {
|
|||||||
fn milliTimestampWindows() u64 {
|
fn milliTimestampWindows() u64 {
|
||||||
//FileTime has a granularity of 100 nanoseconds
|
//FileTime has a granularity of 100 nanoseconds
|
||||||
// and uses the NTFS/Windows epoch
|
// and uses the NTFS/Windows epoch
|
||||||
var ft: i64 = undefined;
|
var ft: windows.FILETIME = undefined;
|
||||||
windows.GetSystemTimeAsFileTime(&ft);
|
windows.GetSystemTimeAsFileTime(&ft);
|
||||||
const hns_per_ms = (ns_per_s / 100) / ms_per_s;
|
const hns_per_ms = (ns_per_s / 100) / ms_per_s;
|
||||||
const epoch_adj = epoch.windows * ms_per_s;
|
const epoch_adj = epoch.windows * ms_per_s;
|
||||||
return u64(@divFloor(ft, hns_per_ms) + epoch_adj);
|
|
||||||
|
const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||||
|
return @divFloor(ft64, hns_per_ms) - -epoch_adj;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn milliTimestampDarwin() u64 {
|
fn milliTimestampDarwin() u64 {
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
test "import" {
|
||||||
|
_ = @import("util.zig");
|
||||||
|
}
|
||||||
|
|
||||||
pub const ERROR = @import("error.zig");
|
pub const ERROR = @import("error.zig");
|
||||||
|
|
||||||
pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
|
pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
|
||||||
@ -61,6 +65,10 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
|
|||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
|
pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
|
||||||
|
|
||||||
|
pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
|
||||||
|
pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
|
||||||
|
pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
|
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
|
pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
|
||||||
@ -77,6 +85,8 @@ pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCo
|
|||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
|
pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
|
||||||
|
|
||||||
|
pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
|
pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
|
pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
|
||||||
@ -97,21 +107,21 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
|
|||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
|
pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(?*FILETIME) void;
|
pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
|
pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
|
||||||
pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
|
pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
|
||||||
pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]c_void, dwBytes: SIZE_T) ?[*]c_void;
|
pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
|
||||||
pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]const c_void) SIZE_T;
|
pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
|
||||||
pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]const c_void) BOOL;
|
pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
|
||||||
pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
|
pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
|
||||||
pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
|
pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
|
pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?[*]c_void;
|
pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]c_void) BOOL;
|
pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn MoveFileExA(
|
pub extern "kernel32" stdcallcc fn MoveFileExA(
|
||||||
lpExistingFileName: LPCSTR,
|
lpExistingFileName: LPCSTR,
|
||||||
@ -123,16 +133,16 @@ pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *
|
|||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
|
pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
|
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn ReadFile(
|
pub extern "kernel32" stdcallcc fn ReadFile(
|
||||||
in_hFile: HANDLE,
|
in_hFile: HANDLE,
|
||||||
out_lpBuffer: [*]c_void,
|
out_lpBuffer: *c_void,
|
||||||
in_nNumberOfBytesToRead: DWORD,
|
in_nNumberOfBytesToRead: DWORD,
|
||||||
out_lpNumberOfBytesRead: *DWORD,
|
out_lpNumberOfBytesRead: *DWORD,
|
||||||
in_out_lpOverlapped: ?*OVERLAPPED,
|
in_out_lpOverlapped: ?*OVERLAPPED,
|
||||||
) BOOL;
|
) BOOL;
|
||||||
|
|
||||||
|
pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
|
||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn SetFilePointerEx(
|
pub extern "kernel32" stdcallcc fn SetFilePointerEx(
|
||||||
in_fFile: HANDLE,
|
in_fFile: HANDLE,
|
||||||
in_liDistanceToMove: LARGE_INTEGER,
|
in_liDistanceToMove: LARGE_INTEGER,
|
||||||
@ -150,7 +160,7 @@ pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMillis
|
|||||||
|
|
||||||
pub extern "kernel32" stdcallcc fn WriteFile(
|
pub extern "kernel32" stdcallcc fn WriteFile(
|
||||||
in_hFile: HANDLE,
|
in_hFile: HANDLE,
|
||||||
in_lpBuffer: [*]const c_void,
|
in_lpBuffer: *const c_void,
|
||||||
in_nNumberOfBytesToWrite: DWORD,
|
in_nNumberOfBytesToWrite: DWORD,
|
||||||
out_lpNumberOfBytesWritten: ?*DWORD,
|
out_lpNumberOfBytesWritten: ?*DWORD,
|
||||||
in_out_lpOverlapped: ?*OVERLAPPED,
|
in_out_lpOverlapped: ?*OVERLAPPED,
|
||||||
@ -163,6 +173,8 @@ pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
|
|||||||
|
|
||||||
pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
|
pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
|
||||||
|
|
||||||
|
pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
|
||||||
|
|
||||||
pub const PROV_RSA_FULL = 1;
|
pub const PROV_RSA_FULL = 1;
|
||||||
|
|
||||||
pub const BOOL = c_int;
|
pub const BOOL = c_int;
|
||||||
@ -196,7 +208,6 @@ pub const UNICODE = false;
|
|||||||
pub const WCHAR = u16;
|
pub const WCHAR = u16;
|
||||||
pub const WORD = u16;
|
pub const WORD = u16;
|
||||||
pub const LARGE_INTEGER = i64;
|
pub const LARGE_INTEGER = i64;
|
||||||
pub const FILETIME = i64;
|
|
||||||
|
|
||||||
pub const TRUE = 1;
|
pub const TRUE = 1;
|
||||||
pub const FALSE = 0;
|
pub const FALSE = 0;
|
||||||
@ -212,6 +223,8 @@ pub const STD_ERROR_HANDLE = @maxValue(DWORD) - 12 + 1;
|
|||||||
|
|
||||||
pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, @maxValue(usize));
|
pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, @maxValue(usize));
|
||||||
|
|
||||||
|
pub const INVALID_FILE_ATTRIBUTES = DWORD(@maxValue(DWORD));
|
||||||
|
|
||||||
pub const OVERLAPPED = extern struct {
|
pub const OVERLAPPED = extern struct {
|
||||||
Internal: ULONG_PTR,
|
Internal: ULONG_PTR,
|
||||||
InternalHigh: ULONG_PTR,
|
InternalHigh: ULONG_PTR,
|
||||||
@ -293,13 +306,24 @@ pub const OPEN_EXISTING = 3;
|
|||||||
pub const TRUNCATE_EXISTING = 5;
|
pub const TRUNCATE_EXISTING = 5;
|
||||||
|
|
||||||
pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
|
pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
|
||||||
|
pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
|
||||||
|
pub const FILE_ATTRIBUTE_DEVICE = 0x40;
|
||||||
|
pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
|
||||||
pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
|
pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
|
||||||
pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
|
pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
|
||||||
|
pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
|
||||||
pub const FILE_ATTRIBUTE_NORMAL = 0x80;
|
pub const FILE_ATTRIBUTE_NORMAL = 0x80;
|
||||||
|
pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
|
||||||
|
pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
|
||||||
pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
|
pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
|
||||||
pub const FILE_ATTRIBUTE_READONLY = 0x1;
|
pub const FILE_ATTRIBUTE_READONLY = 0x1;
|
||||||
|
pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
|
||||||
|
pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
|
||||||
|
pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
|
||||||
|
pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
|
||||||
pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
|
pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
|
||||||
pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
|
pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
|
||||||
|
pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
|
||||||
|
|
||||||
pub const PROCESS_INFORMATION = extern struct {
|
pub const PROCESS_INFORMATION = extern struct {
|
||||||
hProcess: HANDLE,
|
hProcess: HANDLE,
|
||||||
@ -372,6 +396,20 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;
|
|||||||
pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
|
pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
|
||||||
pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
|
pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
|
||||||
|
|
||||||
test "import" {
|
pub const WIN32_FIND_DATAA = extern struct {
|
||||||
_ = @import("util.zig");
|
dwFileAttributes: DWORD,
|
||||||
}
|
ftCreationTime: FILETIME,
|
||||||
|
ftLastAccessTime: FILETIME,
|
||||||
|
ftLastWriteTime: FILETIME,
|
||||||
|
nFileSizeHigh: DWORD,
|
||||||
|
nFileSizeLow: DWORD,
|
||||||
|
dwReserved0: DWORD,
|
||||||
|
dwReserved1: DWORD,
|
||||||
|
cFileName: [260]CHAR,
|
||||||
|
cAlternateFileName: [14]CHAR,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const FILETIME = extern struct {
|
||||||
|
dwLowDateTime: DWORD,
|
||||||
|
dwHighDateTime: DWORD,
|
||||||
|
};
|
||||||
|
|||||||
@ -42,7 +42,7 @@ pub const WriteError = error{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
|
pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
|
||||||
if (windows.WriteFile(handle, @ptrCast([*]const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
|
if (windows.WriteFile(handle, @ptrCast(*const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
|
||||||
const err = windows.GetLastError();
|
const err = windows.GetLastError();
|
||||||
return switch (err) {
|
return switch (err) {
|
||||||
windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
|
windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
|
||||||
@ -153,7 +153,7 @@ pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap)
|
|||||||
pub fn windowsLoadDll(allocator: *mem.Allocator, dll_path: []const u8) !windows.HMODULE {
|
pub fn windowsLoadDll(allocator: *mem.Allocator, dll_path: []const u8) !windows.HMODULE {
|
||||||
const padded_buff = try cstr.addNullByte(allocator, dll_path);
|
const padded_buff = try cstr.addNullByte(allocator, dll_path);
|
||||||
defer allocator.free(padded_buff);
|
defer allocator.free(padded_buff);
|
||||||
return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
|
return windows.LoadLibraryA(padded_buff.ptr) orelse error.DllNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
|
pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
|
||||||
@ -170,3 +170,42 @@ test "InvalidDll" {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn windowsFindFirstFile(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
dir_path: []const u8,
|
||||||
|
find_file_data: *windows.WIN32_FIND_DATAA,
|
||||||
|
) !windows.HANDLE {
|
||||||
|
const wild_and_null = []u8{ '\\', '*', 0 };
|
||||||
|
const path_with_wild_and_null = try allocator.alloc(u8, dir_path.len + wild_and_null.len);
|
||||||
|
defer allocator.free(path_with_wild_and_null);
|
||||||
|
|
||||||
|
mem.copy(u8, path_with_wild_and_null, dir_path);
|
||||||
|
mem.copy(u8, path_with_wild_and_null[dir_path.len..], wild_and_null);
|
||||||
|
|
||||||
|
const handle = windows.FindFirstFileA(path_with_wild_and_null.ptr, find_file_data);
|
||||||
|
|
||||||
|
if (handle == windows.INVALID_HANDLE_VALUE) {
|
||||||
|
const err = windows.GetLastError();
|
||||||
|
switch (err) {
|
||||||
|
windows.ERROR.FILE_NOT_FOUND,
|
||||||
|
windows.ERROR.PATH_NOT_FOUND,
|
||||||
|
=> return error.PathNotFound,
|
||||||
|
else => return os.unexpectedErrorWindows(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if there was another file, `false` otherwise.
|
||||||
|
pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAA) !bool {
|
||||||
|
if (windows.FindNextFileA(handle, find_file_data) == 0) {
|
||||||
|
const err = windows.GetLastError();
|
||||||
|
return switch (err) {
|
||||||
|
windows.ERROR.NO_MORE_FILES => false,
|
||||||
|
else => os.unexpectedErrorWindows(err),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -364,7 +364,7 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
|
|||||||
assert(x == 0);
|
assert(x == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(??list.pop() == 100);
|
assert(list.pop().? == 100);
|
||||||
assert(list.len == 99);
|
assert(list.len == 99);
|
||||||
|
|
||||||
try list.pushMany([]i32{
|
try list.pushMany([]i32{
|
||||||
@ -373,9 +373,9 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
|
|||||||
3,
|
3,
|
||||||
});
|
});
|
||||||
assert(list.len == 102);
|
assert(list.len == 102);
|
||||||
assert(??list.pop() == 3);
|
assert(list.pop().? == 3);
|
||||||
assert(??list.pop() == 2);
|
assert(list.pop().? == 2);
|
||||||
assert(??list.pop() == 1);
|
assert(list.pop().? == 1);
|
||||||
assert(list.len == 99);
|
assert(list.len == 99);
|
||||||
|
|
||||||
try list.pushMany([]const i32{});
|
try list.pushMany([]const i32{});
|
||||||
|
|||||||
@ -51,13 +51,13 @@ extern fn WinMainCRTStartup() noreturn {
|
|||||||
|
|
||||||
// TODO https://github.com/ziglang/zig/issues/265
|
// TODO https://github.com/ziglang/zig/issues/265
|
||||||
fn posixCallMainAndExit() noreturn {
|
fn posixCallMainAndExit() noreturn {
|
||||||
const argc = argc_ptr.*;
|
const argc = argc_ptr[0];
|
||||||
const argv = @ptrCast([*][*]u8, argc_ptr + 1);
|
const argv = @ptrCast([*][*]u8, argc_ptr + 1);
|
||||||
|
|
||||||
const envp_nullable = @ptrCast([*]?[*]u8, argv + argc + 1);
|
const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1);
|
||||||
var envp_count: usize = 0;
|
var envp_count: usize = 0;
|
||||||
while (envp_nullable[envp_count]) |_| : (envp_count += 1) {}
|
while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
|
||||||
const envp = @ptrCast([*][*]u8, envp_nullable)[0..envp_count];
|
const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
|
||||||
if (builtin.os == builtin.Os.linux) {
|
if (builtin.os == builtin.Os.linux) {
|
||||||
const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1);
|
const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1);
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
|
|||||||
@ -27,15 +27,15 @@ pub fn main() !void {
|
|||||||
// skip my own exe name
|
// skip my own exe name
|
||||||
_ = arg_it.skip();
|
_ = arg_it.skip();
|
||||||
|
|
||||||
const zig_exe = try unwrapArg(arg_it.next(allocator) ?? {
|
const zig_exe = try unwrapArg(arg_it.next(allocator) orelse {
|
||||||
warn("Expected first argument to be path to zig compiler\n");
|
warn("Expected first argument to be path to zig compiler\n");
|
||||||
return error.InvalidArgs;
|
return error.InvalidArgs;
|
||||||
});
|
});
|
||||||
const build_root = try unwrapArg(arg_it.next(allocator) ?? {
|
const build_root = try unwrapArg(arg_it.next(allocator) orelse {
|
||||||
warn("Expected second argument to be build root directory path\n");
|
warn("Expected second argument to be build root directory path\n");
|
||||||
return error.InvalidArgs;
|
return error.InvalidArgs;
|
||||||
});
|
});
|
||||||
const cache_root = try unwrapArg(arg_it.next(allocator) ?? {
|
const cache_root = try unwrapArg(arg_it.next(allocator) orelse {
|
||||||
warn("Expected third argument to be cache root directory path\n");
|
warn("Expected third argument to be cache root directory path\n");
|
||||||
return error.InvalidArgs;
|
return error.InvalidArgs;
|
||||||
});
|
});
|
||||||
@ -84,12 +84,12 @@ pub fn main() !void {
|
|||||||
} else if (mem.eql(u8, arg, "--help")) {
|
} else if (mem.eql(u8, arg, "--help")) {
|
||||||
return usage(&builder, false, try stdout_stream);
|
return usage(&builder, false, try stdout_stream);
|
||||||
} else if (mem.eql(u8, arg, "--prefix")) {
|
} else if (mem.eql(u8, arg, "--prefix")) {
|
||||||
prefix = try unwrapArg(arg_it.next(allocator) ?? {
|
prefix = try unwrapArg(arg_it.next(allocator) orelse {
|
||||||
warn("Expected argument after --prefix\n\n");
|
warn("Expected argument after --prefix\n\n");
|
||||||
return usageAndErr(&builder, false, try stderr_stream);
|
return usageAndErr(&builder, false, try stderr_stream);
|
||||||
});
|
});
|
||||||
} else if (mem.eql(u8, arg, "--search-prefix")) {
|
} else if (mem.eql(u8, arg, "--search-prefix")) {
|
||||||
const search_prefix = try unwrapArg(arg_it.next(allocator) ?? {
|
const search_prefix = try unwrapArg(arg_it.next(allocator) orelse {
|
||||||
warn("Expected argument after --search-prefix\n\n");
|
warn("Expected argument after --search-prefix\n\n");
|
||||||
return usageAndErr(&builder, false, try stderr_stream);
|
return usageAndErr(&builder, false, try stderr_stream);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {
|
|||||||
|
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
while (index != n) : (index += 1)
|
while (index != n) : (index += 1)
|
||||||
(??dest)[index] = c;
|
dest.?[index] = c;
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]
|
|||||||
|
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
while (index != n) : (index += 1)
|
while (index != n) : (index += 1)
|
||||||
(??dest)[index] = (??src)[index];
|
dest.?[index] = src.?[index];
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@ -40,13 +40,13 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {
|
|||||||
if (@ptrToInt(dest) < @ptrToInt(src)) {
|
if (@ptrToInt(dest) < @ptrToInt(src)) {
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
while (index != n) : (index += 1) {
|
while (index != n) : (index += 1) {
|
||||||
(??dest)[index] = (??src)[index];
|
dest.?[index] = src.?[index];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var index = n;
|
var index = n;
|
||||||
while (index != 0) {
|
while (index != 0) {
|
||||||
index -= 1;
|
index -= 1;
|
||||||
(??dest)[index] = (??src)[index];
|
dest.?[index] = src.?[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
std/special/compiler_rt/divti3.zig
Normal file
26
std/special/compiler_rt/divti3.zig
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const udivmod = @import("udivmod.zig").udivmod;
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const compiler_rt = @import("index.zig");
|
||||||
|
|
||||||
|
pub extern fn __divti3(a: i128, b: i128) i128 {
|
||||||
|
@setRuntimeSafety(builtin.is_test);
|
||||||
|
|
||||||
|
const s_a = a >> (i128.bit_count - 1);
|
||||||
|
const s_b = b >> (i128.bit_count - 1);
|
||||||
|
|
||||||
|
const an = (a ^ s_a) -% s_a;
|
||||||
|
const bn = (b ^ s_b) -% s_b;
|
||||||
|
|
||||||
|
const r = udivmod(u128, @bitCast(u128, an), @bitCast(u128, bn), null);
|
||||||
|
const s = s_a ^ s_b;
|
||||||
|
return (i128(r) ^ s) -% s;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern fn __divti3_windows_x86_64(a: *const i128, b: *const i128) void {
|
||||||
|
@setRuntimeSafety(builtin.is_test);
|
||||||
|
compiler_rt.setXmm0(i128, __divti3(a.*, b.*));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "import divti3" {
|
||||||
|
_ = @import("divti3_test.zig");
|
||||||
|
}
|
||||||
21
std/special/compiler_rt/divti3_test.zig
Normal file
21
std/special/compiler_rt/divti3_test.zig
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const __divti3 = @import("divti3.zig").__divti3;
|
||||||
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
|
fn test__divti3(a: i128, b: i128, expected: i128) void {
|
||||||
|
const x = __divti3(a, b);
|
||||||
|
assert(x == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "divti3" {
|
||||||
|
test__divti3(0, 1, 0);
|
||||||
|
test__divti3(0, -1, 0);
|
||||||
|
test__divti3(2, 1, 2);
|
||||||
|
test__divti3(2, -1, -2);
|
||||||
|
test__divti3(-2, 1, -2);
|
||||||
|
test__divti3(-2, -1, 2);
|
||||||
|
|
||||||
|
test__divti3(@bitCast(i128, u128(0x8 << 124)), 1, @bitCast(i128, u128(0x8 << 124)));
|
||||||
|
test__divti3(@bitCast(i128, u128(0x8 << 124)), -1, @bitCast(i128, u128(0x8 << 124)));
|
||||||
|
test__divti3(@bitCast(i128, u128(0x8 << 124)), -2, @bitCast(i128, u128(0x4 << 124)));
|
||||||
|
test__divti3(@bitCast(i128, u128(0x8 << 124)), 2, @bitCast(i128, u128(0xc << 124)));
|
||||||
|
}
|
||||||
@ -58,6 +58,8 @@ comptime {
|
|||||||
@export("__chkstk", __chkstk, strong_linkage);
|
@export("__chkstk", __chkstk, strong_linkage);
|
||||||
@export("___chkstk_ms", ___chkstk_ms, linkage);
|
@export("___chkstk_ms", ___chkstk_ms, linkage);
|
||||||
}
|
}
|
||||||
|
@export("__divti3", @import("divti3.zig").__divti3_windows_x86_64, linkage);
|
||||||
|
@export("__muloti4", @import("muloti4.zig").__muloti4_windows_x86_64, linkage);
|
||||||
@export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage);
|
@export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage);
|
||||||
@export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
|
@export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
|
||||||
@export("__umodti3", @import("umodti3.zig").__umodti3_windows_x86_64, linkage);
|
@export("__umodti3", @import("umodti3.zig").__umodti3_windows_x86_64, linkage);
|
||||||
@ -65,6 +67,8 @@ comptime {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@export("__divti3", @import("divti3.zig").__divti3, linkage);
|
||||||
|
@export("__muloti4", @import("muloti4.zig").__muloti4, linkage);
|
||||||
@export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
|
@export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
|
||||||
@export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
|
@export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
|
||||||
@export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
|
@export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
|
||||||
|
|||||||
55
std/special/compiler_rt/muloti4.zig
Normal file
55
std/special/compiler_rt/muloti4.zig
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
const udivmod = @import("udivmod.zig").udivmod;
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const compiler_rt = @import("index.zig");
|
||||||
|
|
||||||
|
pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {
|
||||||
|
@setRuntimeSafety(builtin.is_test);
|
||||||
|
|
||||||
|
const min = @bitCast(i128, u128(1 << (i128.bit_count - 1)));
|
||||||
|
const max = ~min;
|
||||||
|
overflow.* = 0;
|
||||||
|
|
||||||
|
const r = a *% b;
|
||||||
|
if (a == min) {
|
||||||
|
if (b != 0 and b != 1) {
|
||||||
|
overflow.* = 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (b == min) {
|
||||||
|
if (a != 0 and a != 1) {
|
||||||
|
overflow.* = 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sa = a >> (i128.bit_count - 1);
|
||||||
|
const abs_a = (a ^ sa) -% sa;
|
||||||
|
const sb = b >> (i128.bit_count - 1);
|
||||||
|
const abs_b = (b ^ sb) -% sb;
|
||||||
|
|
||||||
|
if (abs_a < 2 or abs_b < 2) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sa == sb) {
|
||||||
|
if (abs_a > @divFloor(max, abs_b)) {
|
||||||
|
overflow.* = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (abs_a > @divFloor(min, -abs_b)) {
|
||||||
|
overflow.* = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern fn __muloti4_windows_x86_64(a: *const i128, b: *const i128, overflow: *c_int) void {
|
||||||
|
@setRuntimeSafety(builtin.is_test);
|
||||||
|
compiler_rt.setXmm0(i128, __muloti4(a.*, b.*, overflow));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "import muloti4" {
|
||||||
|
_ = @import("muloti4_test.zig");
|
||||||
|
}
|
||||||
76
std/special/compiler_rt/muloti4_test.zig
Normal file
76
std/special/compiler_rt/muloti4_test.zig
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
const __muloti4 = @import("muloti4.zig").__muloti4;
|
||||||
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
|
fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) void {
|
||||||
|
var overflow: c_int = undefined;
|
||||||
|
const x = __muloti4(a, b, &overflow);
|
||||||
|
assert(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "muloti4" {
|
||||||
|
test__muloti4(0, 0, 0, 0);
|
||||||
|
test__muloti4(0, 1, 0, 0);
|
||||||
|
test__muloti4(1, 0, 0, 0);
|
||||||
|
test__muloti4(0, 10, 0, 0);
|
||||||
|
test__muloti4(10, 0, 0, 0);
|
||||||
|
|
||||||
|
test__muloti4(0, 81985529216486895, 0, 0);
|
||||||
|
test__muloti4(81985529216486895, 0, 0, 0);
|
||||||
|
|
||||||
|
test__muloti4(0, -1, 0, 0);
|
||||||
|
test__muloti4(-1, 0, 0, 0);
|
||||||
|
test__muloti4(0, -10, 0, 0);
|
||||||
|
test__muloti4(-10, 0, 0, 0);
|
||||||
|
test__muloti4(0, -81985529216486895, 0, 0);
|
||||||
|
test__muloti4(-81985529216486895, 0, 0, 0);
|
||||||
|
|
||||||
|
test__muloti4(3037000499, 3037000499, 9223372030926249001, 0);
|
||||||
|
test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0);
|
||||||
|
test__muloti4(3037000499, -3037000499, -9223372030926249001, 0);
|
||||||
|
test__muloti4(-3037000499, -3037000499, 9223372030926249001, 0);
|
||||||
|
|
||||||
|
test__muloti4(4398046511103, 2097152, 9223372036852678656, 0);
|
||||||
|
test__muloti4(-4398046511103, 2097152, -9223372036852678656, 0);
|
||||||
|
test__muloti4(4398046511103, -2097152, -9223372036852678656, 0);
|
||||||
|
test__muloti4(-4398046511103, -2097152, 9223372036852678656, 0);
|
||||||
|
|
||||||
|
test__muloti4(2097152, 4398046511103, 9223372036852678656, 0);
|
||||||
|
test__muloti4(-2097152, 4398046511103, -9223372036852678656, 0);
|
||||||
|
test__muloti4(2097152, -4398046511103, -9223372036852678656, 0);
|
||||||
|
test__muloti4(-2097152, -4398046511103, 9223372036852678656, 0);
|
||||||
|
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x00000000000000B504F333F9DE5BE000)), @bitCast(i128, u128(0x000000000000000000B504F333F9DE5B)), @bitCast(i128, u128(0x7FFFFFFFFFFFF328DF915DA296E8A000)), 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), -2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
|
||||||
|
test__muloti4(-2, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
|
||||||
|
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), -1, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
|
||||||
|
test__muloti4(-1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0, 0, 0);
|
||||||
|
test__muloti4(0, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0, 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
|
||||||
|
test__muloti4(1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
|
||||||
|
test__muloti4(2, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
|
||||||
|
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), -2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
test__muloti4(-2, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), -1, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
test__muloti4(-1, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 0, 0, 0);
|
||||||
|
test__muloti4(0, @bitCast(i128, u128(0x80000000000000000000000000000000)), 0, 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 1, @bitCast(i128, u128(0x80000000000000000000000000000000)), 0);
|
||||||
|
test__muloti4(1, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000000)), 2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
test__muloti4(2, @bitCast(i128, u128(0x80000000000000000000000000000000)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), -2, @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
|
||||||
|
test__muloti4(-2, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 1);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), -1, @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
|
||||||
|
test__muloti4(-1, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 0, 0, 0);
|
||||||
|
test__muloti4(0, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0, 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 1, @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
|
||||||
|
test__muloti4(1, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000001)), 0);
|
||||||
|
test__muloti4(@bitCast(i128, u128(0x80000000000000000000000000000001)), 2, @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
test__muloti4(2, @bitCast(i128, u128(0x80000000000000000000000000000001)), @bitCast(i128, u128(0x80000000000000000000000000000000)), 1);
|
||||||
|
}
|
||||||
@ -220,7 +220,7 @@ const Utf8Iterator = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn nextCodepoint(it: *Utf8Iterator) ?u32 {
|
pub fn nextCodepoint(it: *Utf8Iterator) ?u32 {
|
||||||
const slice = it.nextCodepointSlice() ?? return null;
|
const slice = it.nextCodepointSlice() orelse return null;
|
||||||
|
|
||||||
switch (slice.len) {
|
switch (slice.len) {
|
||||||
1 => return u32(slice[0]),
|
1 => return u32(slice[0]),
|
||||||
@ -286,15 +286,15 @@ fn testUtf8IteratorOnAscii() void {
|
|||||||
const s = Utf8View.initComptime("abc");
|
const s = Utf8View.initComptime("abc");
|
||||||
|
|
||||||
var it1 = s.iterator();
|
var it1 = s.iterator();
|
||||||
debug.assert(std.mem.eql(u8, "a", ??it1.nextCodepointSlice()));
|
debug.assert(std.mem.eql(u8, "a", it1.nextCodepointSlice().?));
|
||||||
debug.assert(std.mem.eql(u8, "b", ??it1.nextCodepointSlice()));
|
debug.assert(std.mem.eql(u8, "b", it1.nextCodepointSlice().?));
|
||||||
debug.assert(std.mem.eql(u8, "c", ??it1.nextCodepointSlice()));
|
debug.assert(std.mem.eql(u8, "c", it1.nextCodepointSlice().?));
|
||||||
debug.assert(it1.nextCodepointSlice() == null);
|
debug.assert(it1.nextCodepointSlice() == null);
|
||||||
|
|
||||||
var it2 = s.iterator();
|
var it2 = s.iterator();
|
||||||
debug.assert(??it2.nextCodepoint() == 'a');
|
debug.assert(it2.nextCodepoint().? == 'a');
|
||||||
debug.assert(??it2.nextCodepoint() == 'b');
|
debug.assert(it2.nextCodepoint().? == 'b');
|
||||||
debug.assert(??it2.nextCodepoint() == 'c');
|
debug.assert(it2.nextCodepoint().? == 'c');
|
||||||
debug.assert(it2.nextCodepoint() == null);
|
debug.assert(it2.nextCodepoint() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,15 +321,15 @@ fn testUtf8ViewOk() void {
|
|||||||
const s = Utf8View.initComptime("東京市");
|
const s = Utf8View.initComptime("東京市");
|
||||||
|
|
||||||
var it1 = s.iterator();
|
var it1 = s.iterator();
|
||||||
debug.assert(std.mem.eql(u8, "東", ??it1.nextCodepointSlice()));
|
debug.assert(std.mem.eql(u8, "東", it1.nextCodepointSlice().?));
|
||||||
debug.assert(std.mem.eql(u8, "京", ??it1.nextCodepointSlice()));
|
debug.assert(std.mem.eql(u8, "京", it1.nextCodepointSlice().?));
|
||||||
debug.assert(std.mem.eql(u8, "市", ??it1.nextCodepointSlice()));
|
debug.assert(std.mem.eql(u8, "市", it1.nextCodepointSlice().?));
|
||||||
debug.assert(it1.nextCodepointSlice() == null);
|
debug.assert(it1.nextCodepointSlice() == null);
|
||||||
|
|
||||||
var it2 = s.iterator();
|
var it2 = s.iterator();
|
||||||
debug.assert(??it2.nextCodepoint() == 0x6771);
|
debug.assert(it2.nextCodepoint().? == 0x6771);
|
||||||
debug.assert(??it2.nextCodepoint() == 0x4eac);
|
debug.assert(it2.nextCodepoint().? == 0x4eac);
|
||||||
debug.assert(??it2.nextCodepoint() == 0x5e02);
|
debug.assert(it2.nextCodepoint().? == 0x5e02);
|
||||||
debug.assert(it2.nextCodepoint() == null);
|
debug.assert(it2.nextCodepoint() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -734,7 +734,7 @@ pub const Node = struct {
|
|||||||
var i = index;
|
var i = index;
|
||||||
|
|
||||||
if (self.doc_comments) |comments| {
|
if (self.doc_comments) |comments| {
|
||||||
if (i < 1) return *comments.base;
|
if (i < 1) return &comments.base;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,7 +1243,7 @@ pub const Node = struct {
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
||||||
if (self.@"else") |@"else"| {
|
if (self.@"else") |@"else"| {
|
||||||
if (i < 1) return *@"else".base;
|
if (i < 1) return &@"else".base;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1296,7 +1296,7 @@ pub const Node = struct {
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
||||||
if (self.@"else") |@"else"| {
|
if (self.@"else") |@"else"| {
|
||||||
if (i < 1) return *@"else".base;
|
if (i < 1) return &@"else".base;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1347,7 +1347,7 @@ pub const Node = struct {
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
||||||
if (self.@"else") |@"else"| {
|
if (self.@"else") |@"else"| {
|
||||||
if (i < 1) return *@"else".base;
|
if (i < 1) return &@"else".base;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1417,7 +1417,7 @@ pub const Node = struct {
|
|||||||
Range,
|
Range,
|
||||||
Sub,
|
Sub,
|
||||||
SubWrap,
|
SubWrap,
|
||||||
UnwrapMaybe,
|
UnwrapOptional,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn iterate(self: *InfixOp, index: usize) ?*Node {
|
pub fn iterate(self: *InfixOp, index: usize) ?*Node {
|
||||||
@ -1475,7 +1475,7 @@ pub const Node = struct {
|
|||||||
Op.Range,
|
Op.Range,
|
||||||
Op.Sub,
|
Op.Sub,
|
||||||
Op.SubWrap,
|
Op.SubWrap,
|
||||||
Op.UnwrapMaybe,
|
Op.UnwrapOptional,
|
||||||
=> {},
|
=> {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1507,14 +1507,13 @@ pub const Node = struct {
|
|||||||
BitNot,
|
BitNot,
|
||||||
BoolNot,
|
BoolNot,
|
||||||
Cancel,
|
Cancel,
|
||||||
MaybeType,
|
OptionalType,
|
||||||
Negation,
|
Negation,
|
||||||
NegationWrap,
|
NegationWrap,
|
||||||
Resume,
|
Resume,
|
||||||
PtrType: PtrInfo,
|
PtrType: PtrInfo,
|
||||||
SliceType: PtrInfo,
|
SliceType: PtrInfo,
|
||||||
Try,
|
Try,
|
||||||
UnwrapMaybe,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PtrInfo = struct {
|
pub const PtrInfo = struct {
|
||||||
@ -1537,33 +1536,36 @@ pub const Node = struct {
|
|||||||
var i = index;
|
var i = index;
|
||||||
|
|
||||||
switch (self.op) {
|
switch (self.op) {
|
||||||
|
// TODO https://github.com/ziglang/zig/issues/1107
|
||||||
Op.SliceType => |addr_of_info| {
|
Op.SliceType => |addr_of_info| {
|
||||||
if (addr_of_info.align_info) |align_info| {
|
if (addr_of_info.align_info) |align_info| {
|
||||||
if (i < 1) return align_info.node;
|
if (i < 1) return align_info.node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Op.AddrOf => |addr_of_info| {
|
|
||||||
|
Op.PtrType => |addr_of_info| {
|
||||||
if (addr_of_info.align_info) |align_info| {
|
if (addr_of_info.align_info) |align_info| {
|
||||||
if (i < 1) return align_info.node;
|
if (i < 1) return align_info.node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Op.ArrayType => |size_expr| {
|
Op.ArrayType => |size_expr| {
|
||||||
if (i < 1) return size_expr;
|
if (i < 1) return size_expr;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Op.AddressOf,
|
||||||
Op.Await,
|
Op.Await,
|
||||||
Op.BitNot,
|
Op.BitNot,
|
||||||
Op.BoolNot,
|
Op.BoolNot,
|
||||||
Op.Cancel,
|
Op.Cancel,
|
||||||
Op.MaybeType,
|
Op.OptionalType,
|
||||||
Op.Negation,
|
Op.Negation,
|
||||||
Op.NegationWrap,
|
Op.NegationWrap,
|
||||||
Op.Try,
|
Op.Try,
|
||||||
Op.Resume,
|
Op.Resume,
|
||||||
Op.UnwrapMaybe,
|
|
||||||
Op.PointerType,
|
|
||||||
=> {},
|
=> {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1619,6 +1621,7 @@ pub const Node = struct {
|
|||||||
ArrayInitializer: InitList,
|
ArrayInitializer: InitList,
|
||||||
StructInitializer: InitList,
|
StructInitializer: InitList,
|
||||||
Deref,
|
Deref,
|
||||||
|
UnwrapOptional,
|
||||||
|
|
||||||
pub const InitList = SegmentedList(*Node, 2);
|
pub const InitList = SegmentedList(*Node, 2);
|
||||||
|
|
||||||
@ -1667,7 +1670,9 @@ pub const Node = struct {
|
|||||||
if (i < fields.len) return fields.at(i).*;
|
if (i < fields.len) return fields.at(i).*;
|
||||||
i -= fields.len;
|
i -= fields.len;
|
||||||
},
|
},
|
||||||
Op.Deref => {},
|
Op.UnwrapOptional,
|
||||||
|
Op.Deref,
|
||||||
|
=> {},
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -2022,7 +2027,7 @@ pub const Node = struct {
|
|||||||
|
|
||||||
switch (self.kind) {
|
switch (self.kind) {
|
||||||
Kind.Variable => |variable_name| {
|
Kind.Variable => |variable_name| {
|
||||||
if (i < 1) return *variable_name.base;
|
if (i < 1) return &variable_name.base;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
},
|
},
|
||||||
Kind.Return => |return_type| {
|
Kind.Return => |return_type| {
|
||||||
@ -2092,10 +2097,10 @@ pub const Node = struct {
|
|||||||
pub fn iterate(self: *Asm, index: usize) ?*Node {
|
pub fn iterate(self: *Asm, index: usize) ?*Node {
|
||||||
var i = index;
|
var i = index;
|
||||||
|
|
||||||
if (i < self.outputs.len) return *(self.outputs.at(index).*).base;
|
if (i < self.outputs.len) return &self.outputs.at(index).*.base;
|
||||||
i -= self.outputs.len;
|
i -= self.outputs.len;
|
||||||
|
|
||||||
if (i < self.inputs.len) return *(self.inputs.at(index).*).base;
|
if (i < self.inputs.len) return &self.inputs.at(index).*.base;
|
||||||
i -= self.inputs.len;
|
i -= self.inputs.len;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -2205,3 +2210,14 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test "iterate" {
|
||||||
|
var root = Node.Root{
|
||||||
|
.base = Node{ .id = Node.Id.Root },
|
||||||
|
.doc_comments = null,
|
||||||
|
.decls = Node.Root.DeclList.init(std.debug.global_allocator),
|
||||||
|
.eof_token = 0,
|
||||||
|
};
|
||||||
|
var base = &root.base;
|
||||||
|
assert(base.iterate(0) == null);
|
||||||
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
|
|
||||||
// skip over line comments at the top of the file
|
// skip over line comments at the top of the file
|
||||||
while (true) {
|
while (true) {
|
||||||
const next_tok = tok_it.peek() ?? break;
|
const next_tok = tok_it.peek() orelse break;
|
||||||
if (next_tok.id != Token.Id.LineComment) break;
|
if (next_tok.id != Token.Id.LineComment) break;
|
||||||
_ = tok_it.next();
|
_ = tok_it.next();
|
||||||
}
|
}
|
||||||
@ -197,7 +197,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
const lib_name_token = nextToken(&tok_it, &tree);
|
const lib_name_token = nextToken(&tok_it, &tree);
|
||||||
const lib_name_token_index = lib_name_token.index;
|
const lib_name_token_index = lib_name_token.index;
|
||||||
const lib_name_token_ptr = lib_name_token.ptr;
|
const lib_name_token_ptr = lib_name_token.ptr;
|
||||||
break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
|
break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) orelse {
|
||||||
prevToken(&tok_it, &tree);
|
prevToken(&tok_it, &tree);
|
||||||
break :blk null;
|
break :blk null;
|
||||||
};
|
};
|
||||||
@ -711,7 +711,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
else => {
|
else => {
|
||||||
// TODO: this is a special case. Remove this when #760 is fixed
|
// TODO: this is a special case. Remove this when #760 is fixed
|
||||||
if (token_ptr.id == Token.Id.Keyword_error) {
|
if (token_ptr.id == Token.Id.Keyword_error) {
|
||||||
if ((??tok_it.peek()).id == Token.Id.LBrace) {
|
if (tok_it.peek().?.id == Token.Id.LBrace) {
|
||||||
const error_type_node = try arena.construct(ast.Node.ErrorType{
|
const error_type_node = try arena.construct(ast.Node.ErrorType{
|
||||||
.base = ast.Node{ .id = ast.Node.Id.ErrorType },
|
.base = ast.Node{ .id = ast.Node.Id.ErrorType },
|
||||||
.token = token_index,
|
.token = token_index,
|
||||||
@ -1434,14 +1434,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
try stack.append(State{
|
try stack.append(State{
|
||||||
.ExpectTokenSave = ExpectTokenSave{
|
.ExpectTokenSave = ExpectTokenSave{
|
||||||
.id = Token.Id.AngleBracketRight,
|
.id = Token.Id.AngleBracketRight,
|
||||||
.ptr = &??async_node.rangle_bracket,
|
.ptr = &async_node.rangle_bracket.?,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } });
|
try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } });
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
State.AsyncEnd => |ctx| {
|
State.AsyncEnd => |ctx| {
|
||||||
const node = ctx.ctx.get() ?? continue;
|
const node = ctx.ctx.get() orelse continue;
|
||||||
|
|
||||||
switch (node.id) {
|
switch (node.id) {
|
||||||
ast.Node.Id.FnProto => {
|
ast.Node.Id.FnProto => {
|
||||||
@ -1567,7 +1567,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
.bit_range = null,
|
.bit_range = null,
|
||||||
};
|
};
|
||||||
// TODO https://github.com/ziglang/zig/issues/1022
|
// TODO https://github.com/ziglang/zig/issues/1022
|
||||||
const align_info = &??addr_of_info.align_info;
|
const align_info = &addr_of_info.align_info.?;
|
||||||
|
|
||||||
try stack.append(State{ .AlignBitRange = align_info });
|
try stack.append(State{ .AlignBitRange = align_info });
|
||||||
try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } });
|
try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } });
|
||||||
@ -1604,7 +1604,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
switch (token.ptr.id) {
|
switch (token.ptr.id) {
|
||||||
Token.Id.Colon => {
|
Token.Id.Colon => {
|
||||||
align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined);
|
align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined);
|
||||||
const bit_range = &??align_info.bit_range;
|
const bit_range = &align_info.bit_range.?;
|
||||||
|
|
||||||
try stack.append(State{ .ExpectToken = Token.Id.RParen });
|
try stack.append(State{ .ExpectToken = Token.Id.RParen });
|
||||||
try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } });
|
try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } });
|
||||||
@ -1814,7 +1814,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
State.RangeExpressionEnd => |opt_ctx| {
|
State.RangeExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
|
if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -1836,7 +1836,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.AssignmentExpressionEnd => |opt_ctx| {
|
State.AssignmentExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -1866,7 +1866,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.UnwrapExpressionEnd => |opt_ctx| {
|
State.UnwrapExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -1901,7 +1901,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.BoolOrExpressionEnd => |opt_ctx| {
|
State.BoolOrExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
|
if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -1925,7 +1925,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.BoolAndExpressionEnd => |opt_ctx| {
|
State.BoolAndExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
|
if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -1949,7 +1949,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.ComparisonExpressionEnd => |opt_ctx| {
|
State.ComparisonExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -1979,7 +1979,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.BinaryOrExpressionEnd => |opt_ctx| {
|
State.BinaryOrExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
|
if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -2003,7 +2003,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.BinaryXorExpressionEnd => |opt_ctx| {
|
State.BinaryXorExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
|
if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -2027,7 +2027,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.BinaryAndExpressionEnd => |opt_ctx| {
|
State.BinaryAndExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
|
if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -2051,7 +2051,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.BitShiftExpressionEnd => |opt_ctx| {
|
State.BitShiftExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -2081,7 +2081,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.AdditionExpressionEnd => |opt_ctx| {
|
State.AdditionExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -2111,7 +2111,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.MultiplyExpressionEnd => |opt_ctx| {
|
State.MultiplyExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -2142,9 +2142,9 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.CurlySuffixExpressionEnd => |opt_ctx| {
|
State.CurlySuffixExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if ((??tok_it.peek()).id == Token.Id.Period) {
|
if (tok_it.peek().?.id == Token.Id.Period) {
|
||||||
const node = try arena.construct(ast.Node.SuffixOp{
|
const node = try arena.construct(ast.Node.SuffixOp{
|
||||||
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
|
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
|
||||||
.lhs = lhs,
|
.lhs = lhs,
|
||||||
@ -2190,7 +2190,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.TypeExprEnd => |opt_ctx| {
|
State.TypeExprEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
|
if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
@ -2270,7 +2270,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State.SuffixOpExpressionEnd => |opt_ctx| {
|
State.SuffixOpExpressionEnd => |opt_ctx| {
|
||||||
const lhs = opt_ctx.get() ?? continue;
|
const lhs = opt_ctx.get() orelse continue;
|
||||||
|
|
||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
@ -2326,6 +2326,17 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
|
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| {
|
||||||
|
const node = try arena.construct(ast.Node.SuffixOp{
|
||||||
|
.base = ast.Node{ .id = ast.Node.Id.SuffixOp },
|
||||||
|
.lhs = lhs,
|
||||||
|
.op = ast.Node.SuffixOp.Op.UnwrapOptional,
|
||||||
|
.rtoken = question_token,
|
||||||
|
});
|
||||||
|
opt_ctx.store(&node.base);
|
||||||
|
stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const node = try arena.construct(ast.Node.InfixOp{
|
const node = try arena.construct(ast.Node.InfixOp{
|
||||||
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
|
.base = ast.Node{ .id = ast.Node.Id.InfixOp },
|
||||||
.lhs = lhs,
|
.lhs = lhs,
|
||||||
@ -2403,12 +2414,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
.arrow_token = next_token_index,
|
.arrow_token = next_token_index,
|
||||||
.return_type = undefined,
|
.return_type = undefined,
|
||||||
};
|
};
|
||||||
const return_type_ptr = &((??node.result).return_type);
|
const return_type_ptr = &node.result.?.return_type;
|
||||||
try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } });
|
try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } });
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
|
Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
|
||||||
opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);
|
opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) orelse unreachable);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
Token.Id.LParen => {
|
Token.Id.LParen => {
|
||||||
@ -2638,7 +2649,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
|||||||
const token = nextToken(&tok_it, &tree);
|
const token = nextToken(&tok_it, &tree);
|
||||||
const token_index = token.index;
|
const token_index = token.index;
|
||||||
const token_ptr = token.ptr;
|
const token_ptr = token.ptr;
|
||||||
opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
|
opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) orelse {
|
||||||
prevToken(&tok_it, &tree);
|
prevToken(&tok_it, &tree);
|
||||||
if (opt_ctx != OptionalCtx.Optional) {
|
if (opt_ctx != OptionalCtx.Optional) {
|
||||||
((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
|
((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
|
||||||
@ -2875,7 +2886,7 @@ const OptionalCtx = union(enum) {
|
|||||||
pub fn get(self: *const OptionalCtx) ?*ast.Node {
|
pub fn get(self: *const OptionalCtx) ?*ast.Node {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
OptionalCtx.Optional => |ptr| return ptr.*,
|
OptionalCtx.Optional => |ptr| return ptr.*,
|
||||||
OptionalCtx.RequiredNull => |ptr| return ??ptr.*,
|
OptionalCtx.RequiredNull => |ptr| return ptr.*.?,
|
||||||
OptionalCtx.Required => |ptr| return ptr.*,
|
OptionalCtx.Required => |ptr| return ptr.*,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3237,7 +3248,7 @@ fn tokenIdToAssignment(id: *const Token.Id) ?ast.Node.InfixOp.Op {
|
|||||||
fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
|
fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
|
||||||
return switch (id) {
|
return switch (id) {
|
||||||
Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null },
|
Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null },
|
||||||
Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op{ .UnwrapMaybe = void{} },
|
Token.Id.Keyword_orelse => ast.Node.InfixOp.Op{ .UnwrapOptional = void{} },
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -3299,8 +3310,7 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
|
|||||||
.volatile_token = null,
|
.volatile_token = null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .MaybeType = void{} },
|
Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} },
|
||||||
Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op{ .UnwrapMaybe = void{} },
|
|
||||||
Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} },
|
Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} },
|
||||||
Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
|
Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
|
||||||
else => null,
|
else => null,
|
||||||
@ -3322,7 +3332,7 @@ fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: *const OptionalCtx, compti
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
|
fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
|
||||||
const token = ??tok_it.peek();
|
const token = tok_it.peek().?;
|
||||||
|
|
||||||
if (token.id == id) {
|
if (token.id == id) {
|
||||||
return nextToken(tok_it, tree).index;
|
return nextToken(tok_it, tree).index;
|
||||||
@ -3334,12 +3344,12 @@ fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(
|
|||||||
fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedToken {
|
fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedToken {
|
||||||
const result = AnnotatedToken{
|
const result = AnnotatedToken{
|
||||||
.index = tok_it.index,
|
.index = tok_it.index,
|
||||||
.ptr = ??tok_it.next(),
|
.ptr = tok_it.next().?,
|
||||||
};
|
};
|
||||||
assert(result.ptr.id != Token.Id.LineComment);
|
assert(result.ptr.id != Token.Id.LineComment);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const next_tok = tok_it.peek() ?? return result;
|
const next_tok = tok_it.peek() orelse return result;
|
||||||
if (next_tok.id != Token.Id.LineComment) return result;
|
if (next_tok.id != Token.Id.LineComment) return result;
|
||||||
_ = tok_it.next();
|
_ = tok_it.next();
|
||||||
}
|
}
|
||||||
@ -3347,7 +3357,7 @@ fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedTok
|
|||||||
|
|
||||||
fn prevToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) void {
|
fn prevToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) void {
|
||||||
while (true) {
|
while (true) {
|
||||||
const prev_tok = tok_it.prev() ?? return;
|
const prev_tok = tok_it.prev() orelse return;
|
||||||
if (prev_tok.id == Token.Id.LineComment) continue;
|
if (prev_tok.id == Token.Id.LineComment) continue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -650,9 +650,10 @@ test "zig fmt: statements with empty line between" {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "zig fmt: ptr deref operator" {
|
test "zig fmt: ptr deref operator and unwrap optional operator" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const a = b.*;
|
\\const a = b.*;
|
||||||
|
\\const a = b.?;
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1150,7 +1151,7 @@ test "zig fmt: infix operators" {
|
|||||||
\\ _ = i!i;
|
\\ _ = i!i;
|
||||||
\\ _ = i ** i;
|
\\ _ = i ** i;
|
||||||
\\ _ = i ++ i;
|
\\ _ = i ++ i;
|
||||||
\\ _ = i ?? i;
|
\\ _ = i orelse i;
|
||||||
\\ _ = i % i;
|
\\ _ = i % i;
|
||||||
\\ _ = i / i;
|
\\ _ = i / i;
|
||||||
\\ _ = i *% i;
|
\\ _ = i *% i;
|
||||||
@ -1209,7 +1210,7 @@ test "zig fmt: precedence" {
|
|||||||
test "zig fmt: prefix operators" {
|
test "zig fmt: prefix operators" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\test "prefix operators" {
|
\\test "prefix operators" {
|
||||||
\\ try return --%~??!*&0;
|
\\ try return --%~!*&0;
|
||||||
\\}
|
\\}
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
|
|||||||
@ -83,7 +83,7 @@ fn renderRoot(
|
|||||||
var start_col: usize = 0;
|
var start_col: usize = 0;
|
||||||
var it = tree.root_node.decls.iterator(0);
|
var it = tree.root_node.decls.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
var decl = (it.next() ?? return).*;
|
var decl = (it.next() orelse return).*;
|
||||||
// look for zig fmt: off comment
|
// look for zig fmt: off comment
|
||||||
var start_token_index = decl.firstToken();
|
var start_token_index = decl.firstToken();
|
||||||
zig_fmt_loop: while (start_token_index != 0) {
|
zig_fmt_loop: while (start_token_index != 0) {
|
||||||
@ -112,7 +112,7 @@ fn renderRoot(
|
|||||||
const start = tree.tokens.at(start_token_index + 1).start;
|
const start = tree.tokens.at(start_token_index + 1).start;
|
||||||
try stream.print("{}\n", tree.source[start..end_token.end]);
|
try stream.print("{}\n", tree.source[start..end_token.end]);
|
||||||
while (tree.tokens.at(decl.firstToken()).start < end_token.end) {
|
while (tree.tokens.at(decl.firstToken()).start < end_token.end) {
|
||||||
decl = (it.next() ?? return).*;
|
decl = (it.next() orelse return).*;
|
||||||
}
|
}
|
||||||
break :zig_fmt_loop;
|
break :zig_fmt_loop;
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const value_expr = ??tag.value_expr;
|
const value_expr = tag.value_expr.?;
|
||||||
try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, start_col, Space.Space); // =
|
try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, start_col, Space.Space); // =
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, value_expr, Space.Comma); // value,
|
try renderExpression(allocator, stream, tree, indent, start_col, value_expr, Space.Comma); // value,
|
||||||
},
|
},
|
||||||
@ -465,8 +465,7 @@ fn renderExpression(
|
|||||||
ast.Node.PrefixOp.Op.BoolNot,
|
ast.Node.PrefixOp.Op.BoolNot,
|
||||||
ast.Node.PrefixOp.Op.Negation,
|
ast.Node.PrefixOp.Op.Negation,
|
||||||
ast.Node.PrefixOp.Op.NegationWrap,
|
ast.Node.PrefixOp.Op.NegationWrap,
|
||||||
ast.Node.PrefixOp.Op.UnwrapMaybe,
|
ast.Node.PrefixOp.Op.OptionalType,
|
||||||
ast.Node.PrefixOp.Op.MaybeType,
|
|
||||||
ast.Node.PrefixOp.Op.AddressOf,
|
ast.Node.PrefixOp.Op.AddressOf,
|
||||||
=> {
|
=> {
|
||||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None);
|
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None);
|
||||||
@ -513,7 +512,7 @@ fn renderExpression(
|
|||||||
|
|
||||||
var it = call_info.params.iterator(0);
|
var it = call_info.params.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const param_node = ??it.next();
|
const param_node = it.next().?;
|
||||||
|
|
||||||
const param_node_new_indent = if (param_node.*.id == ast.Node.Id.MultilineStringLiteral) blk: {
|
const param_node_new_indent = if (param_node.*.id == ast.Node.Id.MultilineStringLiteral) blk: {
|
||||||
break :blk indent;
|
break :blk indent;
|
||||||
@ -559,10 +558,10 @@ fn renderExpression(
|
|||||||
return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
|
return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
|
||||||
},
|
},
|
||||||
|
|
||||||
ast.Node.SuffixOp.Op.Deref => {
|
ast.Node.SuffixOp.Op.Deref, ast.Node.SuffixOp.Op.UnwrapOptional => {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||||
try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
|
try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
|
||||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // *
|
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // * or ?
|
||||||
},
|
},
|
||||||
|
|
||||||
@TagType(ast.Node.SuffixOp.Op).Slice => |range| {
|
@TagType(ast.Node.SuffixOp.Op).Slice => |range| {
|
||||||
@ -595,7 +594,7 @@ fn renderExpression(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (field_inits.len == 1) blk: {
|
if (field_inits.len == 1) blk: {
|
||||||
const field_init = ??field_inits.at(0).*.cast(ast.Node.FieldInitializer);
|
const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?;
|
||||||
|
|
||||||
if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| {
|
if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| {
|
||||||
if (nested_suffix_op.op == ast.Node.SuffixOp.Op.StructInitializer) {
|
if (nested_suffix_op.op == ast.Node.SuffixOp.Op.StructInitializer) {
|
||||||
@ -688,7 +687,7 @@ fn renderExpression(
|
|||||||
var count: usize = 1;
|
var count: usize = 1;
|
||||||
var it = exprs.iterator(0);
|
var it = exprs.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const expr = (??it.next()).*;
|
const expr = it.next().?.*;
|
||||||
if (it.peek()) |next_expr| {
|
if (it.peek()) |next_expr| {
|
||||||
const expr_last_token = expr.*.lastToken() + 1;
|
const expr_last_token = expr.*.lastToken() + 1;
|
||||||
const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken());
|
const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken());
|
||||||
@ -806,7 +805,7 @@ fn renderExpression(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderExpression(allocator, stream, tree, indent, start_col, ??flow_expr.rhs, space);
|
return renderExpression(allocator, stream, tree, indent, start_col, flow_expr.rhs.?, space);
|
||||||
},
|
},
|
||||||
|
|
||||||
ast.Node.Id.Payload => {
|
ast.Node.Id.Payload => {
|
||||||
@ -1245,7 +1244,7 @@ fn renderExpression(
|
|||||||
} else {
|
} else {
|
||||||
var it = switch_case.items.iterator(0);
|
var it = switch_case.items.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const node = ??it.next();
|
const node = it.next().?;
|
||||||
if (it.peek()) |next_node| {
|
if (it.peek()) |next_node| {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
|
||||||
|
|
||||||
@ -1550,7 +1549,7 @@ fn renderExpression(
|
|||||||
|
|
||||||
var it = asm_node.outputs.iterator(0);
|
var it = asm_node.outputs.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const asm_output = ??it.next();
|
const asm_output = it.next().?;
|
||||||
const node = &(asm_output.*).base;
|
const node = &(asm_output.*).base;
|
||||||
|
|
||||||
if (it.peek()) |next_asm_output| {
|
if (it.peek()) |next_asm_output| {
|
||||||
@ -1588,7 +1587,7 @@ fn renderExpression(
|
|||||||
|
|
||||||
var it = asm_node.inputs.iterator(0);
|
var it = asm_node.inputs.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const asm_input = ??it.next();
|
const asm_input = it.next().?;
|
||||||
const node = &(asm_input.*).base;
|
const node = &(asm_input.*).base;
|
||||||
|
|
||||||
if (it.peek()) |next_asm_input| {
|
if (it.peek()) |next_asm_input| {
|
||||||
@ -1620,7 +1619,7 @@ fn renderExpression(
|
|||||||
|
|
||||||
var it = asm_node.clobbers.iterator(0);
|
var it = asm_node.clobbers.iterator(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const clobber_token = ??it.next();
|
const clobber_token = it.next().?;
|
||||||
|
|
||||||
if (it.peek() == null) {
|
if (it.peek() == null) {
|
||||||
try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.Newline);
|
try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.Newline);
|
||||||
@ -1994,7 +1993,7 @@ fn renderDocComments(
|
|||||||
indent: usize,
|
indent: usize,
|
||||||
start_col: *usize,
|
start_col: *usize,
|
||||||
) (@typeOf(stream).Child.Error || Error)!void {
|
) (@typeOf(stream).Child.Error || Error)!void {
|
||||||
const comment = node.doc_comments ?? return;
|
const comment = node.doc_comments orelse return;
|
||||||
var it = comment.lines.iterator(0);
|
var it = comment.lines.iterator(0);
|
||||||
const first_token = node.firstToken();
|
const first_token = node.firstToken();
|
||||||
while (it.next()) |line_token_index| {
|
while (it.next()) |line_token_index| {
|
||||||
@ -2022,7 +2021,7 @@ fn nodeIsBlock(base: *const ast.Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
|
fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
|
||||||
const infix_op = base.cast(ast.Node.InfixOp) ?? return false;
|
const infix_op = base.cast(ast.Node.InfixOp) orelse return false;
|
||||||
return switch (infix_op.op) {
|
return switch (infix_op.op) {
|
||||||
ast.Node.InfixOp.Op.Period => false,
|
ast.Node.InfixOp.Op.Period => false,
|
||||||
else => true,
|
else => true,
|
||||||
|
|||||||
@ -39,6 +39,7 @@ pub const Token = struct {
|
|||||||
Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias },
|
Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias },
|
||||||
Keyword{ .bytes = "null", .id = Id.Keyword_null },
|
Keyword{ .bytes = "null", .id = Id.Keyword_null },
|
||||||
Keyword{ .bytes = "or", .id = Id.Keyword_or },
|
Keyword{ .bytes = "or", .id = Id.Keyword_or },
|
||||||
|
Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
|
||||||
Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
|
Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
|
||||||
Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
|
Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
|
||||||
Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
|
Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
|
||||||
@ -129,7 +130,6 @@ pub const Token = struct {
|
|||||||
Ampersand,
|
Ampersand,
|
||||||
AmpersandEqual,
|
AmpersandEqual,
|
||||||
QuestionMark,
|
QuestionMark,
|
||||||
QuestionMarkQuestionMark,
|
|
||||||
AngleBracketLeft,
|
AngleBracketLeft,
|
||||||
AngleBracketLeftEqual,
|
AngleBracketLeftEqual,
|
||||||
AngleBracketAngleBracketLeft,
|
AngleBracketAngleBracketLeft,
|
||||||
@ -171,6 +171,7 @@ pub const Token = struct {
|
|||||||
Keyword_noalias,
|
Keyword_noalias,
|
||||||
Keyword_null,
|
Keyword_null,
|
||||||
Keyword_or,
|
Keyword_or,
|
||||||
|
Keyword_orelse,
|
||||||
Keyword_packed,
|
Keyword_packed,
|
||||||
Keyword_promise,
|
Keyword_promise,
|
||||||
Keyword_pub,
|
Keyword_pub,
|
||||||
@ -254,7 +255,6 @@ pub const Tokenizer = struct {
|
|||||||
Ampersand,
|
Ampersand,
|
||||||
Caret,
|
Caret,
|
||||||
Percent,
|
Percent,
|
||||||
QuestionMark,
|
|
||||||
Plus,
|
Plus,
|
||||||
PlusPercent,
|
PlusPercent,
|
||||||
AngleBracketLeft,
|
AngleBracketLeft,
|
||||||
@ -345,6 +345,11 @@ pub const Tokenizer = struct {
|
|||||||
self.index += 1;
|
self.index += 1;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
'?' => {
|
||||||
|
result.id = Token.Id.QuestionMark;
|
||||||
|
self.index += 1;
|
||||||
|
break;
|
||||||
|
},
|
||||||
':' => {
|
':' => {
|
||||||
result.id = Token.Id.Colon;
|
result.id = Token.Id.Colon;
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
@ -359,9 +364,6 @@ pub const Tokenizer = struct {
|
|||||||
'+' => {
|
'+' => {
|
||||||
state = State.Plus;
|
state = State.Plus;
|
||||||
},
|
},
|
||||||
'?' => {
|
|
||||||
state = State.QuestionMark;
|
|
||||||
},
|
|
||||||
'<' => {
|
'<' => {
|
||||||
state = State.AngleBracketLeft;
|
state = State.AngleBracketLeft;
|
||||||
},
|
},
|
||||||
@ -496,18 +498,6 @@ pub const Tokenizer = struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
State.QuestionMark => switch (c) {
|
|
||||||
'?' => {
|
|
||||||
result.id = Token.Id.QuestionMarkQuestionMark;
|
|
||||||
self.index += 1;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
result.id = Token.Id.QuestionMark;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
State.Percent => switch (c) {
|
State.Percent => switch (c) {
|
||||||
'=' => {
|
'=' => {
|
||||||
result.id = Token.Id.PercentEqual;
|
result.id = Token.Id.PercentEqual;
|
||||||
@ -1084,9 +1074,6 @@ pub const Tokenizer = struct {
|
|||||||
State.Plus => {
|
State.Plus => {
|
||||||
result.id = Token.Id.Plus;
|
result.id = Token.Id.Plus;
|
||||||
},
|
},
|
||||||
State.QuestionMark => {
|
|
||||||
result.id = Token.Id.QuestionMark;
|
|
||||||
},
|
|
||||||
State.Percent => {
|
State.Percent => {
|
||||||
result.id = Token.Id.Percent;
|
result.id = Token.Id.Percent;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -31,6 +31,7 @@ comptime {
|
|||||||
_ = @import("cases/incomplete_struct_param_tld.zig");
|
_ = @import("cases/incomplete_struct_param_tld.zig");
|
||||||
_ = @import("cases/ir_block_deps.zig");
|
_ = @import("cases/ir_block_deps.zig");
|
||||||
_ = @import("cases/math.zig");
|
_ = @import("cases/math.zig");
|
||||||
|
_ = @import("cases/merge_error_sets.zig");
|
||||||
_ = @import("cases/misc.zig");
|
_ = @import("cases/misc.zig");
|
||||||
_ = @import("cases/namespace_depends_on_compile_var/index.zig");
|
_ = @import("cases/namespace_depends_on_compile_var/index.zig");
|
||||||
_ = @import("cases/new_stack_call.zig");
|
_ = @import("cases/new_stack_call.zig");
|
||||||
|
|||||||
@ -116,6 +116,15 @@ test "array len property" {
|
|||||||
assert(@typeOf(x).len == 5);
|
assert(@typeOf(x).len == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "array len field" {
|
||||||
|
var arr = [4]u8{ 0, 0, 0, 0 };
|
||||||
|
var ptr = &arr;
|
||||||
|
assert(arr.len == 4);
|
||||||
|
comptime assert(arr.len == 4);
|
||||||
|
assert(ptr.len == 4);
|
||||||
|
comptime assert(ptr.len == 4);
|
||||||
|
}
|
||||||
|
|
||||||
test "single-item pointer to array indexing and slicing" {
|
test "single-item pointer to array indexing and slicing" {
|
||||||
testSingleItemPtrArrayIndexSlice();
|
testSingleItemPtrArrayIndexSlice();
|
||||||
comptime testSingleItemPtrArrayIndexSlice();
|
comptime testSingleItemPtrArrayIndexSlice();
|
||||||
@ -143,4 +152,3 @@ fn testImplicitCastSingleItemPtr() void {
|
|||||||
slice[0] += 1;
|
slice[0] += 1;
|
||||||
assert(byte == 101);
|
assert(byte == 101);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ const Value = struct {
|
|||||||
align_expr: ?u32,
|
align_expr: ?u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
test "nullable if after an if in a switch prong of a switch with 2 prongs in an else" {
|
test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
|
||||||
foo(false, true);
|
foo(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
const assert = @import("std").debug.assert;
|
const std = @import("std");
|
||||||
const mem = @import("std").mem;
|
const assert = std.debug.assert;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
test "int to ptr cast" {
|
test "int to ptr cast" {
|
||||||
const x = usize(13);
|
const x = usize(13);
|
||||||
@ -72,7 +73,7 @@ fn Struct(comptime T: type) type {
|
|||||||
|
|
||||||
fn maybePointer(self: ?*const Self) Self {
|
fn maybePointer(self: ?*const Self) Self {
|
||||||
const none = Self{ .x = if (T == void) void{} else 0 };
|
const none = Self{ .x = if (T == void) void{} else 0 };
|
||||||
return (self ?? &none).*;
|
return (self orelse &none).*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -86,7 +87,7 @@ const Union = union {
|
|||||||
|
|
||||||
fn maybePointer(self: ?*const Union) Union {
|
fn maybePointer(self: ?*const Union) Union {
|
||||||
const none = Union{ .x = 0 };
|
const none = Union{ .x = 0 };
|
||||||
return (self ?? &none).*;
|
return (self orelse &none).*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,7 +100,7 @@ const Enum = enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn maybePointer(self: ?*const Enum) Enum {
|
fn maybePointer(self: ?*const Enum) Enum {
|
||||||
return (self ?? &Enum.None).*;
|
return (self orelse &Enum.None).*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,16 +109,16 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
|
|||||||
const Self = this;
|
const Self = this;
|
||||||
x: u8,
|
x: u8,
|
||||||
fn constConst(p: *const *const Self) u8 {
|
fn constConst(p: *const *const Self) u8 {
|
||||||
return (p.*).x;
|
return p.*.x;
|
||||||
}
|
}
|
||||||
fn maybeConstConst(p: ?*const *const Self) u8 {
|
fn maybeConstConst(p: ?*const *const Self) u8 {
|
||||||
return ((??p).*).x;
|
return p.?.*.x;
|
||||||
}
|
}
|
||||||
fn constConstConst(p: *const *const *const Self) u8 {
|
fn constConstConst(p: *const *const *const Self) u8 {
|
||||||
return (p.*.*).x;
|
return p.*.*.x;
|
||||||
}
|
}
|
||||||
fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
|
fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
|
||||||
return ((??p).*.*).x;
|
return p.?.*.*.x;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const s = S{ .x = 42 };
|
const s = S{ .x = 42 };
|
||||||
@ -176,56 +177,56 @@ test "string literal to &const []const u8" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "implicitly cast from T to error!?T" {
|
test "implicitly cast from T to error!?T" {
|
||||||
castToMaybeTypeError(1);
|
castToOptionalTypeError(1);
|
||||||
comptime castToMaybeTypeError(1);
|
comptime castToOptionalTypeError(1);
|
||||||
}
|
}
|
||||||
const A = struct {
|
const A = struct {
|
||||||
a: i32,
|
a: i32,
|
||||||
};
|
};
|
||||||
fn castToMaybeTypeError(z: i32) void {
|
fn castToOptionalTypeError(z: i32) void {
|
||||||
const x = i32(1);
|
const x = i32(1);
|
||||||
const y: error!?i32 = x;
|
const y: error!?i32 = x;
|
||||||
assert(??(try y) == 1);
|
assert((try y).? == 1);
|
||||||
|
|
||||||
const f = z;
|
const f = z;
|
||||||
const g: error!?i32 = f;
|
const g: error!?i32 = f;
|
||||||
|
|
||||||
const a = A{ .a = z };
|
const a = A{ .a = z };
|
||||||
const b: error!?A = a;
|
const b: error!?A = a;
|
||||||
assert((??(b catch unreachable)).a == 1);
|
assert((b catch unreachable).?.a == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "implicitly cast from int to error!?T" {
|
test "implicitly cast from int to error!?T" {
|
||||||
implicitIntLitToMaybe();
|
implicitIntLitToOptional();
|
||||||
comptime implicitIntLitToMaybe();
|
comptime implicitIntLitToOptional();
|
||||||
}
|
}
|
||||||
fn implicitIntLitToMaybe() void {
|
fn implicitIntLitToOptional() void {
|
||||||
const f: ?i32 = 1;
|
const f: ?i32 = 1;
|
||||||
const g: error!?i32 = 1;
|
const g: error!?i32 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "return null from fn() error!?&T" {
|
test "return null from fn() error!?&T" {
|
||||||
const a = returnNullFromMaybeTypeErrorRef();
|
const a = returnNullFromOptionalTypeErrorRef();
|
||||||
const b = returnNullLitFromMaybeTypeErrorRef();
|
const b = returnNullLitFromOptionalTypeErrorRef();
|
||||||
assert((try a) == null and (try b) == null);
|
assert((try a) == null and (try b) == null);
|
||||||
}
|
}
|
||||||
fn returnNullFromMaybeTypeErrorRef() error!?*A {
|
fn returnNullFromOptionalTypeErrorRef() error!?*A {
|
||||||
const a: ?*A = null;
|
const a: ?*A = null;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
fn returnNullLitFromMaybeTypeErrorRef() error!?*A {
|
fn returnNullLitFromOptionalTypeErrorRef() error!?*A {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "peer type resolution: ?T and T" {
|
test "peer type resolution: ?T and T" {
|
||||||
assert(??peerTypeTAndMaybeT(true, false) == 0);
|
assert(peerTypeTAndOptionalT(true, false).? == 0);
|
||||||
assert(??peerTypeTAndMaybeT(false, false) == 3);
|
assert(peerTypeTAndOptionalT(false, false).? == 3);
|
||||||
comptime {
|
comptime {
|
||||||
assert(??peerTypeTAndMaybeT(true, false) == 0);
|
assert(peerTypeTAndOptionalT(true, false).? == 0);
|
||||||
assert(??peerTypeTAndMaybeT(false, false) == 3);
|
assert(peerTypeTAndOptionalT(false, false).? == 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
|
fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
|
||||||
if (c) {
|
if (c) {
|
||||||
return if (b) null else usize(0);
|
return if (b) null else usize(0);
|
||||||
}
|
}
|
||||||
@ -250,11 +251,11 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "implicitly cast from [N]T to ?[]const T" {
|
test "implicitly cast from [N]T to ?[]const T" {
|
||||||
assert(mem.eql(u8, ??castToMaybeSlice(), "hi"));
|
assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
|
||||||
comptime assert(mem.eql(u8, ??castToMaybeSlice(), "hi"));
|
comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn castToMaybeSlice() ?[]const u8 {
|
fn castToOptionalSlice() ?[]const u8 {
|
||||||
return "hi";
|
return "hi";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,3 +385,24 @@ test "const slice widen cast" {
|
|||||||
|
|
||||||
assert(@bitCast(u32, bytes) == 0x12121212);
|
assert(@bitCast(u32, bytes) == 0x12121212);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "single-item pointer of array to slice and to unknown length pointer" {
|
||||||
|
testCastPtrOfArrayToSliceAndPtr();
|
||||||
|
comptime testCastPtrOfArrayToSliceAndPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testCastPtrOfArrayToSliceAndPtr() void {
|
||||||
|
var array = "ao" ++ "eu"; // TODO https://github.com/ziglang/zig/issues/1076
|
||||||
|
const x: [*]u8 = &array;
|
||||||
|
x[0] += 1;
|
||||||
|
assert(mem.eql(u8, array[0..], "boeu"));
|
||||||
|
const y: []u8 = &array;
|
||||||
|
y[0] += 1;
|
||||||
|
assert(mem.eql(u8, array[0..], "coeu"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
|
||||||
|
const window_name = [1][*]const u8{c"window name"};
|
||||||
|
const x: [*]const ?[*]const u8 = &window_name;
|
||||||
|
assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
|
||||||
|
}
|
||||||
|
|||||||
@ -883,3 +883,12 @@ test "empty extern enum with members" {
|
|||||||
};
|
};
|
||||||
assert(@sizeOf(E) == @sizeOf(c_int));
|
assert(@sizeOf(E) == @sizeOf(c_int));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "aoeu" {
|
||||||
|
const LocalFoo = enum {
|
||||||
|
A = 1,
|
||||||
|
B = 0,
|
||||||
|
};
|
||||||
|
var b = LocalFoo.B;
|
||||||
|
assert(mem.eql(u8, @tagName(b), "B"));
|
||||||
|
}
|
||||||
|
|||||||
@ -140,7 +140,7 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
|
|||||||
if (x) |v| assert(v == 1234) else |err| @compileError("bad");
|
if (x) |v| assert(v == 1234) else |err| @compileError("bad");
|
||||||
}
|
}
|
||||||
|
|
||||||
test "syntax: nullable operator in front of error union operator" {
|
test "syntax: optional operator in front of error union operator" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(?error!i32 == ?(error!i32));
|
assert(?error!i32 == ?(error!i32));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ fn fibonacci(x: i32) i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unwrapAndAddOne(blah: ?i32) i32 {
|
fn unwrapAndAddOne(blah: ?i32) i32 {
|
||||||
return ??blah + 1;
|
return blah.? + 1;
|
||||||
}
|
}
|
||||||
const should_be_1235 = unwrapAndAddOne(1234);
|
const should_be_1235 = unwrapAndAddOne(1234);
|
||||||
test "static add one" {
|
test "static add one" {
|
||||||
@ -610,3 +610,16 @@ test "slice of type" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Wrapper = struct {
|
||||||
|
T: type,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn wrap(comptime T: type) Wrapper {
|
||||||
|
return Wrapper{ .T = T };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "function which returns struct with type field causes implicit comptime" {
|
||||||
|
const ty = wrap(i32).T;
|
||||||
|
assert(ty == i32);
|
||||||
|
}
|
||||||
|
|||||||
@ -127,7 +127,7 @@ test "generic fn with implicit cast" {
|
|||||||
}) == 0);
|
}) == 0);
|
||||||
}
|
}
|
||||||
fn getByte(ptr: ?*const u8) u8 {
|
fn getByte(ptr: ?*const u8) u8 {
|
||||||
return (??ptr).*;
|
return ptr.?.*;
|
||||||
}
|
}
|
||||||
fn getFirstByte(comptime T: type, mem: []const T) u8 {
|
fn getFirstByte(comptime T: type, mem: []const T) u8 {
|
||||||
return getByte(@ptrCast(*const u8, &mem[0]));
|
return getByte(@ptrCast(*const u8, &mem[0]));
|
||||||
|
|||||||
21
test/cases/merge_error_sets.zig
Normal file
21
test/cases/merge_error_sets.zig
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const A = error{
|
||||||
|
PathNotFound,
|
||||||
|
NotDir,
|
||||||
|
};
|
||||||
|
const B = error{OutOfMemory};
|
||||||
|
|
||||||
|
const C = A || B;
|
||||||
|
|
||||||
|
fn foo() C!void {
|
||||||
|
return error.NotDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "merge error sets" {
|
||||||
|
if (foo()) {
|
||||||
|
@panic("unexpected");
|
||||||
|
} else |err| switch (err) {
|
||||||
|
error.OutOfMemory => @panic("unexpected"),
|
||||||
|
error.PathNotFound => @panic("unexpected"),
|
||||||
|
error.NotDir => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -505,7 +505,7 @@ test "@typeId" {
|
|||||||
assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
|
assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
|
||||||
assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
|
assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
|
||||||
assert(@typeId(@typeOf(null)) == Tid.Null);
|
assert(@typeId(@typeOf(null)) == Tid.Null);
|
||||||
assert(@typeId(?i32) == Tid.Nullable);
|
assert(@typeId(?i32) == Tid.Optional);
|
||||||
assert(@typeId(error!i32) == Tid.ErrorUnion);
|
assert(@typeId(error!i32) == Tid.ErrorUnion);
|
||||||
assert(@typeId(error) == Tid.ErrorSet);
|
assert(@typeId(error) == Tid.ErrorSet);
|
||||||
assert(@typeId(AnEnum) == Tid.Enum);
|
assert(@typeId(AnEnum) == Tid.Enum);
|
||||||
@ -523,14 +523,6 @@ test "@typeId" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@canImplicitCast" {
|
|
||||||
comptime {
|
|
||||||
assert(@canImplicitCast(i64, i32(3)));
|
|
||||||
assert(!@canImplicitCast(i32, f32(1.234)));
|
|
||||||
assert(@canImplicitCast([]const u8, "aoeu"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "@typeName" {
|
test "@typeName" {
|
||||||
const Struct = struct {};
|
const Struct = struct {};
|
||||||
const Union = union {
|
const Union = union {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const assert = @import("std").debug.assert;
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
test "nullable type" {
|
test "optional type" {
|
||||||
const x: ?bool = true;
|
const x: ?bool = true;
|
||||||
|
|
||||||
if (x) |y| {
|
if (x) |y| {
|
||||||
@ -15,13 +15,13 @@ test "nullable type" {
|
|||||||
|
|
||||||
const next_x: ?i32 = null;
|
const next_x: ?i32 = null;
|
||||||
|
|
||||||
const z = next_x ?? 1234;
|
const z = next_x orelse 1234;
|
||||||
|
|
||||||
assert(z == 1234);
|
assert(z == 1234);
|
||||||
|
|
||||||
const final_x: ?i32 = 13;
|
const final_x: ?i32 = 13;
|
||||||
|
|
||||||
const num = final_x ?? unreachable;
|
const num = final_x orelse unreachable;
|
||||||
|
|
||||||
assert(num == 13);
|
assert(num == 13);
|
||||||
}
|
}
|
||||||
@ -33,12 +33,12 @@ test "test maybe object and get a pointer to the inner value" {
|
|||||||
b.* = false;
|
b.* = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(??maybe_bool == false);
|
assert(maybe_bool.? == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "rhs maybe unwrap return" {
|
test "rhs maybe unwrap return" {
|
||||||
const x: ?bool = true;
|
const x: ?bool = true;
|
||||||
const y = x ?? return;
|
const y = x orelse return;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "maybe return" {
|
test "maybe return" {
|
||||||
@ -47,13 +47,13 @@ test "maybe return" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn maybeReturnImpl() void {
|
fn maybeReturnImpl() void {
|
||||||
assert(??foo(1235));
|
assert(foo(1235).?);
|
||||||
if (foo(null) != null) unreachable;
|
if (foo(null) != null) unreachable;
|
||||||
assert(!??foo(1234));
|
assert(!foo(1234).?);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(x: ?i32) ?bool {
|
fn foo(x: ?i32) ?bool {
|
||||||
const value = x ?? return null;
|
const value = x orelse return null;
|
||||||
return value > 1234;
|
return value > 1234;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,12 +102,12 @@ fn testTestNullRuntime(x: ?i32) void {
|
|||||||
assert(!(x != null));
|
assert(!(x != null));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "nullable void" {
|
test "optional void" {
|
||||||
nullableVoidImpl();
|
optionalVoidImpl();
|
||||||
comptime nullableVoidImpl();
|
comptime optionalVoidImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nullableVoidImpl() void {
|
fn optionalVoidImpl() void {
|
||||||
assert(bar(null) == null);
|
assert(bar(null) == null);
|
||||||
assert(bar({}) != null);
|
assert(bar({}) != null);
|
||||||
}
|
}
|
||||||
@ -120,19 +120,19 @@ fn bar(x: ?void) ?void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const StructWithNullable = struct {
|
const StructWithOptional = struct {
|
||||||
field: ?i32,
|
field: ?i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
var struct_with_nullable: StructWithNullable = undefined;
|
var struct_with_optional: StructWithOptional = undefined;
|
||||||
|
|
||||||
test "unwrap nullable which is field of global var" {
|
test "unwrap optional which is field of global var" {
|
||||||
struct_with_nullable.field = null;
|
struct_with_optional.field = null;
|
||||||
if (struct_with_nullable.field) |payload| {
|
if (struct_with_optional.field) |payload| {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
struct_with_nullable.field = 1234;
|
struct_with_optional.field = 1234;
|
||||||
if (struct_with_nullable.field) |payload| {
|
if (struct_with_optional.field) |payload| {
|
||||||
assert(payload == 1234);
|
assert(payload == 1234);
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
unreachable;
|
||||||
@ -140,6 +140,17 @@ test "unwrap nullable which is field of global var" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "null with default unwrap" {
|
test "null with default unwrap" {
|
||||||
const x: i32 = null ?? 1;
|
const x: i32 = null orelse 1;
|
||||||
assert(x == 1);
|
assert(x == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "optional types" {
|
||||||
|
comptime {
|
||||||
|
const opt_type_struct = StructWithOptionalType { .t=u8, };
|
||||||
|
assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const StructWithOptionalType = struct {
|
||||||
|
t: ?type,
|
||||||
|
};
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
|
|||||||
const mem = @import("std").mem;
|
const mem = @import("std").mem;
|
||||||
const reflection = this;
|
const reflection = this;
|
||||||
|
|
||||||
test "reflection: array, pointer, nullable, error union type child" {
|
test "reflection: array, pointer, optional, error union type child" {
|
||||||
comptime {
|
comptime {
|
||||||
assert(([10]u8).Child == u8);
|
assert(([10]u8).Child == u8);
|
||||||
assert((*u8).Child == u8);
|
assert((*u8).Child == u8);
|
||||||
|
|||||||
@ -421,3 +421,20 @@ const Expr = union(enum) {
|
|||||||
fn alloc(comptime T: type) []T {
|
fn alloc(comptime T: type) []T {
|
||||||
return []T{};
|
return []T{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "call method with mutable reference to struct with no fields" {
|
||||||
|
const S = struct {
|
||||||
|
fn doC(s: *const this) bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
fn do(s: *this) bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var s = S{};
|
||||||
|
assert(S.doC(&s));
|
||||||
|
assert(s.doC());
|
||||||
|
assert(S.do(&s));
|
||||||
|
assert(s.do());
|
||||||
|
}
|
||||||
|
|||||||
@ -39,12 +39,28 @@ test "type info: pointer type info" {
|
|||||||
fn testPointer() void {
|
fn testPointer() void {
|
||||||
const u32_ptr_info = @typeInfo(*u32);
|
const u32_ptr_info = @typeInfo(*u32);
|
||||||
assert(TypeId(u32_ptr_info) == TypeId.Pointer);
|
assert(TypeId(u32_ptr_info) == TypeId.Pointer);
|
||||||
|
assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
|
||||||
assert(u32_ptr_info.Pointer.is_const == false);
|
assert(u32_ptr_info.Pointer.is_const == false);
|
||||||
assert(u32_ptr_info.Pointer.is_volatile == false);
|
assert(u32_ptr_info.Pointer.is_volatile == false);
|
||||||
assert(u32_ptr_info.Pointer.alignment == 4);
|
assert(u32_ptr_info.Pointer.alignment == @alignOf(u32));
|
||||||
assert(u32_ptr_info.Pointer.child == u32);
|
assert(u32_ptr_info.Pointer.child == u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "type info: unknown length pointer type info" {
|
||||||
|
testUnknownLenPtr();
|
||||||
|
comptime testUnknownLenPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testUnknownLenPtr() void {
|
||||||
|
const u32_ptr_info = @typeInfo([*]const volatile f64);
|
||||||
|
assert(TypeId(u32_ptr_info) == TypeId.Pointer);
|
||||||
|
assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||||
|
assert(u32_ptr_info.Pointer.is_const == true);
|
||||||
|
assert(u32_ptr_info.Pointer.is_volatile == true);
|
||||||
|
assert(u32_ptr_info.Pointer.alignment == @alignOf(f64));
|
||||||
|
assert(u32_ptr_info.Pointer.child == f64);
|
||||||
|
}
|
||||||
|
|
||||||
test "type info: slice type info" {
|
test "type info: slice type info" {
|
||||||
testSlice();
|
testSlice();
|
||||||
comptime testSlice();
|
comptime testSlice();
|
||||||
@ -52,11 +68,12 @@ test "type info: slice type info" {
|
|||||||
|
|
||||||
fn testSlice() void {
|
fn testSlice() void {
|
||||||
const u32_slice_info = @typeInfo([]u32);
|
const u32_slice_info = @typeInfo([]u32);
|
||||||
assert(TypeId(u32_slice_info) == TypeId.Slice);
|
assert(TypeId(u32_slice_info) == TypeId.Pointer);
|
||||||
assert(u32_slice_info.Slice.is_const == false);
|
assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
|
||||||
assert(u32_slice_info.Slice.is_volatile == false);
|
assert(u32_slice_info.Pointer.is_const == false);
|
||||||
assert(u32_slice_info.Slice.alignment == 4);
|
assert(u32_slice_info.Pointer.is_volatile == false);
|
||||||
assert(u32_slice_info.Slice.child == u32);
|
assert(u32_slice_info.Pointer.alignment == 4);
|
||||||
|
assert(u32_slice_info.Pointer.child == u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "type info: array type info" {
|
test "type info: array type info" {
|
||||||
@ -71,15 +88,15 @@ fn testArray() void {
|
|||||||
assert(arr_info.Array.child == bool);
|
assert(arr_info.Array.child == bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "type info: nullable type info" {
|
test "type info: optional type info" {
|
||||||
testNullable();
|
testOptional();
|
||||||
comptime testNullable();
|
comptime testOptional();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testNullable() void {
|
fn testOptional() void {
|
||||||
const null_info = @typeInfo(?void);
|
const null_info = @typeInfo(?void);
|
||||||
assert(TypeId(null_info) == TypeId.Nullable);
|
assert(TypeId(null_info) == TypeId.Optional);
|
||||||
assert(null_info.Nullable.child == void);
|
assert(null_info.Optional.child == void);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "type info: promise info" {
|
test "type info: promise info" {
|
||||||
@ -149,11 +166,11 @@ fn testUnion() void {
|
|||||||
assert(TypeId(typeinfo_info) == TypeId.Union);
|
assert(TypeId(typeinfo_info) == TypeId.Union);
|
||||||
assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
|
assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
|
||||||
assert(typeinfo_info.Union.tag_type == TypeId);
|
assert(typeinfo_info.Union.tag_type == TypeId);
|
||||||
assert(typeinfo_info.Union.fields.len == 26);
|
assert(typeinfo_info.Union.fields.len == 25);
|
||||||
assert(typeinfo_info.Union.fields[4].enum_field != null);
|
assert(typeinfo_info.Union.fields[4].enum_field != null);
|
||||||
assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
|
assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
|
||||||
assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
|
assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
|
||||||
assert(typeinfo_info.Union.defs.len == 21);
|
assert(typeinfo_info.Union.defs.len == 20);
|
||||||
|
|
||||||
const TestNoTagUnion = union {
|
const TestNoTagUnion = union {
|
||||||
Foo: void,
|
Foo: void,
|
||||||
|
|||||||
@ -81,7 +81,7 @@ test "while with else" {
|
|||||||
assert(got_else == 1);
|
assert(got_else == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while with nullable as condition" {
|
test "while with optional as condition" {
|
||||||
numbers_left = 10;
|
numbers_left = 10;
|
||||||
var sum: i32 = 0;
|
var sum: i32 = 0;
|
||||||
while (getNumberOrNull()) |value| {
|
while (getNumberOrNull()) |value| {
|
||||||
@ -90,7 +90,7 @@ test "while with nullable as condition" {
|
|||||||
assert(sum == 45);
|
assert(sum == 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while with nullable as condition with else" {
|
test "while with optional as condition with else" {
|
||||||
numbers_left = 10;
|
numbers_left = 10;
|
||||||
var sum: i32 = 0;
|
var sum: i32 = 0;
|
||||||
var got_else: i32 = 0;
|
var got_else: i32 = 0;
|
||||||
@ -132,7 +132,7 @@ fn getNumberOrNull() ?i32 {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on nullable with else result follow else prong" {
|
test "while on optional with else result follow else prong" {
|
||||||
const result = while (returnNull()) |value| {
|
const result = while (returnNull()) |value| {
|
||||||
break value;
|
break value;
|
||||||
} else
|
} else
|
||||||
@ -140,8 +140,8 @@ test "while on nullable with else result follow else prong" {
|
|||||||
assert(result == 2);
|
assert(result == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "while on nullable with else result follow break prong" {
|
test "while on optional with else result follow break prong" {
|
||||||
const result = while (returnMaybe(10)) |value| {
|
const result = while (returnOptional(10)) |value| {
|
||||||
break value;
|
break value;
|
||||||
} else
|
} else
|
||||||
i32(2);
|
i32(2);
|
||||||
@ -210,7 +210,7 @@ fn testContinueOuter() void {
|
|||||||
fn returnNull() ?i32 {
|
fn returnNull() ?i32 {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
fn returnMaybe(x: i32) ?i32 {
|
fn returnOptional(x: i32) ?i32 {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
fn returnError() error!i32 {
|
fn returnError() error!i32 {
|
||||||
|
|||||||
@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
|||||||
cases.addC("expose function pointer to C land",
|
cases.addC("expose function pointer to C land",
|
||||||
\\const c = @cImport(@cInclude("stdlib.h"));
|
\\const c = @cImport(@cInclude("stdlib.h"));
|
||||||
\\
|
\\
|
||||||
\\export fn compare_fn(a: ?[*]const c_void, b: ?[*]const c_void) c_int {
|
\\export fn compare_fn(a: ?*const c_void, b: ?*const c_void) c_int {
|
||||||
\\ const a_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), a));
|
\\ const a_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), a));
|
||||||
\\ const b_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), b));
|
\\ const b_int = @ptrCast(*const i32, @alignCast(@alignOf(i32), b));
|
||||||
\\ if (a_int.* < b_int.*) {
|
\\ if (a_int.* < b_int.*) {
|
||||||
@ -299,7 +299,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
|||||||
\\export fn main() c_int {
|
\\export fn main() c_int {
|
||||||
\\ var array = []u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
|
\\ var array = []u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
|
||||||
\\
|
\\
|
||||||
\\ c.qsort(@ptrCast(?[*]c_void, array[0..].ptr), c_ulong(array.len), @sizeOf(i32), compare_fn);
|
\\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), c_ulong(array.len), @sizeOf(i32), compare_fn);
|
||||||
\\
|
\\
|
||||||
\\ for (array) |item, i| {
|
\\ for (array) |item, i| {
|
||||||
\\ if (item != i) {
|
\\ if (item != i) {
|
||||||
|
|||||||
@ -1,6 +1,57 @@
|
|||||||
const tests = @import("tests.zig");
|
const tests = @import("tests.zig");
|
||||||
|
|
||||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||||
|
cases.add(
|
||||||
|
"use implicit casts to assign null to non-nullable pointer",
|
||||||
|
\\export fn entry() void {
|
||||||
|
\\ var x: i32 = 1234;
|
||||||
|
\\ var p: *i32 = &x;
|
||||||
|
\\ var pp: *?*i32 = &p;
|
||||||
|
\\ pp.* = null;
|
||||||
|
\\ var y = p.*;
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'",
|
||||||
|
);
|
||||||
|
|
||||||
|
cases.add(
|
||||||
|
"attempted implicit cast from T to [*]const T",
|
||||||
|
\\export fn entry() void {
|
||||||
|
\\ const x: [*]const bool = true;
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'",
|
||||||
|
);
|
||||||
|
|
||||||
|
cases.add(
|
||||||
|
"dereference unknown length pointer",
|
||||||
|
\\export fn entry(x: [*]i32) i32 {
|
||||||
|
\\ return x.*;
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
".tmp_source.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
|
||||||
|
);
|
||||||
|
|
||||||
|
cases.add(
|
||||||
|
"field access of unknown length pointer",
|
||||||
|
\\const Foo = extern struct {
|
||||||
|
\\ a: i32,
|
||||||
|
\\};
|
||||||
|
\\
|
||||||
|
\\export fn entry(foo: [*]Foo) void {
|
||||||
|
\\ foo.a += 1;
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
".tmp_source.zig:6:8: error: type '[*]Foo' does not support field access",
|
||||||
|
);
|
||||||
|
|
||||||
|
cases.add(
|
||||||
|
"unknown length pointer to opaque",
|
||||||
|
\\export const T = [*]@OpaqueType();
|
||||||
|
,
|
||||||
|
".tmp_source.zig:1:18: error: unknown-length pointer to opaque",
|
||||||
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"error when evaluating return type",
|
"error when evaluating return type",
|
||||||
\\const Foo = struct {
|
\\const Foo = struct {
|
||||||
@ -1303,7 +1354,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
\\ if (true) |x| { }
|
\\ if (true) |x| { }
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
".tmp_source.zig:2:9: error: expected nullable type, found 'bool'",
|
".tmp_source.zig:2:9: error: expected optional type, found 'bool'",
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
@ -1742,7 +1793,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"assign null to non-nullable pointer",
|
"assign null to non-optional pointer",
|
||||||
\\const a: *u8 = null;
|
\\const a: *u8 = null;
|
||||||
\\
|
\\
|
||||||
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
|
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
|
||||||
@ -2258,7 +2309,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
\\
|
\\
|
||||||
\\ defer try canFail();
|
\\ defer try canFail();
|
||||||
\\
|
\\
|
||||||
\\ const a = maybeInt() ?? return;
|
\\ const a = maybeInt() orelse return;
|
||||||
\\}
|
\\}
|
||||||
\\
|
\\
|
||||||
\\fn canFail() error!void { }
|
\\fn canFail() error!void { }
|
||||||
@ -2779,7 +2830,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"while expected bool, got nullable",
|
"while expected bool, got optional",
|
||||||
\\export fn foo() void {
|
\\export fn foo() void {
|
||||||
\\ while (bar()) {}
|
\\ while (bar()) {}
|
||||||
\\}
|
\\}
|
||||||
@ -2799,23 +2850,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"while expected nullable, got bool",
|
"while expected optional, got bool",
|
||||||
\\export fn foo() void {
|
\\export fn foo() void {
|
||||||
\\ while (bar()) |x| {}
|
\\ while (bar()) |x| {}
|
||||||
\\}
|
\\}
|
||||||
\\fn bar() bool { return true; }
|
\\fn bar() bool { return true; }
|
||||||
,
|
,
|
||||||
".tmp_source.zig:2:15: error: expected nullable type, found 'bool'",
|
".tmp_source.zig:2:15: error: expected optional type, found 'bool'",
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"while expected nullable, got error union",
|
"while expected optional, got error union",
|
||||||
\\export fn foo() void {
|
\\export fn foo() void {
|
||||||
\\ while (bar()) |x| {}
|
\\ while (bar()) |x| {}
|
||||||
\\}
|
\\}
|
||||||
\\fn bar() error!i32 { return 1; }
|
\\fn bar() error!i32 { return 1; }
|
||||||
,
|
,
|
||||||
".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'",
|
".tmp_source.zig:2:15: error: expected optional type, found 'error!i32'",
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
@ -2829,7 +2880,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"while expected error union, got nullable",
|
"while expected error union, got optional",
|
||||||
\\export fn foo() void {
|
\\export fn foo() void {
|
||||||
\\ while (bar()) |x| {} else |err| {}
|
\\ while (bar()) |x| {} else |err| {}
|
||||||
\\}
|
\\}
|
||||||
@ -3291,7 +3342,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
|
".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
|
||||||
".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
|
".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
|
||||||
".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",
|
".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",
|
||||||
".tmp_source.zig:12:4: error: variable of type 'Opaque' must be const or comptime",
|
".tmp_source.zig:12:4: error: variable of type 'Opaque' not allowed",
|
||||||
".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
|
".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
|
||||||
".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
|
".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
|
||||||
".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
|
".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
|
||||||
|
|||||||
@ -282,8 +282,8 @@ pub const CompareOutputContext = struct {
|
|||||||
var stdout = Buffer.initNull(b.allocator);
|
var stdout = Buffer.initNull(b.allocator);
|
||||||
var stderr = Buffer.initNull(b.allocator);
|
var stderr = Buffer.initNull(b.allocator);
|
||||||
|
|
||||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
|
||||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
|
||||||
|
|
||||||
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
|
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
|
||||||
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
|
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
|
||||||
@ -601,8 +601,8 @@ pub const CompileErrorContext = struct {
|
|||||||
var stdout_buf = Buffer.initNull(b.allocator);
|
var stdout_buf = Buffer.initNull(b.allocator);
|
||||||
var stderr_buf = Buffer.initNull(b.allocator);
|
var stderr_buf = Buffer.initNull(b.allocator);
|
||||||
|
|
||||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
|
||||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
|
||||||
|
|
||||||
stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
|
stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
|
||||||
stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
|
stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
|
||||||
@ -872,8 +872,8 @@ pub const TranslateCContext = struct {
|
|||||||
var stdout_buf = Buffer.initNull(b.allocator);
|
var stdout_buf = Buffer.initNull(b.allocator);
|
||||||
var stderr_buf = Buffer.initNull(b.allocator);
|
var stderr_buf = Buffer.initNull(b.allocator);
|
||||||
|
|
||||||
var stdout_file_in_stream = io.FileInStream.init(&??child.stdout);
|
var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?);
|
||||||
var stderr_file_in_stream = io.FileInStream.init(&??child.stderr);
|
var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?);
|
||||||
|
|
||||||
stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
|
stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
|
||||||
stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
|
stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
|
||||||
|
|||||||
@ -99,7 +99,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
cases.add("restrict -> noalias",
|
cases.add("restrict -> noalias",
|
||||||
\\void foo(void *restrict bar, void *restrict);
|
\\void foo(void *restrict bar, void *restrict);
|
||||||
,
|
,
|
||||||
\\pub extern fn foo(noalias bar: ?[*]c_void, noalias arg1: ?[*]c_void) void;
|
\\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add("simple struct",
|
cases.add("simple struct",
|
||||||
@ -172,7 +172,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
,
|
,
|
||||||
\\pub const struct_Foo = @OpaqueType();
|
\\pub const struct_Foo = @OpaqueType();
|
||||||
,
|
,
|
||||||
\\pub extern fn some_func(foo: ?[*]struct_Foo, x: c_int) ?[*]struct_Foo;
|
\\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
|
||||||
,
|
,
|
||||||
\\pub const Foo = struct_Foo;
|
\\pub const Foo = struct_Foo;
|
||||||
);
|
);
|
||||||
@ -233,7 +233,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
,
|
,
|
||||||
\\pub const Foo = c_void;
|
\\pub const Foo = c_void;
|
||||||
,
|
,
|
||||||
\\pub extern fn fun(a: ?[*]Foo) Foo;
|
\\pub extern fn fun(a: ?*Foo) Foo;
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add("generate inline func for #define global extern fn",
|
cases.add("generate inline func for #define global extern fn",
|
||||||
@ -246,13 +246,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\pub extern var fn_ptr: ?extern fn() void;
|
\\pub extern var fn_ptr: ?extern fn() void;
|
||||||
,
|
,
|
||||||
\\pub inline fn foo() void {
|
\\pub inline fn foo() void {
|
||||||
\\ return (??fn_ptr)();
|
\\ return fn_ptr.?();
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub extern var fn_ptr2: ?extern fn(c_int, f32) u8;
|
\\pub extern var fn_ptr2: ?extern fn(c_int, f32) u8;
|
||||||
,
|
,
|
||||||
\\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
|
\\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
|
||||||
\\ return (??fn_ptr2)(arg0, arg1);
|
\\ return fn_ptr2.?(arg0, arg1);
|
||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -505,7 +505,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ return 6;
|
\\ return 6;
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?[*]c_void) c_int {
|
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||||
\\ if ((a != 0) and (b != 0)) return 0;
|
\\ if ((a != 0) and (b != 0)) return 0;
|
||||||
\\ if ((b != 0) and (c != null)) return 1;
|
\\ if ((b != 0) and (c != null)) return 1;
|
||||||
\\ if ((a != 0) and (c != null)) return 2;
|
\\ if ((a != 0) and (c != null)) return 2;
|
||||||
@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ field: c_int,
|
\\ field: c_int,
|
||||||
\\};
|
\\};
|
||||||
\\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
|
\\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
|
||||||
\\ return (??foo).field;
|
\\ return foo.?.field;
|
||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -653,8 +653,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ return x;
|
\\ return x;
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub export fn foo(x: ?[*]c_ushort) ?[*]c_void {
|
\\pub export fn foo(x: ?[*]c_ushort) ?*c_void {
|
||||||
\\ return @ptrCast(?[*]c_void, x);
|
\\ return @ptrCast(?*c_void, x);
|
||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -969,11 +969,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\pub export fn bar() void {
|
\\pub export fn bar() void {
|
||||||
\\ var f: ?extern fn() void = foo;
|
\\ var f: ?extern fn() void = foo;
|
||||||
\\ var b: ?extern fn() c_int = baz;
|
\\ var b: ?extern fn() c_int = baz;
|
||||||
\\ (??f)();
|
\\ f.?();
|
||||||
\\ (??f)();
|
\\ f.?();
|
||||||
\\ foo();
|
\\ foo();
|
||||||
\\ _ = (??b)();
|
\\ _ = b.?();
|
||||||
\\ _ = (??b)();
|
\\ _ = b.?();
|
||||||
\\ _ = baz();
|
\\ _ = baz();
|
||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
@ -984,7 +984,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub export fn foo(x: ?[*]c_int) void {
|
\\pub export fn foo(x: ?[*]c_int) void {
|
||||||
\\ (??x).* = 1;
|
\\ x.?.* = 1;
|
||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1012,7 +1012,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\pub fn foo() c_int {
|
\\pub fn foo() c_int {
|
||||||
\\ var x: c_int = 1234;
|
\\ var x: c_int = 1234;
|
||||||
\\ var ptr: ?[*]c_int = &x;
|
\\ var ptr: ?[*]c_int = &x;
|
||||||
\\ return (??ptr).*;
|
\\ return ptr.?.*;
|
||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1119,7 +1119,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\pub const glClearPFN = PFNGLCLEARPROC;
|
\\pub const glClearPFN = PFNGLCLEARPROC;
|
||||||
,
|
,
|
||||||
\\pub inline fn glClearUnion(arg0: GLbitfield) void {
|
\\pub inline fn glClearUnion(arg0: GLbitfield) void {
|
||||||
\\ return (??glProcs.gl.Clear)(arg0);
|
\\ return glProcs.gl.Clear.?(arg0);
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub const OpenGLProcs = union_OpenGLProcs;
|
\\pub const OpenGLProcs = union_OpenGLProcs;
|
||||||
@ -1173,7 +1173,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ return !c;
|
\\ return !c;
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub fn foo(a: c_int, b: f32, c: ?[*]c_void) c_int {
|
\\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||||
\\ return !(a == 0);
|
\\ return !(a == 0);
|
||||||
\\ return !(a != 0);
|
\\ return !(a != 0);
|
||||||
\\ return !(b != 0);
|
\\ return !(b != 0);
|
||||||
@ -1231,7 +1231,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ B,
|
\\ B,
|
||||||
\\ C,
|
\\ C,
|
||||||
\\};
|
\\};
|
||||||
\\pub fn if_none_bool(a: c_int, b: f32, c: ?[*]c_void, d: enum_SomeEnum) c_int {
|
\\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
|
||||||
\\ if (a != 0) return 0;
|
\\ if (a != 0) return 0;
|
||||||
\\ if (b != 0) return 1;
|
\\ if (b != 0) return 1;
|
||||||
\\ if (c != null) return 2;
|
\\ if (c != null) return 2;
|
||||||
@ -1248,7 +1248,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ return 3;
|
\\ return 3;
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub fn while_none_bool(a: c_int, b: f32, c: ?[*]c_void) c_int {
|
\\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||||
\\ while (a != 0) return 0;
|
\\ while (a != 0) return 0;
|
||||||
\\ while (b != 0) return 1;
|
\\ while (b != 0) return 1;
|
||||||
\\ while (c != null) return 2;
|
\\ while (c != null) return 2;
|
||||||
@ -1264,7 +1264,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ return 3;
|
\\ return 3;
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
\\pub fn for_none_bool(a: c_int, b: f32, c: ?[*]c_void) c_int {
|
\\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||||
\\ while (a != 0) return 0;
|
\\ while (a != 0) return 0;
|
||||||
\\ while (b != 0) return 1;
|
\\ while (b != 0) return 1;
|
||||||
\\ while (c != null) return 2;
|
\\ while (c != null) return 2;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user