authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-06-26 20:06:12+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-06-26 20:06:12+03:00
log22194efe68a112d6d0688f49bf6340a8a952d47c
treef8d4c601b7edac8222cf4cb2c28d08db77726075
parent7325f80bb2aa1759ea5477b8ea26266ecc607db7
parentfa42c99d82448c74a657d16e0f2e5f9877e364c0
signature Signed by PGP key 4AEE18F83AFDEB23

Merge branch 'master' into comment-in-array


9 files changed, 463 insertions(+), 377 deletions(-)

src-self-hosted/dep_tokenizer.zig+1-1
...@@ -998,7 +998,7 @@ fn printCharValues(out: var, bytes: []const u8) !void {...@@ -998,7 +998,7 @@ fn printCharValues(out: var, bytes: []const u8) !void {
998998
999fn printUnderstandableChar(out: var, char: u8) !void {999fn printUnderstandableChar(out: var, char: u8) !void {
1000 if (!std.ascii.isPrint(char) or char == ' ') {1000 if (!std.ascii.isPrint(char) or char == ' ') {
1001 std.fmt.format(out.context, anyerror, out.output, "\\x{X2}", char) catch {};1001 std.fmt.format(out.context, anyerror, out.output, "\\x{X:2}", char) catch {};
1002 } else {1002 } else {
1003 try out.write("'");1003 try out.write("'");
1004 try out.write([_]u8{printable_char_tab[char]});1004 try out.write([_]u8{printable_char_tab[char]});
src/ir.cpp+8-2
...@@ -23280,10 +23280,16 @@ static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr,...@@ -23280,10 +23280,16 @@ static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr,
23280 BuiltinFnId fop = source_instr->op;23280 BuiltinFnId fop = source_instr->op;
23281 unsigned bits;23281 unsigned bits;
2328223282
23283 if (float_type->id == ZigTypeIdComptimeFloat) {23283 switch (float_type->id) {
23284 case ZigTypeIdComptimeFloat:
23284 bits = 128;23285 bits = 128;
23285 } else if (float_type->id == ZigTypeIdFloat)23286 break;
23287 case ZigTypeIdFloat:
23286 bits = float_type->data.floating.bit_count;23288 bits = float_type->data.floating.bit_count;
23289 break;
23290 default:
23291 zig_unreachable();
23292 }
2328723293
23288 switch (bits) {23294 switch (bits) {
23289 case 16: {23295 case 16: {
std/fmt.zig+397-363
...@@ -10,6 +10,42 @@ const lossyCast = std.math.lossyCast;...@@ -10,6 +10,42 @@ const lossyCast = std.math.lossyCast;
1010
11pub const default_max_depth = 3;11pub const default_max_depth = 3;
1212
13pub const Alignment = enum {
14 Left,
15 Center,
16 Right,
17};
18
19pub const FormatOptions = struct {
20 precision: ?usize = null,
21 width: ?usize = null,
22 alignment: ?Alignment = null,
23 fill: u8 = ' ',
24};
25
26fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int, comptime next_arg: *comptime_int) comptime_int {
27 if (maybe_pos_arg) |pos_arg| {
28 used_pos_args.* |= 1 << pos_arg;
29 return pos_arg;
30 } else {
31 const arg = next_arg.*;
32 next_arg.* += 1;
33 return arg;
34 }
35}
36
37fn peekIsAlign(comptime fmt: []const u8) bool {
38 // Should only be called during a state transition to the format segment.
39 std.debug.assert(fmt[0] == ':');
40
41 inline for (([_]u8{ 1, 2 })[0..]) |i| {
42 if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
43 return true;
44 }
45 }
46 return false;
47}
48
13/// Renders fmt string with args, calling output with slices of bytes.49/// Renders fmt string with args, calling output with slices of bytes.
14/// If `output` returns an error, the error is returned from `format` and50/// If `output` returns an error, the error is returned from `format` and
15/// `output` is not called again.51/// `output` is not called again.
...@@ -20,17 +56,30 @@ pub fn format(...@@ -20,17 +56,30 @@ pub fn format(
20 comptime fmt: []const u8,56 comptime fmt: []const u8,
21 args: ...,57 args: ...,
22) Errors!void {58) Errors!void {
59 const ArgSetType = @IntType(false, 32);
60 if (args.len > ArgSetType.bit_count) {
61 @compileError("32 arguments max are supported per format call");
62 }
63
23 const State = enum {64 const State = enum {
24 Start,65 Start,
25 OpenBrace,66 Positional,
26 CloseBrace,67 CloseBrace,
27 FormatString,68 Specifier,
69 FormatFillAndAlign,
70 FormatWidth,
71 FormatPrecision,
28 Pointer,72 Pointer,
29 };73 };
3074
31 comptime var start_index = 0;75 comptime var start_index = 0;
32 comptime var state = State.Start;76 comptime var state = State.Start;
33 comptime var next_arg = 0;77 comptime var next_arg = 0;
78 comptime var maybe_pos_arg: ?comptime_int = null;
79 comptime var used_pos_args: ArgSetType = 0;
80 comptime var specifier_start = 0;
81 comptime var specifier_end = 0;
82 comptime var options = FormatOptions{};
3483
35 inline for (fmt) |c, i| {84 inline for (fmt) |c, i| {
36 switch (state) {85 switch (state) {
...@@ -39,58 +88,183 @@ pub fn format(...@@ -39,58 +88,183 @@ pub fn format(
39 if (start_index < i) {88 if (start_index < i) {
40 try output(context, fmt[start_index..i]);89 try output(context, fmt[start_index..i]);
41 }90 }
91
42 start_index = i;92 start_index = i;
43 state = State.OpenBrace;93 specifier_start = i + 1;
94 specifier_end = i + 1;
95 maybe_pos_arg = null;
96 state = .Positional;
97 options = FormatOptions{};
44 },98 },
45
46 '}' => {99 '}' => {
47 if (start_index < i) {100 if (start_index < i) {
48 try output(context, fmt[start_index..i]);101 try output(context, fmt[start_index..i]);
49 }102 }
50 state = State.CloseBrace;103 state = .CloseBrace;
51 },104 },
52 else => {},105 else => {},
53 },106 },
54 .OpenBrace => switch (c) {107 .Positional => switch (c) {
55 '{' => {108 '{' => {
56 state = State.Start;109 state = .Start;
57 start_index = i;110 start_index = i;
58 },111 },
112 '*' => {
113 state = .Pointer;
114 },
115 ':' => {
116 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
117 specifier_end = i;
118 },
119 '0'...'9' => {
120 if (maybe_pos_arg == null) {
121 maybe_pos_arg = 0;
122 }
123
124 maybe_pos_arg.? *= 10;
125 maybe_pos_arg.? += c - '0';
126 specifier_start = i + 1;
127
128 if (maybe_pos_arg.? >= args.len) {
129 @compileError("Positional value refers to non-existent argument");
130 }
131 },
59 '}' => {132 '}' => {
60 try formatType(args[next_arg], fmt[0..0], context, Errors, output, default_max_depth);133 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
61 next_arg += 1;134
62 state = State.Start;135 try formatType(
136 args[arg_to_print],
137 fmt[0..0],
138 options,
139 context,
140 Errors,
141 output,
142 default_max_depth,
143 );
144
145 state = .Start;
63 start_index = i + 1;146 start_index = i + 1;
64 },147 },
65 '*' => state = State.Pointer,
66 else => {148 else => {
67 state = State.FormatString;149 state = .Specifier;
150 specifier_start = i;
68 },151 },
69 },152 },
70 .CloseBrace => switch (c) {153 .CloseBrace => switch (c) {
71 '}' => {154 '}' => {
72 state = State.Start;155 state = .Start;
73 start_index = i;156 start_index = i;
74 },157 },
75 else => @compileError("Single '}' encountered in format string"),158 else => @compileError("Single '}' encountered in format string"),
76 },159 },
77 .FormatString => switch (c) {160 .Specifier => switch (c) {
161 ':' => {
162 specifier_end = i;
163 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
164 },
78 '}' => {165 '}' => {
79 const s = start_index + 1;166 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
80 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);167
81 next_arg += 1;168 try formatType(
82 state = State.Start;169 args[arg_to_print],
170 fmt[specifier_start..i],
171 options,
172 context,
173 Errors,
174 output,
175 default_max_depth,
176 );
177 state = .Start;
83 start_index = i + 1;178 start_index = i + 1;
84 },179 },
85 else => {},180 else => {},
86 },181 },
182 // Only entered if the format string contains a fill/align segment.
183 .FormatFillAndAlign => switch (c) {
184 '<' => {
185 options.alignment = Alignment.Left;
186 state = .FormatWidth;
187 },
188 '^' => {
189 options.alignment = Alignment.Center;
190 state = .FormatWidth;
191 },
192 '>' => {
193 options.alignment = Alignment.Right;
194 state = .FormatWidth;
195 },
196 else => {
197 options.fill = c;
198 },
199 },
200 .FormatWidth => switch (c) {
201 '0'...'9' => {
202 if (options.width == null) {
203 options.width = 0;
204 }
205
206 options.width.? *= 10;
207 options.width.? += c - '0';
208 },
209 '.' => {
210 state = .FormatPrecision;
211 },
212 '}' => {
213 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
214
215 try formatType(
216 args[arg_to_print],
217 fmt[specifier_start..specifier_end],
218 options,
219 context,
220 Errors,
221 output,
222 default_max_depth,
223 );
224 state = .Start;
225 start_index = i + 1;
226 },
227 else => {
228 @compileError("Unexpected character in width value: " ++ [_]u8{c});
229 },
230 },
231 .FormatPrecision => switch (c) {
232 '0'...'9' => {
233 if (options.precision == null) {
234 options.precision = 0;
235 }
236
237 options.precision.? *= 10;
238 options.precision.? += c - '0';
239 },
240 '}' => {
241 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
242
243 try formatType(
244 args[arg_to_print],
245 fmt[specifier_start..specifier_end],
246 options,
247 context,
248 Errors,
249 output,
250 default_max_depth,
251 );
252 state = .Start;
253 start_index = i + 1;
254 },
255 else => {
256 @compileError("Unexpected character in precision value: " ++ [_]u8{c});
257 },
258 },
87 .Pointer => switch (c) {259 .Pointer => switch (c) {
88 '}' => {260 '}' => {
89 try output(context, @typeName(@typeOf(args[next_arg]).Child));261 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
262
263 try output(context, @typeName(@typeOf(args[arg_to_print]).Child));
90 try output(context, "@");264 try output(context, "@");
91 try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);265 try formatInt(@ptrToInt(args[arg_to_print]), 16, false, 0, context, Errors, output);
92 next_arg += 1;266
93 state = State.Start;267 state = .Start;
94 start_index = i + 1;268 start_index = i + 1;
95 },269 },
96 else => @compileError("Unexpected format character after '*'"),270 else => @compileError("Unexpected format character after '*'"),
...@@ -98,7 +272,13 @@ pub fn format(...@@ -98,7 +272,13 @@ pub fn format(
98 }272 }
99 }273 }
100 comptime {274 comptime {
101 if (args.len != next_arg) {275 // All arguments must have been printed but we allow mixing positional and fixed to achieve this.
276 var i: usize = 0;
277 inline while (i < next_arg) : (i += 1) {
278 used_pos_args |= 1 << i;
279 }
280
281 if (@popCount(ArgSetType, used_pos_args) != args.len) {
102 @compileError("Unused arguments");282 @compileError("Unused arguments");
103 }283 }
104 if (state != State.Start) {284 if (state != State.Start) {
...@@ -113,6 +293,7 @@ pub fn format(...@@ -113,6 +293,7 @@ pub fn format(
113pub fn formatType(293pub fn formatType(
114 value: var,294 value: var,
115 comptime fmt: []const u8,295 comptime fmt: []const u8,
296 comptime options: FormatOptions,
116 context: var,297 context: var,
117 comptime Errors: type,298 comptime Errors: type,
118 output: fn (@typeOf(context), []const u8) Errors!void,299 output: fn (@typeOf(context), []const u8) Errors!void,
...@@ -121,7 +302,7 @@ pub fn formatType(...@@ -121,7 +302,7 @@ pub fn formatType(
121 const T = @typeOf(value);302 const T = @typeOf(value);
122 switch (@typeInfo(T)) {303 switch (@typeInfo(T)) {
123 .ComptimeInt, .Int, .Float => {304 .ComptimeInt, .Int, .Float => {
124 return formatValue(value, fmt, context, Errors, output);305 return formatValue(value, fmt, options, context, Errors, output);
125 },306 },
126 .Void => {307 .Void => {
127 return output(context, "void");308 return output(context, "void");
...@@ -131,16 +312,16 @@ pub fn formatType(...@@ -131,16 +312,16 @@ pub fn formatType(
131 },312 },
132 .Optional => {313 .Optional => {
133 if (value) |payload| {314 if (value) |payload| {
134 return formatType(payload, fmt, context, Errors, output, max_depth);315 return formatType(payload, fmt, options, context, Errors, output, max_depth);
135 } else {316 } else {
136 return output(context, "null");317 return output(context, "null");
137 }318 }
138 },319 },
139 .ErrorUnion => {320 .ErrorUnion => {
140 if (value) |payload| {321 if (value) |payload| {
141 return formatType(payload, fmt, context, Errors, output, max_depth);322 return formatType(payload, fmt, options, context, Errors, output, max_depth);
142 } else |err| {323 } else |err| {
143 return formatType(err, fmt, context, Errors, output, max_depth);324 return formatType(err, fmt, options, context, Errors, output, max_depth);
144 }325 }
145 },326 },
146 .ErrorSet => {327 .ErrorSet => {
...@@ -152,16 +333,16 @@ pub fn formatType(...@@ -152,16 +333,16 @@ pub fn formatType(
152 },333 },
153 .Enum => {334 .Enum => {
154 if (comptime std.meta.trait.hasFn("format")(T)) {335 if (comptime std.meta.trait.hasFn("format")(T)) {
155 return value.format(fmt, context, Errors, output);336 return value.format(fmt, options, context, Errors, output);
156 }337 }
157338
158 try output(context, @typeName(T));339 try output(context, @typeName(T));
159 try output(context, ".");340 try output(context, ".");
160 return formatType(@tagName(value), "", context, Errors, output, max_depth);341 return formatType(@tagName(value), "", options, context, Errors, output, max_depth);
161 },342 },
162 .Union => {343 .Union => {
163 if (comptime std.meta.trait.hasFn("format")(T)) {344 if (comptime std.meta.trait.hasFn("format")(T)) {
164 return value.format(fmt, context, Errors, output);345 return value.format(fmt, options, context, Errors, output);
165 }346 }
166347
167 try output(context, @typeName(T));348 try output(context, @typeName(T));
...@@ -175,7 +356,7 @@ pub fn formatType(...@@ -175,7 +356,7 @@ pub fn formatType(
175 try output(context, " = ");356 try output(context, " = ");
176 inline for (info.fields) |u_field| {357 inline for (info.fields) |u_field| {
177 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {358 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
178 try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth - 1);359 try formatType(@field(value, u_field.name), "", options, context, Errors, output, max_depth - 1);
179 }360 }
180 }361 }
181 try output(context, " }");362 try output(context, " }");
...@@ -185,7 +366,7 @@ pub fn formatType(...@@ -185,7 +366,7 @@ pub fn formatType(
185 },366 },
186 .Struct => {367 .Struct => {
187 if (comptime std.meta.trait.hasFn("format")(T)) {368 if (comptime std.meta.trait.hasFn("format")(T)) {
188 return value.format(fmt, context, Errors, output);369 return value.format(fmt, options, context, Errors, output);
189 }370 }
190371
191 try output(context, @typeName(T));372 try output(context, @typeName(T));
...@@ -201,7 +382,7 @@ pub fn formatType(...@@ -201,7 +382,7 @@ pub fn formatType(
201 }382 }
202 try output(context, @memberName(T, field_i));383 try output(context, @memberName(T, field_i));
203 try output(context, " = ");384 try output(context, " = ");
204 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);385 try formatType(@field(value, @memberName(T, field_i)), "", options, context, Errors, output, max_depth - 1);
205 }386 }
206 try output(context, " }");387 try output(context, " }");
207 },388 },
...@@ -209,12 +390,12 @@ pub fn formatType(...@@ -209,12 +390,12 @@ pub fn formatType(
209 .One => switch (@typeInfo(ptr_info.child)) {390 .One => switch (@typeInfo(ptr_info.child)) {
210 builtin.TypeId.Array => |info| {391 builtin.TypeId.Array => |info| {
211 if (info.child == u8) {392 if (info.child == u8) {
212 return formatText(value, fmt, context, Errors, output);393 return formatText(value, fmt, options, context, Errors, output);
213 }394 }
214 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));395 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
215 },396 },
216 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {397 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
217 return formatType(value.*, fmt, context, Errors, output, max_depth);398 return formatType(value.*, fmt, options, context, Errors, output, max_depth);
218 },399 },
219 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),400 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
220 },401 },
...@@ -222,17 +403,17 @@ pub fn formatType(...@@ -222,17 +403,17 @@ pub fn formatType(
222 if (ptr_info.child == u8) {403 if (ptr_info.child == u8) {
223 if (fmt.len > 0 and fmt[0] == 's') {404 if (fmt.len > 0 and fmt[0] == 's') {
224 const len = mem.len(u8, value);405 const len = mem.len(u8, value);
225 return formatText(value[0..len], fmt, context, Errors, output);406 return formatText(value[0..len], fmt, options, context, Errors, output);
226 }407 }
227 }408 }
228 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));409 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
229 },410 },
230 .Slice => {411 .Slice => {
231 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {412 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
232 return formatText(value, fmt, context, Errors, output);413 return formatText(value, fmt, options, context, Errors, output);
233 }414 }
234 if (ptr_info.child == u8) {415 if (ptr_info.child == u8) {
235 return formatText(value, fmt, context, Errors, output);416 return formatText(value, fmt, options, context, Errors, output);
236 }417 }
237 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));418 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
238 },419 },
...@@ -242,7 +423,7 @@ pub fn formatType(...@@ -242,7 +423,7 @@ pub fn formatType(
242 },423 },
243 .Array => |info| {424 .Array => |info| {
244 if (info.child == u8) {425 if (info.child == u8) {
245 return formatText(value, fmt, context, Errors, output);426 return formatText(value, fmt, options, context, Errors, output);
246 }427 }
247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));428 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
248 },429 },
...@@ -256,28 +437,25 @@ pub fn formatType(...@@ -256,28 +437,25 @@ pub fn formatType(
256fn formatValue(437fn formatValue(
257 value: var,438 value: var,
258 comptime fmt: []const u8,439 comptime fmt: []const u8,
440 comptime options: FormatOptions,
259 context: var,441 context: var,
260 comptime Errors: type,442 comptime Errors: type,
261 output: fn (@typeOf(context), []const u8) Errors!void,443 output: fn (@typeOf(context), []const u8) Errors!void,
262) Errors!void {444) Errors!void {
263 if (fmt.len > 0 and fmt[0] == 'B') {445 if (comptime std.mem.eql(u8, fmt, "B")) {
264 comptime var width: ?usize = null;446 // TODO https://github.com/ziglang/zig/issues/2725
265 if (fmt.len > 1) {447 if (options.width) |w| return formatBytes(value, w, 1000, context, Errors, output);
266 if (fmt[1] == 'i') {448 return formatBytes(value, null, 1000, context, Errors, output);
267 if (fmt.len > 2) {449 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);450 // TODO https://github.com/ziglang/zig/issues/2725
269 }451 if (options.width) |w| return formatBytes(value, w, 1024, context, Errors, output);
270 return formatBytes(value, width, 1024, context, Errors, output);452 return formatBytes(value, null, 1024, context, Errors, output);
271 }
272 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
273 }
274 return formatBytes(value, width, 1000, context, Errors, output);
275 }453 }
276454
277 const T = @typeOf(value);455 const T = @typeOf(value);
278 switch (@typeId(T)) {456 switch (@typeId(T)) {
279 .Float => return formatFloatValue(value, fmt, context, Errors, output),457 .Float => return formatFloatValue(value, fmt, options, context, Errors, output),
280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),458 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
281 else => comptime unreachable,459 else => comptime unreachable,
282 }460 }
283}461}
...@@ -285,13 +463,13 @@ fn formatValue(...@@ -285,13 +463,13 @@ fn formatValue(
285pub fn formatIntValue(463pub fn formatIntValue(
286 value: var,464 value: var,
287 comptime fmt: []const u8,465 comptime fmt: []const u8,
466 comptime options: FormatOptions,
288 context: var,467 context: var,
289 comptime Errors: type,468 comptime Errors: type,
290 output: fn (@typeOf(context), []const u8) Errors!void,469 output: fn (@typeOf(context), []const u8) Errors!void,
291) Errors!void {470) Errors!void {
292 comptime var radix = 10;471 comptime var radix = 10;
293 comptime var uppercase = false;472 comptime var uppercase = false;
294 comptime var width = 0;
295473
296 const int_value = if (@typeOf(value) == comptime_int) blk: {474 const int_value = if (@typeOf(value) == comptime_int) blk: {
297 const Int = math.IntFittingRange(value, value);475 const Int = math.IntFittingRange(value, value);
...@@ -299,83 +477,75 @@ pub fn formatIntValue(...@@ -299,83 +477,75 @@ pub fn formatIntValue(
299 } else477 } else
300 value;478 value;
301479
302 if (fmt.len > 0) {480 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
303 switch (fmt[0]) {481 radix = 10;
304 'c' => {482 uppercase = false;
305 if (@typeOf(int_value).bit_count <= 8) {483 } else if (comptime std.mem.eql(u8, fmt, "c")) {
306 if (fmt.len > 1)484 if (@typeOf(int_value).bit_count <= 8) {
307 @compileError("Unknown format character: " ++ [_]u8{fmt[1]});485 return formatAsciiChar(u8(int_value), context, Errors, output);
308 return formatAsciiChar(u8(int_value), context, Errors, output);486 } else {
309 }487 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
310 },
311 'b' => {
312 radix = 2;
313 uppercase = false;
314 width = 0;
315 },
316 'd' => {
317 radix = 10;
318 uppercase = false;
319 width = 0;
320 },
321 'x' => {
322 radix = 16;
323 uppercase = false;
324 width = 0;
325 },
326 'X' => {
327 radix = 16;
328 uppercase = true;
329 width = 0;
330 },
331 else => @compileError("Unknown format character: " ++ [_]u8{fmt[0]}),
332 }488 }
333 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);489 } else if (comptime std.mem.eql(u8, fmt, "b")) {
490 radix = 2;
491 uppercase = false;
492 } else if (comptime std.mem.eql(u8, fmt, "x")) {
493 radix = 16;
494 uppercase = false;
495 } else if (comptime std.mem.eql(u8, fmt, "X")) {
496 radix = 16;
497 uppercase = true;
498 } else {
499 @compileError("Unknown format string: '" ++ fmt ++ "'");
334 }500 }
335 return formatInt(int_value, radix, uppercase, width, context, Errors, output);501
502 // TODO https://github.com/ziglang/zig/issues/2725
503 if (options.width) |w| return formatInt(int_value, radix, uppercase, w, context, Errors, output);
504 return formatInt(int_value, radix, uppercase, 0, context, Errors, output);
336}505}
337506
338fn formatFloatValue(507fn formatFloatValue(
339 value: var,508 value: var,
340 comptime fmt: []const u8,509 comptime fmt: []const u8,
510 comptime options: FormatOptions,
341 context: var,511 context: var,
342 comptime Errors: type,512 comptime Errors: type,
343 output: fn (@typeOf(context), []const u8) Errors!void,513 output: fn (@typeOf(context), []const u8) Errors!void,
344) Errors!void {514) Errors!void {
345 comptime var width: ?usize = null;515 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
346 comptime var float_fmt = 'e';516 // TODO https://github.com/ziglang/zig/issues/2725
347 if (fmt.len > 0) {517 if (options.precision) |p| return formatFloatScientific(value, p, context, Errors, output);
348 float_fmt = fmt[0];518 return formatFloatScientific(value, null, context, Errors, output);
349 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);519 } else if (comptime std.mem.eql(u8, fmt, "d")) {
350 }520 // TODO https://github.com/ziglang/zig/issues/2725
351521 if (options.precision) |p| return formatFloatDecimal(value, p, context, Errors, output);
352 switch (float_fmt) {522 return formatFloatDecimal(value, null, context, Errors, output);
353 'e' => try formatFloatScientific(value, width, context, Errors, output),523 } else {
354 '.' => try formatFloatDecimal(value, width, context, Errors, output),524 @compileError("Unknown format string: '" ++ fmt ++ "'");
355 else => @compileError("Unknown format character: " ++ [_]u8{float_fmt}),
356 }525 }
357}526}
358527
359pub fn formatText(528pub fn formatText(
360 bytes: []const u8,529 bytes: []const u8,
361 comptime fmt: []const u8,530 comptime fmt: []const u8,
531 comptime options: FormatOptions,
362 context: var,532 context: var,
363 comptime Errors: type,533 comptime Errors: type,
364 output: fn (@typeOf(context), []const u8) Errors!void,534 output: fn (@typeOf(context), []const u8) Errors!void,
365) Errors!void {535) Errors!void {
366 if (fmt.len > 0) {536 if (fmt.len == 0) {
367 if (fmt[0] == 's') {537 return output(context, bytes);
368 comptime var width = 0;538 } else if (comptime std.mem.eql(u8, fmt, "s")) {
369 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);539 if (options.width) |w| return formatBuf(bytes, w, context, Errors, output);
370 return formatBuf(bytes, width, context, Errors, output);540 return formatBuf(bytes, 0, context, Errors, output);
371 } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {541 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
372 for (bytes) |c| {542 for (bytes) |c| {
373 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);543 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
374 }544 }
375 return;545 return;
376 } else @compileError("Unknown format character: " ++ [_]u8{fmt[0]});546 } else {
547 @compileError("Unknown format string: '" ++ fmt ++ "'");
377 }548 }
378 return output(context, bytes);
379}549}
380550
381pub fn formatAsciiChar(551pub fn formatAsciiChar(
...@@ -868,7 +1038,7 @@ test "parseUnsigned" {...@@ -868,7 +1038,7 @@ test "parseUnsigned" {
8681038
869pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;1039pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
8701040
871test "fmt.parseFloat" {1041test "parseFloat" {
872 _ = @import("fmt/parse_float.zig");1042 _ = @import("fmt/parse_float.zig");
873}1043}
8741044
...@@ -960,7 +1130,7 @@ test "parse unsigned comptime" {...@@ -960,7 +1130,7 @@ test "parse unsigned comptime" {
960 }1130 }
961}1131}
9621132
963test "fmt.optional" {1133test "optional" {
964 {1134 {
965 const value: ?i32 = 1234;1135 const value: ?i32 = 1234;
966 try testFmt("optional: 1234\n", "optional: {}\n", value);1136 try testFmt("optional: 1234\n", "optional: {}\n", value);
...@@ -971,7 +1141,7 @@ test "fmt.optional" {...@@ -971,7 +1141,7 @@ test "fmt.optional" {
971 }1141 }
972}1142}
9731143
974test "fmt.error" {1144test "error" {
975 {1145 {
976 const value: anyerror!i32 = 1234;1146 const value: anyerror!i32 = 1234;
977 try testFmt("error union: 1234\n", "error union: {}\n", value);1147 try testFmt("error union: 1234\n", "error union: {}\n", value);
...@@ -982,14 +1152,14 @@ test "fmt.error" {...@@ -982,14 +1152,14 @@ test "fmt.error" {
982 }1152 }
983}1153}
9841154
985test "fmt.int.small" {1155test "int.small" {
986 {1156 {
987 const value: u3 = 0b101;1157 const value: u3 = 0b101;
988 try testFmt("u3: 5\n", "u3: {}\n", value);1158 try testFmt("u3: 5\n", "u3: {}\n", value);
989 }1159 }
990}1160}
9911161
992test "fmt.int.specifier" {1162test "int.specifier" {
993 {1163 {
994 const value: u8 = 'a';1164 const value: u8 = 'a';
995 try testFmt("u8: a\n", "u8: {c}\n", value);1165 try testFmt("u8: a\n", "u8: {c}\n", value);
...@@ -1000,27 +1170,31 @@ test "fmt.int.specifier" {...@@ -1000,27 +1170,31 @@ test "fmt.int.specifier" {
1000 }1170 }
1001}1171}
10021172
1003test "fmt.buffer" {1173test "int.padded" {
1174 try testFmt("u8: '0001'", "u8: '{:4}'", u8(1));
1175}
1176
1177test "buffer" {
1004 {1178 {
1005 var buf1: [32]u8 = undefined;1179 var buf1: [32]u8 = undefined;
1006 var context = BufPrintContext{ .remaining = buf1[0..] };1180 var context = BufPrintContext{ .remaining = buf1[0..] };
1007 try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);1181 try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1008 var res = buf1[0 .. buf1.len - context.remaining.len];1182 var res = buf1[0 .. buf1.len - context.remaining.len];
1009 testing.expect(mem.eql(u8, res, "1234"));1183 testing.expect(mem.eql(u8, res, "1234"));
10101184
1011 context = BufPrintContext{ .remaining = buf1[0..] };1185 context = BufPrintContext{ .remaining = buf1[0..] };
1012 try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);1186 try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1013 res = buf1[0 .. buf1.len - context.remaining.len];1187 res = buf1[0 .. buf1.len - context.remaining.len];
1014 testing.expect(mem.eql(u8, res, "a"));1188 testing.expect(mem.eql(u8, res, "a"));
10151189
1016 context = BufPrintContext{ .remaining = buf1[0..] };1190 context = BufPrintContext{ .remaining = buf1[0..] };
1017 try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);1191 try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1018 res = buf1[0 .. buf1.len - context.remaining.len];1192 res = buf1[0 .. buf1.len - context.remaining.len];
1019 testing.expect(mem.eql(u8, res, "1100"));1193 testing.expect(mem.eql(u8, res, "1100"));
1020 }1194 }
1021}1195}
10221196
1023test "fmt.array" {1197test "array" {
1024 {1198 {
1025 const value: [3]u8 = "abc";1199 const value: [3]u8 = "abc";
1026 try testFmt("array: abc\n", "array: {}\n", value);1200 try testFmt("array: abc\n", "array: {}\n", value);
...@@ -1035,7 +1209,7 @@ test "fmt.array" {...@@ -1035,7 +1209,7 @@ test "fmt.array" {
1035 }1209 }
1036}1210}
10371211
1038test "fmt.slice" {1212test "slice" {
1039 {1213 {
1040 const value: []const u8 = "abc";1214 const value: []const u8 = "abc";
1041 try testFmt("slice: abc\n", "slice: {}\n", value);1215 try testFmt("slice: abc\n", "slice: {}\n", value);
...@@ -1045,11 +1219,11 @@ test "fmt.slice" {...@@ -1045,11 +1219,11 @@ test "fmt.slice" {
1045 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);1219 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
1046 }1220 }
10471221
1048 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");1222 try testFmt("buf: Test \n", "buf: {s:5}\n", "Test");
1049 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");1223 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1050}1224}
10511225
1052test "fmt.pointer" {1226test "pointer" {
1053 {1227 {
1054 const value = @intToPtr(*i32, 0xdeadbeef);1228 const value = @intToPtr(*i32, 0xdeadbeef);
1055 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);1229 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
...@@ -1065,17 +1239,17 @@ test "fmt.pointer" {...@@ -1065,17 +1239,17 @@ test "fmt.pointer" {
1065 }1239 }
1066}1240}
10671241
1068test "fmt.cstr" {1242test "cstr" {
1069 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");1243 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
1070 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");1244 try testFmt("cstr: Test C \n", "cstr: {s:10}\n", c"Test C");
1071}1245}
10721246
1073test "fmt.filesize" {1247test "filesize" {
1074 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));1248 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1075 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));1249 try testFmt("file size: 66.06MB\n", "file size: {B:2}\n", usize(63 * 1024 * 1024));
1076}1250}
10771251
1078test "fmt.struct" {1252test "struct" {
1079 {1253 {
1080 const Struct = struct {1254 const Struct = struct {
1081 field: u8,1255 field: u8,
...@@ -1094,7 +1268,7 @@ test "fmt.struct" {...@@ -1094,7 +1268,7 @@ test "fmt.struct" {
1094 }1268 }
1095}1269}
10961270
1097test "fmt.enum" {1271test "enum" {
1098 const Enum = enum {1272 const Enum = enum {
1099 One,1273 One,
1100 Two,1274 Two,
...@@ -1104,229 +1278,71 @@ test "fmt.enum" {...@@ -1104,229 +1278,71 @@ test "fmt.enum" {
1104 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);1278 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1105}1279}
11061280
1107test "fmt.float.scientific" {1281test "float.scientific" {
1108 {1282 try testFmt("f32: 1.34000003e+00", "f32: {e}", f32(1.34));
1109 var buf1: [32]u8 = undefined;1283 try testFmt("f32: 1.23400001e+01", "f32: {e}", f32(12.34));
1110 const value: f32 = 1.34;1284 try testFmt("f64: -1.234e+11", "f64: {e}", f64(-12.34e10));
1111 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);1285 try testFmt("f64: 9.99996e-40", "f64: {e}", f64(9.999960e-40));
1112 testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
1113 }
1114 {
1115 var buf1: [32]u8 = undefined;
1116 const value: f32 = 12.34;
1117 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
1118 testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
1119 }
1120 {
1121 var buf1: [32]u8 = undefined;
1122 const value: f64 = -12.34e10;
1123 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1124 testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
1125 }
1126 {
1127 // This fails on release due to a minor rounding difference.
1128 // --release-fast outputs 9.999960000000001e-40 vs. the expected.
1129 // TODO fix this, it should be the same in Debug and ReleaseFast
1130 if (builtin.mode == builtin.Mode.Debug) {
1131 var buf1: [32]u8 = undefined;
1132 const value: f64 = 9.999960e-40;
1133 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1134 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
1135 }
1136 }
1137}1286}
11381287
1139test "fmt.float.scientific.precision" {1288test "float.scientific.precision" {
1140 {1289 try testFmt("f64: 1.40971e-42", "f64: {e:.5}", f64(1.409706e-42));
1141 var buf1: [32]u8 = undefined;1290 try testFmt("f64: 1.00000e-09", "f64: {e:.5}", f64(@bitCast(f32, u32(814313563))));
1142 const value: f64 = 1.409706e-42;1291 try testFmt("f64: 7.81250e-03", "f64: {e:.5}", f64(@bitCast(f32, u32(1006632960))));
1143 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);1292 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1144 testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));1293 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1145 }1294 try testFmt("f64: 1.00001e+05", "f64: {e:.5}", f64(@bitCast(f32, u32(1203982400))));
1146 {
1147 var buf1: [32]u8 = undefined;
1148 const value: f64 = @bitCast(f32, u32(814313563));
1149 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1150 testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
1151 }
1152 {
1153 var buf1: [32]u8 = undefined;
1154 const value: f64 = @bitCast(f32, u32(1006632960));
1155 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1156 testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
1157 }
1158 {
1159 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1160 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1161 var buf1: [32]u8 = undefined;
1162 const value: f64 = @bitCast(f32, u32(1203982400));
1163 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1164 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
1165 }
1166}1295}
11671296
1168test "fmt.float.special" {1297test "float.special" {
1169 {1298 try testFmt("f64: nan", "f64: {}", math.nan_f64);
1170 var buf1: [32]u8 = undefined;1299 // negative nan is not defined by IEE 754,
1171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);1300 // and ARM thus normalizes it to positive nan
1172 testing.expect(mem.eql(u8, result, "f64: nan\n"));
1173 }
1174 if (builtin.arch != builtin.Arch.arm) {1301 if (builtin.arch != builtin.Arch.arm) {
1175 // negative nan is not defined by IEE 754,1302 try testFmt("f64: -nan", "f64: {}", -math.nan_f64);
1176 // and ARM thus normalizes it to positive nan
1177 var buf1: [32]u8 = undefined;
1178 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
1179 testing.expect(mem.eql(u8, result, "f64: -nan\n"));
1180 }
1181 {
1182 var buf1: [32]u8 = undefined;
1183 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
1184 testing.expect(mem.eql(u8, result, "f64: inf\n"));
1185 }
1186 {
1187 var buf1: [32]u8 = undefined;
1188 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
1189 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
1190 }1303 }
1304 try testFmt("f64: inf", "f64: {}", math.inf_f64);
1305 try testFmt("f64: -inf", "f64: {}", -math.inf_f64);
1191}1306}
11921307
1193test "fmt.float.decimal" {1308test "float.decimal" {
1194 {1309 try testFmt("f64: 152314000000000000000000000000", "f64: {d}", f64(1.52314e+29));
1195 var buf1: [64]u8 = undefined;1310 try testFmt("f32: 1.1", "f32: {d:.1}", f32(1.1234));
1196 const value: f64 = 1.52314e+29;1311 try testFmt("f32: 1234.57", "f32: {d:.2}", f32(1234.567));
1197 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);1312 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1198 testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));1313 // -11.12339... is rounded back up to -11.1234
1199 }1314 try testFmt("f32: -11.1234", "f32: {d:.4}", f32(-11.1234));
1200 {1315 try testFmt("f32: 91.12345", "f32: {d:.5}", f32(91.12345));
1201 var buf1: [32]u8 = undefined;1316 try testFmt("f64: 91.1234567890", "f64: {d:.10}", f64(91.12345678901235));
1202 const value: f32 = 1.1234;1317 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(0.0));
1203 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);1318 try testFmt("f64: 6", "f64: {d:.0}", f64(5.700));
1204 testing.expect(mem.eql(u8, result, "f32: 1.1\n"));1319 try testFmt("f64: 10.0", "f64: {d:.1}", f64(9.999));
1205 }1320 try testFmt("f64: 1.000", "f64: {d:.3}", f64(1.0));
1206 {1321 try testFmt("f64: 0.00030000", "f64: {d:.8}", f64(0.0003));
1207 var buf1: [32]u8 = undefined;1322 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(1.40130e-45));
1208 const value: f32 = 1234.567;1323 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(9.999960e-40));
1209 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
1210 testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
1211 }
1212 {
1213 var buf1: [32]u8 = undefined;
1214 const value: f32 = -11.1234;
1215 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
1216 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1217 // -11.12339... is rounded back up to -11.1234
1218 testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
1219 }
1220 {
1221 var buf1: [32]u8 = undefined;
1222 const value: f32 = 91.12345;
1223 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
1224 testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
1225 }
1226 {
1227 var buf1: [32]u8 = undefined;
1228 const value: f64 = 91.12345678901235;
1229 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
1230 testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
1231 }
1232 {
1233 var buf1: [32]u8 = undefined;
1234 const value: f64 = 0.0;
1235 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1236 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1237 }
1238 {
1239 var buf1: [32]u8 = undefined;
1240 const value: f64 = 5.700;
1241 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
1242 testing.expect(mem.eql(u8, result, "f64: 6\n"));
1243 }
1244 {
1245 var buf1: [32]u8 = undefined;
1246 const value: f64 = 9.999;
1247 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
1248 testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
1249 }
1250 {
1251 var buf1: [32]u8 = undefined;
1252 const value: f64 = 1.0;
1253 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
1254 testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
1255 }
1256 {
1257 var buf1: [32]u8 = undefined;
1258 const value: f64 = 0.0003;
1259 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
1260 testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
1261 }
1262 {
1263 var buf1: [32]u8 = undefined;
1264 const value: f64 = 1.40130e-45;
1265 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1266 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1267 }
1268 {
1269 var buf1: [32]u8 = undefined;
1270 const value: f64 = 9.999960e-40;
1271 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1272 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1273 }
1274}1324}
12751325
1276test "fmt.float.libc.sanity" {1326test "float.libc.sanity" {
1277 {1327 try testFmt("f64: 0.00001", "f64: {d:.5}", f64(@bitCast(f32, u32(916964781))));
1278 var buf1: [32]u8 = undefined;1328 try testFmt("f64: 0.00001", "f64: {d:.5}", f64(@bitCast(f32, u32(925353389))));
1279 const value: f64 = f64(@bitCast(f32, u32(916964781)));1329 try testFmt("f64: 0.10000", "f64: {d:.5}", f64(@bitCast(f32, u32(1036831278))));
1280 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1330 try testFmt("f64: 1.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1065353133))));
1281 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));1331 try testFmt("f64: 10.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1092616192))));
1282 }1332
1283 {
1284 var buf1: [32]u8 = undefined;
1285 const value: f64 = f64(@bitCast(f32, u32(925353389)));
1286 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1287 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1288 }
1289 {
1290 var buf1: [32]u8 = undefined;
1291 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
1292 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1293 testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
1294 }
1295 {
1296 var buf1: [32]u8 = undefined;
1297 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
1298 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1299 testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
1300 }
1301 {
1302 var buf1: [32]u8 = undefined;
1303 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
1304 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1305 testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
1306 }
1307 // libc differences1333 // libc differences
1308 {1334 //
1309 var buf1: [32]u8 = undefined;1335 // This is 0.015625 exactly according to gdb. We thus round down,
1310 // This is 0.015625 exactly according to gdb. We thus round down,1336 // however glibc rounds up for some reason. This occurs for all
1311 // however glibc rounds up for some reason. This occurs for all1337 // floats of the form x.yyyy25 on a precision point.
1312 // floats of the form x.yyyy25 on a precision point.1338 try testFmt("f64: 0.01563", "f64: {d:.5}", f64(@bitCast(f32, u32(1015021568))));
1313 const value: f64 = f64(@bitCast(f32, u32(1015021568)));1339 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1314 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1340 // also rounds to 630 so I'm inclined to believe libc is not
1315 testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));1341 // optimal here.
1316 }1342 try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1518338049))));
1317 // std-windows-x86_64-Debug-bare test case fails
1318 {
1319 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1320 // also rounds to 630 so I'm inclined to believe libc is not
1321 // optimal here.
1322 var buf1: [32]u8 = undefined;
1323 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
1324 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1325 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1326 }
1327}1343}
13281344
1329test "fmt.custom" {1345test "custom" {
1330 const Vec2 = struct {1346 const Vec2 = struct {
1331 const SelfType = @This();1347 const SelfType = @This();
1332 x: f32,1348 x: f32,
...@@ -1335,20 +1351,17 @@ test "fmt.custom" {...@@ -1335,20 +1351,17 @@ test "fmt.custom" {
1335 pub fn format(1351 pub fn format(
1336 self: SelfType,1352 self: SelfType,
1337 comptime fmt: []const u8,1353 comptime fmt: []const u8,
1354 comptime options: FormatOptions,
1338 context: var,1355 context: var,
1339 comptime Errors: type,1356 comptime Errors: type,
1340 output: fn (@typeOf(context), []const u8) Errors!void,1357 output: fn (@typeOf(context), []const u8) Errors!void,
1341 ) Errors!void {1358 ) Errors!void {
1342 switch (fmt.len) {1359 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1360 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", self.x, self.y);
1344 1 => switch (fmt[0]) {1361 } else if (comptime std.mem.eql(u8, fmt, "d")) {
1345 //point format1362 return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", self.x, self.y);
1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1363 } else {
1347 //dimension format1364 @compileError("Unknown format character: '" ++ fmt ++ "'");
1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1349 else => unreachable,
1350 },
1351 else => unreachable,
1352 }1365 }
1353 }1366 }
1354 };1367 };
...@@ -1366,7 +1379,7 @@ test "fmt.custom" {...@@ -1366,7 +1379,7 @@ test "fmt.custom" {
1366 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);1379 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1367}1380}
13681381
1369test "fmt.struct" {1382test "struct" {
1370 const S = struct {1383 const S = struct {
1371 a: u32,1384 a: u32,
1372 b: anyerror,1385 b: anyerror,
...@@ -1380,7 +1393,7 @@ test "fmt.struct" {...@@ -1380,7 +1393,7 @@ test "fmt.struct" {
1380 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);1393 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1381}1394}
13821395
1383test "fmt.union" {1396test "union" {
1384 const TU = union(enum) {1397 const TU = union(enum) {
1385 float: f32,1398 float: f32,
1386 int: u32,1399 int: u32,
...@@ -1410,7 +1423,7 @@ test "fmt.union" {...@@ -1410,7 +1423,7 @@ test "fmt.union" {
1410 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));1423 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1411}1424}
14121425
1413test "fmt.enum" {1426test "enum" {
1414 const E = enum {1427 const E = enum {
1415 One,1428 One,
1416 Two,1429 Two,
...@@ -1422,7 +1435,7 @@ test "fmt.enum" {...@@ -1422,7 +1435,7 @@ test "fmt.enum" {
1422 try testFmt("E.Two", "{}", inst);1435 try testFmt("E.Two", "{}", inst);
1423}1436}
14241437
1425test "fmt.struct.self-referential" {1438test "struct.self-referential" {
1426 const S = struct {1439 const S = struct {
1427 const SelfType = @This();1440 const SelfType = @This();
1428 a: ?*SelfType,1441 a: ?*SelfType,
...@@ -1436,7 +1449,7 @@ test "fmt.struct.self-referential" {...@@ -1436,7 +1449,7 @@ test "fmt.struct.self-referential" {
1436 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);1449 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
1437}1450}
14381451
1439test "fmt.bytes.hex" {1452test "bytes.hex" {
1440 const some_bytes = "\xCA\xFE\xBA\xBE";1453 const some_bytes = "\xCA\xFE\xBA\xBE";
1441 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);1454 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1442 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);1455 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
...@@ -1478,7 +1491,7 @@ pub fn trim(buf: []const u8) []const u8 {...@@ -1478,7 +1491,7 @@ pub fn trim(buf: []const u8) []const u8 {
1478 return buf[start..end];1491 return buf[start..end];
1479}1492}
14801493
1481test "fmt.trim" {1494test "trim" {
1482 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));1495 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
1483 testing.expect(mem.eql(u8, "", trim(" ")));1496 testing.expect(mem.eql(u8, "", trim(" ")));
1484 testing.expect(mem.eql(u8, "", trim("")));1497 testing.expect(mem.eql(u8, "", trim("")));
...@@ -1505,22 +1518,22 @@ pub fn hexToBytes(out: []u8, input: []const u8) !void {...@@ -1505,22 +1518,22 @@ pub fn hexToBytes(out: []u8, input: []const u8) !void {
1505 }1518 }
1506}1519}
15071520
1508test "fmt.hexToBytes" {1521test "hexToBytes" {
1509 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";1522 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1510 var pb: [32]u8 = undefined;1523 var pb: [32]u8 = undefined;
1511 try hexToBytes(pb[0..], test_hex_str);1524 try hexToBytes(pb[0..], test_hex_str);
1512 try testFmt(test_hex_str, "{X}", pb);1525 try testFmt(test_hex_str, "{X}", pb);
1513}1526}
15141527
1515test "fmt.formatIntValue with comptime_int" {1528test "formatIntValue with comptime_int" {
1516 const value: comptime_int = 123456789123456789;1529 const value: comptime_int = 123456789123456789;
15171530
1518 var buf = try std.Buffer.init(std.debug.global_allocator, "");1531 var buf = try std.Buffer.init(std.debug.global_allocator, "");
1519 try formatIntValue(value, "", &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append);1532 try formatIntValue(value, "", FormatOptions{}, &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append);
1520 assert(mem.eql(u8, buf.toSlice(), "123456789123456789"));1533 assert(mem.eql(u8, buf.toSlice(), "123456789123456789"));
1521}1534}
15221535
1523test "fmt.formatType max_depth" {1536test "formatType max_depth" {
1524 const Vec2 = struct {1537 const Vec2 = struct {
1525 const SelfType = @This();1538 const SelfType = @This();
1526 x: f32,1539 x: f32,
...@@ -1529,11 +1542,16 @@ test "fmt.formatType max_depth" {...@@ -1529,11 +1542,16 @@ test "fmt.formatType max_depth" {
1529 pub fn format(1542 pub fn format(
1530 self: SelfType,1543 self: SelfType,
1531 comptime fmt: []const u8,1544 comptime fmt: []const u8,
1545 comptime options: FormatOptions,
1532 context: var,1546 context: var,
1533 comptime Errors: type,1547 comptime Errors: type,
1534 output: fn (@typeOf(context), []const u8) Errors!void,1548 output: fn (@typeOf(context), []const u8) Errors!void,
1535 ) Errors!void {1549 ) Errors!void {
1536 return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y);1550 if (fmt.len == 0) {
1551 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", self.x, self.y);
1552 } else {
1553 @compileError("Unknown format string: '" ++ fmt ++ "'");
1554 }
1537 }1555 }
1538 };1556 };
1539 const E = enum {1557 const E = enum {
...@@ -1565,18 +1583,34 @@ test "fmt.formatType max_depth" {...@@ -1565,18 +1583,34 @@ test "fmt.formatType max_depth" {
1565 inst.tu.ptr = &inst.tu;1583 inst.tu.ptr = &inst.tu;
15661584
1567 var buf0 = try std.Buffer.init(std.debug.global_allocator, "");1585 var buf0 = try std.Buffer.init(std.debug.global_allocator, "");
1568 try formatType(inst, "", &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0);1586 try formatType(inst, "", FormatOptions{}, &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0);
1569 assert(mem.eql(u8, buf0.toSlice(), "S{ ... }"));1587 assert(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
15701588
1571 var buf1 = try std.Buffer.init(std.debug.global_allocator, "");1589 var buf1 = try std.Buffer.init(std.debug.global_allocator, "");
1572 try formatType(inst, "", &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1);1590 try formatType(inst, "", FormatOptions{}, &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1);
1573 assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));1591 assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
15741592
1575 var buf2 = try std.Buffer.init(std.debug.global_allocator, "");1593 var buf2 = try std.Buffer.init(std.debug.global_allocator, "");
1576 try formatType(inst, "", &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2);1594 try formatType(inst, "", FormatOptions{}, &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2);
1577 assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));1595 assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
15781596
1579 var buf3 = try std.Buffer.init(std.debug.global_allocator, "");1597 var buf3 = try std.Buffer.init(std.debug.global_allocator, "");
1580 try formatType(inst, "", &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3);1598 try formatType(inst, "", FormatOptions{}, &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3);
1581 assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));1599 assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
1582}1600}
1601
1602test "positional" {
1603 try testFmt("2 1 0", "{2} {1} {0}", usize(0), usize(1), usize(2));
1604 try testFmt("2 1 0", "{2} {1} {}", usize(0), usize(1), usize(2));
1605 try testFmt("0 0", "{0} {0}", usize(0));
1606 try testFmt("0 1", "{} {1}", usize(0), usize(1));
1607 try testFmt("1 0 0 1", "{1} {} {0} {}", usize(0), usize(1));
1608}
1609
1610test "positional with specifier" {
1611 try testFmt("10.0", "{0d:.1}", f64(9.999));
1612}
1613
1614test "positional/alignment/width/precision" {
1615 try testFmt("10.0", "{0d: >3.1}", f64(9.999));
1616}
std/math/big/int.zig+1
...@@ -519,6 +519,7 @@ pub const Int = struct {...@@ -519,6 +519,7 @@ pub const Int = struct {
519 pub fn format(519 pub fn format(
520 self: Int,520 self: Int,
521 comptime fmt: []const u8,521 comptime fmt: []const u8,
522 comptime options: std.fmt.FormatOptions,
522 context: var,523 context: var,
523 comptime FmtError: type,524 comptime FmtError: type,
524 output: fn (@typeOf(context), []const u8) FmtError!void,525 output: fn (@typeOf(context), []const u8) FmtError!void,
std/special/build_runner.zig+2-2
...@@ -167,7 +167,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {...@@ -167,7 +167,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
167167
168 const allocator = builder.allocator;168 const allocator = builder.allocator;
169 for (builder.top_level_steps.toSliceConst()) |top_level_step| {169 for (builder.top_level_steps.toSliceConst()) |top_level_step| {
170 try out_stream.print(" {s22} {}\n", top_level_step.step.name, top_level_step.description);170 try out_stream.print(" {s:22} {}\n", top_level_step.step.name, top_level_step.description);
171 }171 }
172172
173 try out_stream.write(173 try out_stream.write(
...@@ -188,7 +188,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {...@@ -188,7 +188,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
188 for (builder.available_options_list.toSliceConst()) |option| {188 for (builder.available_options_list.toSliceConst()) |option| {
189 const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));189 const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
190 defer allocator.free(name);190 defer allocator.free(name);
191 try out_stream.print("{s24} {}\n", name, option.description);191 try out_stream.print("{s:24} {}\n", name, option.description);
192 }192 }
193 }193 }
194194
std/special/compiler_rt.zig+39-6
...@@ -405,15 +405,15 @@ const use_thumb_1 = usesThumb1(builtin.arch);...@@ -405,15 +405,15 @@ const use_thumb_1 = usesThumb1(builtin.arch);
405405
406fn usesThumb1(arch: builtin.Arch) bool {406fn usesThumb1(arch: builtin.Arch) bool {
407 return switch (arch) {407 return switch (arch) {
408 .arm => switch (arch.arm) {408 .arm => |sub_arch| switch (sub_arch) {
409 .v6m => true,409 .v6m => true,
410 else => false,410 else => false,
411 },411 },
412 .armeb => switch (arch.armeb) {412 .armeb => |sub_arch| switch (sub_arch) {
413 .v6m => true,413 .v6m => true,
414 else => false,414 else => false,
415 },415 },
416 .thumb => switch (arch.thumb) {416 .thumb => |sub_arch| switch (sub_arch) {
417 .v5,417 .v5,
418 .v5te,418 .v5te,
419 .v4t,419 .v4t,
...@@ -423,7 +423,7 @@ fn usesThumb1(arch: builtin.Arch) bool {...@@ -423,7 +423,7 @@ fn usesThumb1(arch: builtin.Arch) bool {
423 => true,423 => true,
424 else => false,424 else => false,
425 },425 },
426 .thumbeb => switch (arch.thumbeb) {426 .thumbeb => |sub_arch| switch (sub_arch) {
427 .v5,427 .v5,
428 .v5te,428 .v5te,
429 .v4t,429 .v4t,
...@@ -471,6 +471,22 @@ test "usesThumb1" {...@@ -471,6 +471,22 @@ test "usesThumb1" {
471 //etc.471 //etc.
472}472}
473473
474const use_thumb_1_pre_armv6 = usesThumb1PreArmv6(builtin.arch);
475
476fn usesThumb1PreArmv6(arch: builtin.Arch) bool {
477 return switch (arch) {
478 .thumb => |sub_arch| switch (sub_arch) {
479 .v5, .v5te, .v4t => true,
480 else => false,
481 },
482 .thumbeb => |sub_arch| switch (sub_arch) {
483 .v5, .v5te, .v4t => true,
484 else => false,
485 },
486 else => false,
487 };
488}
489
474nakedcc fn __aeabi_memcpy() noreturn {490nakedcc fn __aeabi_memcpy() noreturn {
475 @setRuntimeSafety(false);491 @setRuntimeSafety(false);
476 if (use_thumb_1) {492 if (use_thumb_1) {
...@@ -505,7 +521,16 @@ nakedcc fn __aeabi_memmove() noreturn {...@@ -505,7 +521,16 @@ nakedcc fn __aeabi_memmove() noreturn {
505521
506nakedcc fn __aeabi_memset() noreturn {522nakedcc fn __aeabi_memset() noreturn {
507 @setRuntimeSafety(false);523 @setRuntimeSafety(false);
508 if (use_thumb_1) {524 if (use_thumb_1_pre_armv6) {
525 asm volatile (
526 \\ eors r1, r2
527 \\ eors r2, r1
528 \\ eors r1, r2
529 \\ push {r7, lr}
530 \\ b memset
531 \\ pop {r7, pc}
532 );
533 } else if (use_thumb_1) {
509 asm volatile (534 asm volatile (
510 \\ mov r3, r1535 \\ mov r3, r1
511 \\ mov r1, r2536 \\ mov r1, r2
...@@ -527,7 +552,15 @@ nakedcc fn __aeabi_memset() noreturn {...@@ -527,7 +552,15 @@ nakedcc fn __aeabi_memset() noreturn {
527552
528nakedcc fn __aeabi_memclr() noreturn {553nakedcc fn __aeabi_memclr() noreturn {
529 @setRuntimeSafety(false);554 @setRuntimeSafety(false);
530 if (use_thumb_1) {555 if (use_thumb_1_pre_armv6) {
556 asm volatile (
557 \\ adds r2, r1, #0
558 \\ movs r1, #0
559 \\ push {r7, lr}
560 \\ bl memset
561 \\ pop {r7, pc}
562 );
563 } else if (use_thumb_1) {
531 asm volatile (564 asm volatile (
532 \\ mov r2, r1565 \\ mov r2, r1
533 \\ movs r1, #0566 \\ movs r1, #0
std/zig/parse.zig+2-2
...@@ -2833,8 +2833,8 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node...@@ -2833,8 +2833,8 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node
28332833
2834 const else_token = eatToken(it, .Keyword_else) orelse return node;2834 const else_token = eatToken(it, .Keyword_else) orelse return node;
2835 const payload = try parsePayload(arena, it, tree);2835 const payload = try parsePayload(arena, it, tree);
2836 const else_expr = try expectNode(arena, it, tree, parseExpr, AstError{2836 const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{
2837 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2837 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2838 });2838 });
2839 const else_node = try arena.create(Node.Else);2839 const else_node = try arena.create(Node.Else);
2840 else_node.* = Node.Else{2840 else_node.* = Node.Else{
std/zig/parser_test.zig+12
...@@ -2234,6 +2234,18 @@ test "zig fmt: multiline string in array" {...@@ -2234,6 +2234,18 @@ test "zig fmt: multiline string in array" {
2234 );2234 );
2235}2235}
22362236
2237test "zig fmt: if type expr" {
2238 try testCanonical(
2239 \\const mycond = true;
2240 \\pub fn foo() if (mycond) i32 else void {
2241 \\ if (mycond) {
2242 \\ return 42;
2243 \\ }
2244 \\}
2245 \\
2246 );
2247}
2248
2237test "zig fmt: line comment in array" {2249test "zig fmt: line comment in array" {
2238 try testTransform(2250 try testTransform(
2239 \\test "a" {2251 \\test "a" {
test/compare_output.zig+1-1
...@@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
122 \\122 \\
123 \\pub fn main() void {123 \\pub fn main() void {
124 \\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;124 \\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;125 \\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
126 \\}126 \\}
127 , "Hello, world!\n0012 012 a\n");127 , "Hello, world!\n0012 012 a\n");
128128