Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ziglang/zig
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 96164ce61377
Choose a base ref
...
head repository: ziglang/zig
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8dfa66fee30f
Choose a head ref
  • 9 commits
  • 2 files changed
  • 2 contributors

Commits on May 12, 2018

  1. Merge pull request #1 from zig-lang/master

    Sync with zig-lang/zig master
    tgschultz authored May 12, 2018
    Copy the full SHA
    8c18725 View commit details

Commits on May 30, 2018

  1. Merge pull request #2 from ziglang/master

    sync with ziglang
    tgschultz authored May 30, 2018
    Copy the full SHA
    8174f97 View commit details
  2. Copy the full SHA
    8fc52a9 View commit details
  3. Minor typo

    tgschultz committed May 30, 2018
    Copy the full SHA
    4e1d0a5 View commit details
  4. Formatting

    tgschultz committed May 30, 2018
    Copy the full SHA
    8938c16 View commit details
  5. Fixed character handling

    tgschultz committed May 30, 2018
    Copy the full SHA
    fb001f5 View commit details
  6. Copy the full SHA
    940a854 View commit details

Commits on Jun 4, 2018

  1. Merge branch 'zig-custom-format' of https://github.com/tgschultz/zig

    …into tgschultz-zig-custom-format
    
    I removed the code that checks for type signature and type.
    A function named `format` is enough for zig to give it a try.
    andrewrk committed Jun 4, 2018
    Copy the full SHA
    11e7e03 View commit details
  2. Copy the full SHA
    8dfa66f View commit details
Showing with 243 additions and 209 deletions.
  1. +242 −208 std/fmt/index.zig
  2. +1 −1 std/os/time.zig
450 changes: 242 additions & 208 deletions std/fmt/index.zig
Original file line number Diff line number Diff line change
@@ -16,27 +16,12 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
Start,
OpenBrace,
CloseBrace,
Integer,
IntegerWidth,
Float,
FloatWidth,
FloatScientific,
FloatScientificWidth,
Character,
Buf,
BufWidth,
Bytes,
BytesBase,
BytesWidth,
FormatString,
};

comptime var start_index = 0;
comptime var state = State.Start;
comptime var next_arg = 0;
comptime var radix = 0;
comptime var uppercase = false;
comptime var width = 0;
comptime var width_start = 0;

inline for (fmt) |c, i| {
switch (state) {
@@ -45,8 +30,10 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
if (start_index < i) {
try output(context, fmt[start_index..i]);
}
start_index = i;
state = State.OpenBrace;
},

'}' => {
if (start_index < i) {
try output(context, fmt[start_index..i]);
@@ -61,57 +48,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
start_index = i;
},
'}' => {
try formatValue(args[next_arg], context, Errors, output);
try formatType(args[next_arg], fmt[0..0], context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'd' => {
radix = 10;
uppercase = false;
width = 0;
state = State.Integer;
},
'x' => {
radix = 16;
uppercase = false;
width = 0;
state = State.Integer;
},
'X' => {
radix = 16;
uppercase = true;
width = 0;
state = State.Integer;
},
'c' => {
state = State.Character;
},
's' => {
state = State.Buf;
},
'e' => {
state = State.FloatScientific;
},
'.' => {
state = State.Float;
},
'B' => {
width = 0;
radix = 1000;
state = State.Bytes;
},
else => @compileError("Unknown format character: " ++ []u8{c}),
},
State.Buf => switch (c) {
'}' => {
return output(context, args[next_arg]);
},
'0'...'9' => {
width_start = i;
state = State.BufWidth;
else => {
state = State.FormatString;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.CloseBrace => switch (c) {
'}' => {
@@ -120,138 +64,15 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
},
else => @compileError("Single '}' encountered in format string"),
},
State.Integer => switch (c) {
'}' => {
try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {
width_start = i;
state = State.IntegerWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.IntegerWidth => switch (c) {
State.FormatString => switch (c) {
'}' => {
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
try formatInt(args[next_arg], radix, uppercase, width, context, Errors, output);
const s = start_index + 1;
try formatType(args[next_arg], fmt[s..i], context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.FloatScientific => switch (c) {
'}' => {
try formatFloatScientific(args[next_arg], null, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {
width_start = i;
state = State.FloatScientificWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.FloatScientificWidth => switch (c) {
'}' => {
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
try formatFloatScientific(args[next_arg], width, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.Float => switch (c) {
'}' => {
try formatFloatDecimal(args[next_arg], null, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {
width_start = i;
state = State.FloatWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.FloatWidth => switch (c) {
'}' => {
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
try formatFloatDecimal(args[next_arg], width, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.BufWidth => switch (c) {
'}' => {
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
try formatBuf(args[next_arg], width, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.Character => switch (c) {
'}' => {
try formatAsciiChar(args[next_arg], context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.Bytes => switch (c) {
'}' => {
try formatBytes(args[next_arg], 0, radix, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'i' => {
radix = 1024;
state = State.BytesBase;
},
'0'...'9' => {
width_start = i;
state = State.BytesWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.BytesBase => switch (c) {
'}' => {
try formatBytes(args[next_arg], 0, radix, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {
width_start = i;
state = State.BytesWidth;
},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
State.BytesWidth => switch (c) {
'}' => {
width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
try formatBytes(args[next_arg], width, radix, context, Errors, output);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
'0'...'9' => {},
else => @compileError("Unexpected character in format string: " ++ []u8{c}),
else => {},
},
}
}
@@ -268,14 +89,17 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
}
}

pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
pub fn formatType(
value: var,
comptime fmt: []const u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
const T = @typeOf(value);
switch (@typeId(T)) {
builtin.TypeId.Int => {
return formatInt(value, 10, false, 0, context, Errors, output);
},
builtin.TypeId.Float => {
return formatFloatScientific(value, null, context, Errors, output);
builtin.TypeId.Int, builtin.TypeId.Float => {
return formatValue(value, fmt, context, Errors, output);
},
builtin.TypeId.Void => {
return output(context, "void");
@@ -285,27 +109,51 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn (
},
builtin.TypeId.Nullable => {
if (value) |payload| {
return formatValue(payload, context, Errors, output);
return formatType(payload, fmt, context, Errors, output);
} else {
return output(context, "null");
}
},
builtin.TypeId.ErrorUnion => {
if (value) |payload| {
return formatValue(payload, context, Errors, output);
return formatType(payload, fmt, context, Errors, output);
} else |err| {
return formatValue(err, context, Errors, output);
return formatType(err, fmt, context, Errors, output);
}
},
builtin.TypeId.ErrorSet => {
try output(context, "error.");
return output(context, @errorName(value));
},
builtin.TypeId.Pointer => {
if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
return output(context, (value.*)[0..]);
} else {
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
switch (@typeId(T.Child)) {
builtin.TypeId.Array => {
if (T.Child.Child == u8) {
return formatText(value, fmt, context, Errors, output);
}
},
builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
const has_cust_fmt = comptime cf: {
const info = @typeInfo(T.Child);
const defs = switch (info) {
builtin.TypeId.Struct => |s| s.defs,
builtin.TypeId.Union => |u| u.defs,
builtin.TypeId.Enum => |e| e.defs,
else => unreachable,
};

for (defs) |def| {
if (mem.eql(u8, def.name, "format")) {
break :cf true;
}
}
break :cf false;
};

if (has_cust_fmt) return value.format(fmt, context, Errors, output);
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
},
else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
}
},
else => if (@canImplicitCast([]const u8, value)) {
@@ -317,11 +165,129 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn (
}
}

pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
fn formatValue(
value: var,
comptime fmt: []const u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
if (fmt.len > 0) {
if (fmt[0] == 'B') {
comptime var width: ?usize = null;
if (fmt.len > 1) {
if (fmt[1] == 'i') {
if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
return formatBytes(value, width, 1024, context, Errors, output);
}
width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
}
return formatBytes(value, width, 1000, context, Errors, output);
}
}

comptime var T = @typeOf(value);
switch (@typeId(T)) {
builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
else => unreachable,
}
}

pub fn formatIntValue(
value: var,
comptime fmt: []const u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
comptime var radix = 10;
comptime var uppercase = false;
comptime var width = 0;
if (fmt.len > 0) {
switch (fmt[0]) {
'c' => {
if (@typeOf(value) == u8) {
if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]});
return formatAsciiChar(value, context, Errors, output);
}
},
'd' => {
radix = 10;
uppercase = false;
width = 0;
},
'x' => {
radix = 16;
uppercase = false;
width = 0;
},
'X' => {
radix = 16;
uppercase = true;
width = 0;
},
else => @compileError("Unknown format character: " ++ []u8{fmt[0]}),
}
if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
}
return formatInt(value, radix, uppercase, width, context, Errors, output);
}

fn formatFloatValue(
value: var,
comptime fmt: []const u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
comptime var width: ?usize = null;
comptime var float_fmt = 'e';
if (fmt.len > 0) {
float_fmt = fmt[0];
if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
}

switch (float_fmt) {
'e' => try formatFloatScientific(value, width, context, Errors, output),
'.' => try formatFloatDecimal(value, width, context, Errors, output),
else => @compileError("Unknown format character: " ++ []u8{float_fmt}),
}
}

pub fn formatText(
bytes: []const u8,
comptime fmt: []const u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
if (fmt.len > 0) {
if (fmt[0] == 's') {
comptime var width = 0;
if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
return formatBuf(bytes, width, context, Errors, output);
} else @compileError("Unknown format character: " ++ []u8{fmt[0]});
}
return output(context, bytes);
}

pub fn formatAsciiChar(
c: u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
return output(context, (&c)[0..1]);
}

pub fn formatBuf(buf: []const u8, width: usize, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
pub fn formatBuf(
buf: []const u8,
width: usize,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
try output(context, buf);

var leftover_padding = if (width > buf.len) (width - buf.len) else return;
@@ -334,7 +300,13 @@ pub fn formatBuf(buf: []const u8, width: usize, context: var, comptime Errors: t
// Print a float in scientific notation to the specified precision. Null uses full precision.
// It should be the case that every full precision, printed value can be re-parsed back to the
// same type unambiguously.
pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
pub fn formatFloatScientific(
value: var,
maybe_precision: ?usize,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
var x = f64(value);

// Errol doesn't handle these special cases.
@@ -423,7 +395,13 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,

// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
// By default floats are printed at full precision (no rounding).
pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
pub fn formatFloatDecimal(
value: var,
maybe_precision: ?usize,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
var x = f64(value);

// Errol doesn't handle these special cases.
@@ -613,7 +591,15 @@ pub fn formatInt(
}
}

fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
fn formatIntSigned(
value: var,
base: u8,
uppercase: bool,
width: usize,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
const uint = @IntType(false, @typeOf(value).bit_count);
if (value < 0) {
const minus_sign: u8 = '-';
@@ -632,7 +618,15 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, context:
}
}

fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void) Errors!void {
fn formatIntUnsigned(
value: var,
base: u8,
uppercase: bool,
width: usize,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
// max_int_digits accounts for the minus sign. when printing an unsigned
// number we don't need to do that.
var buf: [max_int_digits - 1]u8 = undefined;
@@ -831,6 +825,10 @@ test "fmt.format" {
const value: u3 = 0b101;
try testFmt("u3: 5\n", "u3: {}\n", value);
}
{
const value: u8 = 'a';
try testFmt("u8: a\n", "u8: {c}\n", value);
}
try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
{
@@ -1048,6 +1046,42 @@ test "fmt.format" {
const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
}
//custom type format
{
const Vec2 = struct {
const SelfType = this;
x: f32,
y: f32,

pub fn format(
self: *SelfType,
comptime fmt: []const u8,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) Errors!void {
if (fmt.len > 0) {
if (fmt.len > 1) unreachable;
switch (fmt[0]) {
//point format
'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
//dimension format
'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
else => unreachable,
}
}
return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y);
}
};

var buf1: [32]u8 = undefined;
var value = Vec2{
.x = 10.2,
.y = 2.22,
};
try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
}
}

fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
2 changes: 1 addition & 1 deletion std/os/time.zig
Original file line number Diff line number Diff line change
@@ -266,7 +266,7 @@ test "os.time.timestamp" {

test "os.time.Timer" {
const ns_per_ms = (ns_per_s / ms_per_s);
const margin = ns_per_ms * 50;
const margin = ns_per_ms * 150;

var timer = try Timer.start();
sleep(0, 10 * ns_per_ms);