diff options
| author | Tristan Ross <tristan.ross@midstall.com> | 2023-03-31 13:25:32 -0700 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2023-05-15 12:11:11 +0300 |
| commit | de6cafa80fba3c1fb93bf82b76c1efffbc61bf98 (patch) | |
| tree | e62148b27c6bb351962ad8a251cac36b45383673 /lib/std/fmt.zig | |
| parent | 6f3dacc1073c30d10f640fe630580a4866cbd9db (diff) | |
| download | zig-de6cafa80fba3c1fb93bf82b76c1efffbc61bf98.tar.gz zig-de6cafa80fba3c1fb93bf82b76c1efffbc61bf98.zip | |
std: expose fmt methods and structs for parsing
Diffstat (limited to 'lib/std/fmt.zig')
| -rw-r--r-- | lib/std/fmt.zig | 164 |
1 files changed, 82 insertions, 82 deletions
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 41add83c3b..38a7975ffd 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -148,7 +148,7 @@ pub fn format( comptime assert(fmt[i] == '}'); i += 1; - const placeholder = comptime parsePlaceholder(fmt[fmt_begin..fmt_end].*); + const placeholder = comptime Placeholder.parse(fmt[fmt_begin..fmt_end].*); const arg_pos = comptime switch (placeholder.arg) { .none => null, .number => |pos| pos, @@ -205,102 +205,102 @@ pub fn format( } } -fn parsePlaceholder(comptime str: anytype) Placeholder { - comptime var parser = Parser{ .buf = &str }; +fn cacheString(str: anytype) []const u8 { + return &str; +} - // Parse the positional argument number - const arg = comptime parser.specifier() catch |err| - @compileError(@errorName(err)); +pub const Placeholder = struct { + specifier_arg: []const u8, + fill: u8, + alignment: Alignment, + arg: Specifier, + width: Specifier, + precision: Specifier, - // Parse the format specifier - const specifier_arg = comptime parser.until(':'); + pub fn parse(comptime str: anytype) Placeholder { + comptime var parser = Parser{ .buf = &str }; - // Skip the colon, if present - if (comptime parser.char()) |ch| { - if (ch != ':') { - @compileError("expected : or }, found '" ++ [1]u8{ch} ++ "'"); - } - } + // Parse the positional argument number + const arg = comptime parser.specifier() catch |err| + @compileError(@errorName(err)); - // Parse the fill character - // The fill parameter requires the alignment parameter to be specified - // too - const fill = comptime if (parser.peek(1)) |ch| - switch (ch) { - '<', '^', '>' => parser.char().?, - else => ' ', - } - else - ' '; + // Parse the format specifier + const specifier_arg = comptime parser.until(':'); - // Parse the alignment parameter - const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: { - switch (ch) { - '<', '^', '>' => _ = parser.char(), - else => {}, + // Skip the colon, if present + if (comptime parser.char()) |ch| { + if (ch != ':') { + @compileError("expected : or }, found '" ++ [1]u8{ch} ++ "'"); + } } - break :init switch (ch) { - '<' => .Left, - '^' => .Center, - else => .Right, - }; - } else .Right; - // Parse the width parameter - const width = comptime parser.specifier() catch |err| - @compileError(@errorName(err)); + // Parse the fill character + // The fill parameter requires the alignment parameter to be specified + // too + const fill = comptime if (parser.peek(1)) |ch| + switch (ch) { + '<', '^', '>' => parser.char().?, + else => ' ', + } + else + ' '; - // Skip the dot, if present - if (comptime parser.char()) |ch| { - if (ch != '.') { - @compileError("expected . or }, found '" ++ [1]u8{ch} ++ "'"); - } - } + // Parse the alignment parameter + const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: { + switch (ch) { + '<', '^', '>' => _ = parser.char(), + else => {}, + } + break :init switch (ch) { + '<' => .Left, + '^' => .Center, + else => .Right, + }; + } else .Right; - // Parse the precision parameter - const precision = comptime parser.specifier() catch |err| - @compileError(@errorName(err)); + // Parse the width parameter + const width = comptime parser.specifier() catch |err| + @compileError(@errorName(err)); - if (comptime parser.char()) |ch| { - @compileError("extraneous trailing character '" ++ [1]u8{ch} ++ "'"); - } + // Skip the dot, if present + if (comptime parser.char()) |ch| { + if (ch != '.') { + @compileError("expected . or }, found '" ++ [1]u8{ch} ++ "'"); + } + } - return Placeholder{ - .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*), - .fill = fill, - .alignment = alignment, - .arg = arg, - .width = width, - .precision = precision, - }; -} + // Parse the precision parameter + const precision = comptime parser.specifier() catch |err| + @compileError(@errorName(err)); -fn cacheString(str: anytype) []const u8 { - return &str; -} + if (comptime parser.char()) |ch| { + @compileError("extraneous trailing character '" ++ [1]u8{ch} ++ "'"); + } -const Placeholder = struct { - specifier_arg: []const u8, - fill: u8, - alignment: Alignment, - arg: Specifier, - width: Specifier, - precision: Specifier, + return Placeholder{ + .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*), + .fill = fill, + .alignment = alignment, + .arg = arg, + .width = width, + .precision = precision, + }; + } }; -const Specifier = union(enum) { +pub const Specifier = union(enum) { none, number: usize, named: []const u8, }; -const Parser = struct { +pub const Parser = struct { buf: []const u8, pos: usize = 0, // Returns a decimal number or null if the current character is not a // digit - fn number(self: *@This()) ?usize { + pub fn number(self: *@This()) ?usize { var r: ?usize = null; while (self.pos < self.buf.len) : (self.pos += 1) { @@ -319,7 +319,7 @@ const Parser = struct { // Returns a substring of the input starting from the current position // and ending where `ch` is found or until the end if not found - fn until(self: *@This(), ch: u8) []const u8 { + pub fn until(self: *@This(), ch: u8) []const u8 { const start = self.pos; if (start >= self.buf.len) @@ -332,7 +332,7 @@ const Parser = struct { } // Returns one character, if available - fn char(self: *@This()) ?u8 { + pub fn char(self: *@This()) ?u8 { if (self.pos < self.buf.len) { const ch = self.buf[self.pos]; self.pos += 1; @@ -341,7 +341,7 @@ const Parser = struct { return null; } - fn maybe(self: *@This(), val: u8) bool { + pub fn maybe(self: *@This(), val: u8) bool { if (self.pos < self.buf.len and self.buf[self.pos] == val) { self.pos += 1; return true; @@ -351,7 +351,7 @@ const Parser = struct { // Returns a decimal number or null if the current character is not a // digit - fn specifier(self: *@This()) !Specifier { + pub fn specifier(self: *@This()) !Specifier { if (self.maybe('[')) { const arg_name = self.until(']'); @@ -367,24 +367,24 @@ const Parser = struct { } // Returns the n-th next character or null if that's past the end - fn peek(self: *@This(), n: usize) ?u8 { + pub fn peek(self: *@This(), n: usize) ?u8 { return if (self.pos + n < self.buf.len) self.buf[self.pos + n] else null; } }; -const ArgSetType = u32; +pub const ArgSetType = u32; const max_format_args = @typeInfo(ArgSetType).Int.bits; -const ArgState = struct { +pub const ArgState = struct { next_arg: usize = 0, used_args: ArgSetType = 0, args_len: usize, - fn hasUnusedArgs(self: *@This()) bool { + pub fn hasUnusedArgs(self: *@This()) bool { return @popCount(self.used_args) != self.args_len; } - fn nextArg(self: *@This(), arg_index: ?usize) ?usize { + pub fn nextArg(self: *@This(), arg_index: ?usize) ?usize { const next_index = arg_index orelse init: { const arg = self.next_arg; self.next_arg += 1; @@ -430,7 +430,7 @@ pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @T // This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948 const ANY = "any"; -fn defaultSpec(comptime T: type) [:0]const u8 { +pub fn defaultSpec(comptime T: type) [:0]const u8 { switch (@typeInfo(T)) { .Array => |_| return ANY, .Pointer => |ptr_info| switch (ptr_info.size) { |
