mirror of
https://github.com/ziglang/zig.git
synced 2025-12-25 23:53:15 +00:00
closes #672 the crash and compile errors are fixed but structs inside functions still get named after the functions they're in. this will be fixed later.
599 lines
14 KiB
Zig
599 lines
14 KiB
Zig
const assert = @import("std").debug.assert;
|
|
const mem = @import("std").mem;
|
|
const cstr = @import("std").cstr;
|
|
const builtin = @import("builtin");
|
|
|
|
// normal comment
|
|
/// this is a documentation comment
|
|
/// doc comment line 2
|
|
fn emptyFunctionWithComments() {}
|
|
|
|
test "empty function with comments" {
|
|
emptyFunctionWithComments();
|
|
}
|
|
|
|
comptime {
|
|
@export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
|
|
}
|
|
|
|
extern fn disabledExternFn() {
|
|
}
|
|
|
|
test "call disabled extern fn" {
|
|
disabledExternFn();
|
|
}
|
|
|
|
test "@IntType builtin" {
|
|
assert(@IntType(true, 8) == i8);
|
|
assert(@IntType(true, 16) == i16);
|
|
assert(@IntType(true, 32) == i32);
|
|
assert(@IntType(true, 64) == i64);
|
|
|
|
assert(@IntType(false, 8) == u8);
|
|
assert(@IntType(false, 16) == u16);
|
|
assert(@IntType(false, 32) == u32);
|
|
assert(@IntType(false, 64) == u64);
|
|
|
|
assert(i8.bit_count == 8);
|
|
assert(i16.bit_count == 16);
|
|
assert(i32.bit_count == 32);
|
|
assert(i64.bit_count == 64);
|
|
|
|
assert(i8.is_signed);
|
|
assert(i16.is_signed);
|
|
assert(i32.is_signed);
|
|
assert(i64.is_signed);
|
|
assert(isize.is_signed);
|
|
|
|
assert(!u8.is_signed);
|
|
assert(!u16.is_signed);
|
|
assert(!u32.is_signed);
|
|
assert(!u64.is_signed);
|
|
assert(!usize.is_signed);
|
|
}
|
|
|
|
test "floating point primitive bit counts" {
|
|
assert(f32.bit_count == 32);
|
|
assert(f64.bit_count == 64);
|
|
}
|
|
|
|
const u1 = @IntType(false, 1);
|
|
const u63 = @IntType(false, 63);
|
|
const i1 = @IntType(true, 1);
|
|
const i63 = @IntType(true, 63);
|
|
|
|
test "@minValue and @maxValue" {
|
|
assert(@maxValue(u1) == 1);
|
|
assert(@maxValue(u8) == 255);
|
|
assert(@maxValue(u16) == 65535);
|
|
assert(@maxValue(u32) == 4294967295);
|
|
assert(@maxValue(u64) == 18446744073709551615);
|
|
|
|
assert(@maxValue(i1) == 0);
|
|
assert(@maxValue(i8) == 127);
|
|
assert(@maxValue(i16) == 32767);
|
|
assert(@maxValue(i32) == 2147483647);
|
|
assert(@maxValue(i63) == 4611686018427387903);
|
|
assert(@maxValue(i64) == 9223372036854775807);
|
|
|
|
assert(@minValue(u1) == 0);
|
|
assert(@minValue(u8) == 0);
|
|
assert(@minValue(u16) == 0);
|
|
assert(@minValue(u32) == 0);
|
|
assert(@minValue(u63) == 0);
|
|
assert(@minValue(u64) == 0);
|
|
|
|
assert(@minValue(i1) == -1);
|
|
assert(@minValue(i8) == -128);
|
|
assert(@minValue(i16) == -32768);
|
|
assert(@minValue(i32) == -2147483648);
|
|
assert(@minValue(i63) == -4611686018427387904);
|
|
assert(@minValue(i64) == -9223372036854775808);
|
|
}
|
|
|
|
test "max value type" {
|
|
// If the type of @maxValue(i32) was i32 then this implicit cast to
|
|
// u32 would not work. But since the value is a number literal,
|
|
// it works fine.
|
|
const x: u32 = @maxValue(i32);
|
|
assert(x == 2147483647);
|
|
}
|
|
|
|
test "short circuit" {
|
|
testShortCircuit(false, true);
|
|
comptime testShortCircuit(false, true);
|
|
}
|
|
|
|
fn testShortCircuit(f: bool, t: bool) {
|
|
var hit_1 = f;
|
|
var hit_2 = f;
|
|
var hit_3 = f;
|
|
var hit_4 = f;
|
|
|
|
if (t or x: {assert(f); break :x f;}) {
|
|
hit_1 = t;
|
|
}
|
|
if (f or x: { hit_2 = t; break :x f; }) {
|
|
assert(f);
|
|
}
|
|
|
|
if (t and x: { hit_3 = t; break :x f; }) {
|
|
assert(f);
|
|
}
|
|
if (f and x: {assert(f); break :x f;}) {
|
|
assert(f);
|
|
} else {
|
|
hit_4 = t;
|
|
}
|
|
assert(hit_1);
|
|
assert(hit_2);
|
|
assert(hit_3);
|
|
assert(hit_4);
|
|
}
|
|
|
|
test "truncate" {
|
|
assert(testTruncate(0x10fd) == 0xfd);
|
|
}
|
|
fn testTruncate(x: u32) -> u8 {
|
|
return @truncate(u8, x);
|
|
}
|
|
|
|
fn first4KeysOfHomeRow() -> []const u8 {
|
|
return "aoeu";
|
|
}
|
|
|
|
test "return string from function" {
|
|
assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
|
|
}
|
|
|
|
const g1 : i32 = 1233 + 1;
|
|
var g2 : i32 = 0;
|
|
|
|
test "global variables" {
|
|
assert(g2 == 0);
|
|
g2 = g1;
|
|
assert(g2 == 1234);
|
|
}
|
|
|
|
|
|
test "memcpy and memset intrinsics" {
|
|
var foo : [20]u8 = undefined;
|
|
var bar : [20]u8 = undefined;
|
|
|
|
@memset(&foo[0], 'A', foo.len);
|
|
@memcpy(&bar[0], &foo[0], bar.len);
|
|
|
|
if (bar[11] != 'A') unreachable;
|
|
}
|
|
|
|
test "builtin static eval" {
|
|
const x : i32 = comptime x: {break :x 1 + 2 + 3;};
|
|
assert(x == comptime 6);
|
|
}
|
|
|
|
test "slicing" {
|
|
var array : [20]i32 = undefined;
|
|
|
|
array[5] = 1234;
|
|
|
|
var slice = array[5..10];
|
|
|
|
if (slice.len != 5) unreachable;
|
|
|
|
const ptr = &slice[0];
|
|
if (ptr[0] != 1234) unreachable;
|
|
|
|
var slice_rest = array[10..];
|
|
if (slice_rest.len != 10) unreachable;
|
|
}
|
|
|
|
|
|
test "constant equal function pointers" {
|
|
const alias = emptyFn;
|
|
assert(comptime x: {break :x emptyFn == alias;});
|
|
}
|
|
|
|
fn emptyFn() {}
|
|
|
|
|
|
test "hex escape" {
|
|
assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
|
|
}
|
|
|
|
test "string concatenation" {
|
|
assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
|
|
}
|
|
|
|
test "array mult operator" {
|
|
assert(mem.eql(u8, "ab" ** 5, "ababababab"));
|
|
}
|
|
|
|
test "string escapes" {
|
|
assert(mem.eql(u8, "\"", "\x22"));
|
|
assert(mem.eql(u8, "\'", "\x27"));
|
|
assert(mem.eql(u8, "\n", "\x0a"));
|
|
assert(mem.eql(u8, "\r", "\x0d"));
|
|
assert(mem.eql(u8, "\t", "\x09"));
|
|
assert(mem.eql(u8, "\\", "\x5c"));
|
|
assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
|
|
}
|
|
|
|
test "multiline string" {
|
|
const s1 =
|
|
\\one
|
|
\\two)
|
|
\\three
|
|
;
|
|
const s2 = "one\ntwo)\nthree";
|
|
assert(mem.eql(u8, s1, s2));
|
|
}
|
|
|
|
test "multiline C string" {
|
|
const s1 =
|
|
c\\one
|
|
c\\two)
|
|
c\\three
|
|
;
|
|
const s2 = c"one\ntwo)\nthree";
|
|
assert(cstr.cmp(s1, s2) == 0);
|
|
}
|
|
|
|
|
|
test "type equality" {
|
|
assert(&const u8 != &u8);
|
|
}
|
|
|
|
|
|
const global_a: i32 = 1234;
|
|
const global_b: &const i32 = &global_a;
|
|
const global_c: &const f32 = @ptrCast(&const f32, global_b);
|
|
test "compile time global reinterpret" {
|
|
const d = @ptrCast(&const i32, global_c);
|
|
assert(*d == 1234);
|
|
}
|
|
|
|
test "explicit cast maybe pointers" {
|
|
const a: ?&i32 = undefined;
|
|
const b: ?&f32 = @ptrCast(?&f32, a);
|
|
}
|
|
|
|
test "generic malloc free" {
|
|
const a = %%memAlloc(u8, 10);
|
|
memFree(u8, a);
|
|
}
|
|
const some_mem : [100]u8 = undefined;
|
|
fn memAlloc(comptime T: type, n: usize) -> %[]T {
|
|
return @ptrCast(&T, &some_mem[0])[0..n];
|
|
}
|
|
fn memFree(comptime T: type, memory: []T) { }
|
|
|
|
|
|
test "cast undefined" {
|
|
const array: [100]u8 = undefined;
|
|
const slice = ([]const u8)(array);
|
|
testCastUndefined(slice);
|
|
}
|
|
fn testCastUndefined(x: []const u8) {}
|
|
|
|
|
|
test "cast small unsigned to larger signed" {
|
|
assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
|
|
assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
|
|
}
|
|
fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { return x; }
|
|
fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { return x; }
|
|
|
|
|
|
test "implicit cast after unreachable" {
|
|
assert(outer() == 1234);
|
|
}
|
|
fn inner() -> i32 { return 1234; }
|
|
fn outer() -> i64 {
|
|
return inner();
|
|
}
|
|
|
|
|
|
test "pointer dereferencing" {
|
|
var x = i32(3);
|
|
const y = &x;
|
|
|
|
*y += 1;
|
|
|
|
assert(x == 4);
|
|
assert(*y == 4);
|
|
}
|
|
|
|
test "call result of if else expression" {
|
|
assert(mem.eql(u8, f2(true), "a"));
|
|
assert(mem.eql(u8, f2(false), "b"));
|
|
}
|
|
fn f2(x: bool) -> []const u8 {
|
|
return (if (x) fA else fB)();
|
|
}
|
|
fn fA() -> []const u8 { return "a"; }
|
|
fn fB() -> []const u8 { return "b"; }
|
|
|
|
|
|
test "const expression eval handling of variables" {
|
|
var x = true;
|
|
while (x) {
|
|
x = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
test "constant enum initialization with differing sizes" {
|
|
test3_1(test3_foo);
|
|
test3_2(test3_bar);
|
|
}
|
|
const Test3Foo = union(enum) {
|
|
One: void,
|
|
Two: f32,
|
|
Three: Test3Point,
|
|
};
|
|
const Test3Point = struct {
|
|
x: i32,
|
|
y: i32,
|
|
};
|
|
const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
|
|
const test3_bar = Test3Foo { .Two = 13};
|
|
fn test3_1(f: &const Test3Foo) {
|
|
switch (*f) {
|
|
Test3Foo.Three => |pt| {
|
|
assert(pt.x == 3);
|
|
assert(pt.y == 4);
|
|
},
|
|
else => unreachable,
|
|
}
|
|
}
|
|
fn test3_2(f: &const Test3Foo) {
|
|
switch (*f) {
|
|
Test3Foo.Two => |x| {
|
|
assert(x == 13);
|
|
},
|
|
else => unreachable,
|
|
}
|
|
}
|
|
|
|
|
|
test "character literals" {
|
|
assert('\'' == single_quote);
|
|
}
|
|
const single_quote = '\'';
|
|
|
|
|
|
|
|
test "take address of parameter" {
|
|
testTakeAddressOfParameter(12.34);
|
|
}
|
|
fn testTakeAddressOfParameter(f: f32) {
|
|
const f_ptr = &f;
|
|
assert(*f_ptr == 12.34);
|
|
}
|
|
|
|
|
|
test "pointer comparison" {
|
|
const a = ([]const u8)("a");
|
|
const b = &a;
|
|
assert(ptrEql(b, b));
|
|
}
|
|
fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {
|
|
return a == b;
|
|
}
|
|
|
|
|
|
test "C string concatenation" {
|
|
const a = c"OK" ++ c" IT " ++ c"WORKED";
|
|
const b = c"OK IT WORKED";
|
|
|
|
const len = cstr.len(b);
|
|
const len_with_null = len + 1;
|
|
{var i: u32 = 0; while (i < len_with_null) : (i += 1) {
|
|
assert(a[i] == b[i]);
|
|
}}
|
|
assert(a[len] == 0);
|
|
assert(b[len] == 0);
|
|
}
|
|
|
|
test "cast slice to u8 slice" {
|
|
assert(@sizeOf(i32) == 4);
|
|
var big_thing_array = []i32{1, 2, 3, 4};
|
|
const big_thing_slice: []i32 = big_thing_array[0..];
|
|
const bytes = ([]u8)(big_thing_slice);
|
|
assert(bytes.len == 4 * 4);
|
|
bytes[4] = 0;
|
|
bytes[5] = 0;
|
|
bytes[6] = 0;
|
|
bytes[7] = 0;
|
|
assert(big_thing_slice[1] == 0);
|
|
const big_thing_again = ([]align(1) i32)(bytes);
|
|
assert(big_thing_again[2] == 3);
|
|
big_thing_again[2] = -1;
|
|
assert(bytes[8] == @maxValue(u8));
|
|
assert(bytes[9] == @maxValue(u8));
|
|
assert(bytes[10] == @maxValue(u8));
|
|
assert(bytes[11] == @maxValue(u8));
|
|
}
|
|
|
|
test "pointer to void return type" {
|
|
%%testPointerToVoidReturnType();
|
|
}
|
|
fn testPointerToVoidReturnType() -> %void {
|
|
const a = testPointerToVoidReturnType2();
|
|
return *a;
|
|
}
|
|
const test_pointer_to_void_return_type_x = void{};
|
|
fn testPointerToVoidReturnType2() -> &const void {
|
|
return &test_pointer_to_void_return_type_x;
|
|
}
|
|
|
|
|
|
test "non const ptr to aliased type" {
|
|
const int = i32;
|
|
assert(?&int == ?&i32);
|
|
}
|
|
|
|
|
|
|
|
test "array 2D const double ptr" {
|
|
const rect_2d_vertexes = [][1]f32 {
|
|
[]f32{1.0},
|
|
[]f32{2.0},
|
|
};
|
|
testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
|
|
}
|
|
|
|
fn testArray2DConstDoublePtr(ptr: &const f32) {
|
|
assert(ptr[0] == 1.0);
|
|
assert(ptr[1] == 2.0);
|
|
}
|
|
|
|
const Tid = builtin.TypeId;
|
|
const AStruct = struct { x: i32, };
|
|
const AnEnum = enum { One, Two, };
|
|
const AUnionEnum = union(enum) { One: i32, Two: void, };
|
|
const AUnion = union { One: void, Two: void };
|
|
|
|
test "@typeId" {
|
|
comptime {
|
|
assert(@typeId(type) == Tid.Type);
|
|
assert(@typeId(void) == Tid.Void);
|
|
assert(@typeId(bool) == Tid.Bool);
|
|
assert(@typeId(noreturn) == Tid.NoReturn);
|
|
assert(@typeId(i8) == Tid.Int);
|
|
assert(@typeId(u8) == Tid.Int);
|
|
assert(@typeId(i64) == Tid.Int);
|
|
assert(@typeId(u64) == Tid.Int);
|
|
assert(@typeId(f32) == Tid.Float);
|
|
assert(@typeId(f64) == Tid.Float);
|
|
assert(@typeId(&f32) == Tid.Pointer);
|
|
assert(@typeId([2]u8) == Tid.Array);
|
|
assert(@typeId(AStruct) == Tid.Struct);
|
|
assert(@typeId(@typeOf(1)) == Tid.IntLiteral);
|
|
assert(@typeId(@typeOf(1.0)) == Tid.FloatLiteral);
|
|
assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);
|
|
assert(@typeId(@typeOf(null)) == Tid.NullLiteral);
|
|
assert(@typeId(?i32) == Tid.Nullable);
|
|
assert(@typeId(%i32) == Tid.ErrorUnion);
|
|
assert(@typeId(error) == Tid.Error);
|
|
assert(@typeId(AnEnum) == Tid.Enum);
|
|
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
|
|
assert(@typeId(AUnionEnum) == Tid.Union);
|
|
assert(@typeId(AUnion) == Tid.Union);
|
|
assert(@typeId(fn()) == Tid.Fn);
|
|
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
|
assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);
|
|
// TODO bound fn
|
|
// TODO arg tuple
|
|
// TODO opaque
|
|
}
|
|
}
|
|
|
|
test "@canImplicitCast" {
|
|
comptime {
|
|
assert(@canImplicitCast(i64, i32(3)));
|
|
assert(!@canImplicitCast(i32, f32(1.234)));
|
|
assert(@canImplicitCast([]const u8, "aoeu"));
|
|
}
|
|
}
|
|
|
|
test "@typeName" {
|
|
comptime {
|
|
assert(mem.eql(u8, @typeName(i64), "i64"));
|
|
assert(mem.eql(u8, @typeName(&usize), "&usize"));
|
|
}
|
|
}
|
|
|
|
test "volatile load and store" {
|
|
var number: i32 = 1234;
|
|
const ptr = (&volatile i32)(&number);
|
|
*ptr += 1;
|
|
assert(*ptr == 1235);
|
|
}
|
|
|
|
test "slice string literal has type []const u8" {
|
|
comptime {
|
|
assert(@typeOf("aoeu"[0..]) == []const u8);
|
|
const array = []i32{1, 2, 3, 4};
|
|
assert(@typeOf(array[0..]) == []const i32);
|
|
}
|
|
}
|
|
|
|
test "global variable initialized to global variable array element" {
|
|
assert(global_ptr == &gdt[0]);
|
|
}
|
|
const GDTEntry = struct {
|
|
field: i32,
|
|
};
|
|
var gdt = []GDTEntry {
|
|
GDTEntry {.field = 1},
|
|
GDTEntry {.field = 2},
|
|
};
|
|
var global_ptr = &gdt[0];
|
|
|
|
|
|
// can't really run this test but we can make sure it has no compile error
|
|
// and generates code
|
|
const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];
|
|
export fn writeToVRam() {
|
|
vram[0] = 'X';
|
|
}
|
|
|
|
test "pointer child field" {
|
|
assert((&u32).Child == u32);
|
|
}
|
|
|
|
const OpaqueA = @OpaqueType();
|
|
const OpaqueB = @OpaqueType();
|
|
test "@OpaqueType" {
|
|
assert(&OpaqueA != &OpaqueB);
|
|
assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
|
|
assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
|
|
}
|
|
|
|
test "variable is allowed to be a pointer to an opaque type" {
|
|
var x: i32 = 1234;
|
|
_ = hereIsAnOpaqueType(@ptrCast(&OpaqueA, &x));
|
|
}
|
|
fn hereIsAnOpaqueType(ptr: &OpaqueA) -> &OpaqueA {
|
|
var a = ptr;
|
|
return a;
|
|
}
|
|
|
|
test "comptime if inside runtime while which unconditionally breaks" {
|
|
testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
|
comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
|
}
|
|
fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) {
|
|
while (cond) {
|
|
if (false) { }
|
|
break;
|
|
}
|
|
}
|
|
|
|
test "implicit comptime while" {
|
|
while (false) {
|
|
@compileError("bad");
|
|
}
|
|
}
|
|
|
|
test "struct inside function" {
|
|
testStructInFn();
|
|
comptime testStructInFn();
|
|
}
|
|
|
|
fn testStructInFn() {
|
|
const BlockKind = u32;
|
|
|
|
const Block = struct {
|
|
kind: BlockKind,
|
|
};
|
|
|
|
var block = Block { .kind = 1234 };
|
|
|
|
block.kind += 1;
|
|
|
|
assert(block.kind == 1235);
|
|
}
|