Merge branch 'DrDeano-master'

closes #5648
This commit is contained in:
Andrew Kelley 2020-06-20 23:06:04 -04:00
commit edea7a46e5
9 changed files with 199 additions and 131 deletions

View File

@ -162,7 +162,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
mem.copy(T, self.items[oldlen..], items);
}
pub usingnamespace if (T != u8) struct { } else struct {
pub usingnamespace if (T != u8) struct {} else struct {
pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);
/// Initializes a Writer which will append to the list.

View File

@ -278,62 +278,62 @@ pub const Token = struct {
// TODO extensions
pub const keywords = std.ComptimeStringMap(Id, .{
.{"auto", .Keyword_auto},
.{"break", .Keyword_break},
.{"case", .Keyword_case},
.{"char", .Keyword_char},
.{"const", .Keyword_const},
.{"continue", .Keyword_continue},
.{"default", .Keyword_default},
.{"do", .Keyword_do},
.{"double", .Keyword_double},
.{"else", .Keyword_else},
.{"enum", .Keyword_enum},
.{"extern", .Keyword_extern},
.{"float", .Keyword_float},
.{"for", .Keyword_for},
.{"goto", .Keyword_goto},
.{"if", .Keyword_if},
.{"int", .Keyword_int},
.{"long", .Keyword_long},
.{"register", .Keyword_register},
.{"return", .Keyword_return},
.{"short", .Keyword_short},
.{"signed", .Keyword_signed},
.{"sizeof", .Keyword_sizeof},
.{"static", .Keyword_static},
.{"struct", .Keyword_struct},
.{"switch", .Keyword_switch},
.{"typedef", .Keyword_typedef},
.{"union", .Keyword_union},
.{"unsigned", .Keyword_unsigned},
.{"void", .Keyword_void},
.{"volatile", .Keyword_volatile},
.{"while", .Keyword_while},
.{ "auto", .Keyword_auto },
.{ "break", .Keyword_break },
.{ "case", .Keyword_case },
.{ "char", .Keyword_char },
.{ "const", .Keyword_const },
.{ "continue", .Keyword_continue },
.{ "default", .Keyword_default },
.{ "do", .Keyword_do },
.{ "double", .Keyword_double },
.{ "else", .Keyword_else },
.{ "enum", .Keyword_enum },
.{ "extern", .Keyword_extern },
.{ "float", .Keyword_float },
.{ "for", .Keyword_for },
.{ "goto", .Keyword_goto },
.{ "if", .Keyword_if },
.{ "int", .Keyword_int },
.{ "long", .Keyword_long },
.{ "register", .Keyword_register },
.{ "return", .Keyword_return },
.{ "short", .Keyword_short },
.{ "signed", .Keyword_signed },
.{ "sizeof", .Keyword_sizeof },
.{ "static", .Keyword_static },
.{ "struct", .Keyword_struct },
.{ "switch", .Keyword_switch },
.{ "typedef", .Keyword_typedef },
.{ "union", .Keyword_union },
.{ "unsigned", .Keyword_unsigned },
.{ "void", .Keyword_void },
.{ "volatile", .Keyword_volatile },
.{ "while", .Keyword_while },
// ISO C99
.{"_Bool", .Keyword_bool},
.{"_Complex", .Keyword_complex},
.{"_Imaginary", .Keyword_imaginary},
.{"inline", .Keyword_inline},
.{"restrict", .Keyword_restrict},
.{ "_Bool", .Keyword_bool },
.{ "_Complex", .Keyword_complex },
.{ "_Imaginary", .Keyword_imaginary },
.{ "inline", .Keyword_inline },
.{ "restrict", .Keyword_restrict },
// ISO C11
.{"_Alignas", .Keyword_alignas},
.{"_Alignof", .Keyword_alignof},
.{"_Atomic", .Keyword_atomic},
.{"_Generic", .Keyword_generic},
.{"_Noreturn", .Keyword_noreturn},
.{"_Static_assert", .Keyword_static_assert},
.{"_Thread_local", .Keyword_thread_local},
.{ "_Alignas", .Keyword_alignas },
.{ "_Alignof", .Keyword_alignof },
.{ "_Atomic", .Keyword_atomic },
.{ "_Generic", .Keyword_generic },
.{ "_Noreturn", .Keyword_noreturn },
.{ "_Static_assert", .Keyword_static_assert },
.{ "_Thread_local", .Keyword_thread_local },
// Preprocessor directives
.{"include", .Keyword_include},
.{"define", .Keyword_define},
.{"ifdef", .Keyword_ifdef},
.{"ifndef", .Keyword_ifndef},
.{"error", .Keyword_error},
.{"pragma", .Keyword_pragma},
.{ "include", .Keyword_include },
.{ "define", .Keyword_define },
.{ "ifdef", .Keyword_ifdef },
.{ "ifndef", .Keyword_ifndef },
.{ "error", .Keyword_error },
.{ "pragma", .Keyword_pragma },
});
// TODO do this in the preprocessor

View File

@ -261,17 +261,7 @@ pub const Dir = struct {
name: []const u8,
kind: Kind,
pub const Kind = enum {
BlockDevice,
CharacterDevice,
Directory,
NamedPipe,
SymLink,
File,
UnixDomainSocket,
Whiteout,
Unknown,
};
pub const Kind = File.Kind;
};
const IteratorError = error{AccessDenied} || os.UnexpectedError;
@ -1527,9 +1517,9 @@ pub const Dir = struct {
var size: ?u64 = null;
const mode = options.override_mode orelse blk: {
const stat = try in_file.stat();
size = stat.size;
break :blk stat.mode;
const st = try in_file.stat();
size = st.size;
break :blk st.mode;
};
var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
@ -1555,6 +1545,17 @@ pub const Dir = struct {
return AtomicFile.init(dest_path, options.mode, self, false);
}
}
pub const Stat = File.Stat;
pub const StatError = File.StatError;
pub fn stat(self: Dir) StatError!Stat {
const file: File = .{
.handle = self.fd,
.capable_io_mode = .blocking,
};
return file.stat();
}
};
/// Returns an handle to the current working directory. It is not opened with iteration capability.

View File

@ -29,6 +29,18 @@ pub const File = struct {
pub const Mode = os.mode_t;
pub const INode = os.ino_t;
pub const Kind = enum {
BlockDevice,
CharacterDevice,
Directory,
NamedPipe,
SymLink,
File,
UnixDomainSocket,
Whiteout,
Unknown,
};
pub const default_mode = switch (builtin.os.tag) {
.windows => 0,
.wasi => 0,
@ -219,13 +231,14 @@ pub const File = struct {
/// unique across time, as some file systems may reuse an inode after its file has been deleted.
/// Some systems may change the inode of a file over time.
///
/// On Linux, the inode _is_ structure that stores the metadata, and the inode _number_ is what
/// On Linux, the inode is a structure that stores the metadata, and the inode _number_ is what
/// you see here: the index number of the inode.
///
/// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.
inode: INode,
size: u64,
mode: Mode,
kind: Kind,
/// Access time in nanoseconds, relative to UTC 1970-01-01.
atime: i128,
@ -254,6 +267,7 @@ pub const File = struct {
.inode = info.InternalInformation.IndexNumber,
.size = @bitCast(u64, info.StandardInformation.EndOfFile),
.mode = 0,
.kind = if (info.StandardInformation.Directory == 0) .File else .Directory,
.atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
.mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
.ctime = windows.fromSysTime(info.BasicInformation.CreationTime),
@ -268,6 +282,27 @@ pub const File = struct {
.inode = st.ino,
.size = @bitCast(u64, st.size),
.mode = st.mode,
.kind = switch (builtin.os.tag) {
.wasi => switch (st.filetype) {
os.FILETYPE_BLOCK_DEVICE => Kind.BlockDevice,
os.FILETYPE_CHARACTER_DEVICE => Kind.CharacterDevice,
os.FILETYPE_DIRECTORY => Kind.Directory,
os.FILETYPE_SYMBOLIC_LINK => Kind.SymLink,
os.FILETYPE_REGULAR_FILE => Kind.File,
os.FILETYPE_SOCKET_STREAM, os.FILETYPE_SOCKET_DGRAM => Kind.UnixDomainSocket,
else => Kind.Unknown,
},
else => switch (st.mode & os.S_IFMT) {
os.S_IFBLK => Kind.BlockDevice,
os.S_IFCHR => Kind.CharacterDevice,
os.S_IFDIR => Kind.Directory,
os.S_IFIFO => Kind.NamedPipe,
os.S_IFLNK => Kind.SymLink,
os.S_IFREG => Kind.File,
os.S_IFSOCK => Kind.UnixDomainSocket,
else => Kind.Unknown,
},
},
.atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
.mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
.ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,

View File

@ -2,4 +2,4 @@
pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;
/// Deprecated: use `std.io.buffered_writer.bufferedWriter`
pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter
pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter;

View File

@ -2576,8 +2576,8 @@ pub fn stringify(
},
.Array => return stringify(&value, options, out_stream),
.Vector => |info| {
const array: [info.len]info.child = value;
return stringify(&array, options, out_stream);
const array: [info.len]info.child = value;
return stringify(&array, options, out_stream);
},
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
}
@ -2770,4 +2770,3 @@ test "stringify struct with custom stringifier" {
test "stringify vector" {
try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});
}

View File

@ -163,16 +163,16 @@ pub const IPPROTO_UDP = 17;
pub const IPPROTO_ICMPV6 = 58;
pub const IPPROTO_RM = 113;
pub const AI_PASSIVE = 0x00001;
pub const AI_CANONNAME = 0x00002;
pub const AI_NUMERICHOST = 0x00004;
pub const AI_NUMERICSERV = 0x00008;
pub const AI_ADDRCONFIG = 0x00400;
pub const AI_V4MAPPED = 0x00800;
pub const AI_NON_AUTHORITATIVE = 0x04000;
pub const AI_SECURE = 0x08000;
pub const AI_PASSIVE = 0x00001;
pub const AI_CANONNAME = 0x00002;
pub const AI_NUMERICHOST = 0x00004;
pub const AI_NUMERICSERV = 0x00008;
pub const AI_ADDRCONFIG = 0x00400;
pub const AI_V4MAPPED = 0x00800;
pub const AI_NON_AUTHORITATIVE = 0x04000;
pub const AI_SECURE = 0x08000;
pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
pub const AI_DISABLE_IDN_ENCODING = 0x80000;
pub const AI_DISABLE_IDN_ENCODING = 0x80000;
pub const FIONBIO = -2147195266;

View File

@ -937,7 +937,6 @@ const Parser = struct {
return node;
}
while_prefix.body = try p.expectNode(parseAssignExpr, .{
.ExpectedBlockOrAssignment = .{ .token = p.tok_i },
});

View File

@ -546,8 +546,9 @@ const Fmt = struct {
any_error: bool,
color: Color,
gpa: *Allocator,
out_buffer: std.ArrayList(u8),
const SeenMap = std.BufSet;
const SeenMap = std.AutoHashMap(fs.File.INode, void);
};
pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
@ -641,10 +642,20 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
.seen = Fmt.SeenMap.init(gpa),
.any_error = false,
.color = color,
.out_buffer = std.ArrayList(u8).init(gpa),
};
defer fmt.seen.deinit();
defer fmt.out_buffer.deinit();
for (input_files.span()) |file_path| {
try fmtPath(&fmt, file_path, check_flag);
// Get the real path here to avoid Windows failing on relative file paths with . or .. in them.
const real_path = fs.realpathAlloc(gpa, file_path) catch |err| {
std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
process.exit(1);
};
defer gpa.free(real_path);
try fmtPath(&fmt, file_path, check_flag, fs.cwd(), real_path);
}
if (fmt.any_error) {
process.exit(1);
@ -670,61 +681,79 @@ const FmtError = error{
ReadOnlyFileSystem,
LinkQuotaExceeded,
FileBusy,
EndOfStream,
} || fs.File.OpenError;
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
// get the real path here to avoid Windows failing on relative file paths with . or .. in them
var real_path = fs.realpathAlloc(fmt.gpa, file_path) catch |err| {
std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
fmt.any_error = true;
return;
};
defer fmt.gpa.free(real_path);
if (fmt.seen.exists(real_path)) return;
try fmt.seen.put(real_path);
const source_file = fs.cwd().openFile(real_path, .{}) catch |err| switch (err) {
error.IsDir, error.AccessDenied => {
var dir = try fs.cwd().openDir(file_path, .{ .iterate = true });
defer dir.close();
var dir_it = dir.iterate();
while (try dir_it.next()) |entry| {
if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
try fmtPath(fmt, full_path, check_mode);
}
}
return;
},
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 => {
std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
std.debug.warn("unable to format '{}': {}\n", .{ file_path, 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.put(stat.inode, {})) |_| return;
var dir_it = dir.iterate();
while (try dir_it.next()) |entry| {
const is_dir = entry.kind == .Directory;
if (is_dir or mem.endsWith(u8, entry.name, ".zig")) {
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| {
std.debug.warn("unable to format '{}': {}\n", .{ full_path, 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, .{});
defer source_file.close();
const stat = source_file.stat() catch |err| {
std.debug.warn("unable to stat '{}': {}\n", .{ file_path, err });
fmt.any_error = true;
return;
};
const stat = try source_file.stat();
const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| {
std.debug.warn("unable to read '{}': {}\n", .{ file_path, err });
fmt.any_error = true;
return;
if (stat.kind == .Directory)
return error.IsDir;
const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) {
error.ConnectionResetByPeer => unreachable,
error.ConnectionTimedOut => unreachable,
else => |e| return e,
};
defer fmt.gpa.free(source_code);
const tree = std.zig.parse(fmt.gpa, source_code) catch |err| {
std.debug.warn("error parsing file '{}': {}\n", .{ file_path, err });
fmt.any_error = true;
return;
};
// Add to set after no longer possible to get error.IsDir.
if (try fmt.seen.put(stat.inode, {})) |_| return;
const tree = try std.zig.parse(fmt.gpa, source_code);
defer tree.deinit();
for (tree.errors) |parse_error| {
@ -742,14 +771,19 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
fmt.any_error = true;
}
} else {
const baf = try io.BufferedAtomicFile.create(fmt.gpa, fs.cwd(), real_path, .{ .mode = stat.mode });
defer baf.destroy();
// As a heuristic, we make enough capacity for the same as the input source.
try fmt.out_buffer.ensureCapacity(source_code.len);
fmt.out_buffer.items.len = 0;
const anything_changed = try std.zig.render(fmt.gpa, fmt.out_buffer.writer(), tree);
if (!anything_changed)
return; // Good thing we didn't waste any file system access on this.
const anything_changed = try std.zig.render(fmt.gpa, baf.stream(), tree);
if (anything_changed) {
std.debug.warn("{}\n", .{file_path});
try baf.finish();
}
var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
defer af.deinit();
try af.file.writeAll(fmt.out_buffer.items);
try af.finish();
std.debug.warn("{}\n", .{file_path});
}
}