| ... | @@ -14,6 +14,8 @@ const State = enum { // TODO put inside format function and make sure the name a | ... | @@ -14,6 +14,8 @@ const State = enum { // TODO put inside format function and make sure the name a |
| 14 | CloseBrace, | 14 | CloseBrace, |
| 15 | Integer, | 15 | Integer, |
| 16 | IntegerWidth, | 16 | IntegerWidth, |
| | 17 | Float, |
| | 18 | FloatWidth, |
| 17 | Character, | 19 | Character, |
| 18 | Buf, | 20 | Buf, |
| 19 | BufWidth, | 21 | BufWidth, |
| ... | @@ -85,6 +87,8 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void, | ... | @@ -85,6 +87,8 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void, |
| 85 | }, | 87 | }, |
| 86 | 's' => { | 88 | 's' => { |
| 87 | state = State.Buf; | 89 | state = State.Buf; |
| | 90 | },'.' => { |
| | 91 | state = State.Float; |
| 88 | }, | 92 | }, |
| 89 | else => @compileError("Unknown format character: " ++ []u8{c}), | 93 | else => @compileError("Unknown format character: " ++ []u8{c}), |
| 90 | }, | 94 | }, |
| ... | @@ -129,6 +133,30 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void, | ... | @@ -129,6 +133,30 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void, |
| 129 | '0' ... '9' => {}, | 133 | '0' ... '9' => {}, |
| 130 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), | 134 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), |
| 131 | }, | 135 | }, |
| | 136 | State.Float => switch (c) { |
| | 137 | '}' => { |
| | 138 | %return formatFloatDecimal(args[next_arg], 0, context, output); |
| | 139 | next_arg += 1; |
| | 140 | state = State.Start; |
| | 141 | start_index = i + 1; |
| | 142 | }, |
| | 143 | '0' ... '9' => { |
| | 144 | width_start = i; |
| | 145 | state = State.FloatWidth; |
| | 146 | }, |
| | 147 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), |
| | 148 | }, |
| | 149 | State.FloatWidth => switch (c) { |
| | 150 | '}' => { |
| | 151 | width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10); |
| | 152 | %return formatFloatDecimal(args[next_arg], width, context, output); |
| | 153 | next_arg += 1; |
| | 154 | state = State.Start; |
| | 155 | start_index = i + 1; |
| | 156 | }, |
| | 157 | '0' ... '9' => {}, |
| | 158 | else => @compileError("Unexpected character in format string: " ++ []u8{c}), |
| | 159 | }, |
| 132 | State.BufWidth => switch (c) { | 160 | State.BufWidth => switch (c) { |
| 133 | '}' => { | 161 | '}' => { |
| 134 | width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10); | 162 | width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10); |
| ... | @@ -267,6 +295,47 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons | ... | @@ -267,6 +295,47 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons |
| 267 | } | 295 | } |
| 268 | } | 296 | } |
| 269 | | 297 | |
| | 298 | pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void { |
| | 299 | var x = f64(value); |
| | 300 | |
| | 301 | // Errol doesn't handle these special cases. |
| | 302 | if (math.isNan(x)) { |
| | 303 | return output(context, "NaN"); |
| | 304 | } |
| | 305 | if (math.signbit(x)) { |
| | 306 | %return output(context, "-"); |
| | 307 | x = -x; |
| | 308 | } |
| | 309 | if (math.isPositiveInf(x)) { |
| | 310 | return output(context, "Infinity"); |
| | 311 | } |
| | 312 | if (x == 0.0) { |
| | 313 | return output(context, "0.0"); |
| | 314 | } |
| | 315 | |
| | 316 | var buffer: [32]u8 = undefined; |
| | 317 | const float_decimal = errol3(x, buffer[0..]); |
| | 318 | |
| | 319 | const num_left_digits = if (float_decimal.exp > 0) usize(float_decimal.exp) else 1; |
| | 320 | |
| | 321 | %return output(context, float_decimal.digits[0 .. num_left_digits]); |
| | 322 | %return output(context, "."); |
| | 323 | if (float_decimal.digits.len > 1) { |
| | 324 | const num_valid_digtis = if (@typeOf(value) == f32) math.min(usize(7), float_decimal.digits.len) |
| | 325 | else |
| | 326 | float_decimal.digits.len; |
| | 327 | |
| | 328 | const num_right_digits = if (precision != 0) |
| | 329 | math.min(precision, (num_valid_digtis-num_left_digits)) |
| | 330 | else |
| | 331 | num_valid_digtis - num_left_digits; |
| | 332 | %return output(context, float_decimal.digits[num_left_digits .. (num_left_digits + num_right_digits)]); |
| | 333 | } else { |
| | 334 | %return output(context, "0"); |
| | 335 | } |
| | 336 | } |
| | 337 | |
| | 338 | |
| 270 | pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, | 339 | pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, |
| 271 | context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void | 340 | context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void |
| 272 | { | 341 | { |
| ... | @@ -540,6 +609,39 @@ test "fmt.format" { | ... | @@ -540,6 +609,39 @@ test "fmt.format" { |
| 540 | const result = %%bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); | 609 | const result = %%bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); |
| 541 | assert(mem.eql(u8, result, "f64: -Infinity\n")); | 610 | assert(mem.eql(u8, result, "f64: -Infinity\n")); |
| 542 | } | 611 | } |
| | 612 | { |
| | 613 | var buf1: [32]u8 = undefined; |
| | 614 | const value: f32 = 1.1234; |
| | 615 | const result = %%bufPrint(buf1[0..], "f32: {.1}\n", value); |
| | 616 | assert(mem.eql(u8, result, "f32: 1.1\n")); |
| | 617 | } |
| | 618 | { |
| | 619 | var buf1: [32]u8 = undefined; |
| | 620 | const value: f32 = 1234.567; |
| | 621 | const result = %%bufPrint(buf1[0..], "f32: {.2}\n", value); |
| | 622 | assert(mem.eql(u8, result, "f32: 1234.56\n")); |
| | 623 | } |
| | 624 | { |
| | 625 | var buf1: [32]u8 = undefined; |
| | 626 | const value: f32 = -11.1234; |
| | 627 | const result = %%bufPrint(buf1[0..], "f32: {.4}\n", value); |
| | 628 | // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64). |
| | 629 | // -11.12339... is truncated to -11.1233 |
| | 630 | assert(mem.eql(u8, result, "f32: -11.1233\n")); |
| | 631 | } |
| | 632 | { |
| | 633 | var buf1: [32]u8 = undefined; |
| | 634 | const value: f32 = 91.12345; |
| | 635 | const result = %%bufPrint(buf1[0..], "f32: {.}\n", value); |
| | 636 | assert(mem.eql(u8, result, "f32: 91.12345\n")); |
| | 637 | } |
| | 638 | { |
| | 639 | var buf1: [32]u8 = undefined; |
| | 640 | const value: f64 = 91.12345678901235; |
| | 641 | const result = %%bufPrint(buf1[0..], "f64: {.10}\n", value); |
| | 642 | assert(mem.eql(u8, result, "f64: 91.1234567890\n")); |
| | 643 | } |
| | 644 | |
| 543 | } | 645 | } |
| 544 | } | 646 | } |
| 545 | | 647 | |