Merge pull request #19102 from ziglang/decouple-zir
JIT `zig fmt` and `zig reduce`
This commit is contained in:
@@ -505,6 +505,7 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/unicode.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/Ast.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/AstGen.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/AstRlAnnotate.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/Parse.zig"
|
||||
@@ -515,8 +516,8 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/system/NativePaths.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/system/x86.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/Zir.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Air.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/AstGen.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Compilation/Config.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
|
||||
@@ -527,7 +528,6 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/Sema.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/TypedValue.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Value.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Zir.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/CodeGen.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"
|
||||
|
||||
@@ -34,7 +34,6 @@ pub fn build(b: *std.Build) !void {
|
||||
const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files;
|
||||
const skip_install_autodocs = b.option(bool, "no-autodocs", "skip copying of standard library autodocs to the installation prefix") orelse skip_install_lib_files;
|
||||
const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;
|
||||
const only_reduce = b.option(bool, "only-reduce", "only build zig reduce") orelse false;
|
||||
|
||||
const docgen_exe = b.addExecutable(.{
|
||||
.name = "docgen",
|
||||
@@ -245,7 +244,6 @@ pub fn build(b: *std.Build) !void {
|
||||
exe_options.addOption(bool, "force_gpa", force_gpa);
|
||||
exe_options.addOption(bool, "only_c", only_c);
|
||||
exe_options.addOption(bool, "only_core_functionality", only_c);
|
||||
exe_options.addOption(bool, "only_reduce", only_reduce);
|
||||
|
||||
if (link_libc) {
|
||||
exe.linkLibC();
|
||||
@@ -407,7 +405,6 @@ pub fn build(b: *std.Build) !void {
|
||||
test_cases_options.addOption(bool, "force_gpa", force_gpa);
|
||||
test_cases_options.addOption(bool, "only_c", only_c);
|
||||
test_cases_options.addOption(bool, "only_core_functionality", true);
|
||||
test_cases_options.addOption(bool, "only_reduce", false);
|
||||
test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu);
|
||||
test_cases_options.addOption(bool, "enable_wine", b.enable_wine);
|
||||
test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
|
||||
@@ -599,7 +596,6 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
|
||||
exe_options.addOption(bool, "enable_tracy_allocation", false);
|
||||
exe_options.addOption(bool, "value_tracing", false);
|
||||
exe_options.addOption(bool, "only_core_functionality", true);
|
||||
exe_options.addOption(bool, "only_reduce", false);
|
||||
|
||||
const run_opt = b.addSystemCommand(&.{
|
||||
"wasm-opt",
|
||||
|
||||
@@ -13,7 +13,7 @@ const Step = std.Build.Step;
|
||||
pub const dependencies = @import("@dependencies");
|
||||
|
||||
pub fn main() !void {
|
||||
// Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,
|
||||
// Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
|
||||
// one shot program. We don't need to waste time freeing memory and finding places to squish
|
||||
// bytes into. So we free everything all at once at the very end.
|
||||
var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
|
||||
342
lib/compiler/fmt.zig
Normal file
342
lib/compiler/fmt.zig
Normal file
@@ -0,0 +1,342 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const fs = std.fs;
|
||||
const process = std.process;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const warn = std.log.warn;
|
||||
const Color = std.zig.Color;
|
||||
|
||||
const usage_fmt =
|
||||
\\Usage: zig fmt [file]...
|
||||
\\
|
||||
\\ Formats the input files and modifies them in-place.
|
||||
\\ Arguments can be files or directories, which are searched
|
||||
\\ recursively.
|
||||
\\
|
||||
\\Options:
|
||||
\\ -h, --help Print this help and exit
|
||||
\\ --color [auto|off|on] Enable or disable colored error messages
|
||||
\\ --stdin Format code from stdin; output to stdout
|
||||
\\ --check List non-conforming files and exit with an error
|
||||
\\ if the list is non-empty
|
||||
\\ --ast-check Run zig ast-check on every file
|
||||
\\ --exclude [file] Exclude file or directory from formatting
|
||||
\\
|
||||
\\
|
||||
;
|
||||
|
||||
const Fmt = struct {
|
||||
seen: SeenMap,
|
||||
any_error: bool,
|
||||
check_ast: bool,
|
||||
color: Color,
|
||||
gpa: Allocator,
|
||||
arena: Allocator,
|
||||
out_buffer: std.ArrayList(u8),
|
||||
|
||||
const SeenMap = std.AutoHashMap(fs.File.INode, void);
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena_instance.deinit();
|
||||
const arena = arena_instance.allocator();
|
||||
const gpa = arena;
|
||||
|
||||
const args = try process.argsAlloc(arena);
|
||||
|
||||
var color: Color = .auto;
|
||||
var stdin_flag: bool = false;
|
||||
var check_flag: bool = false;
|
||||
var check_ast_flag: bool = false;
|
||||
var input_files = std.ArrayList([]const u8).init(gpa);
|
||||
defer input_files.deinit();
|
||||
var excluded_files = std.ArrayList([]const u8).init(gpa);
|
||||
defer excluded_files.deinit();
|
||||
|
||||
{
|
||||
var i: usize = 1;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (mem.startsWith(u8, arg, "-")) {
|
||||
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
try stdout.writeAll(usage_fmt);
|
||||
return process.cleanExit();
|
||||
} else if (mem.eql(u8, arg, "--color")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected [auto|on|off] after --color", .{});
|
||||
}
|
||||
i += 1;
|
||||
const next_arg = args[i];
|
||||
color = std.meta.stringToEnum(Color, next_arg) orelse {
|
||||
fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
|
||||
};
|
||||
} else if (mem.eql(u8, arg, "--stdin")) {
|
||||
stdin_flag = true;
|
||||
} else if (mem.eql(u8, arg, "--check")) {
|
||||
check_flag = true;
|
||||
} else if (mem.eql(u8, arg, "--ast-check")) {
|
||||
check_ast_flag = true;
|
||||
} else if (mem.eql(u8, arg, "--exclude")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected parameter after --exclude", .{});
|
||||
}
|
||||
i += 1;
|
||||
const next_arg = args[i];
|
||||
try excluded_files.append(next_arg);
|
||||
} else {
|
||||
fatal("unrecognized parameter: '{s}'", .{arg});
|
||||
}
|
||||
} else {
|
||||
try input_files.append(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stdin_flag) {
|
||||
if (input_files.items.len != 0) {
|
||||
fatal("cannot use --stdin with positional arguments", .{});
|
||||
}
|
||||
|
||||
const stdin = std.io.getStdIn();
|
||||
const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| {
|
||||
fatal("unable to read stdin: {}", .{err});
|
||||
};
|
||||
defer gpa.free(source_code);
|
||||
|
||||
var tree = std.zig.Ast.parse(gpa, source_code, .zig) catch |err| {
|
||||
fatal("error parsing stdin: {}", .{err});
|
||||
};
|
||||
defer tree.deinit(gpa);
|
||||
|
||||
if (check_ast_flag) {
|
||||
var zir = try std.zig.AstGen.generate(gpa, tree);
|
||||
|
||||
if (zir.hasCompileErrors()) {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try wip_errors.addZirErrorMessages(zir, tree, source_code, "<stdin>");
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(color.renderOptions());
|
||||
process.exit(2);
|
||||
}
|
||||
} else if (tree.errors.len != 0) {
|
||||
try std.zig.printAstErrorsToStderr(gpa, tree, "<stdin>", color);
|
||||
process.exit(2);
|
||||
}
|
||||
const formatted = try tree.render(gpa);
|
||||
defer gpa.free(formatted);
|
||||
|
||||
if (check_flag) {
|
||||
const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
return std.io.getStdOut().writeAll(formatted);
|
||||
}
|
||||
|
||||
if (input_files.items.len == 0) {
|
||||
fatal("expected at least one source file argument", .{});
|
||||
}
|
||||
|
||||
var fmt = Fmt{
|
||||
.gpa = gpa,
|
||||
.arena = arena,
|
||||
.seen = Fmt.SeenMap.init(gpa),
|
||||
.any_error = false,
|
||||
.check_ast = check_ast_flag,
|
||||
.color = color,
|
||||
.out_buffer = std.ArrayList(u8).init(gpa),
|
||||
};
|
||||
defer fmt.seen.deinit();
|
||||
defer fmt.out_buffer.deinit();
|
||||
|
||||
// Mark any excluded files/directories as already seen,
|
||||
// so that they are skipped later during actual processing
|
||||
for (excluded_files.items) |file_path| {
|
||||
const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
|
||||
error.FileNotFound => continue,
|
||||
// On Windows, statFile does not work for directories
|
||||
error.IsDir => dir: {
|
||||
var dir = try fs.cwd().openDir(file_path, .{});
|
||||
defer dir.close();
|
||||
break :dir try dir.stat();
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try fmt.seen.put(stat.inode, {});
|
||||
}
|
||||
|
||||
for (input_files.items) |file_path| {
|
||||
try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
|
||||
}
|
||||
if (fmt.any_error) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const FmtError = error{
|
||||
SystemResources,
|
||||
OperationAborted,
|
||||
IoPending,
|
||||
BrokenPipe,
|
||||
Unexpected,
|
||||
WouldBlock,
|
||||
FileClosed,
|
||||
DestinationAddressRequired,
|
||||
DiskQuota,
|
||||
FileTooBig,
|
||||
InputOutput,
|
||||
NoSpaceLeft,
|
||||
AccessDenied,
|
||||
OutOfMemory,
|
||||
RenameAcrossMountPoints,
|
||||
ReadOnlyFileSystem,
|
||||
LinkQuotaExceeded,
|
||||
FileBusy,
|
||||
EndOfStream,
|
||||
Unseekable,
|
||||
NotOpenForWriting,
|
||||
UnsupportedEncoding,
|
||||
ConnectionResetByPeer,
|
||||
SocketNotConnected,
|
||||
LockViolation,
|
||||
NetNameDeleted,
|
||||
InvalidArgument,
|
||||
} || fs.File.OpenError;
|
||||
|
||||
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
|
||||
fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
|
||||
error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
|
||||
else => {
|
||||
warn("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
|
||||
fmt.any_error = true;
|
||||
return;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn fmtPathDir(
|
||||
fmt: *Fmt,
|
||||
file_path: []const u8,
|
||||
check_mode: bool,
|
||||
parent_dir: fs.Dir,
|
||||
parent_sub_path: []const u8,
|
||||
) FmtError!void {
|
||||
var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
const stat = try dir.stat();
|
||||
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
|
||||
|
||||
var dir_it = dir.iterate();
|
||||
while (try dir_it.next()) |entry| {
|
||||
const is_dir = entry.kind == .directory;
|
||||
|
||||
if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
|
||||
|
||||
if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
|
||||
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
|
||||
defer fmt.gpa.free(full_path);
|
||||
|
||||
if (is_dir) {
|
||||
try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
|
||||
} else {
|
||||
fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
|
||||
warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
|
||||
fmt.any_error = true;
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmtPathFile(
|
||||
fmt: *Fmt,
|
||||
file_path: []const u8,
|
||||
check_mode: bool,
|
||||
dir: fs.Dir,
|
||||
sub_path: []const u8,
|
||||
) FmtError!void {
|
||||
const source_file = try dir.openFile(sub_path, .{});
|
||||
var file_closed = false;
|
||||
errdefer if (!file_closed) source_file.close();
|
||||
|
||||
const stat = try source_file.stat();
|
||||
|
||||
if (stat.kind == .directory)
|
||||
return error.IsDir;
|
||||
|
||||
const gpa = fmt.gpa;
|
||||
const source_code = try std.zig.readSourceFileToEndAlloc(
|
||||
gpa,
|
||||
source_file,
|
||||
std.math.cast(usize, stat.size) orelse return error.FileTooBig,
|
||||
);
|
||||
defer gpa.free(source_code);
|
||||
|
||||
source_file.close();
|
||||
file_closed = true;
|
||||
|
||||
// Add to set after no longer possible to get error.IsDir.
|
||||
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
|
||||
|
||||
var tree = try std.zig.Ast.parse(gpa, source_code, .zig);
|
||||
defer tree.deinit(gpa);
|
||||
|
||||
if (tree.errors.len != 0) {
|
||||
try std.zig.printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
|
||||
fmt.any_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmt.check_ast) {
|
||||
if (stat.size > std.zig.max_src_size)
|
||||
return error.FileTooBig;
|
||||
|
||||
var zir = try std.zig.AstGen.generate(gpa, tree);
|
||||
defer zir.deinit(gpa);
|
||||
|
||||
if (zir.hasCompileErrors()) {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try wip_errors.addZirErrorMessages(zir, tree, source_code, file_path);
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(fmt.color.renderOptions());
|
||||
fmt.any_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
// As a heuristic, we make enough capacity for the same as the input source.
|
||||
fmt.out_buffer.shrinkRetainingCapacity(0);
|
||||
try fmt.out_buffer.ensureTotalCapacity(source_code.len);
|
||||
|
||||
try tree.renderToArrayList(&fmt.out_buffer, .{});
|
||||
if (mem.eql(u8, fmt.out_buffer.items, source_code))
|
||||
return;
|
||||
|
||||
if (check_mode) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
try stdout.print("{s}\n", .{file_path});
|
||||
fmt.any_error = true;
|
||||
} else {
|
||||
var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
|
||||
defer af.deinit();
|
||||
|
||||
try af.file.writeAll(fmt.out_buffer.items);
|
||||
try af.finish();
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
try stdout.print("{s}\n", .{file_path});
|
||||
}
|
||||
}
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.err(format, args);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -2,11 +2,10 @@ const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const fatal = @import("./main.zig").fatal;
|
||||
const Ast = std.zig.Ast;
|
||||
const Walk = @import("reduce/Walk.zig");
|
||||
const AstGen = @import("AstGen.zig");
|
||||
const Zir = @import("Zir.zig");
|
||||
const AstGen = std.zig.AstGen;
|
||||
const Zir = std.zig.Zir;
|
||||
|
||||
const usage =
|
||||
\\zig reduce [options] ./checker root_source_file.zig [-- [argv]]
|
||||
@@ -47,7 +46,16 @@ const Interestingness = enum { interesting, unknown, boring };
|
||||
// - reduce flags sent to the compiler
|
||||
// - integrate with the build system?
|
||||
|
||||
pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
pub fn main() !void {
|
||||
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena_instance.deinit();
|
||||
const arena = arena_instance.allocator();
|
||||
|
||||
var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
|
||||
const gpa = general_purpose_allocator.allocator();
|
||||
|
||||
const args = try std.process.argsAlloc(arena);
|
||||
|
||||
var opt_checker_path: ?[]const u8 = null;
|
||||
var opt_root_source_file_path: ?[]const u8 = null;
|
||||
var argv: []const []const u8 = &.{};
|
||||
@@ -55,7 +63,7 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
var skip_smoke_test = false;
|
||||
|
||||
{
|
||||
var i: usize = 2; // skip over "zig" and "reduce"
|
||||
var i: usize = 1;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (mem.startsWith(u8, arg, "-")) {
|
||||
@@ -411,3 +419,8 @@ fn parse(gpa: Allocator, file_path: []const u8) !Ast {
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.err(format, args);
|
||||
std.process.exit(1);
|
||||
}
|
||||
@@ -193,7 +193,9 @@ pub const valgrind = @import("valgrind.zig");
|
||||
/// Constants and types representing the Wasm binary format.
|
||||
pub const wasm = @import("wasm.zig");
|
||||
|
||||
/// Tokenizing and parsing of Zig code and other Zig-specific language tooling.
|
||||
/// Builds of the Zig compiler are distributed partly in source form. That
|
||||
/// source lives here. These APIs are provided as-is and have absolutely no API
|
||||
/// guarantees whatsoever.
|
||||
pub const zig = @import("zig.zig");
|
||||
|
||||
pub const start = @import("start.zig");
|
||||
|
||||
603
lib/std/zig.zig
603
lib/std/zig.zig
@@ -1,17 +1,14 @@
|
||||
pub const fmt = @import("zig/fmt.zig");
|
||||
|
||||
pub const ErrorBundle = @import("zig/ErrorBundle.zig");
|
||||
pub const Server = @import("zig/Server.zig");
|
||||
pub const Client = @import("zig/Client.zig");
|
||||
pub const Token = tokenizer.Token;
|
||||
pub const Tokenizer = tokenizer.Tokenizer;
|
||||
pub const fmtId = fmt.fmtId;
|
||||
pub const fmtEscapes = fmt.fmtEscapes;
|
||||
pub const isValidId = fmt.isValidId;
|
||||
pub const string_literal = @import("zig/string_literal.zig");
|
||||
pub const number_literal = @import("zig/number_literal.zig");
|
||||
pub const primitives = @import("zig/primitives.zig");
|
||||
pub const Ast = @import("zig/Ast.zig");
|
||||
pub const AstGen = @import("zig/AstGen.zig");
|
||||
pub const Zir = @import("zig/Zir.zig");
|
||||
pub const system = @import("zig/system.zig");
|
||||
/// Deprecated: use `std.Target.Query`.
|
||||
pub const CrossTarget = std.Target.Query;
|
||||
@@ -30,6 +27,36 @@ pub const c_translation = @import("zig/c_translation.zig");
|
||||
pub const SrcHasher = std.crypto.hash.Blake3;
|
||||
pub const SrcHash = [16]u8;
|
||||
|
||||
pub const Color = enum {
|
||||
/// Determine whether stderr is a terminal or not automatically.
|
||||
auto,
|
||||
/// Assume stderr is not a terminal.
|
||||
off,
|
||||
/// Assume stderr is a terminal.
|
||||
on,
|
||||
|
||||
pub fn get_tty_conf(color: Color) std.io.tty.Config {
|
||||
return switch (color) {
|
||||
.auto => std.io.tty.detectConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
|
||||
const ttyconf = get_tty_conf(color);
|
||||
return .{
|
||||
.ttyconf = ttyconf,
|
||||
.include_source_line = ttyconf != .no_color,
|
||||
.include_reference_trace = ttyconf != .no_color,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// There are many assumptions in the entire codebase that Zig source files can
|
||||
/// be byte-indexed with a u32 integer.
|
||||
pub const max_src_size = std.math.maxInt(u32);
|
||||
|
||||
pub fn hashSrc(src: []const u8) SrcHash {
|
||||
var out: SrcHash = undefined;
|
||||
SrcHasher.hash(src, &out, .{});
|
||||
@@ -315,11 +342,573 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
|
||||
return buffer.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub const DeclIndex = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
|
||||
return @enumFromInt(@intFromEnum(i));
|
||||
}
|
||||
};
|
||||
|
||||
pub const OptionalDeclIndex = enum(u32) {
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
pub fn init(oi: ?DeclIndex) OptionalDeclIndex {
|
||||
return @enumFromInt(@intFromEnum(oi orelse return .none));
|
||||
}
|
||||
|
||||
pub fn unwrap(oi: OptionalDeclIndex) ?DeclIndex {
|
||||
if (oi == .none) return null;
|
||||
return @enumFromInt(@intFromEnum(oi));
|
||||
}
|
||||
};
|
||||
|
||||
/// Resolving a source location into a byte offset may require doing work
|
||||
/// that we would rather not do unless the error actually occurs.
|
||||
/// Therefore we need a data structure that contains the information necessary
|
||||
/// to lazily produce a `SrcLoc` as required.
|
||||
/// Most of the offsets in this data structure are relative to the containing Decl.
|
||||
/// This makes the source location resolve properly even when a Decl gets
|
||||
/// shifted up or down in the file, as long as the Decl's contents itself
|
||||
/// do not change.
|
||||
pub const LazySrcLoc = union(enum) {
|
||||
/// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
|
||||
/// that all code paths which would need to resolve the source location are
|
||||
/// unreachable. If you are debugging this tag incorrectly being this value,
|
||||
/// look into using reverse-continue with a memory watchpoint to see where the
|
||||
/// value is being set to this tag.
|
||||
unneeded,
|
||||
/// Means the source location points to an entire file; not any particular
|
||||
/// location within the file. `file_scope` union field will be active.
|
||||
entire_file,
|
||||
/// The source location points to a byte offset within a source file,
|
||||
/// offset from 0. The source file is determined contextually.
|
||||
/// Inside a `SrcLoc`, the `file_scope` union field will be active.
|
||||
byte_abs: u32,
|
||||
/// The source location points to a token within a source file,
|
||||
/// offset from 0. The source file is determined contextually.
|
||||
/// Inside a `SrcLoc`, the `file_scope` union field will be active.
|
||||
token_abs: u32,
|
||||
/// The source location points to an AST node within a source file,
|
||||
/// offset from 0. The source file is determined contextually.
|
||||
/// Inside a `SrcLoc`, the `file_scope` union field will be active.
|
||||
node_abs: u32,
|
||||
/// The source location points to a byte offset within a source file,
|
||||
/// offset from the byte offset of the Decl within the file.
|
||||
/// The Decl is determined contextually.
|
||||
byte_offset: u32,
|
||||
/// This data is the offset into the token list from the Decl token.
|
||||
/// The Decl is determined contextually.
|
||||
token_offset: u32,
|
||||
/// The source location points to an AST node, which is this value offset
|
||||
/// from its containing Decl node AST index.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset: TracedOffset,
|
||||
/// The source location points to the main token of an AST node, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_main_token: i32,
|
||||
/// The source location points to the beginning of a struct initializer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_initializer: i32,
|
||||
/// The source location points to a variable declaration type expression,
|
||||
/// found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a variable declaration AST node. Next, navigate
|
||||
/// to the type expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_var_decl_ty: i32,
|
||||
/// The source location points to the alignment expression of a var decl.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_var_decl_align: i32,
|
||||
/// The source location points to the linksection expression of a var decl.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_var_decl_section: i32,
|
||||
/// The source location points to the addrspace expression of a var decl.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_var_decl_addrspace: i32,
|
||||
/// The source location points to the initializer of a var decl.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_var_decl_init: i32,
|
||||
/// The source location points to the first parameter of a builtin
|
||||
/// function call, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a builtin call AST node. Next, navigate
|
||||
/// to the first parameter.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_builtin_call_arg0: i32,
|
||||
/// Same as `node_offset_builtin_call_arg0` except arg index 1.
|
||||
node_offset_builtin_call_arg1: i32,
|
||||
node_offset_builtin_call_arg2: i32,
|
||||
node_offset_builtin_call_arg3: i32,
|
||||
node_offset_builtin_call_arg4: i32,
|
||||
node_offset_builtin_call_arg5: i32,
|
||||
/// Like `node_offset_builtin_call_arg0` but recurses through arbitrarily many calls
|
||||
/// to pointer cast builtins.
|
||||
node_offset_ptrcast_operand: i32,
|
||||
/// The source location points to the index expression of an array access
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to an array access AST node. Next, navigate
|
||||
/// to the index expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_array_access_index: i32,
|
||||
/// The source location points to the LHS of a slice expression
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a slice AST node. Next, navigate
|
||||
/// to the sentinel expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_slice_ptr: i32,
|
||||
/// The source location points to start expression of a slice expression
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a slice AST node. Next, navigate
|
||||
/// to the sentinel expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_slice_start: i32,
|
||||
/// The source location points to the end expression of a slice
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a slice AST node. Next, navigate
|
||||
/// to the sentinel expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_slice_end: i32,
|
||||
/// The source location points to the sentinel expression of a slice
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a slice AST node. Next, navigate
|
||||
/// to the sentinel expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_slice_sentinel: i32,
|
||||
/// The source location points to the callee expression of a function
|
||||
/// call expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function call AST node. Next, navigate
|
||||
/// to the callee expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_call_func: i32,
|
||||
/// The payload is offset from the containing Decl AST node.
|
||||
/// The source location points to the field name of:
|
||||
/// * a field access expression (`a.b`), or
|
||||
/// * the callee of a method call (`a.b()`)
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_field_name: i32,
|
||||
/// The payload is offset from the containing Decl AST node.
|
||||
/// The source location points to the field name of the operand ("b" node)
|
||||
/// of a field initialization expression (`.a = b`)
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_field_name_init: i32,
|
||||
/// The source location points to the pointer of a pointer deref expression,
|
||||
/// found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a pointer deref AST node. Next, navigate
|
||||
/// to the pointer expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_deref_ptr: i32,
|
||||
/// The source location points to the assembly source code of an inline assembly
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to inline assembly AST node. Next, navigate
|
||||
/// to the asm template source code.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_asm_source: i32,
|
||||
/// The source location points to the return type of an inline assembly
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to inline assembly AST node. Next, navigate
|
||||
/// to the return type expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_asm_ret_ty: i32,
|
||||
/// The source location points to the condition expression of an if
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to an if expression AST node. Next, navigate
|
||||
/// to the condition expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_if_cond: i32,
|
||||
/// The source location points to a binary expression, such as `a + b`, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_bin_op: i32,
|
||||
/// The source location points to the LHS of a binary expression, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node,
|
||||
/// which points to a binary expression AST node. Next, navigate to the LHS.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_bin_lhs: i32,
|
||||
/// The source location points to the RHS of a binary expression, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node,
|
||||
/// which points to a binary expression AST node. Next, navigate to the RHS.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_bin_rhs: i32,
|
||||
/// The source location points to the operand of a switch expression, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node,
|
||||
/// which points to a switch expression AST node. Next, navigate to the operand.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_switch_operand: i32,
|
||||
/// The source location points to the else/`_` prong of a switch expression, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node,
|
||||
/// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_switch_special_prong: i32,
|
||||
/// The source location points to all the ranges of a switch expression, found
|
||||
/// by taking this AST node index offset from the containing Decl AST node,
|
||||
/// which points to a switch expression AST node. Next, navigate to any of the
|
||||
/// range nodes. The error applies to all of them.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_switch_range: i32,
|
||||
/// The source location points to the capture of a switch_prong.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_switch_prong_capture: i32,
|
||||
/// The source location points to the tag capture of a switch_prong.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_switch_prong_tag_capture: i32,
|
||||
/// The source location points to the align expr of a function type
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function type AST node. Next, navigate to
|
||||
/// the calling convention node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_fn_type_align: i32,
|
||||
/// The source location points to the addrspace expr of a function type
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function type AST node. Next, navigate to
|
||||
/// the calling convention node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_fn_type_addrspace: i32,
|
||||
/// The source location points to the linksection expr of a function type
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function type AST node. Next, navigate to
|
||||
/// the calling convention node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_fn_type_section: i32,
|
||||
/// The source location points to the calling convention of a function type
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function type AST node. Next, navigate to
|
||||
/// the calling convention node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_fn_type_cc: i32,
|
||||
/// The source location points to the return type of a function type
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function type AST node. Next, navigate to
|
||||
/// the return type node.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_fn_type_ret_ty: i32,
|
||||
node_offset_param: i32,
|
||||
token_offset_param: i32,
|
||||
/// The source location points to the type expression of an `anyframe->T`
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
|
||||
/// to the type expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_anyframe_type: i32,
|
||||
/// The source location points to the string literal of `extern "foo"`, found
|
||||
/// by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function prototype or variable declaration
|
||||
/// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_lib_name: i32,
|
||||
/// The source location points to the len expression of an `[N:S]T`
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
|
||||
/// to the len expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_array_type_len: i32,
|
||||
/// The source location points to the sentinel expression of an `[N:S]T`
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
|
||||
/// to the sentinel expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_array_type_sentinel: i32,
|
||||
/// The source location points to the elem expression of an `[N:S]T`
|
||||
/// expression, found by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
|
||||
/// to the elem expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_array_type_elem: i32,
|
||||
/// The source location points to the operand of an unary expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_un_op: i32,
|
||||
/// The source location points to the elem type of a pointer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_ptr_elem: i32,
|
||||
/// The source location points to the sentinel of a pointer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_ptr_sentinel: i32,
|
||||
/// The source location points to the align expr of a pointer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_ptr_align: i32,
|
||||
/// The source location points to the addrspace expr of a pointer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_ptr_addrspace: i32,
|
||||
/// The source location points to the bit-offset of a pointer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_ptr_bitoffset: i32,
|
||||
/// The source location points to the host size of a pointer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_ptr_hostsize: i32,
|
||||
/// The source location points to the tag type of an union or an enum.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_container_tag: i32,
|
||||
/// The source location points to the default value of a field.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_field_default: i32,
|
||||
/// The source location points to the type of an array or struct initializer.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_init_ty: i32,
|
||||
/// The source location points to the LHS of an assignment.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_store_ptr: i32,
|
||||
/// The source location points to the RHS of an assignment.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_store_operand: i32,
|
||||
/// The source location points to the operand of a `return` statement, or
|
||||
/// the `return` itself if there is no explicit operand.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_return_operand: i32,
|
||||
/// The source location points to a for loop input.
|
||||
/// The Decl is determined contextually.
|
||||
for_input: struct {
|
||||
/// Points to the for loop AST node.
|
||||
for_node_offset: i32,
|
||||
/// Picks one of the inputs from the condition.
|
||||
input_index: u32,
|
||||
},
|
||||
/// The source location points to one of the captures of a for loop, found
|
||||
/// by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to one of the input nodes of a for loop.
|
||||
/// Next, navigate to the corresponding capture.
|
||||
/// The Decl is determined contextually.
|
||||
for_capture_from_input: i32,
|
||||
/// The source location points to the argument node of a function call.
|
||||
call_arg: struct {
|
||||
decl: DeclIndex,
|
||||
/// Points to the function call AST node.
|
||||
call_node_offset: i32,
|
||||
/// The index of the argument the source location points to.
|
||||
arg_index: u32,
|
||||
},
|
||||
fn_proto_param: struct {
|
||||
decl: DeclIndex,
|
||||
/// Points to the function prototype AST node.
|
||||
fn_proto_node_offset: i32,
|
||||
/// The index of the parameter the source location points to.
|
||||
param_index: u32,
|
||||
},
|
||||
array_cat_lhs: ArrayCat,
|
||||
array_cat_rhs: ArrayCat,
|
||||
|
||||
const ArrayCat = struct {
|
||||
/// Points to the array concat AST node.
|
||||
array_cat_offset: i32,
|
||||
/// The index of the element the source location points to.
|
||||
elem_index: u32,
|
||||
};
|
||||
|
||||
pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
|
||||
|
||||
noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
|
||||
var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
|
||||
result.node_offset.trace.addAddr(@returnAddress(), "init");
|
||||
return result;
|
||||
}
|
||||
|
||||
fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
|
||||
return .{ .node_offset = .{ .x = node_offset } };
|
||||
}
|
||||
|
||||
/// This wraps a simple integer in debug builds so that later on we can find out
|
||||
/// where in semantic analysis the value got set.
|
||||
pub const TracedOffset = struct {
|
||||
x: i32,
|
||||
trace: std.debug.Trace = .{},
|
||||
|
||||
const want_tracing = false;
|
||||
};
|
||||
};
|
||||
|
||||
const std = @import("std.zig");
|
||||
const tokenizer = @import("zig/tokenizer.zig");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
/// Return a Formatter for a Zig identifier
|
||||
pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
/// Print the string as a Zig identifier escaping it with @"" syntax if needed.
|
||||
fn formatId(
|
||||
bytes: []const u8,
|
||||
comptime unused_format_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_format_string;
|
||||
if (isValidId(bytes)) {
|
||||
return writer.writeAll(bytes);
|
||||
}
|
||||
try writer.writeAll("@\"");
|
||||
try stringEscape(bytes, "", options, writer);
|
||||
try writer.writeByte('"');
|
||||
}
|
||||
|
||||
/// Return a Formatter for Zig Escapes of a double quoted string.
|
||||
/// The format specifier must be one of:
|
||||
/// * `{}` treats contents as a double-quoted string.
|
||||
/// * `{'}` treats contents as a single-quoted string.
|
||||
pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
test "escape invalid identifiers" {
|
||||
const expectFmt = std.testing.expectFmt;
|
||||
try expectFmt("@\"while\"", "{}", .{fmtId("while")});
|
||||
try expectFmt("hello", "{}", .{fmtId("hello")});
|
||||
try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
|
||||
try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
|
||||
try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
|
||||
try expectFmt(
|
||||
\\" \\ hi \x07 \x11 " derp \'"
|
||||
, "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
|
||||
try expectFmt(
|
||||
\\" \\ hi \x07 \x11 \" derp '"
|
||||
, "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
|
||||
}
|
||||
|
||||
/// Print the string as escaped contents of a double quoted or single-quoted string.
|
||||
/// Format `{}` treats contents as a double-quoted string.
|
||||
/// Format `{'}` treats contents as a single-quoted string.
|
||||
pub fn stringEscape(
|
||||
bytes: []const u8,
|
||||
comptime f: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = options;
|
||||
for (bytes) |byte| switch (byte) {
|
||||
'\n' => try writer.writeAll("\\n"),
|
||||
'\r' => try writer.writeAll("\\r"),
|
||||
'\t' => try writer.writeAll("\\t"),
|
||||
'\\' => try writer.writeAll("\\\\"),
|
||||
'"' => {
|
||||
if (f.len == 1 and f[0] == '\'') {
|
||||
try writer.writeByte('"');
|
||||
} else if (f.len == 0) {
|
||||
try writer.writeAll("\\\"");
|
||||
} else {
|
||||
@compileError("expected {} or {'}, found {" ++ f ++ "}");
|
||||
}
|
||||
},
|
||||
'\'' => {
|
||||
if (f.len == 1 and f[0] == '\'') {
|
||||
try writer.writeAll("\\'");
|
||||
} else if (f.len == 0) {
|
||||
try writer.writeByte('\'');
|
||||
} else {
|
||||
@compileError("expected {} or {'}, found {" ++ f ++ "}");
|
||||
}
|
||||
},
|
||||
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
|
||||
// Use hex escapes for rest any unprintable characters.
|
||||
else => {
|
||||
try writer.writeAll("\\x");
|
||||
try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isValidId(bytes: []const u8) bool {
|
||||
if (bytes.len == 0) return false;
|
||||
if (std.mem.eql(u8, bytes, "_")) return false;
|
||||
for (bytes, 0..) |c, i| {
|
||||
switch (c) {
|
||||
'_', 'a'...'z', 'A'...'Z' => {},
|
||||
'0'...'9' => if (i == 0) return false,
|
||||
else => return false,
|
||||
}
|
||||
}
|
||||
return std.zig.Token.getKeyword(bytes) == null;
|
||||
}
|
||||
|
||||
test isValidId {
|
||||
try std.testing.expect(!isValidId(""));
|
||||
try std.testing.expect(isValidId("foobar"));
|
||||
try std.testing.expect(!isValidId("a b c"));
|
||||
try std.testing.expect(!isValidId("3d"));
|
||||
try std.testing.expect(!isValidId("enum"));
|
||||
try std.testing.expect(isValidId("i386"));
|
||||
}
|
||||
|
||||
pub fn readSourceFileToEndAlloc(
|
||||
allocator: Allocator,
|
||||
input: std.fs.File,
|
||||
size_hint: ?usize,
|
||||
) ![:0]u8 {
|
||||
const source_code = input.readToEndAllocOptions(
|
||||
allocator,
|
||||
max_src_size,
|
||||
size_hint,
|
||||
@alignOf(u16),
|
||||
0,
|
||||
) catch |err| switch (err) {
|
||||
error.ConnectionResetByPeer => unreachable,
|
||||
error.ConnectionTimedOut => unreachable,
|
||||
error.NotOpenForReading => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
errdefer allocator.free(source_code);
|
||||
|
||||
// Detect unsupported file types with their Byte Order Mark
|
||||
const unsupported_boms = [_][]const u8{
|
||||
"\xff\xfe\x00\x00", // UTF-32 little endian
|
||||
"\xfe\xff\x00\x00", // UTF-32 big endian
|
||||
"\xfe\xff", // UTF-16 big endian
|
||||
};
|
||||
for (unsupported_boms) |bom| {
|
||||
if (std.mem.startsWith(u8, source_code, bom)) {
|
||||
return error.UnsupportedEncoding;
|
||||
}
|
||||
}
|
||||
|
||||
// If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
|
||||
if (std.mem.startsWith(u8, source_code, "\xff\xfe")) {
|
||||
const source_code_utf16_le = std.mem.bytesAsSlice(u16, source_code);
|
||||
const source_code_utf8 = std.unicode.utf16LeToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {
|
||||
error.DanglingSurrogateHalf => error.UnsupportedEncoding,
|
||||
error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
|
||||
error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
allocator.free(source_code);
|
||||
return source_code_utf8;
|
||||
}
|
||||
|
||||
return source_code;
|
||||
}
|
||||
|
||||
pub fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
|
||||
try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
|
||||
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(color.renderOptions());
|
||||
}
|
||||
|
||||
pub fn putAstErrorsIntoBundle(
|
||||
gpa: Allocator,
|
||||
tree: Ast,
|
||||
path: []const u8,
|
||||
wip_errors: *std.zig.ErrorBundle.Wip,
|
||||
) Allocator.Error!void {
|
||||
var zir = try AstGen.generate(gpa, tree);
|
||||
defer zir.deinit(gpa);
|
||||
|
||||
try wip_errors.addZirErrorMessages(zir, tree, tree.source, path);
|
||||
}
|
||||
|
||||
test {
|
||||
_ = Ast;
|
||||
_ = AstRlAnnotate;
|
||||
_ = BuiltinFn;
|
||||
_ = Client;
|
||||
_ = ErrorBundle;
|
||||
_ = Server;
|
||||
_ = number_literal;
|
||||
_ = primitives;
|
||||
_ = string_literal;
|
||||
_ = system;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,12 @@ pub const Location = struct {
|
||||
line_end: usize,
|
||||
};
|
||||
|
||||
pub const Span = struct {
|
||||
start: u32,
|
||||
end: u32,
|
||||
main: u32,
|
||||
};
|
||||
|
||||
pub fn deinit(tree: *Ast, gpa: Allocator) void {
|
||||
tree.tokens.deinit(gpa);
|
||||
tree.nodes.deinit(gpa);
|
||||
@@ -105,9 +111,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A
|
||||
};
|
||||
}
|
||||
|
||||
/// `gpa` is used for allocating the resulting formatted source code, as well as
|
||||
/// for allocating extra stack memory if needed, because this function utilizes recursion.
|
||||
/// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006.
|
||||
/// `gpa` is used for allocating the resulting formatted source code.
|
||||
/// Caller owns the returned slice of bytes, allocated with `gpa`.
|
||||
pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 {
|
||||
var buffer = std.ArrayList(u8).init(gpa);
|
||||
@@ -3535,6 +3539,39 @@ pub const Node = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
|
||||
return tokensToSpan(
|
||||
tree,
|
||||
tree.firstToken(node),
|
||||
tree.lastToken(node),
|
||||
tree.nodes.items(.main_token)[node],
|
||||
);
|
||||
}
|
||||
|
||||
pub fn tokenToSpan(tree: *const Ast, token: Ast.TokenIndex) Span {
|
||||
return tokensToSpan(tree, token, token, token);
|
||||
}
|
||||
|
||||
pub fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
|
||||
const token_starts = tree.tokens.items(.start);
|
||||
var start_tok = start;
|
||||
var end_tok = end;
|
||||
|
||||
if (tree.tokensOnSameLine(start, end)) {
|
||||
// do nothing
|
||||
} else if (tree.tokensOnSameLine(start, main)) {
|
||||
end_tok = main;
|
||||
} else if (tree.tokensOnSameLine(main, end)) {
|
||||
start_tok = main;
|
||||
} else {
|
||||
start_tok = main;
|
||||
end_tok = main;
|
||||
}
|
||||
const start_off = token_starts[start_tok];
|
||||
const end_off = token_starts[end_tok] + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
|
||||
return Span{ .start = start_off, .end = end_off, .main = token_starts[main] };
|
||||
}
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
@@ -3546,5 +3583,6 @@ const Parse = @import("Parse.zig");
|
||||
const private_render = @import("./render.zig");
|
||||
|
||||
test {
|
||||
testing.refAllDecls(@This());
|
||||
_ = Parse;
|
||||
_ = private_render;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const StringIndexContext = std.hash_map.StringIndexContext;
|
||||
|
||||
const isPrimitive = std.zig.primitives.isPrimitive;
|
||||
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const BuiltinFn = std.zig.BuiltinFn;
|
||||
const AstRlAnnotate = std.zig.AstRlAnnotate;
|
||||
|
||||
@@ -459,6 +459,90 @@ pub const Wip = struct {
|
||||
return @intCast(wip.extra.items.len - notes_len);
|
||||
}
|
||||
|
||||
pub fn addZirErrorMessages(
|
||||
eb: *ErrorBundle.Wip,
|
||||
zir: std.zig.Zir,
|
||||
tree: std.zig.Ast,
|
||||
source: [:0]const u8,
|
||||
src_path: []const u8,
|
||||
) !void {
|
||||
const Zir = std.zig.Zir;
|
||||
const payload_index = zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
|
||||
assert(payload_index != 0);
|
||||
|
||||
const header = zir.extraData(Zir.Inst.CompileErrors, payload_index);
|
||||
const items_len = header.data.items_len;
|
||||
var extra_index = header.end;
|
||||
for (0..items_len) |_| {
|
||||
const item = zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
|
||||
extra_index = item.end;
|
||||
const err_span = blk: {
|
||||
if (item.data.node != 0) {
|
||||
break :blk tree.nodeToSpan(item.data.node);
|
||||
}
|
||||
const token_starts = tree.tokens.items(.start);
|
||||
const start = token_starts[item.data.token] + item.data.byte_offset;
|
||||
const end = start + @as(u32, @intCast(tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
|
||||
break :blk std.zig.Ast.Span{ .start = start, .end = end, .main = start };
|
||||
};
|
||||
const err_loc = std.zig.findLineColumn(source, err_span.main);
|
||||
|
||||
{
|
||||
const msg = zir.nullTerminatedString(item.data.msg);
|
||||
try eb.addRootErrorMessage(.{
|
||||
.msg = try eb.addString(msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(src_path),
|
||||
.span_start = err_span.start,
|
||||
.span_main = err_span.main,
|
||||
.span_end = err_span.end,
|
||||
.line = @intCast(err_loc.line),
|
||||
.column = @intCast(err_loc.column),
|
||||
.source_line = try eb.addString(err_loc.source_line),
|
||||
}),
|
||||
.notes_len = item.data.notesLen(zir),
|
||||
});
|
||||
}
|
||||
|
||||
if (item.data.notes != 0) {
|
||||
const notes_start = try eb.reserveNotes(item.data.notes);
|
||||
const block = zir.extraData(Zir.Inst.Block, item.data.notes);
|
||||
const body = zir.extra[block.end..][0..block.data.body_len];
|
||||
for (notes_start.., body) |note_i, body_elem| {
|
||||
const note_item = zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
|
||||
const msg = zir.nullTerminatedString(note_item.data.msg);
|
||||
const span = blk: {
|
||||
if (note_item.data.node != 0) {
|
||||
break :blk tree.nodeToSpan(note_item.data.node);
|
||||
}
|
||||
const token_starts = tree.tokens.items(.start);
|
||||
const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
|
||||
const end = start + @as(u32, @intCast(tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
|
||||
break :blk std.zig.Ast.Span{ .start = start, .end = end, .main = start };
|
||||
};
|
||||
const loc = std.zig.findLineColumn(source, span.main);
|
||||
|
||||
eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
|
||||
.msg = try eb.addString(msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(src_path),
|
||||
.span_start = span.start,
|
||||
.span_main = span.main,
|
||||
.span_end = span.end,
|
||||
.line = @intCast(loc.line),
|
||||
.column = @intCast(loc.column),
|
||||
.source_line = if (loc.eql(err_loc))
|
||||
0
|
||||
else
|
||||
try eb.addString(loc.source_line),
|
||||
}),
|
||||
.notes_len = 0, // TODO rework this function to be recursive
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {
|
||||
const other_msg = other.getErrorMessage(msg_index);
|
||||
const src_loc = try wip.addOtherSourceLocation(other, other_msg.src_loc);
|
||||
|
||||
@@ -19,10 +19,8 @@ const BigIntConst = std.math.big.int.Const;
|
||||
const BigIntMutable = std.math.big.int.Mutable;
|
||||
const Ast = std.zig.Ast;
|
||||
|
||||
const InternPool = @import("InternPool.zig");
|
||||
const Zir = @This();
|
||||
const Module = @import("Module.zig");
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
|
||||
instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// In order to store references to strings in fewer bytes, we copy all
|
||||
@@ -2093,9 +2091,11 @@ pub const Inst = struct {
|
||||
/// ZIR is structured so that the outermost "main" struct of any file
|
||||
/// is always at index 0.
|
||||
main_struct_inst = 0,
|
||||
ref_start_index = InternPool.static_len,
|
||||
ref_start_index = static_len,
|
||||
_,
|
||||
|
||||
pub const static_len = 84;
|
||||
|
||||
pub fn toRef(i: Index) Inst.Ref {
|
||||
return @enumFromInt(@intFromEnum(Index.ref_start_index) + @intFromEnum(i));
|
||||
}
|
||||
@@ -2109,7 +2109,7 @@ pub const Inst = struct {
|
||||
/// ZIR is structured so that the outermost "main" struct of any file
|
||||
/// is always at index 0.
|
||||
main_struct_inst = 0,
|
||||
ref_start_index = InternPool.static_len,
|
||||
ref_start_index = Index.static_len,
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
@@ -2127,97 +2127,98 @@ pub const Inst = struct {
|
||||
/// The tag type is specified so that it is safe to bitcast between `[]u32`
|
||||
/// and `[]Ref`.
|
||||
pub const Ref = enum(u32) {
|
||||
u0_type = @intFromEnum(InternPool.Index.u0_type),
|
||||
i0_type = @intFromEnum(InternPool.Index.i0_type),
|
||||
u1_type = @intFromEnum(InternPool.Index.u1_type),
|
||||
u8_type = @intFromEnum(InternPool.Index.u8_type),
|
||||
i8_type = @intFromEnum(InternPool.Index.i8_type),
|
||||
u16_type = @intFromEnum(InternPool.Index.u16_type),
|
||||
i16_type = @intFromEnum(InternPool.Index.i16_type),
|
||||
u29_type = @intFromEnum(InternPool.Index.u29_type),
|
||||
u32_type = @intFromEnum(InternPool.Index.u32_type),
|
||||
i32_type = @intFromEnum(InternPool.Index.i32_type),
|
||||
u64_type = @intFromEnum(InternPool.Index.u64_type),
|
||||
i64_type = @intFromEnum(InternPool.Index.i64_type),
|
||||
u80_type = @intFromEnum(InternPool.Index.u80_type),
|
||||
u128_type = @intFromEnum(InternPool.Index.u128_type),
|
||||
i128_type = @intFromEnum(InternPool.Index.i128_type),
|
||||
usize_type = @intFromEnum(InternPool.Index.usize_type),
|
||||
isize_type = @intFromEnum(InternPool.Index.isize_type),
|
||||
c_char_type = @intFromEnum(InternPool.Index.c_char_type),
|
||||
c_short_type = @intFromEnum(InternPool.Index.c_short_type),
|
||||
c_ushort_type = @intFromEnum(InternPool.Index.c_ushort_type),
|
||||
c_int_type = @intFromEnum(InternPool.Index.c_int_type),
|
||||
c_uint_type = @intFromEnum(InternPool.Index.c_uint_type),
|
||||
c_long_type = @intFromEnum(InternPool.Index.c_long_type),
|
||||
c_ulong_type = @intFromEnum(InternPool.Index.c_ulong_type),
|
||||
c_longlong_type = @intFromEnum(InternPool.Index.c_longlong_type),
|
||||
c_ulonglong_type = @intFromEnum(InternPool.Index.c_ulonglong_type),
|
||||
c_longdouble_type = @intFromEnum(InternPool.Index.c_longdouble_type),
|
||||
f16_type = @intFromEnum(InternPool.Index.f16_type),
|
||||
f32_type = @intFromEnum(InternPool.Index.f32_type),
|
||||
f64_type = @intFromEnum(InternPool.Index.f64_type),
|
||||
f80_type = @intFromEnum(InternPool.Index.f80_type),
|
||||
f128_type = @intFromEnum(InternPool.Index.f128_type),
|
||||
anyopaque_type = @intFromEnum(InternPool.Index.anyopaque_type),
|
||||
bool_type = @intFromEnum(InternPool.Index.bool_type),
|
||||
void_type = @intFromEnum(InternPool.Index.void_type),
|
||||
type_type = @intFromEnum(InternPool.Index.type_type),
|
||||
anyerror_type = @intFromEnum(InternPool.Index.anyerror_type),
|
||||
comptime_int_type = @intFromEnum(InternPool.Index.comptime_int_type),
|
||||
comptime_float_type = @intFromEnum(InternPool.Index.comptime_float_type),
|
||||
noreturn_type = @intFromEnum(InternPool.Index.noreturn_type),
|
||||
anyframe_type = @intFromEnum(InternPool.Index.anyframe_type),
|
||||
null_type = @intFromEnum(InternPool.Index.null_type),
|
||||
undefined_type = @intFromEnum(InternPool.Index.undefined_type),
|
||||
enum_literal_type = @intFromEnum(InternPool.Index.enum_literal_type),
|
||||
atomic_order_type = @intFromEnum(InternPool.Index.atomic_order_type),
|
||||
atomic_rmw_op_type = @intFromEnum(InternPool.Index.atomic_rmw_op_type),
|
||||
calling_convention_type = @intFromEnum(InternPool.Index.calling_convention_type),
|
||||
address_space_type = @intFromEnum(InternPool.Index.address_space_type),
|
||||
float_mode_type = @intFromEnum(InternPool.Index.float_mode_type),
|
||||
reduce_op_type = @intFromEnum(InternPool.Index.reduce_op_type),
|
||||
call_modifier_type = @intFromEnum(InternPool.Index.call_modifier_type),
|
||||
prefetch_options_type = @intFromEnum(InternPool.Index.prefetch_options_type),
|
||||
export_options_type = @intFromEnum(InternPool.Index.export_options_type),
|
||||
extern_options_type = @intFromEnum(InternPool.Index.extern_options_type),
|
||||
type_info_type = @intFromEnum(InternPool.Index.type_info_type),
|
||||
manyptr_u8_type = @intFromEnum(InternPool.Index.manyptr_u8_type),
|
||||
manyptr_const_u8_type = @intFromEnum(InternPool.Index.manyptr_const_u8_type),
|
||||
manyptr_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.manyptr_const_u8_sentinel_0_type),
|
||||
single_const_pointer_to_comptime_int_type = @intFromEnum(InternPool.Index.single_const_pointer_to_comptime_int_type),
|
||||
slice_const_u8_type = @intFromEnum(InternPool.Index.slice_const_u8_type),
|
||||
slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
|
||||
optional_noreturn_type = @intFromEnum(InternPool.Index.optional_noreturn_type),
|
||||
anyerror_void_error_union_type = @intFromEnum(InternPool.Index.anyerror_void_error_union_type),
|
||||
adhoc_inferred_error_set_type = @intFromEnum(InternPool.Index.adhoc_inferred_error_set_type),
|
||||
generic_poison_type = @intFromEnum(InternPool.Index.generic_poison_type),
|
||||
empty_struct_type = @intFromEnum(InternPool.Index.empty_struct_type),
|
||||
undef = @intFromEnum(InternPool.Index.undef),
|
||||
zero = @intFromEnum(InternPool.Index.zero),
|
||||
zero_usize = @intFromEnum(InternPool.Index.zero_usize),
|
||||
zero_u8 = @intFromEnum(InternPool.Index.zero_u8),
|
||||
one = @intFromEnum(InternPool.Index.one),
|
||||
one_usize = @intFromEnum(InternPool.Index.one_usize),
|
||||
one_u8 = @intFromEnum(InternPool.Index.one_u8),
|
||||
four_u8 = @intFromEnum(InternPool.Index.four_u8),
|
||||
negative_one = @intFromEnum(InternPool.Index.negative_one),
|
||||
calling_convention_c = @intFromEnum(InternPool.Index.calling_convention_c),
|
||||
calling_convention_inline = @intFromEnum(InternPool.Index.calling_convention_inline),
|
||||
void_value = @intFromEnum(InternPool.Index.void_value),
|
||||
unreachable_value = @intFromEnum(InternPool.Index.unreachable_value),
|
||||
null_value = @intFromEnum(InternPool.Index.null_value),
|
||||
bool_true = @intFromEnum(InternPool.Index.bool_true),
|
||||
bool_false = @intFromEnum(InternPool.Index.bool_false),
|
||||
empty_struct = @intFromEnum(InternPool.Index.empty_struct),
|
||||
generic_poison = @intFromEnum(InternPool.Index.generic_poison),
|
||||
u0_type,
|
||||
i0_type,
|
||||
u1_type,
|
||||
u8_type,
|
||||
i8_type,
|
||||
u16_type,
|
||||
i16_type,
|
||||
u29_type,
|
||||
u32_type,
|
||||
i32_type,
|
||||
u64_type,
|
||||
i64_type,
|
||||
u80_type,
|
||||
u128_type,
|
||||
i128_type,
|
||||
usize_type,
|
||||
isize_type,
|
||||
c_char_type,
|
||||
c_short_type,
|
||||
c_ushort_type,
|
||||
c_int_type,
|
||||
c_uint_type,
|
||||
c_long_type,
|
||||
c_ulong_type,
|
||||
c_longlong_type,
|
||||
c_ulonglong_type,
|
||||
c_longdouble_type,
|
||||
f16_type,
|
||||
f32_type,
|
||||
f64_type,
|
||||
f80_type,
|
||||
f128_type,
|
||||
anyopaque_type,
|
||||
bool_type,
|
||||
void_type,
|
||||
type_type,
|
||||
anyerror_type,
|
||||
comptime_int_type,
|
||||
comptime_float_type,
|
||||
noreturn_type,
|
||||
anyframe_type,
|
||||
null_type,
|
||||
undefined_type,
|
||||
enum_literal_type,
|
||||
atomic_order_type,
|
||||
atomic_rmw_op_type,
|
||||
calling_convention_type,
|
||||
address_space_type,
|
||||
float_mode_type,
|
||||
reduce_op_type,
|
||||
call_modifier_type,
|
||||
prefetch_options_type,
|
||||
export_options_type,
|
||||
extern_options_type,
|
||||
type_info_type,
|
||||
manyptr_u8_type,
|
||||
manyptr_const_u8_type,
|
||||
manyptr_const_u8_sentinel_0_type,
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
slice_const_u8_type,
|
||||
slice_const_u8_sentinel_0_type,
|
||||
optional_noreturn_type,
|
||||
anyerror_void_error_union_type,
|
||||
adhoc_inferred_error_set_type,
|
||||
generic_poison_type,
|
||||
empty_struct_type,
|
||||
undef,
|
||||
zero,
|
||||
zero_usize,
|
||||
zero_u8,
|
||||
one,
|
||||
one_usize,
|
||||
one_u8,
|
||||
four_u8,
|
||||
negative_one,
|
||||
calling_convention_c,
|
||||
calling_convention_inline,
|
||||
void_value,
|
||||
unreachable_value,
|
||||
null_value,
|
||||
bool_true,
|
||||
bool_false,
|
||||
empty_struct,
|
||||
generic_poison,
|
||||
|
||||
/// This tag is here to match Air and InternPool, however it is unused
|
||||
/// for ZIR purposes.
|
||||
var_args_param_type = @intFromEnum(InternPool.Index.var_args_param_type),
|
||||
var_args_param_type = std.math.maxInt(u32) - 1,
|
||||
/// This Ref does not correspond to any ZIR instruction or constant
|
||||
/// value and may instead be used as a sentinel to indicate null.
|
||||
none = @intFromEnum(InternPool.Index.none),
|
||||
none = std.math.maxInt(u32),
|
||||
|
||||
_,
|
||||
|
||||
pub fn toIndex(inst: Ref) ?Index {
|
||||
@@ -1,110 +0,0 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
|
||||
/// Print the string as a Zig identifier escaping it with @"" syntax if needed.
|
||||
fn formatId(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = fmt;
|
||||
if (isValidId(bytes)) {
|
||||
return writer.writeAll(bytes);
|
||||
}
|
||||
try writer.writeAll("@\"");
|
||||
try stringEscape(bytes, "", options, writer);
|
||||
try writer.writeByte('"');
|
||||
}
|
||||
|
||||
/// Return a Formatter for a Zig identifier
|
||||
pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
pub fn isValidId(bytes: []const u8) bool {
|
||||
if (bytes.len == 0) return false;
|
||||
if (mem.eql(u8, bytes, "_")) return false;
|
||||
for (bytes, 0..) |c, i| {
|
||||
switch (c) {
|
||||
'_', 'a'...'z', 'A'...'Z' => {},
|
||||
'0'...'9' => if (i == 0) return false,
|
||||
else => return false,
|
||||
}
|
||||
}
|
||||
return std.zig.Token.getKeyword(bytes) == null;
|
||||
}
|
||||
|
||||
test "isValidId" {
|
||||
try std.testing.expect(!isValidId(""));
|
||||
try std.testing.expect(isValidId("foobar"));
|
||||
try std.testing.expect(!isValidId("a b c"));
|
||||
try std.testing.expect(!isValidId("3d"));
|
||||
try std.testing.expect(!isValidId("enum"));
|
||||
try std.testing.expect(isValidId("i386"));
|
||||
}
|
||||
|
||||
/// Print the string as escaped contents of a double quoted or single-quoted string.
|
||||
/// Format `{}` treats contents as a double-quoted string.
|
||||
/// Format `{'}` treats contents as a single-quoted string.
|
||||
pub fn stringEscape(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = options;
|
||||
for (bytes) |byte| switch (byte) {
|
||||
'\n' => try writer.writeAll("\\n"),
|
||||
'\r' => try writer.writeAll("\\r"),
|
||||
'\t' => try writer.writeAll("\\t"),
|
||||
'\\' => try writer.writeAll("\\\\"),
|
||||
'"' => {
|
||||
if (fmt.len == 1 and fmt[0] == '\'') {
|
||||
try writer.writeByte('"');
|
||||
} else if (fmt.len == 0) {
|
||||
try writer.writeAll("\\\"");
|
||||
} else {
|
||||
@compileError("expected {} or {'}, found {" ++ fmt ++ "}");
|
||||
}
|
||||
},
|
||||
'\'' => {
|
||||
if (fmt.len == 1 and fmt[0] == '\'') {
|
||||
try writer.writeAll("\\'");
|
||||
} else if (fmt.len == 0) {
|
||||
try writer.writeByte('\'');
|
||||
} else {
|
||||
@compileError("expected {} or {'}, found {" ++ fmt ++ "}");
|
||||
}
|
||||
},
|
||||
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
|
||||
// Use hex escapes for rest any unprintable characters.
|
||||
else => {
|
||||
try writer.writeAll("\\x");
|
||||
try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Return a Formatter for Zig Escapes of a double quoted string.
|
||||
/// The format specifier must be one of:
|
||||
/// * `{}` treats contents as a double-quoted string.
|
||||
/// * `{'}` treats contents as a single-quoted string.
|
||||
pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
test "escape invalid identifiers" {
|
||||
const expectFmt = std.testing.expectFmt;
|
||||
try expectFmt("@\"while\"", "{}", .{fmtId("while")});
|
||||
try expectFmt("hello", "{}", .{fmtId("hello")});
|
||||
try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
|
||||
try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
|
||||
try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
|
||||
try expectFmt(
|
||||
\\" \\ hi \x07 \x11 " derp \'"
|
||||
, "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
|
||||
try expectFmt(
|
||||
\\" \\ hi \x07 \x11 \" derp '"
|
||||
, "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
|
||||
}
|
||||
@@ -9,7 +9,7 @@ const File = Zcu.File;
|
||||
const Module = @import("Package.zig").Module;
|
||||
const Tokenizer = std.zig.Tokenizer;
|
||||
const InternPool = @import("InternPool.zig");
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const Ref = Zir.Inst.Ref;
|
||||
const log = std.log.scoped(.autodoc);
|
||||
const renderer = @import("autodoc/render_source.zig");
|
||||
|
||||
@@ -296,7 +296,7 @@ const Allocator = std.mem.Allocator;
|
||||
const build_options = @import("build_options");
|
||||
const Module = @import("Package/Module.zig");
|
||||
const assert = std.debug.assert;
|
||||
const AstGen = @import("AstGen.zig");
|
||||
const AstGen = std.zig.AstGen;
|
||||
const File = @import("Module.zig").File;
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const log = std.log.scoped(.builtin);
|
||||
|
||||
@@ -35,7 +35,7 @@ const InternPool = @import("InternPool.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const c_codegen = @import("codegen/c.zig");
|
||||
const libtsan = @import("libtsan.zig");
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const Autodoc = @import("Autodoc.zig");
|
||||
const resinator = @import("resinator.zig");
|
||||
const Builtin = @import("Builtin.zig");
|
||||
@@ -3322,85 +3322,10 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
|
||||
assert(file.zir_loaded);
|
||||
assert(file.tree_loaded);
|
||||
assert(file.source_loaded);
|
||||
const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
|
||||
assert(payload_index != 0);
|
||||
const gpa = eb.gpa;
|
||||
|
||||
const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
|
||||
const items_len = header.data.items_len;
|
||||
var extra_index = header.end;
|
||||
for (0..items_len) |_| {
|
||||
const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
|
||||
extra_index = item.end;
|
||||
const err_span = blk: {
|
||||
if (item.data.node != 0) {
|
||||
break :blk Module.SrcLoc.nodeToSpan(&file.tree, item.data.node);
|
||||
}
|
||||
const token_starts = file.tree.tokens.items(.start);
|
||||
const start = token_starts[item.data.token] + item.data.byte_offset;
|
||||
const end = start + @as(u32, @intCast(file.tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
|
||||
break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
|
||||
};
|
||||
const err_loc = std.zig.findLineColumn(file.source, err_span.main);
|
||||
|
||||
{
|
||||
const msg = file.zir.nullTerminatedString(item.data.msg);
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
try eb.addRootErrorMessage(.{
|
||||
.msg = try eb.addString(msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(src_path),
|
||||
.span_start = err_span.start,
|
||||
.span_main = err_span.main,
|
||||
.span_end = err_span.end,
|
||||
.line = @as(u32, @intCast(err_loc.line)),
|
||||
.column = @as(u32, @intCast(err_loc.column)),
|
||||
.source_line = try eb.addString(err_loc.source_line),
|
||||
}),
|
||||
.notes_len = item.data.notesLen(file.zir),
|
||||
});
|
||||
}
|
||||
|
||||
if (item.data.notes != 0) {
|
||||
const notes_start = try eb.reserveNotes(item.data.notes);
|
||||
const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
|
||||
const body = file.zir.extra[block.end..][0..block.data.body_len];
|
||||
for (notes_start.., body) |note_i, body_elem| {
|
||||
const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
|
||||
const msg = file.zir.nullTerminatedString(note_item.data.msg);
|
||||
const span = blk: {
|
||||
if (note_item.data.node != 0) {
|
||||
break :blk Module.SrcLoc.nodeToSpan(&file.tree, note_item.data.node);
|
||||
}
|
||||
const token_starts = file.tree.tokens.items(.start);
|
||||
const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
|
||||
const end = start + @as(u32, @intCast(file.tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
|
||||
break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
|
||||
};
|
||||
const loc = std.zig.findLineColumn(file.source, span.main);
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
|
||||
eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
|
||||
.msg = try eb.addString(msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(src_path),
|
||||
.span_start = span.start,
|
||||
.span_main = span.main,
|
||||
.span_end = span.end,
|
||||
.line = @as(u32, @intCast(loc.line)),
|
||||
.column = @as(u32, @intCast(loc.column)),
|
||||
.source_line = if (loc.eql(err_loc))
|
||||
0
|
||||
else
|
||||
try eb.addString(loc.source_line),
|
||||
}),
|
||||
.notes_len = 0, // TODO rework this function to be recursive
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);
|
||||
}
|
||||
|
||||
pub fn performAllTheWork(
|
||||
|
||||
@@ -338,7 +338,7 @@ const Hash = std.hash.Wyhash;
|
||||
const InternPool = @This();
|
||||
const Module = @import("Module.zig");
|
||||
const Zcu = Module;
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
|
||||
const KeyAdapter = struct {
|
||||
intern_pool: *const InternPool,
|
||||
@@ -383,27 +383,8 @@ pub const RuntimeIndex = enum(u32) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const DeclIndex = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
|
||||
return @enumFromInt(@intFromEnum(i));
|
||||
}
|
||||
};
|
||||
|
||||
pub const OptionalDeclIndex = enum(u32) {
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
pub fn init(oi: ?DeclIndex) OptionalDeclIndex {
|
||||
return @enumFromInt(@intFromEnum(oi orelse return .none));
|
||||
}
|
||||
|
||||
pub fn unwrap(oi: OptionalDeclIndex) ?DeclIndex {
|
||||
if (oi == .none) return null;
|
||||
return @enumFromInt(@intFromEnum(oi));
|
||||
}
|
||||
};
|
||||
pub const DeclIndex = std.zig.DeclIndex;
|
||||
pub const OptionalDeclIndex = std.zig.OptionalDeclIndex;
|
||||
|
||||
pub const NamespaceIndex = enum(u32) {
|
||||
_,
|
||||
@@ -2877,7 +2858,7 @@ pub const static_keys = [_]Key{
|
||||
/// This is specified with an integer literal and a corresponding comptime
|
||||
/// assert below to break an unfortunate and arguably incorrect dependency loop
|
||||
/// when compiling.
|
||||
pub const static_len = 84;
|
||||
pub const static_len = Zir.Inst.Index.static_len;
|
||||
comptime {
|
||||
//@compileLog(static_keys.len);
|
||||
assert(static_len == static_keys.len);
|
||||
|
||||
720
src/Module.zig
720
src/Module.zig
File diff suppressed because it is too large
Load Diff
@@ -126,7 +126,7 @@ pub const Path = struct {
|
||||
) !void {
|
||||
if (fmt_string.len == 1) {
|
||||
// Quote-escape the string.
|
||||
const stringEscape = std.zig.fmt.stringEscape;
|
||||
const stringEscape = std.zig.stringEscape;
|
||||
const f = switch (fmt_string[0]) {
|
||||
'q' => "",
|
||||
'\'' => '\'',
|
||||
|
||||
@@ -592,7 +592,7 @@ fn loadManifest(f: *Fetch, pkg_root: Package.Path) RunError!void {
|
||||
|
||||
if (ast.errors.len > 0) {
|
||||
const file_path = try std.fmt.allocPrint(arena, "{}" ++ Manifest.basename, .{pkg_root});
|
||||
try main.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);
|
||||
try std.zig.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);
|
||||
return error.FetchFailed;
|
||||
}
|
||||
|
||||
@@ -1690,7 +1690,6 @@ const Cache = std.Build.Cache;
|
||||
const ThreadPool = std.Thread.Pool;
|
||||
const WaitGroup = std.Thread.WaitGroup;
|
||||
const Fetch = @This();
|
||||
const main = @import("../main.zig");
|
||||
const git = @import("Fetch/git.zig");
|
||||
const Package = @import("../Package.zig");
|
||||
const Manifest = Package.Manifest;
|
||||
|
||||
80
src/Sema.zig
80
src/Sema.zig
@@ -148,7 +148,7 @@ const Value = @import("Value.zig");
|
||||
const Type = @import("type.zig").Type;
|
||||
const TypedValue = @import("TypedValue.zig");
|
||||
const Air = @import("Air.zig");
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const Module = @import("Module.zig");
|
||||
const trace = @import("tracy.zig").trace;
|
||||
const Namespace = Module.Namespace;
|
||||
@@ -156,7 +156,7 @@ const CompileError = Module.CompileError;
|
||||
const SemaError = Module.SemaError;
|
||||
const Decl = Module.Decl;
|
||||
const CaptureScope = Module.CaptureScope;
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
const RangeSet = @import("RangeSet.zig");
|
||||
const target_util = @import("target.zig");
|
||||
const Package = @import("Package.zig");
|
||||
@@ -397,7 +397,7 @@ pub const Block = struct {
|
||||
break :blk src_loc;
|
||||
} else blk: {
|
||||
const src_decl = mod.declPtr(rt.block.src_decl);
|
||||
break :blk rt.func_src.toSrcLoc(src_decl, mod);
|
||||
break :blk src_decl.toSrcLoc(rt.func_src, mod);
|
||||
};
|
||||
if (rt.return_ty.isGenericPoison()) {
|
||||
return mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
|
||||
@@ -2421,7 +2421,7 @@ fn errNote(
|
||||
) error{OutOfMemory}!void {
|
||||
const mod = sema.mod;
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args);
|
||||
return mod.errNoteNonLazy(src_decl.toSrcLoc(src, mod), parent, format, args);
|
||||
}
|
||||
|
||||
fn addFieldErrNote(
|
||||
@@ -2478,7 +2478,7 @@ fn errMsg(
|
||||
const mod = sema.mod;
|
||||
if (src == .unneeded) return error.NeededSourceLocation;
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args);
|
||||
return Module.ErrorMsg.create(sema.gpa, src_decl.toSrcLoc(src, mod), format, args);
|
||||
}
|
||||
|
||||
pub fn fail(
|
||||
@@ -2556,7 +2556,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg)
|
||||
const decl = mod.declPtr(ref.referencer);
|
||||
try reference_stack.append(.{
|
||||
.decl = decl.name,
|
||||
.src_loc = ref.src.toSrcLoc(decl, mod),
|
||||
.src_loc = decl.toSrcLoc(ref.src, mod),
|
||||
});
|
||||
}
|
||||
referenced_by = ref.referencer;
|
||||
@@ -2599,7 +2599,7 @@ fn reparentOwnedErrorMsg(
|
||||
) !void {
|
||||
const mod = sema.mod;
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
const resolved_src = src.toSrcLoc(src_decl, mod);
|
||||
const resolved_src = src_decl.toSrcLoc(src, mod);
|
||||
const msg_str = try std.fmt.allocPrint(mod.gpa, format, args);
|
||||
|
||||
const orig_notes = msg.notes.len;
|
||||
@@ -5252,7 +5252,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), elem_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
@@ -5716,7 +5716,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
var child_block = parent_block.makeSubBlock();
|
||||
child_block.label = &label;
|
||||
child_block.runtime_cond = null;
|
||||
child_block.runtime_loop = src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
|
||||
child_block.runtime_loop = mod.declPtr(child_block.src_decl).toSrcLoc(src, mod);
|
||||
child_block.runtime_index.increment();
|
||||
const merges = &child_block.label.?.merges;
|
||||
|
||||
@@ -6058,7 +6058,7 @@ fn analyzeBlockBody(
|
||||
try mod.errNoteNonLazy(runtime_src, msg, "runtime control flow here", .{});
|
||||
|
||||
const child_src_decl = mod.declPtr(child_block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, child_src_decl.toSrcLoc(type_src, mod), resolved_ty);
|
||||
|
||||
break :msg msg;
|
||||
};
|
||||
@@ -6213,7 +6213,7 @@ pub fn analyzeExport(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), exported_decl.ty, .other);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, exported_decl.ty);
|
||||
break :msg msg;
|
||||
@@ -8082,7 +8082,7 @@ fn instantiateGenericCall(
|
||||
};
|
||||
try child_sema.errNote(&child_block, param_src, msg, "declared here", .{});
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, arg_src.toSrcLoc(src_decl, mod), arg_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(arg_src, mod), arg_ty);
|
||||
break :msg msg;
|
||||
}),
|
||||
|
||||
@@ -9387,7 +9387,7 @@ fn funcCommon(
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param_ty, .param_ty);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(param_src, mod), param_ty, .param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, param_ty);
|
||||
break :msg msg;
|
||||
@@ -9402,7 +9402,7 @@ fn funcCommon(
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(param_src, mod), param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, param_ty);
|
||||
break :msg msg;
|
||||
@@ -9671,7 +9671,7 @@ fn finishFunc(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ret_ty_src, mod), return_type, .ret_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, return_type);
|
||||
break :msg msg;
|
||||
@@ -9692,7 +9692,7 @@ fn finishFunc(
|
||||
"function with comptime-only return type '{}' requires all parameters to be comptime",
|
||||
.{return_type.fmt(mod)},
|
||||
);
|
||||
try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type);
|
||||
try sema.explainWhyTypeIsComptime(msg, sema.owner_decl.toSrcLoc(ret_ty_src, mod), return_type);
|
||||
|
||||
const tags = sema.code.instructions.items(.tag);
|
||||
const data = sema.code.instructions.items(.data);
|
||||
@@ -9965,7 +9965,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
|
||||
const msg = try sema.errMsg(block, ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, ptr_src.toSrcLoc(src_decl, mod), pointee_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, mod), pointee_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
@@ -11492,7 +11492,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
|
||||
|
||||
var sub_block = child_block.makeSubBlock();
|
||||
sub_block.runtime_loop = null;
|
||||
sub_block.runtime_cond = main_operand_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
|
||||
sub_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(main_operand_src, mod);
|
||||
sub_block.runtime_index.increment();
|
||||
defer sub_block.instructions.deinit(gpa);
|
||||
|
||||
@@ -12227,7 +12227,7 @@ fn analyzeSwitchRuntimeBlock(
|
||||
|
||||
var case_block = child_block.makeSubBlock();
|
||||
case_block.runtime_loop = null;
|
||||
case_block.runtime_cond = operand_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
|
||||
case_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(operand_src, mod);
|
||||
case_block.runtime_index.increment();
|
||||
defer case_block.instructions.deinit(gpa);
|
||||
|
||||
@@ -13663,7 +13663,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
return sema.fail(block, operand_src, "file path name cannot be empty", .{});
|
||||
}
|
||||
|
||||
const src_loc = operand_src.toSrcLoc(mod.declPtr(block.src_decl), mod);
|
||||
const src_loc = mod.declPtr(block.src_decl).toSrcLoc(operand_src, mod);
|
||||
const val = mod.embedFile(block.getFileScope(mod), name, src_loc) catch |err| switch (err) {
|
||||
error.ImportOutsideModulePath => {
|
||||
return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
|
||||
@@ -18766,7 +18766,7 @@ fn zirBoolBr(
|
||||
|
||||
var child_block = parent_block.makeSubBlock();
|
||||
child_block.runtime_loop = null;
|
||||
child_block.runtime_cond = lhs_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
|
||||
child_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(lhs_src, mod);
|
||||
child_block.runtime_index.increment();
|
||||
defer child_block.instructions.deinit(gpa);
|
||||
|
||||
@@ -18963,7 +18963,7 @@ fn zirCondbr(
|
||||
// instructions array in between using it for the then block and else block.
|
||||
var sub_block = parent_block.makeSubBlock();
|
||||
sub_block.runtime_loop = null;
|
||||
sub_block.runtime_cond = cond_src.toSrcLoc(mod.declPtr(parent_block.src_decl), mod);
|
||||
sub_block.runtime_cond = mod.declPtr(parent_block.src_decl).toSrcLoc(cond_src, mod);
|
||||
sub_block.runtime_index.increment();
|
||||
defer sub_block.instructions.deinit(gpa);
|
||||
|
||||
@@ -19503,7 +19503,7 @@ fn analyzeRet(
|
||||
|
||||
if (sema.fn_ret_ty.isError(mod) and ret_val.getErrorName(mod) != .none) {
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
const src_loc = src.toSrcLoc(src_decl, mod);
|
||||
const src_loc = src_decl.toSrcLoc(src, mod);
|
||||
try sema.comptime_err_ret_trace.append(src_loc);
|
||||
}
|
||||
return error.ComptimeReturn;
|
||||
@@ -19660,7 +19660,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(elem_ty_src, mod), elem_ty, .other);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, elem_ty);
|
||||
break :msg msg;
|
||||
@@ -21128,7 +21128,7 @@ fn zirReify(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), elem_ty, .other);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, elem_ty);
|
||||
break :msg msg;
|
||||
@@ -21572,7 +21572,7 @@ fn zirReify(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
@@ -21584,7 +21584,7 @@ fn zirReify(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
|
||||
try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
@@ -21939,7 +21939,7 @@ fn reifyStruct(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .struct_field);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
@@ -21951,7 +21951,7 @@ fn reifyStruct(
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
|
||||
try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
@@ -22018,7 +22018,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ty_src, mod), arg_ty, .param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, arg_ty);
|
||||
break :msg msg;
|
||||
@@ -25859,7 +25859,7 @@ fn zirBuiltinExtern(
|
||||
const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ty_src, mod), ty, .other);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
@@ -26003,7 +26003,7 @@ fn validateVarType(
|
||||
const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), var_ty, .other);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
@@ -26026,7 +26026,7 @@ fn validateVarType(
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), var_ty);
|
||||
if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) {
|
||||
try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
|
||||
}
|
||||
@@ -28093,7 +28093,7 @@ fn validateRuntimeElemAccess(
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty);
|
||||
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(parent_src, mod), parent_ty);
|
||||
|
||||
break :msg msg;
|
||||
};
|
||||
@@ -28492,7 +28492,7 @@ const CoerceOpts = struct {
|
||||
.lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param),
|
||||
};
|
||||
}
|
||||
return param_src.toSrcLoc(fn_decl, mod);
|
||||
return fn_decl.toSrcLoc(param_src, mod);
|
||||
}
|
||||
} = .{},
|
||||
};
|
||||
@@ -29110,7 +29110,7 @@ fn coerceExtra(
|
||||
|
||||
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
|
||||
const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
|
||||
try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{});
|
||||
try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "'noreturn' declared here", .{});
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
@@ -29145,9 +29145,9 @@ fn coerceExtra(
|
||||
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
|
||||
const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
|
||||
if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {
|
||||
try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{});
|
||||
try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function cannot return an error", .{});
|
||||
} else {
|
||||
try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{});
|
||||
try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function return type declared here", .{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30165,7 +30165,7 @@ fn coerceVarArgParam(
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(inst_src, mod), coerced_ty, .param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, coerced_ty);
|
||||
break :msg msg;
|
||||
@@ -37180,7 +37180,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
|
||||
});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
const decl_ptr = mod.declPtr(tag_info.decl);
|
||||
try mod.errNoteNonLazy(enum_field_src.toSrcLoc(decl_ptr, mod), msg, "enum field here", .{});
|
||||
try mod.errNoteNonLazy(decl_ptr.toSrcLoc(enum_field_src, mod), msg, "enum field here", .{});
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(&block_scope, msg);
|
||||
|
||||
@@ -16,7 +16,7 @@ const Decl = Module.Decl;
|
||||
const Type = @import("../../type.zig").Type;
|
||||
const Value = @import("../../Value.zig");
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
const link = @import("../../link.zig");
|
||||
const TypedValue = @import("../../TypedValue.zig");
|
||||
const Air = @import("../../Air.zig");
|
||||
@@ -767,8 +767,7 @@ pub fn deinit(func: *CodeGen) void {
|
||||
/// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
|
||||
fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError {
|
||||
const mod = func.bin_file.base.comp.module.?;
|
||||
const src = LazySrcLoc.nodeOffset(0);
|
||||
const src_loc = src.toSrcLoc(func.decl, mod);
|
||||
const src_loc = func.decl.srcLoc(mod);
|
||||
func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args);
|
||||
return error.CodegenFail;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const Target = std.Target;
|
||||
const Type = @import("type.zig").Type;
|
||||
const TypedValue = @import("TypedValue.zig");
|
||||
const Value = @import("Value.zig");
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const Alignment = InternPool.Alignment;
|
||||
|
||||
pub const Result = union(enum) {
|
||||
|
||||
@@ -13,7 +13,7 @@ const TypedValue = @import("../TypedValue.zig");
|
||||
const C = link.File.C;
|
||||
const Decl = Module.Decl;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
@@ -570,8 +570,7 @@ pub const DeclGen = struct {
|
||||
const mod = dg.module;
|
||||
const decl_index = dg.pass.decl;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const src = LazySrcLoc.nodeOffset(0);
|
||||
const src_loc = src.toSrcLoc(decl, mod);
|
||||
const src_loc = decl.srcLoc(mod);
|
||||
dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const Value = @import("../Value.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
const x86_64_abi = @import("../arch/x86_64/abi.zig");
|
||||
const wasm_c_abi = @import("../arch/wasm/abi.zig");
|
||||
const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
|
||||
@@ -4686,7 +4686,7 @@ pub const DeclGen = struct {
|
||||
const o = dg.object;
|
||||
const gpa = o.gpa;
|
||||
const mod = o.module;
|
||||
const src_loc = LazySrcLoc.nodeOffset(0).toSrcLoc(dg.decl, mod);
|
||||
const src_loc = dg.decl.srcLoc(mod);
|
||||
dg.err_msg = try Module.ErrorMsg.create(gpa, src_loc, "TODO (LLVM): " ++ format, args);
|
||||
return error.CodegenFail;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ const Module = @import("../Module.zig");
|
||||
const Decl = Module.Decl;
|
||||
const Type = @import("../type.zig").Type;
|
||||
const Value = @import("../Value.zig");
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
const Air = @import("../Air.zig");
|
||||
const Zir = @import("../Zir.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
|
||||
@@ -413,8 +412,7 @@ const DeclGen = struct {
|
||||
pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
|
||||
@setCold(true);
|
||||
const mod = self.module;
|
||||
const src = LazySrcLoc.nodeOffset(0);
|
||||
const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index), mod);
|
||||
const src_loc = self.module.declPtr(self.decl_index).srcLoc(mod);
|
||||
assert(self.error_msg == null);
|
||||
self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
|
||||
return error.CodegenFail;
|
||||
@@ -5270,8 +5268,7 @@ const DeclGen = struct {
|
||||
// TODO: Translate proper error locations.
|
||||
assert(as.errors.items.len != 0);
|
||||
assert(self.error_msg == null);
|
||||
const loc = LazySrcLoc.nodeOffset(0);
|
||||
const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index), mod);
|
||||
const src_loc = self.module.declPtr(self.decl_index).srcLoc(mod);
|
||||
self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
|
||||
const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const native_os = builtin.os.tag;
|
||||
|
||||
const Module = @import("Module.zig");
|
||||
const Sema = @import("Sema.zig");
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const Decl = Module.Decl;
|
||||
|
||||
pub const is_enabled = builtin.mode == .Debug;
|
||||
|
||||
@@ -153,6 +153,7 @@ pub const EnvVar = enum {
|
||||
ZIG_VERBOSE_LINK,
|
||||
ZIG_VERBOSE_CC,
|
||||
ZIG_BTRFS_WORKAROUND,
|
||||
ZIG_DEBUG_CMD,
|
||||
CC,
|
||||
NO_COLOR,
|
||||
XDG_CACHE_HOME,
|
||||
|
||||
658
src/main.zig
658
src/main.zig
@@ -8,6 +8,7 @@ const process = std.process;
|
||||
const Allocator = mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Ast = std.zig.Ast;
|
||||
const Color = std.zig.Color;
|
||||
const warn = std.log.warn;
|
||||
const ThreadPool = std.Thread.Pool;
|
||||
const cleanExit = std.process.cleanExit;
|
||||
@@ -25,7 +26,7 @@ const Cache = std.Build.Cache;
|
||||
const target_util = @import("target.zig");
|
||||
const crash_report = @import("crash_report.zig");
|
||||
const Module = @import("Module.zig");
|
||||
const AstGen = @import("AstGen.zig");
|
||||
const AstGen = std.zig.AstGen;
|
||||
const mingw = @import("mingw.zig");
|
||||
const Server = std.zig.Server;
|
||||
|
||||
@@ -66,18 +67,8 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/// There are many assumptions in the entire codebase that Zig source files can
|
||||
/// be byte-indexed with a u32 integer.
|
||||
const max_src_size = std.math.maxInt(u32);
|
||||
|
||||
const debug_extensions_enabled = builtin.mode == .Debug;
|
||||
|
||||
const Color = enum {
|
||||
auto,
|
||||
off,
|
||||
on,
|
||||
};
|
||||
|
||||
const normal_usage =
|
||||
\\Usage: zig [command] [options]
|
||||
\\
|
||||
@@ -212,14 +203,6 @@ pub fn main() anyerror!void {
|
||||
}
|
||||
}
|
||||
|
||||
if (build_options.only_reduce) {
|
||||
if (mem.eql(u8, args[1], "reduce")) {
|
||||
return @import("reduce.zig").main(gpa, arena, args);
|
||||
} else {
|
||||
@panic("only reduce is supported in a -Donly-reduce build");
|
||||
}
|
||||
}
|
||||
|
||||
return mainArgs(gpa, arena, args);
|
||||
}
|
||||
|
||||
@@ -311,7 +294,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
} else if (mem.eql(u8, cmd, "rc")) {
|
||||
return cmdRc(gpa, arena, args[1..]);
|
||||
} else if (mem.eql(u8, cmd, "fmt")) {
|
||||
return cmdFmt(gpa, arena, cmd_args);
|
||||
return jitCmd(gpa, arena, cmd_args, "fmt", "fmt.zig");
|
||||
} else if (mem.eql(u8, cmd, "objcopy")) {
|
||||
return @import("objcopy.zig").cmdObjCopy(gpa, arena, cmd_args);
|
||||
} else if (mem.eql(u8, cmd, "fetch")) {
|
||||
@@ -334,7 +317,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
verifyLibcxxCorrectlyLinked();
|
||||
return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
|
||||
} else if (mem.eql(u8, cmd, "reduce")) {
|
||||
return @import("reduce.zig").main(gpa, arena, args);
|
||||
return jitCmd(gpa, arena, cmd_args, "reduce", "reduce.zig");
|
||||
} else if (mem.eql(u8, cmd, "zen")) {
|
||||
return io.getStdOut().writeAll(info_zen);
|
||||
} else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
|
||||
@@ -2756,6 +2739,7 @@ fn buildOutputType(
|
||||
.paths = .{
|
||||
.root = .{
|
||||
.root_dir = zig_lib_directory,
|
||||
.sub_path = "compiler",
|
||||
},
|
||||
.root_src_path = "test_runner.zig",
|
||||
},
|
||||
@@ -4501,7 +4485,7 @@ fn updateModule(comp: *Compilation, color: Color) !void {
|
||||
defer errors.deinit(comp.gpa);
|
||||
|
||||
if (errors.errorMessageCount() > 0) {
|
||||
errors.renderToStdErr(renderOptions(color));
|
||||
errors.renderToStdErr(color.renderOptions());
|
||||
return error.SemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
@@ -4601,7 +4585,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
|
||||
p.errors = errors;
|
||||
return;
|
||||
} else {
|
||||
errors.renderToStdErr(renderOptions(color));
|
||||
errors.renderToStdErr(color.renderOptions());
|
||||
process.exit(1);
|
||||
}
|
||||
},
|
||||
@@ -5402,7 +5386,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
},
|
||||
.root_src_path = fs.path.basename(runner),
|
||||
} else .{
|
||||
.root = .{ .root_dir = zig_lib_directory },
|
||||
.root = .{
|
||||
.root_dir = zig_lib_directory,
|
||||
},
|
||||
.root_src_path = "build_runner.zig",
|
||||
};
|
||||
|
||||
@@ -5528,7 +5514,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
|
||||
if (fetch.error_bundle.root_list.items.len > 0) {
|
||||
var errors = try fetch.error_bundle.toOwnedBundle("");
|
||||
errors.renderToStdErr(renderOptions(color));
|
||||
errors.renderToStdErr(color.renderOptions());
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -5719,470 +5705,165 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn readSourceFileToEndAlloc(
|
||||
allocator: Allocator,
|
||||
input: *const fs.File,
|
||||
size_hint: ?usize,
|
||||
) ![:0]u8 {
|
||||
const source_code = input.readToEndAllocOptions(
|
||||
allocator,
|
||||
max_src_size,
|
||||
size_hint,
|
||||
@alignOf(u16),
|
||||
0,
|
||||
) catch |err| switch (err) {
|
||||
error.ConnectionResetByPeer => unreachable,
|
||||
error.ConnectionTimedOut => unreachable,
|
||||
error.NotOpenForReading => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
errdefer allocator.free(source_code);
|
||||
|
||||
// Detect unsupported file types with their Byte Order Mark
|
||||
const unsupported_boms = [_][]const u8{
|
||||
"\xff\xfe\x00\x00", // UTF-32 little endian
|
||||
"\xfe\xff\x00\x00", // UTF-32 big endian
|
||||
"\xfe\xff", // UTF-16 big endian
|
||||
};
|
||||
for (unsupported_boms) |bom| {
|
||||
if (mem.startsWith(u8, source_code, bom)) {
|
||||
return error.UnsupportedEncoding;
|
||||
}
|
||||
}
|
||||
|
||||
// If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
|
||||
if (mem.startsWith(u8, source_code, "\xff\xfe")) {
|
||||
const source_code_utf16_le = mem.bytesAsSlice(u16, source_code);
|
||||
const source_code_utf8 = std.unicode.utf16LeToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {
|
||||
error.DanglingSurrogateHalf => error.UnsupportedEncoding,
|
||||
error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
|
||||
error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
allocator.free(source_code);
|
||||
return source_code_utf8;
|
||||
}
|
||||
|
||||
return source_code;
|
||||
}
|
||||
|
||||
const usage_fmt =
|
||||
\\Usage: zig fmt [file]...
|
||||
\\
|
||||
\\ Formats the input files and modifies them in-place.
|
||||
\\ Arguments can be files or directories, which are searched
|
||||
\\ recursively.
|
||||
\\
|
||||
\\Options:
|
||||
\\ -h, --help Print this help and exit
|
||||
\\ --color [auto|off|on] Enable or disable colored error messages
|
||||
\\ --stdin Format code from stdin; output to stdout
|
||||
\\ --check List non-conforming files and exit with an error
|
||||
\\ if the list is non-empty
|
||||
\\ --ast-check Run zig ast-check on every file
|
||||
\\ --exclude [file] Exclude file or directory from formatting
|
||||
\\
|
||||
\\
|
||||
;
|
||||
|
||||
const Fmt = struct {
|
||||
seen: SeenMap,
|
||||
any_error: bool,
|
||||
check_ast: bool,
|
||||
color: Color,
|
||||
fn jitCmd(
|
||||
gpa: Allocator,
|
||||
arena: Allocator,
|
||||
out_buffer: std.ArrayList(u8),
|
||||
args: []const []const u8,
|
||||
cmd_name: []const u8,
|
||||
root_src_path: []const u8,
|
||||
) !void {
|
||||
const color: Color = .auto;
|
||||
|
||||
const SeenMap = std.AutoHashMap(fs.File.INode, void);
|
||||
};
|
||||
|
||||
fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
var color: Color = .auto;
|
||||
var stdin_flag: bool = false;
|
||||
var check_flag: bool = false;
|
||||
var check_ast_flag: bool = false;
|
||||
var input_files = ArrayList([]const u8).init(gpa);
|
||||
defer input_files.deinit();
|
||||
var excluded_files = ArrayList([]const u8).init(gpa);
|
||||
defer excluded_files.deinit();
|
||||
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (mem.startsWith(u8, arg, "-")) {
|
||||
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
|
||||
const stdout = io.getStdOut().writer();
|
||||
try stdout.writeAll(usage_fmt);
|
||||
return cleanExit();
|
||||
} else if (mem.eql(u8, arg, "--color")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected [auto|on|off] after --color", .{});
|
||||
}
|
||||
i += 1;
|
||||
const next_arg = args[i];
|
||||
color = std.meta.stringToEnum(Color, next_arg) orelse {
|
||||
fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
|
||||
};
|
||||
} else if (mem.eql(u8, arg, "--stdin")) {
|
||||
stdin_flag = true;
|
||||
} else if (mem.eql(u8, arg, "--check")) {
|
||||
check_flag = true;
|
||||
} else if (mem.eql(u8, arg, "--ast-check")) {
|
||||
check_ast_flag = true;
|
||||
} else if (mem.eql(u8, arg, "--exclude")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected parameter after --exclude", .{});
|
||||
}
|
||||
i += 1;
|
||||
const next_arg = args[i];
|
||||
try excluded_files.append(next_arg);
|
||||
} else {
|
||||
fatal("unrecognized parameter: '{s}'", .{arg});
|
||||
}
|
||||
} else {
|
||||
try input_files.append(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stdin_flag) {
|
||||
if (input_files.items.len != 0) {
|
||||
fatal("cannot use --stdin with positional arguments", .{});
|
||||
}
|
||||
|
||||
const stdin = io.getStdIn();
|
||||
const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| {
|
||||
fatal("unable to read stdin: {}", .{err});
|
||||
};
|
||||
defer gpa.free(source_code);
|
||||
|
||||
var tree = Ast.parse(gpa, source_code, .zig) catch |err| {
|
||||
fatal("error parsing stdin: {}", .{err});
|
||||
};
|
||||
defer tree.deinit(gpa);
|
||||
|
||||
if (check_ast_flag) {
|
||||
var file: Module.File = .{
|
||||
.status = .never_loaded,
|
||||
.source_loaded = true,
|
||||
.zir_loaded = false,
|
||||
.sub_file_path = "<stdin>",
|
||||
.source = source_code,
|
||||
.stat = undefined,
|
||||
.tree = tree,
|
||||
.tree_loaded = true,
|
||||
.zir = undefined,
|
||||
.mod = undefined,
|
||||
.root_decl = .none,
|
||||
};
|
||||
|
||||
file.mod = try Package.Module.createLimited(arena, .{
|
||||
.root = Package.Path.cwd(),
|
||||
.root_src_path = file.sub_file_path,
|
||||
.fully_qualified_name = "root",
|
||||
});
|
||||
|
||||
file.zir = try AstGen.generate(gpa, file.tree);
|
||||
file.zir_loaded = true;
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(color));
|
||||
process.exit(2);
|
||||
}
|
||||
} else if (tree.errors.len != 0) {
|
||||
try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
|
||||
process.exit(2);
|
||||
}
|
||||
const formatted = try tree.render(gpa);
|
||||
defer gpa.free(formatted);
|
||||
|
||||
if (check_flag) {
|
||||
const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
return io.getStdOut().writeAll(formatted);
|
||||
}
|
||||
|
||||
if (input_files.items.len == 0) {
|
||||
fatal("expected at least one source file argument", .{});
|
||||
}
|
||||
|
||||
var fmt = Fmt{
|
||||
.gpa = gpa,
|
||||
.arena = arena,
|
||||
.seen = Fmt.SeenMap.init(gpa),
|
||||
.any_error = false,
|
||||
.check_ast = check_ast_flag,
|
||||
.color = color,
|
||||
.out_buffer = std.ArrayList(u8).init(gpa),
|
||||
const target_query: std.Target.Query = .{};
|
||||
const resolved_target: Package.Module.ResolvedTarget = .{
|
||||
.result = resolveTargetQueryOrFatal(target_query),
|
||||
.is_native_os = true,
|
||||
.is_native_abi = true,
|
||||
};
|
||||
defer fmt.seen.deinit();
|
||||
defer fmt.out_buffer.deinit();
|
||||
|
||||
// Mark any excluded files/directories as already seen,
|
||||
// so that they are skipped later during actual processing
|
||||
for (excluded_files.items) |file_path| {
|
||||
const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
|
||||
error.FileNotFound => continue,
|
||||
// On Windows, statFile does not work for directories
|
||||
error.IsDir => dir: {
|
||||
var dir = try fs.cwd().openDir(file_path, .{});
|
||||
defer dir.close();
|
||||
break :dir try dir.stat();
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try fmt.seen.put(stat.inode, {});
|
||||
}
|
||||
const exe_basename = try std.zig.binNameAlloc(arena, .{
|
||||
.root_name = cmd_name,
|
||||
.target = resolved_target.result,
|
||||
.output_mode = .Exe,
|
||||
});
|
||||
const emit_bin: Compilation.EmitLoc = .{
|
||||
.directory = null, // Use the global zig-cache.
|
||||
.basename = exe_basename,
|
||||
};
|
||||
|
||||
for (input_files.items) |file_path| {
|
||||
try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
|
||||
}
|
||||
if (fmt.any_error) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
const self_exe_path = introspect.findZigExePath(arena) catch |err| {
|
||||
fatal("unable to find self exe path: {s}", .{@errorName(err)});
|
||||
};
|
||||
|
||||
const FmtError = error{
|
||||
SystemResources,
|
||||
OperationAborted,
|
||||
IoPending,
|
||||
BrokenPipe,
|
||||
Unexpected,
|
||||
WouldBlock,
|
||||
FileClosed,
|
||||
DestinationAddressRequired,
|
||||
DiskQuota,
|
||||
FileTooBig,
|
||||
InputOutput,
|
||||
NoSpaceLeft,
|
||||
AccessDenied,
|
||||
OutOfMemory,
|
||||
RenameAcrossMountPoints,
|
||||
ReadOnlyFileSystem,
|
||||
LinkQuotaExceeded,
|
||||
FileBusy,
|
||||
EndOfStream,
|
||||
Unseekable,
|
||||
NotOpenForWriting,
|
||||
UnsupportedEncoding,
|
||||
ConnectionResetByPeer,
|
||||
SocketNotConnected,
|
||||
LockViolation,
|
||||
NetNameDeleted,
|
||||
InvalidArgument,
|
||||
} || fs.File.OpenError;
|
||||
const optimize_mode: std.builtin.OptimizeMode = if (EnvVar.ZIG_DEBUG_CMD.isSet())
|
||||
.Debug
|
||||
else
|
||||
.ReleaseFast;
|
||||
const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
|
||||
const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
|
||||
|
||||
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
|
||||
fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
|
||||
error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
|
||||
else => {
|
||||
warn("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
|
||||
fmt.any_error = true;
|
||||
return;
|
||||
var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
|
||||
.path = lib_dir,
|
||||
.handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
|
||||
fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
|
||||
},
|
||||
} else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
|
||||
};
|
||||
}
|
||||
defer zig_lib_directory.handle.close();
|
||||
|
||||
fn fmtPathDir(
|
||||
fmt: *Fmt,
|
||||
file_path: []const u8,
|
||||
check_mode: bool,
|
||||
parent_dir: fs.Dir,
|
||||
parent_sub_path: []const u8,
|
||||
) FmtError!void {
|
||||
var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
var global_cache_directory: Compilation.Directory = l: {
|
||||
const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
|
||||
break :l .{
|
||||
.handle = try fs.cwd().makeOpenPath(p, .{}),
|
||||
.path = p,
|
||||
};
|
||||
};
|
||||
defer global_cache_directory.handle.close();
|
||||
|
||||
const stat = try dir.stat();
|
||||
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
|
||||
var thread_pool: ThreadPool = undefined;
|
||||
try thread_pool.init(.{ .allocator = gpa });
|
||||
defer thread_pool.deinit();
|
||||
|
||||
var dir_it = dir.iterate();
|
||||
while (try dir_it.next()) |entry| {
|
||||
const is_dir = entry.kind == .directory;
|
||||
var child_argv: std.ArrayListUnmanaged([]const u8) = .{};
|
||||
try child_argv.ensureUnusedCapacity(arena, args.len + 1);
|
||||
|
||||
if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
|
||||
|
||||
if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
|
||||
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
|
||||
defer fmt.gpa.free(full_path);
|
||||
|
||||
if (is_dir) {
|
||||
try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
|
||||
} else {
|
||||
fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
|
||||
warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
|
||||
fmt.any_error = true;
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmtPathFile(
|
||||
fmt: *Fmt,
|
||||
file_path: []const u8,
|
||||
check_mode: bool,
|
||||
dir: fs.Dir,
|
||||
sub_path: []const u8,
|
||||
) FmtError!void {
|
||||
const source_file = try dir.openFile(sub_path, .{});
|
||||
var file_closed = false;
|
||||
errdefer if (!file_closed) source_file.close();
|
||||
|
||||
const stat = try source_file.stat();
|
||||
|
||||
if (stat.kind == .directory)
|
||||
return error.IsDir;
|
||||
|
||||
const gpa = fmt.gpa;
|
||||
const source_code = try readSourceFileToEndAlloc(
|
||||
gpa,
|
||||
&source_file,
|
||||
std.math.cast(usize, stat.size) orelse return error.FileTooBig,
|
||||
);
|
||||
defer gpa.free(source_code);
|
||||
|
||||
source_file.close();
|
||||
file_closed = true;
|
||||
|
||||
// Add to set after no longer possible to get error.IsDir.
|
||||
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
|
||||
|
||||
var tree = try Ast.parse(gpa, source_code, .zig);
|
||||
defer tree.deinit(gpa);
|
||||
|
||||
if (tree.errors.len != 0) {
|
||||
try printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
|
||||
fmt.any_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmt.check_ast) {
|
||||
var file: Module.File = .{
|
||||
.status = .never_loaded,
|
||||
.source_loaded = true,
|
||||
.zir_loaded = false,
|
||||
.sub_file_path = file_path,
|
||||
.source = source_code,
|
||||
.stat = .{
|
||||
.size = stat.size,
|
||||
.inode = stat.inode,
|
||||
.mtime = stat.mtime,
|
||||
// We want to release all the locks before executing the child process, so we make a nice
|
||||
// big block here to ensure the cleanup gets run when we extract out our argv.
|
||||
{
|
||||
const main_mod_paths: Package.Module.CreateOptions.Paths = .{
|
||||
.root = .{
|
||||
.root_dir = zig_lib_directory,
|
||||
.sub_path = "compiler",
|
||||
},
|
||||
.tree = tree,
|
||||
.tree_loaded = true,
|
||||
.zir = undefined,
|
||||
.mod = undefined,
|
||||
.root_decl = .none,
|
||||
.root_src_path = root_src_path,
|
||||
};
|
||||
|
||||
file.mod = try Package.Module.createLimited(fmt.arena, .{
|
||||
.root = Package.Path.cwd(),
|
||||
.root_src_path = file.sub_file_path,
|
||||
.fully_qualified_name = "root",
|
||||
const config = try Compilation.Config.resolve(.{
|
||||
.output_mode = .Exe,
|
||||
.root_optimize_mode = optimize_mode,
|
||||
.resolved_target = resolved_target,
|
||||
.have_zcu = true,
|
||||
.emit_bin = true,
|
||||
.is_test = false,
|
||||
});
|
||||
|
||||
if (stat.size > max_src_size)
|
||||
return error.FileTooBig;
|
||||
|
||||
file.zir = try AstGen.generate(gpa, file.tree);
|
||||
file.zir_loaded = true;
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(fmt.color));
|
||||
fmt.any_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
// As a heuristic, we make enough capacity for the same as the input source.
|
||||
fmt.out_buffer.shrinkRetainingCapacity(0);
|
||||
try fmt.out_buffer.ensureTotalCapacity(source_code.len);
|
||||
|
||||
try tree.renderToArrayList(&fmt.out_buffer, .{});
|
||||
if (mem.eql(u8, fmt.out_buffer.items, source_code))
|
||||
return;
|
||||
|
||||
if (check_mode) {
|
||||
const stdout = io.getStdOut().writer();
|
||||
try stdout.print("{s}\n", .{file_path});
|
||||
fmt.any_error = true;
|
||||
} else {
|
||||
var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
|
||||
defer af.deinit();
|
||||
|
||||
try af.file.writeAll(fmt.out_buffer.items);
|
||||
try af.finish();
|
||||
const stdout = io.getStdOut().writer();
|
||||
try stdout.print("{s}\n", .{file_path});
|
||||
}
|
||||
}
|
||||
|
||||
fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
|
||||
try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
|
||||
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(color));
|
||||
}
|
||||
|
||||
pub fn putAstErrorsIntoBundle(
|
||||
gpa: Allocator,
|
||||
tree: Ast,
|
||||
path: []const u8,
|
||||
wip_errors: *std.zig.ErrorBundle.Wip,
|
||||
) Allocator.Error!void {
|
||||
var file: Module.File = .{
|
||||
.status = .never_loaded,
|
||||
.source_loaded = true,
|
||||
.zir_loaded = false,
|
||||
.sub_file_path = path,
|
||||
.source = tree.source,
|
||||
.stat = .{
|
||||
.size = 0,
|
||||
.inode = 0,
|
||||
.mtime = 0,
|
||||
},
|
||||
.tree = tree,
|
||||
.tree_loaded = true,
|
||||
.zir = undefined,
|
||||
.mod = try Package.Module.createLimited(gpa, .{
|
||||
.root = Package.Path.cwd(),
|
||||
.root_src_path = path,
|
||||
const root_mod = try Package.Module.create(arena, .{
|
||||
.global_cache_directory = global_cache_directory,
|
||||
.paths = main_mod_paths,
|
||||
.fully_qualified_name = "root",
|
||||
}),
|
||||
.root_decl = .none,
|
||||
};
|
||||
defer gpa.destroy(file.mod);
|
||||
.cc_argv = &.{},
|
||||
.inherited = .{
|
||||
.resolved_target = resolved_target,
|
||||
.optimize_mode = optimize_mode,
|
||||
},
|
||||
.global = config,
|
||||
.parent = null,
|
||||
.builtin_mod = null,
|
||||
});
|
||||
|
||||
file.zir = try AstGen.generate(gpa, file.tree);
|
||||
file.zir_loaded = true;
|
||||
defer file.zir.deinit(gpa);
|
||||
const comp = Compilation.create(gpa, arena, .{
|
||||
.zig_lib_directory = zig_lib_directory,
|
||||
.local_cache_directory = global_cache_directory,
|
||||
.global_cache_directory = global_cache_directory,
|
||||
.root_name = cmd_name,
|
||||
.config = config,
|
||||
.root_mod = root_mod,
|
||||
.main_mod = root_mod,
|
||||
.emit_bin = emit_bin,
|
||||
.emit_h = null,
|
||||
.self_exe_path = self_exe_path,
|
||||
.thread_pool = &thread_pool,
|
||||
.cache_mode = .whole,
|
||||
}) catch |err| {
|
||||
fatal("unable to create compilation: {s}", .{@errorName(err)});
|
||||
};
|
||||
defer comp.destroy();
|
||||
|
||||
try Compilation.addZirErrorMessages(wip_errors, &file);
|
||||
updateModule(comp, color) catch |err| switch (err) {
|
||||
error.SemanticAnalyzeFail => process.exit(2),
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
const exe_path = try global_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
|
||||
child_argv.appendAssumeCapacity(exe_path);
|
||||
}
|
||||
|
||||
child_argv.appendSliceAssumeCapacity(args);
|
||||
|
||||
if (process.can_execv) {
|
||||
const err = process.execv(gpa, child_argv.items);
|
||||
const cmd = try std.mem.join(arena, " ", child_argv.items);
|
||||
fatal("the following command failed to execve with '{s}':\n{s}", .{
|
||||
@errorName(err),
|
||||
cmd,
|
||||
});
|
||||
}
|
||||
|
||||
if (!process.can_spawn) {
|
||||
const cmd = try std.mem.join(arena, " ", child_argv.items);
|
||||
fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
|
||||
@tagName(builtin.os.tag), cmd,
|
||||
});
|
||||
}
|
||||
|
||||
var child = std.ChildProcess.init(child_argv.items, gpa);
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
const term = try child.spawnAndWait();
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code == 0) return cleanExit();
|
||||
const cmd = try std.mem.join(arena, " ", child_argv.items);
|
||||
fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
|
||||
},
|
||||
else => {
|
||||
const cmd = try std.mem.join(arena, " ", child_argv.items);
|
||||
fatal("the following build command crashed:\n{s}", .{cmd});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const info_zen =
|
||||
@@ -6655,7 +6336,7 @@ fn cmdAstCheck(
|
||||
arena: Allocator,
|
||||
args: []const []const u8,
|
||||
) !void {
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
|
||||
var color: Color = .auto;
|
||||
var want_output_text = false;
|
||||
@@ -6710,7 +6391,7 @@ fn cmdAstCheck(
|
||||
|
||||
const stat = try f.stat();
|
||||
|
||||
if (stat.size > max_src_size)
|
||||
if (stat.size > std.zig.max_src_size)
|
||||
return error.FileTooBig;
|
||||
|
||||
const source = try arena.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
|
||||
@@ -6728,7 +6409,7 @@ fn cmdAstCheck(
|
||||
};
|
||||
} else {
|
||||
const stdin = io.getStdIn();
|
||||
const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| {
|
||||
const source = std.zig.readSourceFileToEndAlloc(arena, stdin, null) catch |err| {
|
||||
fatal("unable to read stdin: {}", .{err});
|
||||
};
|
||||
file.sub_file_path = "<stdin>";
|
||||
@@ -6758,7 +6439,7 @@ fn cmdAstCheck(
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(color));
|
||||
error_bundle.renderToStdErr(color.renderOptions());
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -6817,7 +6498,7 @@ fn cmdDumpZir(
|
||||
args: []const []const u8,
|
||||
) !void {
|
||||
_ = arena;
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
|
||||
const cache_file = args[0];
|
||||
|
||||
@@ -6877,7 +6558,7 @@ fn cmdChangelist(
|
||||
args: []const []const u8,
|
||||
) !void {
|
||||
const color: Color = .auto;
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
|
||||
const old_source_file = args[0];
|
||||
const new_source_file = args[1];
|
||||
@@ -6889,7 +6570,7 @@ fn cmdChangelist(
|
||||
|
||||
const stat = try f.stat();
|
||||
|
||||
if (stat.size > max_src_size)
|
||||
if (stat.size > std.zig.max_src_size)
|
||||
return error.FileTooBig;
|
||||
|
||||
var file: Module.File = .{
|
||||
@@ -6938,7 +6619,7 @@ fn cmdChangelist(
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(color));
|
||||
error_bundle.renderToStdErr(color.renderOptions());
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -6949,7 +6630,7 @@ fn cmdChangelist(
|
||||
|
||||
const new_stat = try new_f.stat();
|
||||
|
||||
if (new_stat.size > max_src_size)
|
||||
if (new_stat.size > std.zig.max_src_size)
|
||||
return error.FileTooBig;
|
||||
|
||||
const new_source = try arena.allocSentinel(u8, @as(usize, @intCast(new_stat.size)), 0);
|
||||
@@ -6973,7 +6654,7 @@ fn cmdChangelist(
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(color));
|
||||
error_bundle.renderToStdErr(color.renderOptions());
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -7241,23 +6922,6 @@ const ClangSearchSanitizer = struct {
|
||||
};
|
||||
};
|
||||
|
||||
fn get_tty_conf(color: Color) std.io.tty.Config {
|
||||
return switch (color) {
|
||||
.auto => std.io.tty.detectConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
}
|
||||
|
||||
fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
|
||||
const ttyconf = get_tty_conf(color);
|
||||
return .{
|
||||
.ttyconf = ttyconf,
|
||||
.include_source_line = ttyconf != .no_color,
|
||||
.include_reference_trace = ttyconf != .no_color,
|
||||
};
|
||||
}
|
||||
|
||||
fn accessLibPath(
|
||||
test_path: *std.ArrayList(u8),
|
||||
checked_paths: *std.ArrayList(u8),
|
||||
@@ -7498,7 +7162,7 @@ fn cmdFetch(
|
||||
|
||||
if (fetch.error_bundle.root_list.items.len > 0) {
|
||||
var errors = try fetch.error_bundle.toOwnedBundle("");
|
||||
errors.renderToStdErr(renderOptions(color));
|
||||
errors.renderToStdErr(color.renderOptions());
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -7790,7 +7454,7 @@ fn loadManifest(
|
||||
errdefer ast.deinit(gpa);
|
||||
|
||||
if (ast.errors.len > 0) {
|
||||
try printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
|
||||
try std.zig.printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
@@ -7807,7 +7471,7 @@ fn loadManifest(
|
||||
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(renderOptions(options.color));
|
||||
error_bundle.renderToStdErr(options.color.renderOptions());
|
||||
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ const assert = std.debug.assert;
|
||||
const Ast = std.zig.Ast;
|
||||
const InternPool = @import("InternPool.zig");
|
||||
|
||||
const Zir = @import("Zir.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const Module = @import("Module.zig");
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const LazySrcLoc = std.zig.LazySrcLoc;
|
||||
|
||||
/// Write human-readable, debug formatted ZIR code to a file.
|
||||
pub fn renderAsTextToFile(
|
||||
|
||||
@@ -13,4 +13,3 @@ pub const skip_non_native = false;
|
||||
pub const only_c = false;
|
||||
pub const force_gpa = false;
|
||||
pub const only_core_functionality = true;
|
||||
pub const only_reduce = false;
|
||||
|
||||
Reference in New Issue
Block a user