aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-02-09 02:50:03 -0500
committerAndrew Kelley <superjoe30@gmail.com>2017-02-09 03:09:25 -0500
commitfc100d7b3b27bd514dca4e02c160e5b96d4da648 (patch)
treeb365fbdf02c7a35d81d9037a15e1e3917a6e77de /std
parent8a859afd580f438f549ee69a3e3487eb5d119fad (diff)
downloadzig-fc100d7b3b27bd514dca4e02c160e5b96d4da648.tar.gz
zig-fc100d7b3b27bd514dca4e02c160e5b96d4da648.zip
lots of miscellaneous things all in one big commit
* add `@compileLog(...)` builtin function - Helps debug code running at compile time - See #240 * fix crash when there is an error on the start value of a slice * add implicit cast from int and float types to int and float literals if the value is known at compile time * make array concatenation work with slices in addition to arrays and c string literals * fix compile error message for something not having field access * fix crash when `@setDebugSafety()` was called from a function being evaluated at compile-time * fix compile-time evaluation of overflow math builtins. * avoid debug safety panic handler in builtin.o and compiler_rt.o since we use no debug safety in these modules anyway * add compiler_rt functions for division on ARM - Closes #254 * move default panic handler to std.debug so users can call it manually * std.io.printf supports a width in the format specifier
Diffstat (limited to 'std')
-rw-r--r--std/builtin.zig5
-rw-r--r--std/compiler_rt.zig263
-rw-r--r--std/debug.zig21
-rw-r--r--std/io.zig134
-rw-r--r--std/math.zig17
-rw-r--r--std/panic.zig23
6 files changed, 399 insertions, 64 deletions
diff --git a/std/builtin.zig b/std/builtin.zig
index 9d150f2224..dfdad01abf 100644
--- a/std/builtin.zig
+++ b/std/builtin.zig
@@ -29,3 +29,8 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) {
while (index != n; index += 1)
d[index] = s[index];
}
+
+// Avoid dragging in the debug safety mechanisms into this .o file.
+pub fn panic(message: []const u8) -> unreachable {
+ @unreachable();
+}
diff --git a/std/compiler_rt.zig b/std/compiler_rt.zig
index 3331ce0aed..aa6217b493 100644
--- a/std/compiler_rt.zig
+++ b/std/compiler_rt.zig
@@ -1,3 +1,13 @@
+// Avoid dragging in the debug safety mechanisms into this .o file,
+// unless we're trying to test this file.
+pub fn panic(message: []const u8) -> unreachable {
+ if (@compileVar("is_test")) {
+ @import("std").debug.panic(message);
+ } else {
+ @unreachable();
+ }
+}
+
const CHAR_BIT = 8;
const du_int = u64;
const di_int = i64;
@@ -212,6 +222,106 @@ export fn __umoddi3(a: du_int, b: du_int) -> du_int {
return r;
}
+fn isArmArch() -> bool {
+ return switch (@compileVar("arch")) {
+ Arch.armv8_2a,
+ Arch.armv8_1a,
+ Arch.armv8,
+ Arch.armv8m_baseline,
+ Arch.armv8m_mainline,
+ Arch.armv7,
+ Arch.armv7em,
+ Arch.armv7m,
+ Arch.armv7s,
+ Arch.armv7k,
+ Arch.armv6,
+ Arch.armv6m,
+ Arch.armv6k,
+ Arch.armv6t2,
+ Arch.armv5,
+ Arch.armv5te,
+ Arch.armv4t,
+ Arch.armeb => true,
+ else => false,
+ };
+}
+
+export nakedcc fn __aeabi_uidivmod() {
+ @setDebugSafety(this, false);
+
+ if (comptime isArmArch()) {
+ asm volatile (
+ \\ push { lr }
+ \\ sub sp, sp, #4
+ \\ mov r2, sp
+ \\ bl __udivmodsi4
+ \\ ldr r1, [sp]
+ \\ add sp, sp, #4
+ \\ pop { pc }
+ ::: "r2", "r1");
+ @unreachable();
+ }
+
+ @setFnVisible(this, false);
+}
+
+export fn __udivmodsi4(a: su_int, b: su_int, rem: &su_int) -> su_int {
+ @setDebugSafety(this, false);
+
+ const d = __udivsi3(a, b);
+ *rem = su_int(si_int(a) -% (si_int(d) * si_int(b)));
+ return d;
+}
+
+
+// TODO make this an alias instead of an extra function call
+// https://github.com/andrewrk/zig/issues/256
+
+export fn __aeabi_uidiv(n: su_int, d: su_int) -> su_int {
+ @setDebugSafety(this, false);
+
+ return __udivsi3(n, d);
+}
+
+export fn __udivsi3(n: su_int, d: su_int) -> su_int {
+ @setDebugSafety(this, false);
+
+ const n_uword_bits: c_uint = @sizeOf(su_int) * CHAR_BIT;
+ // special cases
+ if (d == 0)
+ return 0; // ?!
+ if (n == 0)
+ return 0;
+ var sr: c_uint = @clz(d) - @clz(n);
+ // 0 <= sr <= n_uword_bits - 1 or sr large
+ if (sr > n_uword_bits - 1) // d > r
+ return 0;
+ if (sr == n_uword_bits - 1) // d == 1
+ return n;
+ sr += 1;
+ // 1 <= sr <= n_uword_bits - 1
+ // Not a special case
+ var q: su_int = n << (n_uword_bits - sr);
+ var r: su_int = n >> sr;
+ var carry: su_int = 0;
+ while (sr > 0; sr -= 1) {
+ // r:q = ((r:q) << 1) | carry
+ r = (r << 1) | (q >> (n_uword_bits - 1));
+ q = (q << 1) | carry;
+ // carry = 0;
+ // if (r.all >= d.all)
+ // {
+ // r.all -= d.all;
+ // carry = 1;
+ // }
+ const s = si_int(d - r - 1) >> si_int(n_uword_bits - 1);
+ carry = su_int(s & 1);
+ r -= d & su_int(s);
+ }
+ q = (q << 1) | carry;
+ return q;
+}
+
fn test_umoddi3() {
@setFnTest(this);
@@ -257,6 +367,155 @@ fn test_one_udivmoddi4(a: du_int, b: du_int, expected_q: du_int, expected_r: du_
assert(r == expected_r);
}
-fn assert(b: bool) {
- if (!b) @unreachable();
+fn test_udivsi3() {
+ @setFnTest(this);
+
+ const cases = [][3]su_int {
+ []su_int{0x00000000, 0x00000001, 0x00000000},
+ []su_int{0x00000000, 0x00000002, 0x00000000},
+ []su_int{0x00000000, 0x00000003, 0x00000000},
+ []su_int{0x00000000, 0x00000010, 0x00000000},
+ []su_int{0x00000000, 0x078644FA, 0x00000000},
+ []su_int{0x00000000, 0x0747AE14, 0x00000000},
+ []su_int{0x00000000, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x00000000, 0x80000000, 0x00000000},
+ []su_int{0x00000000, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x00000000, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x00000000, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x00000001, 0x00000001, 0x00000001},
+ []su_int{0x00000001, 0x00000002, 0x00000000},
+ []su_int{0x00000001, 0x00000003, 0x00000000},
+ []su_int{0x00000001, 0x00000010, 0x00000000},
+ []su_int{0x00000001, 0x078644FA, 0x00000000},
+ []su_int{0x00000001, 0x0747AE14, 0x00000000},
+ []su_int{0x00000001, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x00000001, 0x80000000, 0x00000000},
+ []su_int{0x00000001, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x00000001, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x00000001, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x00000002, 0x00000001, 0x00000002},
+ []su_int{0x00000002, 0x00000002, 0x00000001},
+ []su_int{0x00000002, 0x00000003, 0x00000000},
+ []su_int{0x00000002, 0x00000010, 0x00000000},
+ []su_int{0x00000002, 0x078644FA, 0x00000000},
+ []su_int{0x00000002, 0x0747AE14, 0x00000000},
+ []su_int{0x00000002, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x00000002, 0x80000000, 0x00000000},
+ []su_int{0x00000002, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x00000002, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x00000002, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x00000003, 0x00000001, 0x00000003},
+ []su_int{0x00000003, 0x00000002, 0x00000001},
+ []su_int{0x00000003, 0x00000003, 0x00000001},
+ []su_int{0x00000003, 0x00000010, 0x00000000},
+ []su_int{0x00000003, 0x078644FA, 0x00000000},
+ []su_int{0x00000003, 0x0747AE14, 0x00000000},
+ []su_int{0x00000003, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x00000003, 0x80000000, 0x00000000},
+ []su_int{0x00000003, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x00000003, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x00000003, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x00000010, 0x00000001, 0x00000010},
+ []su_int{0x00000010, 0x00000002, 0x00000008},
+ []su_int{0x00000010, 0x00000003, 0x00000005},
+ []su_int{0x00000010, 0x00000010, 0x00000001},
+ []su_int{0x00000010, 0x078644FA, 0x00000000},
+ []su_int{0x00000010, 0x0747AE14, 0x00000000},
+ []su_int{0x00000010, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x00000010, 0x80000000, 0x00000000},
+ []su_int{0x00000010, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x00000010, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x00000010, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x078644FA, 0x00000001, 0x078644FA},
+ []su_int{0x078644FA, 0x00000002, 0x03C3227D},
+ []su_int{0x078644FA, 0x00000003, 0x028216FE},
+ []su_int{0x078644FA, 0x00000010, 0x0078644F},
+ []su_int{0x078644FA, 0x078644FA, 0x00000001},
+ []su_int{0x078644FA, 0x0747AE14, 0x00000001},
+ []su_int{0x078644FA, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x078644FA, 0x80000000, 0x00000000},
+ []su_int{0x078644FA, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x078644FA, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x078644FA, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x0747AE14, 0x00000001, 0x0747AE14},
+ []su_int{0x0747AE14, 0x00000002, 0x03A3D70A},
+ []su_int{0x0747AE14, 0x00000003, 0x026D3A06},
+ []su_int{0x0747AE14, 0x00000010, 0x00747AE1},
+ []su_int{0x0747AE14, 0x078644FA, 0x00000000},
+ []su_int{0x0747AE14, 0x0747AE14, 0x00000001},
+ []su_int{0x0747AE14, 0x7FFFFFFF, 0x00000000},
+ []su_int{0x0747AE14, 0x80000000, 0x00000000},
+ []su_int{0x0747AE14, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x0747AE14, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x0747AE14, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x7FFFFFFF, 0x00000001, 0x7FFFFFFF},
+ []su_int{0x7FFFFFFF, 0x00000002, 0x3FFFFFFF},
+ []su_int{0x7FFFFFFF, 0x00000003, 0x2AAAAAAA},
+ []su_int{0x7FFFFFFF, 0x00000010, 0x07FFFFFF},
+ []su_int{0x7FFFFFFF, 0x078644FA, 0x00000011},
+ []su_int{0x7FFFFFFF, 0x0747AE14, 0x00000011},
+ []su_int{0x7FFFFFFF, 0x7FFFFFFF, 0x00000001},
+ []su_int{0x7FFFFFFF, 0x80000000, 0x00000000},
+ []su_int{0x7FFFFFFF, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x7FFFFFFF, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x7FFFFFFF, 0xFFFFFFFF, 0x00000000},
+ []su_int{0x80000000, 0x00000001, 0x80000000},
+ []su_int{0x80000000, 0x00000002, 0x40000000},
+ []su_int{0x80000000, 0x00000003, 0x2AAAAAAA},
+ []su_int{0x80000000, 0x00000010, 0x08000000},
+ []su_int{0x80000000, 0x078644FA, 0x00000011},
+ []su_int{0x80000000, 0x0747AE14, 0x00000011},
+ []su_int{0x80000000, 0x7FFFFFFF, 0x00000001},
+ []su_int{0x80000000, 0x80000000, 0x00000001},
+ []su_int{0x80000000, 0xFFFFFFFD, 0x00000000},
+ []su_int{0x80000000, 0xFFFFFFFE, 0x00000000},
+ []su_int{0x80000000, 0xFFFFFFFF, 0x00000000},
+ []su_int{0xFFFFFFFD, 0x00000001, 0xFFFFFFFD},
+ []su_int{0xFFFFFFFD, 0x00000002, 0x7FFFFFFE},
+ []su_int{0xFFFFFFFD, 0x00000003, 0x55555554},
+ []su_int{0xFFFFFFFD, 0x00000010, 0x0FFFFFFF},
+ []su_int{0xFFFFFFFD, 0x078644FA, 0x00000022},
+ []su_int{0xFFFFFFFD, 0x0747AE14, 0x00000023},
+ []su_int{0xFFFFFFFD, 0x7FFFFFFF, 0x00000001},
+ []su_int{0xFFFFFFFD, 0x80000000, 0x00000001},
+ []su_int{0xFFFFFFFD, 0xFFFFFFFD, 0x00000001},
+ []su_int{0xFFFFFFFD, 0xFFFFFFFE, 0x00000000},
+ []su_int{0xFFFFFFFD, 0xFFFFFFFF, 0x00000000},
+ []su_int{0xFFFFFFFE, 0x00000001, 0xFFFFFFFE},
+ []su_int{0xFFFFFFFE, 0x00000002, 0x7FFFFFFF},
+ []su_int{0xFFFFFFFE, 0x00000003, 0x55555554},
+ []su_int{0xFFFFFFFE, 0x00000010, 0x0FFFFFFF},
+ []su_int{0xFFFFFFFE, 0x078644FA, 0x00000022},
+ []su_int{0xFFFFFFFE, 0x0747AE14, 0x00000023},
+ []su_int{0xFFFFFFFE, 0x7FFFFFFF, 0x00000002},
+ []su_int{0xFFFFFFFE, 0x80000000, 0x00000001},
+ []su_int{0xFFFFFFFE, 0xFFFFFFFD, 0x00000001},
+ []su_int{0xFFFFFFFE, 0xFFFFFFFE, 0x00000001},
+ []su_int{0xFFFFFFFE, 0xFFFFFFFF, 0x00000000},
+ []su_int{0xFFFFFFFF, 0x00000001, 0xFFFFFFFF},
+ []su_int{0xFFFFFFFF, 0x00000002, 0x7FFFFFFF},
+ []su_int{0xFFFFFFFF, 0x00000003, 0x55555555},
+ []su_int{0xFFFFFFFF, 0x00000010, 0x0FFFFFFF},
+ []su_int{0xFFFFFFFF, 0x078644FA, 0x00000022},
+ []su_int{0xFFFFFFFF, 0x0747AE14, 0x00000023},
+ []su_int{0xFFFFFFFF, 0x7FFFFFFF, 0x00000002},
+ []su_int{0xFFFFFFFF, 0x80000000, 0x00000001},
+ []su_int{0xFFFFFFFF, 0xFFFFFFFD, 0x00000001},
+ []su_int{0xFFFFFFFF, 0xFFFFFFFE, 0x00000001},
+ []su_int{0xFFFFFFFF, 0xFFFFFFFF, 0x00000001},
+ };
+
+ for (cases) |case| {
+ test_one_udivsi3(case[0], case[1], case[2]);
+ }
+}
+
+fn test_one_udivsi3(a: su_int, b: su_int, expected_q: su_int) {
+ const q: su_int = __udivsi3(a, b);
+ assert(q == expected_q);
+}
+
+
+fn assert(ok: bool) {
+ if (!ok) @unreachable();
}
diff --git a/std/debug.zig b/std/debug.zig
index 435d572ac2..f3278a0e45 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -13,6 +13,27 @@ pub fn assert(ok: bool) {
if (!ok) @unreachable()
}
+var panicking = false;
+/// This is the default panic implementation.
+pub coldcc fn panic(message: []const u8) -> unreachable {
+ // TODO
+ // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
+ if (panicking) {
+ // Panicked during a panic.
+ // TODO detect if a different thread caused the panic, because in that case
+ // we would want to return here instead of calling abort, so that the thread
+ // which first called panic can finish printing a stack trace.
+ os.abort();
+ } else {
+ panicking = true;
+ }
+
+ %%io.stderr.printf("{}\n", message);
+ %%printStackTrace();
+
+ os.abort();
+}
+
pub fn printStackTrace() -> %void {
%return writeStackTrace(&io.stderr);
%return io.stderr.flush();
diff --git a/std/io.zig b/std/io.zig
index f726c30cbc..291563cbb4 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -100,14 +100,20 @@ pub const OutStream = struct {
Start,
OpenBrace,
CloseBrace,
- Hex: bool,
+ Integer,
+ IntegerWidth,
};
/// 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 start_index = 0;
comptime var state = State.Start;
- comptime var next_arg: usize = 0;
+ comptime var next_arg = 0;
+ comptime var radix = 0;
+ comptime var uppercase = false;
+ comptime var width = 0;
+ comptime var width_start = 0;
+
inline for (format) |c, i| {
switch (state) {
State.Start => switch (c) {
@@ -132,11 +138,23 @@ pub const OutStream = struct {
state = State.Start;
start_index = i + 1;
},
+ 'd' => {
+ radix = 10;
+ uppercase = false;
+ width = 0;
+ state = State.Integer;
+ },
'x' => {
- state = State.Hex { false };
+ radix = 16;
+ uppercase = false;
+ width = 0;
+ state = State.Integer;
},
'X' => {
- state = State.Hex { true };
+ radix = 16;
+ uppercase = true;
+ width = 0;
+ state = State.Integer;
},
else => @compileError("Unknown format character: " ++ c),
},
@@ -147,14 +165,29 @@ pub const OutStream = struct {
},
else => @compileError("Single '}' encountered in format string"),
},
- State.Hex => |uppercase| switch (c) {
+ State.Integer => switch (c) {
+ '}' => {
+ self.printInt(args[next_arg], radix, uppercase, width);
+ 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) {
'}' => {
- self.printInt(args[next_arg], 16, uppercase);
+ width = comptime %%parseUnsigned(usize, format[width_start...i], 10);
+ self.printInt(args[next_arg], radix, uppercase, width);
next_arg += 1;
state = State.Start;
start_index = i + 1;
},
- else => @compileError("Expected '}' after 'x'/'X' in format string"),
+ '0' ... '9' => {},
+ else => @compileError("Unexpected character in format string: " ++ []u8{c}),
},
}
}
@@ -162,10 +195,8 @@ pub const OutStream = struct {
if (args.len != next_arg) {
@compileError("Unused arguments");
}
- // TODO https://github.com/andrewrk/zig/issues/253
- switch (state) {
- State.Start => {},
- else => @compileError("Incomplete format string: " ++ format),
+ if (state != State.Start) {
+ @compileError("Incomplete format string: " ++ format);
}
}
if (start_index < format.len) {
@@ -177,7 +208,7 @@ pub const OutStream = struct {
pub fn printValue(self: &OutStream, value: var) -> %void {
const T = @typeOf(value);
if (@isInteger(T)) {
- return self.printInt(value, 10, false);
+ return self.printInt(value, 10, false, 0);
} else if (@isFloat(T)) {
return self.printFloat(T, value);
} else if (@canImplicitCast([]const u8, value)) {
@@ -190,11 +221,11 @@ pub const OutStream = struct {
}
}
- pub fn printInt(self: &OutStream, x: var, base: u8, uppercase: bool) -> %void {
+ pub fn printInt(self: &OutStream, x: var, base: u8, uppercase: bool, width: usize) -> %void {
if (self.index + max_int_digits >= self.buffer.len) {
%return self.flush();
}
- const amt_printed = bufPrintInt(self.buffer[self.index...], x, base, uppercase);
+ const amt_printed = bufPrintInt(self.buffer[self.index...], x, base, uppercase, width);
self.index += amt_printed;
}
@@ -474,24 +505,29 @@ fn digitToChar(digit: u8, uppercase: bool) -> u8 {
}
/// Guaranteed to not use more than max_int_digits
-pub fn bufPrintInt(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
+pub fn bufPrintInt(out_buf: []u8, x: var, base: u8, uppercase: bool, width: usize) -> usize {
if (@typeOf(x).is_signed)
- bufPrintSigned(out_buf, x, base, uppercase)
+ bufPrintSigned(out_buf, x, base, uppercase, width)
else
- bufPrintUnsigned(out_buf, x, base, uppercase)
+ bufPrintUnsigned(out_buf, x, base, uppercase, width)
}
-fn bufPrintSigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
+fn bufPrintSigned(out_buf: []u8, x: var, base: u8, uppercase: bool, width: usize) -> usize {
const uint = @intType(false, @typeOf(x).bit_count);
+ // include the sign in the width
+ const new_width = if (width == 0) 0 else (width - 1);
+ var new_value: uint = undefined;
if (x < 0) {
out_buf[0] = '-';
- return 1 + bufPrintUnsigned(out_buf[1...], uint(-(x + 1)) + 1, base, uppercase);
+ new_value = uint(-(x + 1)) + 1;
} else {
- return bufPrintUnsigned(out_buf, uint(x), base, uppercase);
+ out_buf[0] = '+';
+ new_value = uint(x);
}
+ return 1 + bufPrintUnsigned(out_buf[1...], new_value, base, uppercase, new_width);
}
-fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
+fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool, width: usize) -> usize {
// 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;
@@ -508,18 +544,11 @@ fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
}
const src_buf = buf[index...];
- mem.copy(u8, out_buf, src_buf);
- return src_buf.len;
-}
-
-fn parseU64DigitTooBig() {
- @setFnTest(this);
+ const padding = if (width > src_buf.len) (width - src_buf.len) else 0;
- parseUnsigned(u64, "123a", 10) %% |err| {
- if (err == error.InvalidChar) return;
- @unreachable();
- };
- @unreachable();
+ mem.set(u8, out_buf[0...padding], '0');
+ mem.copy(u8, out_buf[padding...], src_buf);
+ return src_buf.len + padding;
}
pub fn openSelfExe(stream: &InStream) -> %void {
@@ -535,18 +564,43 @@ pub fn openSelfExe(stream: &InStream) -> %void {
}
}
-fn bufPrintIntToSlice(buf: []u8, x: var, base: u8, uppercase: bool) -> []u8 {
- return buf[0...bufPrintInt(buf, x, base, uppercase)];
+fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) -> []u8 {
+ return buf[0...bufPrintInt(buf, value, base, uppercase, width)];
+}
+
+fn testParseU64DigitTooBig() {
+ @setFnTest(this);
+
+ parseUnsigned(u64, "123a", 10) %% |err| {
+ if (err == error.InvalidChar) return;
+ @unreachable();
+ };
+ @unreachable();
+}
+
+fn testParseUnsignedComptime() {
+ @setFnTest(this);
+
+ comptime {
+ assert(%%parseUnsigned(usize, "2", 10) == 2);
+ }
}
fn testBufPrintInt() {
@setFnTest(this);
var buf: [max_int_digits]u8 = undefined;
- assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 2, false), "-101111000110000101001110"));
- assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 10, false), "-12345678"));
- assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, false), "-bc614e"));
- assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, true), "-BC614E"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
+
+ assert(mem.eql(bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
+
+ assert(mem.eql(bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
+ assert(mem.eql(bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
+ assert(mem.eql(bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
- assert(mem.eql(bufPrintIntToSlice(buf, u32(12345678), 10, true), "12345678"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
}
diff --git a/std/math.zig b/std/math.zig
index d8e4951fa9..49396ca25d 100644
--- a/std/math.zig
+++ b/std/math.zig
@@ -1,3 +1,5 @@
+const assert = @import("debug.zig").assert;
+
pub const Cmp = enum {
Equal,
Greater,
@@ -66,3 +68,18 @@ fn getReturnTypeForAbs(comptime T: type) -> type {
}
}
+fn testMath() {
+ @setFnTest(this);
+
+ assert(%%mulOverflow(i32, 3, 4) == 12);
+ assert(%%addOverflow(i32, 3, 4) == 7);
+ assert(%%subOverflow(i32, 3, 4) == -1);
+ assert(%%shlOverflow(i32, 0b11, 4) == 0b110000);
+
+ comptime {
+ assert(%%mulOverflow(i32, 3, 4) == 12);
+ assert(%%addOverflow(i32, 3, 4) == 7);
+ assert(%%subOverflow(i32, 3, 4) == -1);
+ assert(%%shlOverflow(i32, 0b11, 4) == 0b110000);
+ }
+}
diff --git a/std/panic.zig b/std/panic.zig
index 593930a4af..5be47b0c6e 100644
--- a/std/panic.zig
+++ b/std/panic.zig
@@ -3,31 +3,10 @@
// If this file wants to import other files *by name*, support for that would
// have to be added in the compiler.
-var panicking = false;
pub coldcc fn panic(message: []const u8) -> unreachable {
if (@compileVar("os") == Os.freestanding) {
while (true) {}
} else {
- const std = @import("std");
- const io = std.io;
- const debug = std.debug;
- const os = std.os;
-
- // TODO
- // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) {
- if (panicking) {
- // Panicked during a panic.
- // TODO detect if a different thread caused the panic, because in that case
- // we would want to return here instead of calling abort, so that the thread
- // which first called panic can finish printing a stack trace.
- os.abort();
- } else {
- panicking = true;
- }
-
- %%io.stderr.printf("{}\n", message);
- %%debug.printStackTrace();
-
- os.abort();
+ @import("std").debug.panic(message);
}
}