authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 18:55:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 21:35:33-07:00
loga2e87aba664c622fe368ce7fcbcdc499b9fd9cf9
tree6b860ab5f8c16dd8dfaa4ad091450146f10a718c
parent7b37bc771b9a1ed38b06358269bf6a716a38de60

rearrange std.zig

This frees up std.zig.fmt to be used for the implementation of `zig fmt`.

5 files changed, 126 insertions(+), 119 deletions(-)

lib/std/std.zig+3-1
...@@ -193,7 +193,9 @@ pub const valgrind = @import("valgrind.zig");...@@ -193,7 +193,9 @@ pub const valgrind = @import("valgrind.zig");
193/// Constants and types representing the Wasm binary format.193/// Constants and types representing the Wasm binary format.
194pub const wasm = @import("wasm.zig");194pub const wasm = @import("wasm.zig");
195195
196/// Tokenizing and parsing of Zig code and other Zig-specific language tooling.196/// Builds of the Zig compiler are distributed partly in source form. That
197/// source lives here. These APIs are provided as-is and have absolutely no API
198/// guarantees whatsoever.
197pub const zig = @import("zig.zig");199pub const zig = @import("zig.zig");
198200
199pub const start = @import("start.zig");201pub const start = @import("start.zig");
lib/std/zig.zig+120-4
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1/// Implementation of `zig fmt`.
1pub const fmt = @import("zig/fmt.zig");2pub const fmt = @import("zig/fmt.zig");
23
3pub const ErrorBundle = @import("zig/ErrorBundle.zig");4pub const ErrorBundle = @import("zig/ErrorBundle.zig");
...@@ -5,9 +6,6 @@ pub const Server = @import("zig/Server.zig");...@@ -5,9 +6,6 @@ pub const Server = @import("zig/Server.zig");
5pub const Client = @import("zig/Client.zig");6pub const Client = @import("zig/Client.zig");
6pub const Token = tokenizer.Token;7pub const Token = tokenizer.Token;
7pub const Tokenizer = tokenizer.Tokenizer;8pub const Tokenizer = tokenizer.Tokenizer;
8pub const fmtId = fmt.fmtId;
9pub const fmtEscapes = fmt.fmtEscapes;
10pub const isValidId = fmt.isValidId;
11pub const string_literal = @import("zig/string_literal.zig");9pub const string_literal = @import("zig/string_literal.zig");
12pub const number_literal = @import("zig/number_literal.zig");10pub const number_literal = @import("zig/number_literal.zig");
13pub const primitives = @import("zig/primitives.zig");11pub const primitives = @import("zig/primitives.zig");
...@@ -694,6 +692,124 @@ const tokenizer = @import("zig/tokenizer.zig");...@@ -694,6 +692,124 @@ const tokenizer = @import("zig/tokenizer.zig");
694const assert = std.debug.assert;692const assert = std.debug.assert;
695const Allocator = std.mem.Allocator;693const Allocator = std.mem.Allocator;
696694
695/// Return a Formatter for a Zig identifier
696pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
697 return .{ .data = bytes };
698}
699
700/// Print the string as a Zig identifier escaping it with @"" syntax if needed.
701fn formatId(
702 bytes: []const u8,
703 comptime unused_format_string: []const u8,
704 options: std.fmt.FormatOptions,
705 writer: anytype,
706) !void {
707 _ = unused_format_string;
708 if (isValidId(bytes)) {
709 return writer.writeAll(bytes);
710 }
711 try writer.writeAll("@\"");
712 try stringEscape(bytes, "", options, writer);
713 try writer.writeByte('"');
714}
715
716/// Return a Formatter for Zig Escapes of a double quoted string.
717/// The format specifier must be one of:
718/// * `{}` treats contents as a double-quoted string.
719/// * `{'}` treats contents as a single-quoted string.
720pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
721 return .{ .data = bytes };
722}
723
724test "escape invalid identifiers" {
725 const expectFmt = std.testing.expectFmt;
726 try expectFmt("@\"while\"", "{}", .{fmtId("while")});
727 try expectFmt("hello", "{}", .{fmtId("hello")});
728 try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
729 try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
730 try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
731 try expectFmt(
732 \\" \\ hi \x07 \x11 " derp \'"
733 , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
734 try expectFmt(
735 \\" \\ hi \x07 \x11 \" derp '"
736 , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
737}
738
739/// Print the string as escaped contents of a double quoted or single-quoted string.
740/// Format `{}` treats contents as a double-quoted string.
741/// Format `{'}` treats contents as a single-quoted string.
742pub fn stringEscape(
743 bytes: []const u8,
744 comptime f: []const u8,
745 options: std.fmt.FormatOptions,
746 writer: anytype,
747) !void {
748 _ = options;
749 for (bytes) |byte| switch (byte) {
750 '\n' => try writer.writeAll("\\n"),
751 '\r' => try writer.writeAll("\\r"),
752 '\t' => try writer.writeAll("\\t"),
753 '\\' => try writer.writeAll("\\\\"),
754 '"' => {
755 if (f.len == 1 and f[0] == '\'') {
756 try writer.writeByte('"');
757 } else if (f.len == 0) {
758 try writer.writeAll("\\\"");
759 } else {
760 @compileError("expected {} or {'}, found {" ++ f ++ "}");
761 }
762 },
763 '\'' => {
764 if (f.len == 1 and f[0] == '\'') {
765 try writer.writeAll("\\'");
766 } else if (f.len == 0) {
767 try writer.writeByte('\'');
768 } else {
769 @compileError("expected {} or {'}, found {" ++ f ++ "}");
770 }
771 },
772 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
773 // Use hex escapes for rest any unprintable characters.
774 else => {
775 try writer.writeAll("\\x");
776 try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
777 },
778 };
779}
780
781pub fn isValidId(bytes: []const u8) bool {
782 if (bytes.len == 0) return false;
783 if (std.mem.eql(u8, bytes, "_")) return false;
784 for (bytes, 0..) |c, i| {
785 switch (c) {
786 '_', 'a'...'z', 'A'...'Z' => {},
787 '0'...'9' => if (i == 0) return false,
788 else => return false,
789 }
790 }
791 return std.zig.Token.getKeyword(bytes) == null;
792}
793
794test isValidId {
795 try std.testing.expect(!isValidId(""));
796 try std.testing.expect(isValidId("foobar"));
797 try std.testing.expect(!isValidId("a b c"));
798 try std.testing.expect(!isValidId("3d"));
799 try std.testing.expect(!isValidId("enum"));
800 try std.testing.expect(isValidId("i386"));
801}
802
697test {803test {
698 @import("std").testing.refAllDecls(@This());804 _ = Ast;
805 _ = AstRlAnnotate;
806 _ = BuiltinFn;
807 _ = Client;
808 _ = ErrorBundle;
809 _ = Server;
810 _ = fmt;
811 _ = number_literal;
812 _ = primitives;
813 _ = string_literal;
814 _ = system;
699}815}
lib/std/zig/Ast.zig+1-3
...@@ -105,9 +105,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A...@@ -105,9 +105,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A
105 };105 };
106}106}
107107
108/// `gpa` is used for allocating the resulting formatted source code, as well as108/// `gpa` is used for allocating the resulting formatted source code.
109/// for allocating extra stack memory if needed, because this function utilizes recursion.
110/// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006.
111/// Caller owns the returned slice of bytes, allocated with `gpa`.109/// Caller owns the returned slice of bytes, allocated with `gpa`.
112pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 {110pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 {
113 var buffer = std.ArrayList(u8).init(gpa);111 var buffer = std.ArrayList(u8).init(gpa);
lib/std/zig/fmt.zig+1-110
...@@ -1,110 +1 @@...@@ -1,110 +1 @@
1const std = @import("std");1const std = @import("../std.zig");
2const mem = std.mem;
3
4/// Print the string as a Zig identifier escaping it with @"" syntax if needed.
5fn formatId(
6 bytes: []const u8,
7 comptime fmt: []const u8,
8 options: std.fmt.FormatOptions,
9 writer: anytype,
10) !void {
11 _ = fmt;
12 if (isValidId(bytes)) {
13 return writer.writeAll(bytes);
14 }
15 try writer.writeAll("@\"");
16 try stringEscape(bytes, "", options, writer);
17 try writer.writeByte('"');
18}
19
20/// Return a Formatter for a Zig identifier
21pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
22 return .{ .data = bytes };
23}
24
25pub fn isValidId(bytes: []const u8) bool {
26 if (bytes.len == 0) return false;
27 if (mem.eql(u8, bytes, "_")) return false;
28 for (bytes, 0..) |c, i| {
29 switch (c) {
30 '_', 'a'...'z', 'A'...'Z' => {},
31 '0'...'9' => if (i == 0) return false,
32 else => return false,
33 }
34 }
35 return std.zig.Token.getKeyword(bytes) == null;
36}
37
38test "isValidId" {
39 try std.testing.expect(!isValidId(""));
40 try std.testing.expect(isValidId("foobar"));
41 try std.testing.expect(!isValidId("a b c"));
42 try std.testing.expect(!isValidId("3d"));
43 try std.testing.expect(!isValidId("enum"));
44 try std.testing.expect(isValidId("i386"));
45}
46
47/// Print the string as escaped contents of a double quoted or single-quoted string.
48/// Format `{}` treats contents as a double-quoted string.
49/// Format `{'}` treats contents as a single-quoted string.
50pub fn stringEscape(
51 bytes: []const u8,
52 comptime fmt: []const u8,
53 options: std.fmt.FormatOptions,
54 writer: anytype,
55) !void {
56 _ = options;
57 for (bytes) |byte| switch (byte) {
58 '\n' => try writer.writeAll("\\n"),
59 '\r' => try writer.writeAll("\\r"),
60 '\t' => try writer.writeAll("\\t"),
61 '\\' => try writer.writeAll("\\\\"),
62 '"' => {
63 if (fmt.len == 1 and fmt[0] == '\'') {
64 try writer.writeByte('"');
65 } else if (fmt.len == 0) {
66 try writer.writeAll("\\\"");
67 } else {
68 @compileError("expected {} or {'}, found {" ++ fmt ++ "}");
69 }
70 },
71 '\'' => {
72 if (fmt.len == 1 and fmt[0] == '\'') {
73 try writer.writeAll("\\'");
74 } else if (fmt.len == 0) {
75 try writer.writeByte('\'');
76 } else {
77 @compileError("expected {} or {'}, found {" ++ fmt ++ "}");
78 }
79 },
80 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
81 // Use hex escapes for rest any unprintable characters.
82 else => {
83 try writer.writeAll("\\x");
84 try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
85 },
86 };
87}
88
89/// Return a Formatter for Zig Escapes of a double quoted string.
90/// The format specifier must be one of:
91/// * `{}` treats contents as a double-quoted string.
92/// * `{'}` treats contents as a single-quoted string.
93pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
94 return .{ .data = bytes };
95}
96
97test "escape invalid identifiers" {
98 const expectFmt = std.testing.expectFmt;
99 try expectFmt("@\"while\"", "{}", .{fmtId("while")});
100 try expectFmt("hello", "{}", .{fmtId("hello")});
101 try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
102 try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
103 try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
104 try expectFmt(
105 \\" \\ hi \x07 \x11 " derp \'"
106 , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
107 try expectFmt(
108 \\" \\ hi \x07 \x11 \" derp '"
109 , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
110}
src/Package.zig+1-1
...@@ -126,7 +126,7 @@ pub const Path = struct {...@@ -126,7 +126,7 @@ pub const Path = struct {
126 ) !void {126 ) !void {
127 if (fmt_string.len == 1) {127 if (fmt_string.len == 1) {
128 // Quote-escape the string.128 // Quote-escape the string.
129 const stringEscape = std.zig.fmt.stringEscape;129 const stringEscape = std.zig.stringEscape;
130 const f = switch (fmt_string[0]) {130 const f = switch (fmt_string[0]) {
131 'q' => "",131 'q' => "",
132 '\'' => '\'',132 '\'' => '\'',