152 lines
3.3 KiB
Zig
152 lines
3.3 KiB
Zig
const std = @import("std");
|
|
const compile = @import("compile.zig");
|
|
const Module = compile.Module;
|
|
|
|
test "compiler: unknown global variable" {
|
|
try testEqual(
|
|
\\{a}
|
|
,
|
|
\\<STDIN>:1:2: error: unknown identifier
|
|
\\1 | {a}
|
|
\\ | ^
|
|
\\
|
|
,
|
|
);
|
|
}
|
|
|
|
test "compiler: duplicate variable declarations" {
|
|
try testEqual(
|
|
\\VAR a = 0
|
|
\\VAR b = 2
|
|
\\VAR a = 1
|
|
,
|
|
\\<STDIN>:3:1: error: duplicate identifier
|
|
\\3 | VAR a = 1
|
|
\\ | ^
|
|
\\
|
|
,
|
|
);
|
|
}
|
|
|
|
test "compiler: duplicate knot declarations" {
|
|
try testEqual(
|
|
\\== a
|
|
\\== a
|
|
,
|
|
\\<STDIN>:2:1: error: duplicate identifier
|
|
\\2 | == a
|
|
\\ | ^
|
|
\\
|
|
,
|
|
);
|
|
}
|
|
|
|
test "compiler: duplicate mixed declarations" {
|
|
try testEqual(
|
|
\\VAR a = 1
|
|
\\== a
|
|
\\Hello, world!
|
|
,
|
|
\\<STDIN>:1:1: error: duplicate identifier
|
|
\\1 | VAR a = 1
|
|
\\ | ^
|
|
\\
|
|
,
|
|
);
|
|
}
|
|
|
|
test "compiler: invalid divert target" {
|
|
try testEqual(
|
|
\\-> foo
|
|
\\
|
|
\\VAR foo = 123
|
|
,
|
|
\\<STDIN>:1:4: error: invalid divert target
|
|
\\1 | -> foo
|
|
\\ | ^
|
|
\\
|
|
);
|
|
}
|
|
|
|
test "compiler: global variable restrictions" {
|
|
try testEqual(
|
|
\\VAR a = b
|
|
\\VAR b = a
|
|
,
|
|
\\<STDIN>:1:9: error: global variable assignments cannot refer to other variables
|
|
\\1 | VAR a = b
|
|
\\ | ^
|
|
\\
|
|
);
|
|
}
|
|
|
|
test "compiler: constant cycle detection" {
|
|
try testEqual(
|
|
\\CONST a = a
|
|
,
|
|
\\<STDIN>:1:11: error: cycle detected in constant initializer
|
|
\\1 | CONST a = a
|
|
\\ | ^
|
|
\\
|
|
);
|
|
}
|
|
|
|
test "compiler: final else case" {
|
|
try testEqual(
|
|
\\{true:
|
|
\\- else:
|
|
\\ False
|
|
\\- 1 == 1:
|
|
\\ Woops!
|
|
\\}
|
|
,
|
|
\\<STDIN>:2:3: error: 'else' case should always be the final case in conditional
|
|
\\2 | - else:
|
|
\\ | ^
|
|
\\
|
|
);
|
|
}
|
|
|
|
test "compiler: final else case 2" {
|
|
try testEqual(
|
|
\\{
|
|
\\- true:
|
|
\\ True
|
|
\\- else:
|
|
\\ False
|
|
\\- else:
|
|
\\ False
|
|
\\}
|
|
,
|
|
\\<STDIN>:4:3: error: 'else' case should always be the final case in conditional
|
|
\\4 | - else:
|
|
\\ | ^
|
|
\\
|
|
);
|
|
}
|
|
|
|
fn testEqual(source_bytes: [:0]const u8, expected_error: []const u8) !void {
|
|
const gpa = std.testing.allocator;
|
|
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
|
defer arena_allocator.deinit();
|
|
|
|
var allocating = std.io.Writer.Allocating.init(gpa);
|
|
defer allocating.deinit();
|
|
|
|
const io_w = &allocating.writer;
|
|
const arena = arena_allocator.allocator();
|
|
|
|
var c = try Module.compile(gpa, arena, .{
|
|
.source_bytes = source_bytes,
|
|
.filename = "<STDIN>",
|
|
.dump_writer = null,
|
|
.dump_use_color = false,
|
|
.dump_ast = false,
|
|
.dump_ir = false,
|
|
});
|
|
defer c.deinit();
|
|
|
|
try std.testing.expect(c.errors.items.len > 0);
|
|
for (c.errors.items) |err| try c.renderError(io_w, err);
|
|
return std.testing.expectEqualSlices(u8, expected_error, allocating.written());
|
|
}
|