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(...@@ -148,7 +148,7 @@ pub fn format(
148 comptime assert(fmt[i] == '}');148 comptime assert(fmt[i] == '}');
149 i += 1;149 i += 1;
150150
151 const placeholder = comptime parsePlaceholder(fmt[fmt_begin..fmt_end].*);151 const placeholder = comptime Placeholder.parse(fmt[fmt_begin..fmt_end].*);
152 const arg_pos = comptime switch (placeholder.arg) {152 const arg_pos = comptime switch (placeholder.arg) {
153 .none => null,153 .none => null,
154 .number => |pos| pos,154 .number => |pos| pos,
...@@ -205,102 +205,102 @@ pub fn format(...@@ -205,102 +205,102 @@ pub fn format(
205 }205 }
206}206}
207207
208fn parsePlaceholder(comptime str: anytype) Placeholder {208fn cacheString(str: anytype) []const u8 {
209 comptime var parser = Parser{ .buf = &str };209 return &str;
210}
210211
211 // Parse the positional argument number212pub const Placeholder = struct {
212 const arg = comptime parser.specifier() catch |err|213 specifier_arg: []const u8,
213 @compileError(@errorName(err));214 fill: u8,
215 alignment: Alignment,
216 arg: Specifier,
217 width: Specifier,
218 precision: Specifier,
214219
215 // Parse the format specifier220 pub fn parse(comptime str: anytype) Placeholder {
216 const specifier_arg = comptime parser.until(':');221 comptime var parser = Parser{ .buf = &str };
217222
218 // Skip the colon, if present223 // Parse the positional argument number
219 if (comptime parser.char()) |ch| {224 const arg = comptime parser.specifier() catch |err|
220 if (ch != ':') {225 @compileError(@errorName(err));
221 @compileError("expected : or }, found '" ++ [1]u8{ch} ++ "'");
222 }
223 }
224226
225 // Parse the fill character227 // Parse the format specifier
226 // The fill parameter requires the alignment parameter to be specified228 const specifier_arg = comptime parser.until(':');
227 // too
228 const fill = comptime if (parser.peek(1)) |ch|
229 switch (ch) {
230 '<', '^', '>' => parser.char().?,
231 else => ' ',
232 }
233 else
234 ' ';
235229
236 // Parse the alignment parameter230 // Skip the colon, if present
237 const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: {231 if (comptime parser.char()) |ch| {
238 switch (ch) {232 if (ch != ':') {
239 '<', '^', '>' => _ = parser.char(),233 @compileError("expected : or }, found '" ++ [1]u8{ch} ++ "'");
240 else => {},234 }
241 }235 }
242 break :init switch (ch) {
243 '<' => .Left,
244 '^' => .Center,
245 else => .Right,
246 };
247 } else .Right;
248236
249 // Parse the width parameter237 // Parse the fill character
250 const width = comptime parser.specifier() catch |err|238 // The fill parameter requires the alignment parameter to be specified
251 @compileError(@errorName(err));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 present248 // Parse the alignment parameter
254 if (comptime parser.char()) |ch| {249 const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: {
255 if (ch != '.') {250 switch (ch) {
256 @compileError("expected . or }, found '" ++ [1]u8{ch} ++ "'");251 '<', '^', '>' => _ = parser.char(),
257 }252 else => {},
258 }253 }
254 break :init switch (ch) {
255 '<' => .Left,
256 '^' => .Center,
257 else => .Right,
258 };
259 } else .Right;
259260
260 // Parse the precision parameter261 // Parse the width parameter
261 const precision = comptime parser.specifier() catch |err|262 const width = comptime parser.specifier() catch |err|
262 @compileError(@errorName(err));263 @compileError(@errorName(err));
263264
264 if (comptime parser.char()) |ch| {265 // Skip the dot, if present
265 @compileError("extraneous trailing character '" ++ [1]u8{ch} ++ "'");266 if (comptime parser.char()) |ch| {
266 }267 if (ch != '.') {
268 @compileError("expected . or }, found '" ++ [1]u8{ch} ++ "'");
269 }
270 }
267271
268 return Placeholder{272 // Parse the precision parameter
269 .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),273 const precision = comptime parser.specifier() catch |err|
270 .fill = fill,274 @compileError(@errorName(err));
271 .alignment = alignment,
272 .arg = arg,
273 .width = width,
274 .precision = precision,
275 };
276}
277275
278fn cacheString(str: anytype) []const u8 {276 if (comptime parser.char()) |ch| {
279 return &str;277 @compileError("extraneous trailing character '" ++ [1]u8{ch} ++ "'");
280}278 }
281279
282const Placeholder = struct {280 return Placeholder{
283 specifier_arg: []const u8,281 .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
284 fill: u8,282 .fill = fill,
285 alignment: Alignment,283 .alignment = alignment,
286 arg: Specifier,284 .arg = arg,
287 width: Specifier,285 .width = width,
288 precision: Specifier,286 .precision = precision,
287 };
288 }
289};289};
290290
291const Specifier = union(enum) {291pub const Specifier = union(enum) {
292 none,292 none,
293 number: usize,293 number: usize,
294 named: []const u8,294 named: []const u8,
295};295};
296296
297const Parser = struct {297pub const Parser = struct {
298 buf: []const u8,298 buf: []const u8,
299 pos: usize = 0,299 pos: usize = 0,
300300
301 // Returns a decimal number or null if the current character is not a301 // Returns a decimal number or null if the current character is not a
302 // digit302 // digit
303 fn number(self: *@This()) ?usize {303 pub fn number(self: *@This()) ?usize {
304 var r: ?usize = null;304 var r: ?usize = null;
305305
306 while (self.pos < self.buf.len) : (self.pos += 1) {306 while (self.pos < self.buf.len) : (self.pos += 1) {
...@@ -319,7 +319,7 @@ const Parser = struct {...@@ -319,7 +319,7 @@ const Parser = struct {
319319
320 // Returns a substring of the input starting from the current position320 // Returns a substring of the input starting from the current position
321 // and ending where `ch` is found or until the end if not found321 // 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 {
323 const start = self.pos;323 const start = self.pos;
324324
325 if (start >= self.buf.len)325 if (start >= self.buf.len)
...@@ -332,7 +332,7 @@ const Parser = struct {...@@ -332,7 +332,7 @@ const Parser = struct {
332 }332 }
333333
334 // Returns one character, if available334 // Returns one character, if available
335 fn char(self: *@This()) ?u8 {335 pub fn char(self: *@This()) ?u8 {
336 if (self.pos < self.buf.len) {336 if (self.pos < self.buf.len) {
337 const ch = self.buf[self.pos];337 const ch = self.buf[self.pos];
338 self.pos += 1;338 self.pos += 1;
...@@ -341,7 +341,7 @@ const Parser = struct {...@@ -341,7 +341,7 @@ const Parser = struct {
341 return null;341 return null;
342 }342 }
343343
344 fn maybe(self: *@This(), val: u8) bool {344 pub fn maybe(self: *@This(), val: u8) bool {
345 if (self.pos < self.buf.len and self.buf[self.pos] == val) {345 if (self.pos < self.buf.len and self.buf[self.pos] == val) {
346 self.pos += 1;346 self.pos += 1;
347 return true;347 return true;
...@@ -351,7 +351,7 @@ const Parser = struct {...@@ -351,7 +351,7 @@ const Parser = struct {
351351
352 // Returns a decimal number or null if the current character is not a352 // Returns a decimal number or null if the current character is not a
353 // digit353 // digit
354 fn specifier(self: *@This()) !Specifier {354 pub fn specifier(self: *@This()) !Specifier {
355 if (self.maybe('[')) {355 if (self.maybe('[')) {
356 const arg_name = self.until(']');356 const arg_name = self.until(']');
357357
...@@ -367,24 +367,24 @@ const Parser = struct {...@@ -367,24 +367,24 @@ const Parser = struct {
367 }367 }
368368
369 // Returns the n-th next character or null if that's past the end369 // 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 {
371 return if (self.pos + n < self.buf.len) self.buf[self.pos + n] else null;371 return if (self.pos + n < self.buf.len) self.buf[self.pos + n] else null;
372 }372 }
373};373};
374374
375const ArgSetType = u32;375pub const ArgSetType = u32;
376const max_format_args = @typeInfo(ArgSetType).Int.bits;376const max_format_args = @typeInfo(ArgSetType).Int.bits;
377377
378const ArgState = struct {378pub const ArgState = struct {
379 next_arg: usize = 0,379 next_arg: usize = 0,
380 used_args: ArgSetType = 0,380 used_args: ArgSetType = 0,
381 args_len: usize,381 args_len: usize,
382382
383 fn hasUnusedArgs(self: *@This()) bool {383 pub fn hasUnusedArgs(self: *@This()) bool {
384 return @popCount(self.used_args) != self.args_len;384 return @popCount(self.used_args) != self.args_len;
385 }385 }
386386
387 fn nextArg(self: *@This(), arg_index: ?usize) ?usize {387 pub fn nextArg(self: *@This(), arg_index: ?usize) ?usize {
388 const next_index = arg_index orelse init: {388 const next_index = arg_index orelse init: {
389 const arg = self.next_arg;389 const arg = self.next_arg;
390 self.next_arg += 1;390 self.next_arg += 1;
...@@ -430,7 +430,7 @@ pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @T...@@ -430,7 +430,7 @@ pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @T
430// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948430// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
431const ANY = "any";431const ANY = "any";
432432
433fn defaultSpec(comptime T: type) [:0]const u8 {433pub fn defaultSpec(comptime T: type) [:0]const u8 {
434 switch (@typeInfo(T)) {434 switch (@typeInfo(T)) {
435 .Array => |_| return ANY,435 .Array => |_| return ANY,
436 .Pointer => |ptr_info| switch (ptr_info.size) {436 .Pointer => |ptr_info| switch (ptr_info.size) {