diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-01-24 01:58:20 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-01-24 02:02:48 -0500 |
| commit | 4b3f18de3c5746b2ecfd6183351913de0909a83b (patch) | |
| tree | e3d0d56fcd8c00d994a13c4d69d60f0ab28fe389 /std/io.zig | |
| parent | 32d8686da80d282e8cd6d84a0e5c331d269a1f69 (diff) | |
| download | zig-4b3f18de3c5746b2ecfd6183351913de0909a83b.tar.gz zig-4b3f18de3c5746b2ecfd6183351913de0909a83b.zip | |
printf var args proof of concept
See #167
Need to troubleshoot when we send 2 slices to printf. It goes
into an infinite loop.
This commit introduces 4 builtin functions:
* `@isInteger`
* `@isFloat`
* `@canImplictCast`
* `@typeName`
Diffstat (limited to 'std/io.zig')
| -rw-r--r-- | std/io.zig | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/std/io.zig b/std/io.zig index 752f01c3de..9da4c17b16 100644 --- a/std/io.zig +++ b/std/io.zig @@ -80,7 +80,7 @@ pub const OutStream = struct { self.index += 1; } - pub fn write(self: &OutStream, bytes: []const u8) -> %usize { + pub fn write(self: &OutStream, bytes: []const u8) -> %void { var src_bytes_left = bytes.len; var src_index: usize = 0; const dest_space_left = self.buffer.len - self.index; @@ -94,25 +94,89 @@ pub const OutStream = struct { } src_bytes_left -= copy_amt; } - return bytes.len; } - /// Prints a byte buffer, flushes the buffer, then returns the number of - /// bytes printed. The "f" is for "flush". - pub fn printf(self: &OutStream, str: []const u8) -> %usize { - const byte_count = %return self.write(str); + const State = enum { // TODO put inside printf function and make sure the name and debug info is correct + Start, + OpenBrace, + CloseBrace, + }; + + /// Calls print and then flushes the buffer. + pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void { + comptime var start_index: usize = 0; + comptime var state = State.Start; + comptime var next_arg: usize = 0; + inline for (format) |c, i| { + switch (state) { + State.Start => switch (c) { + '{' => { + if (start_index < i) %return self.write(format[start_index...i]); + state = State.OpenBrace; + }, + '}' => { + if (start_index < i) %return self.write(format[start_index...i]); + state = State.CloseBrace; + }, + else => {}, + }, + State.OpenBrace => switch (c) { + '{' => { + state = State.Start; + start_index = i; + }, + '}' => { + %return self.printValue(args[next_arg]); + next_arg += 1; + state = State.Start; + start_index = i + 1; + }, + else => @compileError("Unknown format character: " ++ c), + }, + State.CloseBrace => switch (c) { + '}' => { + state = State.Start; + start_index = i; + }, + else => @compileError("Single '}' encountered in format string"), + }, + } + } + comptime { + if (args.len != next_arg) { + @compileError("Unused arguments"); + } + if (state != State.Start) { + @compileError("Incomplete format string: " ++ format); + } + } + inline if (start_index < format.len) { + %return self.write(format[start_index...format.len]); + } %return self.flush(); - return byte_count; } - pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %usize { + pub fn printValue(self: &OutStream, value: var) -> %void { + const T = @typeOf(value); + if (@isInteger(T)) { + return self.printInt(T, value); + } else if (@isFloat(T)) { + return self.printFloat(T, value); + } else if (@canImplicitCast([]const u8, value)) { + const casted_value = ([]const u8)(value); + return self.write(casted_value); + } else { + @compileError("Unable to print type '" ++ @typeName(T) ++ "'"); + } + } + + pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %void { // TODO replace max_u64_base10_digits with math.log10(math.pow(2, @sizeOf(T))) if (self.index + max_u64_base10_digits >= self.buffer.len) { %return self.flush(); } const amt_printed = bufPrintInt(T, self.buffer[self.index...], x); self.index += amt_printed; - return amt_printed; } pub fn flush(self: &OutStream) -> %void { |
