authorgravatar for tristan.ross@midstall.comTristan Ross <tristan.ross@midstall.com> 2023-03-31 13:25:32-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-15 12:11:11+03:00
logde6cafa80fba3c1fb93bf82b76c1efffbc61bf98
treee62148b27c6bb351962ad8a251cac36b45383673
parent6f3dacc1073c30d10f640fe630580a4866cbd9db

std: expose fmt methods and structs for parsing


1 files changed, 82 insertions(+), 82 deletions(-)

lib/std/fmt.zig+82-82
......@@ -148,7 +148,7 @@ pub fn format(
148148 comptime assert(fmt[i] == '}');
149149 i += 1;
150150
151 const placeholder = comptime parsePlaceholder(fmt[fmt_begin..fmt_end].*);
151 const placeholder = comptime Placeholder.parse(fmt[fmt_begin..fmt_end].*);
152152 const arg_pos = comptime switch (placeholder.arg) {
153153 .none => null,
154154 .number => |pos| pos,
......@@ -205,102 +205,102 @@ pub fn format(
205205 }
206206}
207207
208fn parsePlaceholder(comptime str: anytype) Placeholder {
209 comptime var parser = Parser{ .buf = &str };
208fn cacheString(str: anytype) []const u8 {
209 return &str;
210}
210211
211 // Parse the positional argument number
212 const arg = comptime parser.specifier() catch |err|
213 @compileError(@errorName(err));
212pub const Placeholder = struct {
213 specifier_arg: []const u8,
214 fill: u8,
215 alignment: Alignment,
216 arg: Specifier,
217 width: Specifier,
218 precision: Specifier,
214219
215 // Parse the format specifier
216 const specifier_arg = comptime parser.until(':');
220 pub fn parse(comptime str: anytype) Placeholder {
221 comptime var parser = Parser{ .buf = &str };
217222
218 // Skip the colon, if present
219 if (comptime parser.char()) |ch| {
220 if (ch != ':') {
221 @compileError("expected : or }, found '" ++ [1]u8{ch} ++ "'");
222 }
223 }
223 // Parse the positional argument number
224 const arg = comptime parser.specifier() catch |err|
225 @compileError(@errorName(err));
224226
225 // Parse the fill character
226 // The fill parameter requires the alignment parameter to be specified
227 // too
228 const fill = comptime if (parser.peek(1)) |ch|
229 switch (ch) {
230 '<', '^', '>' => parser.char().?,
231 else => ' ',
232 }
233 else
234 ' ';
227 // Parse the format specifier
228 const specifier_arg = comptime parser.until(':');
235229
236 // Parse the alignment parameter
237 const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: {
238 switch (ch) {
239 '<', '^', '>' => _ = parser.char(),
240 else => {},
230 // Skip the colon, if present
231 if (comptime parser.char()) |ch| {
232 if (ch != ':') {
233 @compileError("expected : or }, found '" ++ [1]u8{ch} ++ "'");
234 }
241235 }
242 break :init switch (ch) {
243 '<' => .Left,
244 '^' => .Center,
245 else => .Right,
246 };
247 } else .Right;
248236
249 // Parse the width parameter
250 const width = comptime parser.specifier() catch |err|
251 @compileError(@errorName(err));
237 // Parse the fill character
238 // The fill parameter requires the alignment parameter to be specified
239 // too
240 const fill = comptime if (parser.peek(1)) |ch|
241 switch (ch) {
242 '<', '^', '>' => parser.char().?,
243 else => ' ',
244 }
245 else
246 ' ';
252247
253 // Skip the dot, if present
254 if (comptime parser.char()) |ch| {
255 if (ch != '.') {
256 @compileError("expected . or }, found '" ++ [1]u8{ch} ++ "'");
257 }
258 }
248 // Parse the alignment parameter
249 const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: {
250 switch (ch) {
251 '<', '^', '>' => _ = parser.char(),
252 else => {},
253 }
254 break :init switch (ch) {
255 '<' => .Left,
256 '^' => .Center,
257 else => .Right,
258 };
259 } else .Right;
259260
260 // Parse the precision parameter
261 const precision = comptime parser.specifier() catch |err|
262 @compileError(@errorName(err));
261 // Parse the width parameter
262 const width = comptime parser.specifier() catch |err|
263 @compileError(@errorName(err));
263264
264 if (comptime parser.char()) |ch| {
265 @compileError("extraneous trailing character '" ++ [1]u8{ch} ++ "'");
266 }
265 // Skip the dot, if present
266 if (comptime parser.char()) |ch| {
267 if (ch != '.') {
268 @compileError("expected . or }, found '" ++ [1]u8{ch} ++ "'");
269 }
270 }
267271
268 return Placeholder{
269 .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
270 .fill = fill,
271 .alignment = alignment,
272 .arg = arg,
273 .width = width,
274 .precision = precision,
275 };
276}
272 // Parse the precision parameter
273 const precision = comptime parser.specifier() catch |err|
274 @compileError(@errorName(err));
277275
278fn cacheString(str: anytype) []const u8 {
279 return &str;
280}
276 if (comptime parser.char()) |ch| {
277 @compileError("extraneous trailing character '" ++ [1]u8{ch} ++ "'");
278 }
281279
282const Placeholder = struct {
283 specifier_arg: []const u8,
284 fill: u8,
285 alignment: Alignment,
286 arg: Specifier,
287 width: Specifier,
288 precision: Specifier,
280 return Placeholder{
281 .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
282 .fill = fill,
283 .alignment = alignment,
284 .arg = arg,
285 .width = width,
286 .precision = precision,
287 };
288 }
289289};
290290
291const Specifier = union(enum) {
291pub const Specifier = union(enum) {
292292 none,
293293 number: usize,
294294 named: []const u8,
295295};
296296
297const Parser = struct {
297pub const Parser = struct {
298298 buf: []const u8,
299299 pos: usize = 0,
300300
301301 // Returns a decimal number or null if the current character is not a
302302 // digit
303 fn number(self: *@This()) ?usize {
303 pub fn number(self: *@This()) ?usize {
304304 var r: ?usize = null;
305305
306306 while (self.pos < self.buf.len) : (self.pos += 1) {
......@@ -319,7 +319,7 @@ const Parser = struct {
319319
320320 // Returns a substring of the input starting from the current position
321321 // and ending where `ch` is found or until the end if not found
322 fn until(self: *@This(), ch: u8) []const u8 {
322 pub fn until(self: *@This(), ch: u8) []const u8 {
323323 const start = self.pos;
324324
325325 if (start >= self.buf.len)
......@@ -332,7 +332,7 @@ const Parser = struct {
332332 }
333333
334334 // Returns one character, if available
335 fn char(self: *@This()) ?u8 {
335 pub fn char(self: *@This()) ?u8 {
336336 if (self.pos < self.buf.len) {
337337 const ch = self.buf[self.pos];
338338 self.pos += 1;
......@@ -341,7 +341,7 @@ const Parser = struct {
341341 return null;
342342 }
343343
344 fn maybe(self: *@This(), val: u8) bool {
344 pub fn maybe(self: *@This(), val: u8) bool {
345345 if (self.pos < self.buf.len and self.buf[self.pos] == val) {
346346 self.pos += 1;
347347 return true;
......@@ -351,7 +351,7 @@ const Parser = struct {
351351
352352 // Returns a decimal number or null if the current character is not a
353353 // digit
354 fn specifier(self: *@This()) !Specifier {
354 pub fn specifier(self: *@This()) !Specifier {
355355 if (self.maybe('[')) {
356356 const arg_name = self.until(']');
357357
......@@ -367,24 +367,24 @@ const Parser = struct {
367367 }
368368
369369 // Returns the n-th next character or null if that's past the end
370 fn peek(self: *@This(), n: usize) ?u8 {
370 pub fn peek(self: *@This(), n: usize) ?u8 {
371371 return if (self.pos + n < self.buf.len) self.buf[self.pos + n] else null;
372372 }
373373};
374374
375const ArgSetType = u32;
375pub const ArgSetType = u32;
376376const max_format_args = @typeInfo(ArgSetType).Int.bits;
377377
378const ArgState = struct {
378pub const ArgState = struct {
379379 next_arg: usize = 0,
380380 used_args: ArgSetType = 0,
381381 args_len: usize,
382382
383 fn hasUnusedArgs(self: *@This()) bool {
383 pub fn hasUnusedArgs(self: *@This()) bool {
384384 return @popCount(self.used_args) != self.args_len;
385385 }
386386
387 fn nextArg(self: *@This(), arg_index: ?usize) ?usize {
387 pub fn nextArg(self: *@This(), arg_index: ?usize) ?usize {
388388 const next_index = arg_index orelse init: {
389389 const arg = self.next_arg;
390390 self.next_arg += 1;
......@@ -430,7 +430,7 @@ pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @T
430430// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
431431const ANY = "any";
432432
433fn defaultSpec(comptime T: type) [:0]const u8 {
433pub fn defaultSpec(comptime T: type) [:0]const u8 {
434434 switch (@typeInfo(T)) {
435435 .Array => |_| return ANY,
436436 .Pointer => |ptr_info| switch (ptr_info.size) {