| author | |
| committer | |
| log | a2e87aba664c622fe368ce7fcbcdc499b9fd9cf9 |
| tree | 6b860ab5f8c16dd8dfaa4ad091450146f10a718c |
| parent | 7b37bc771b9a1ed38b06358269bf6a716a38de60 |
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 | 193 | /// Constants and types representing the Wasm binary format. |
| 194 | 194 | pub const wasm = @import("wasm.zig"); |
| 195 | 195 | |
| 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. | |
| 197 | 199 | pub const zig = @import("zig.zig"); |
| 198 | 200 | |
| 199 | 201 | pub const start = @import("start.zig"); |
lib/std/zig.zig+120-4| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | /// Implementation of `zig fmt`. | |
| 1 | 2 | pub const fmt = @import("zig/fmt.zig"); |
| 2 | 3 | |
| 3 | 4 | pub const ErrorBundle = @import("zig/ErrorBundle.zig"); |
| ... | ... | @@ -5,9 +6,6 @@ pub const Server = @import("zig/Server.zig"); |
| 5 | 6 | pub const Client = @import("zig/Client.zig"); |
| 6 | 7 | pub const Token = tokenizer.Token; |
| 7 | 8 | pub const Tokenizer = tokenizer.Tokenizer; |
| 8 | pub const fmtId = fmt.fmtId; | |
| 9 | pub const fmtEscapes = fmt.fmtEscapes; | |
| 10 | pub const isValidId = fmt.isValidId; | |
| 11 | 9 | pub const string_literal = @import("zig/string_literal.zig"); |
| 12 | 10 | pub const number_literal = @import("zig/number_literal.zig"); |
| 13 | 11 | pub const primitives = @import("zig/primitives.zig"); |
| ... | ... | @@ -694,6 +692,124 @@ const tokenizer = @import("zig/tokenizer.zig"); |
| 694 | 692 | const assert = std.debug.assert; |
| 695 | 693 | const Allocator = std.mem.Allocator; |
| 696 | 694 | |
| 695 | /// Return a Formatter for a Zig identifier | |
| 696 | pub 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. | |
| 701 | fn 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. | |
| 720 | pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) { | |
| 721 | return .{ .data = bytes }; | |
| 722 | } | |
| 723 | ||
| 724 | test "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. | |
| 742 | pub 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 | ||
| 781 | pub 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 | ||
| 794 | test 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 | ||
| 697 | 803 | test { |
| 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 | 105 | }; |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | /// `gpa` is used for allocating the resulting formatted source code, as well as | |
| 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. | |
| 108 | /// `gpa` is used for allocating the resulting formatted source code. | |
| 111 | 109 | /// Caller owns the returned slice of bytes, allocated with `gpa`. |
| 112 | 110 | pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 { |
| 113 | 111 | var buffer = std.ArrayList(u8).init(gpa); |
lib/std/zig/fmt.zig+1-110| ... | ... | @@ -1,110 +1 @@ |
| 1 | const std = @import("std"); | |
| 2 | const mem = std.mem; | |
| 3 | ||
| 4 | /// Print the string as a Zig identifier escaping it with @"" syntax if needed. | |
| 5 | fn 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 | |
| 21 | pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) { | |
| 22 | return .{ .data = bytes }; | |
| 23 | } | |
| 24 | ||
| 25 | pub 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 | ||
| 38 | test "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. | |
| 50 | pub 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. | |
| 93 | pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) { | |
| 94 | return .{ .data = bytes }; | |
| 95 | } | |
| 96 | ||
| 97 | test "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 | } | |
| 1 | const std = @import("../std.zig"); |
src/Package.zig+1-1| ... | ... | @@ -126,7 +126,7 @@ pub const Path = struct { |
| 126 | 126 | ) !void { |
| 127 | 127 | if (fmt_string.len == 1) { |
| 128 | 128 | // Quote-escape the string. |
| 129 | const stringEscape = std.zig.fmt.stringEscape; | |
| 129 | const stringEscape = std.zig.stringEscape; | |
| 130 | 130 | const f = switch (fmt_string[0]) { |
| 131 | 131 | 'q' => "", |
| 132 | 132 | '\'' => '\'', |