aboutsummaryrefslogtreecommitdiff
path: root/std/io.zig
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-01-24 01:58:20 -0500
committerAndrew Kelley <superjoe30@gmail.com>2017-01-24 02:02:48 -0500
commit4b3f18de3c5746b2ecfd6183351913de0909a83b (patch)
treee3d0d56fcd8c00d994a13c4d69d60f0ab28fe389 /std/io.zig
parent32d8686da80d282e8cd6d84a0e5c331d269a1f69 (diff)
downloadzig-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.zig82
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 {