mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
rearrange std.zig
This frees up std.zig.fmt to be used for the implementation of `zig fmt`.
This commit is contained in:
parent
7b37bc771b
commit
a2e87aba66
@ -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");
|
||||
|
||||
126
lib/std/zig.zig
126
lib/std/zig.zig
@ -1,3 +1,4 @@
|
||||
/// Implementation of `zig fmt`.
|
||||
pub const fmt = @import("zig/fmt.zig");
|
||||
|
||||
pub const ErrorBundle = @import("zig/ErrorBundle.zig");
|
||||
@ -5,9 +6,6 @@ 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");
|
||||
@ -694,6 +692,124 @@ 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"));
|
||||
}
|
||||
|
||||
test {
|
||||
_ = Ast;
|
||||
_ = AstRlAnnotate;
|
||||
_ = BuiltinFn;
|
||||
_ = Client;
|
||||
_ = ErrorBundle;
|
||||
_ = Server;
|
||||
_ = fmt;
|
||||
_ = number_literal;
|
||||
_ = primitives;
|
||||
_ = string_literal;
|
||||
_ = system;
|
||||
}
|
||||
|
||||
@ -105,9 +105,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);
|
||||
|
||||
@ -1,110 +1 @@
|
||||
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 '")});
|
||||
}
|
||||
const std = @import("../std.zig");
|
||||
|
||||
@ -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' => "",
|
||||
'\'' => '\'',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user