From 04d281340c1a79c9b15be9f13a2a9b365b64e2dd Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Sat, 14 Jan 2023 14:08:15 +0100 Subject: [PATCH] restructure ComptieInterpreter tests --- src/zls.zig | 1 + .../comptime_interpreter.zig | 200 ++++++++++++------ 2 files changed, 134 insertions(+), 67 deletions(-) diff --git a/src/zls.zig b/src/zls.zig index fb362d0..ffb943e 100644 --- a/src/zls.zig +++ b/src/zls.zig @@ -12,3 +12,4 @@ pub const types = @import("lsp.zig"); pub const URI = @import("uri.zig"); pub const DocumentStore = @import("DocumentStore.zig"); pub const ComptimeInterpreter = @import("ComptimeInterpreter.zig"); +pub const InternPool = @import("InternPool.zig"); diff --git a/tests/language_features/comptime_interpreter.zig b/tests/language_features/comptime_interpreter.zig index 61f8176..e04e843 100644 --- a/tests/language_features/comptime_interpreter.zig +++ b/tests/language_features/comptime_interpreter.zig @@ -1,98 +1,164 @@ const std = @import("std"); const zls = @import("zls"); +const builtin = @import("builtin"); const Ast = std.zig.Ast; const ComptimeInterpreter = zls.ComptimeInterpreter; +const InternPool = zls.InternPool; +const Index = InternPool.Index; +const Key = InternPool.Key; const allocator: std.mem.Allocator = std.testing.allocator; -test "ComptimeInterpreter - basic test" { - var config = zls.Config{}; - var doc_store = zls.DocumentStore{ - .allocator = allocator, - .config = &config, - }; - defer doc_store.deinit(); - - _ = try doc_store.openDocument("file:///file.zig", - \\pub fn ReturnMyType(comptime my_arg: bool) type { - \\ var abc = z: {break :z if (!my_arg) 123 else 0;}; - \\ if (abc == 123) return u69; - \\ return u8; +test "ComptimeInterpreter - call return primitive type" { + try testCallCheck( + \\pub fn Foo() type { + \\ return bool; \\} - ); + , &.{}, .{ .simple = .bool }); - var interpreter = ComptimeInterpreter{ - .allocator = allocator, - .arena = std.heap.ArenaAllocator.init(allocator), - .document_store = &doc_store, - .uri = "file:///file.zig", - }; - defer interpreter.deinit(); + try testCallCheck( + \\pub fn Foo() type { + \\ return u32; + \\} + , &.{}, .{ .int_type = .{ .signedness = .unsigned, .bits = 32 } }); - _ = try interpreter.interpret(0, 0, .{}); + try testCallCheck( + \\pub fn Foo() type { + \\ return i128; + \\} + , &.{}, .{ .int_type = .{ .signedness = .signed, .bits = 128 } }); - var bool_type = try interpreter.ip.get(allocator, .{ .simple = .bool }); - var bool_true = try interpreter.ip.get(allocator, .{ .simple = .bool_true }); - var bool_false = try interpreter.ip.get(allocator, .{ .simple = .bool_false }); - - var arg_false = ComptimeInterpreter.Value{ - .interpreter = &interpreter, - .node_idx = std.math.maxInt(Ast.Node.Index), - .ty = bool_type, - .val = bool_false, - }; - var arg_true = ComptimeInterpreter.Value{ - .interpreter = &interpreter, - .node_idx = std.math.maxInt(Ast.Node.Index), - .ty = bool_type, - .val = bool_true, - }; - - const function_node: Ast.Node.Index = 4; - - const call_with_false = try interpreter.call(0, function_node, &.{arg_false}, .{}); - const call_with_true = try interpreter.call(0, function_node, &.{arg_true}, .{}); - - try std.testing.expectFmt("u69", "{any}", .{call_with_false.result.value.val.fmtValue(call_with_false.result.value.ty, &interpreter.ip)}); - try std.testing.expectFmt("u8", "{any}", .{call_with_true.result.value.val.fmtValue(call_with_true.result.value.ty, &interpreter.ip)}); + try testCallCheck( + \\pub fn Foo() type { + \\ const alpha = i128; + \\ return alpha; + \\} + , &.{}, .{ .int_type = .{ .signedness = .signed, .bits = 128 } }); } -test "ComptimeInterpreter - struct" { - var config = zls.Config{}; - var doc_store = zls.DocumentStore{ - .allocator = allocator, - .config = &config, - }; - defer doc_store.deinit(); - - _ = try doc_store.openDocument("file:///file.zig", - \\pub fn ReturnMyType() type { +test "ComptimeInterpreter - call return struct" { + var result = try testCall( + \\pub fn Foo() type { \\ return struct { \\ slay: bool, \\ var abc = 123; \\ }; \\} - ); + , &.{}); + defer result.deinit(); + const struct_info = result.key.struct_type; + try std.testing.expectEqual(Index.none, struct_info.backing_int_ty); + try std.testing.expectEqual(std.builtin.Type.ContainerLayout.Auto, struct_info.layout); + try std.testing.expectEqual(@as(usize, 1), struct_info.fields.len); + // try std.testing.expectEqualStrings("slay", struct_info.fields[0].name); + // try std.testing.expect(struct_info.fields[0].ty != .none); // TODO check for bool +} + +test "ComptimeInterpreter - call comptime argument" { + const source = + \\pub fn Foo(comptime my_arg: bool) type { + \\ var abc = z: {break :z if (!my_arg) 123 else 0;}; + \\ if (abc == 123) return u69; + \\ return u8; + \\} + ; + + var result1 = try testCall(source, &.{ + Value{ + .ty = .{ .simple = .bool }, + .val = .{ .simple = .bool_true }, + }, + }); + defer result1.deinit(); + try std.testing.expectEqual(Key{ .int_type = .{ .signedness = .unsigned, .bits = 8 } }, result1.key); + + var result2 = try testCall(source, &.{ + Value{ + .ty = .{ .simple = .bool }, + .val = .{ .simple = .bool_false }, + }, + }); + defer result2.deinit(); + try std.testing.expectEqual(Key{ .int_type = .{ .signedness = .unsigned, .bits = 69 } }, result2.key); +} + +// +// Helper functions +// + +const CallResult = struct { + interpreter: ComptimeInterpreter, + key: Key, + + pub fn deinit(self: *CallResult) void { + self.interpreter.deinit(); + } +}; + +const Value = struct { + ty: Key, + val: Key, +}; + +fn testCall(source: []const u8, arguments: []const Value) !CallResult { + var config = zls.Config{}; + var doc_store = zls.DocumentStore{ + .allocator = allocator, + .config = &config, + }; + defer doc_store.deinit(); + + const test_uri: []const u8 = switch (builtin.os.tag) { + .windows => "file:///C:\\test.zig", + else => "file:///test.zig", + }; + + const handle = try doc_store.openDocument(test_uri, source); var interpreter = ComptimeInterpreter{ .allocator = allocator, .arena = std.heap.ArenaAllocator.init(allocator), .document_store = &doc_store, - .uri = "file:///file.zig", + .uri = handle.uri, }; - defer interpreter.deinit(); + errdefer interpreter.deinit(); - _ = try interpreter.interpret(0, 0, .{}); + _ = try interpreter.interpret(0, .none, .{}); - const function_node: Ast.Node.Index = 3; + var args = try allocator.alloc(ComptimeInterpreter.Value, arguments.len); + defer allocator.free(args); - const call_result = try interpreter.call(0, function_node, &.{}, .{}); + for (arguments) |argument, i| { + args[i] = .{ + .interpreter = &interpreter, + .node_idx = 0, + .ty = try interpreter.ip.get(interpreter.allocator, argument.ty), + .val = try interpreter.ip.get(interpreter.allocator, argument.val), + }; + } - const result_struct = interpreter.ip.indexToKey(call_result.result.value.val).struct_type; - - try std.testing.expectEqual(@intCast(usize, 1), result_struct.fields.len); - try std.testing.expectEqualStrings("slay", result_struct.fields[0].name); - try std.testing.expectFmt("bool", "{}", .{result_struct.fields[0].ty.fmtType(&interpreter.ip)}); + const func_node = for (handle.tree.nodes.items(.tag)) |tag, i| { + if (tag == .fn_decl) break @intCast(Ast.Node.Index, i); + } else unreachable; + + const call_result = try interpreter.call(.none, func_node, args, .{}); + + try std.testing.expectEqual(Key{ .simple = .type }, interpreter.ip.indexToKey(call_result.result.value.ty)); + + return CallResult{ + .interpreter = interpreter, + .key = interpreter.ip.indexToKey(call_result.result.value.val), + }; +} + +fn testCallCheck( + source: []const u8, + arguments: []const Value, + expected: Key, +) !void { + var result = try testCall(source, arguments); + defer result.deinit(); + try std.testing.expectEqual(expected, result.key); }