From c8dffc1f9b1d92acf6fc6476dfd868255674221f Mon Sep 17 00:00:00 2001 From: Auguste Rame <19855629+SuperAuguste@users.noreply.github.com> Date: Thu, 10 Nov 2022 20:51:02 -0500 Subject: [PATCH] Some comptime interpreter fixes --- src/ComptimeInterpreter.zig | 49 +++++++++++------ src/DocumentStore.zig | 2 +- src/Server.zig | 30 ++++++++++- src/zls.zig | 5 +- .../comptime_interpreter.zig | 54 ++++++++++++++----- tests/tests.zig | 2 +- 6 files changed, 109 insertions(+), 33 deletions(-) diff --git a/src/ComptimeInterpreter.zig b/src/ComptimeInterpreter.zig index be300db..619c3cc 100644 --- a/src/ComptimeInterpreter.zig +++ b/src/ComptimeInterpreter.zig @@ -17,7 +17,7 @@ const log = std.log.scoped(.comptime_interpreter); allocator: std.mem.Allocator, document_store: *DocumentStore, -handle: *const DocumentStore.Handle, +uri: DocumentStore.Uri, root_type: ?Type = null, /// Interpreter diagnostic errors @@ -30,6 +30,11 @@ type_info_map: std.HashMapUnmanaged(TypeInfo, usize, TypeInfo.Context, std.hash_ // TODO: Use DOD value_data_list: std.ArrayListUnmanaged(*ValueData) = .{}, +pub fn getHandle(interpreter: *ComptimeInterpreter) *const DocumentStore.Handle { + // This interpreter is loaded from a known-valid handle so a valid handle must exist + return interpreter.document_store.getOrLoadHandle(interpreter.uri).?; +} + pub const InterpreterError = struct { code: []const u8, message: []const u8, @@ -231,9 +236,7 @@ pub const ValueData = union(enum) { @"type": Type, @"bool": bool, - // @"struct": struct { - - // }, + @"struct": struct {}, /// This is what a pointer is; we don't need to map /// this to anything because @ptrToInt is comptime-illegal /// Pointer equality scares me though :( (but that's for later) @@ -311,7 +314,7 @@ pub const Declaration = struct { pub fn getValue(decl: *Declaration) InterpretError!Value { var interpreter = decl.scope.interpreter; - const tree = decl.scope.interpreter.handle.tree; + const tree = decl.scope.interpreter.getHandle().tree; const tags = tree.nodes.items(.tag); if (decl.value == null) { @@ -350,7 +353,7 @@ pub const Declaration = struct { } pub fn isConstant(declaration: Declaration) bool { - const tree = declaration.scope.interpreter.handle.tree; + const tree = declaration.scope.interpreter.getHandle().tree; return switch (tree.nodes.items(.tag)[declaration.node_idx]) { .global_var_decl, .local_var_decl, @@ -491,7 +494,7 @@ pub const InterpreterScope = struct { pub const ScopeKind = enum { container, block, function }; pub fn scopeKind(scope: InterpreterScope) ScopeKind { - const tree = scope.interpreter.handle.tree; + const tree = scope.interpreter.getHandle().tree; return switch (tree.nodes.items(.tag)[scope.node_idx]) { .container_decl, .container_decl_trailing, @@ -513,7 +516,7 @@ pub const InterpreterScope = struct { } pub fn getLabel(scope: InterpreterScope) ?Ast.TokenIndex { - const tree = scope.interpreter.handle.tree; + const tree = scope.interpreter.getHandle().tree; const token_tags = tree.tokens.items(.tag); return switch (scope.scopeKind()) { @@ -621,7 +624,7 @@ pub fn huntItDown( decl_name: []const u8, options: InterpretOptions, ) InterpretError!*Declaration { - const tree = interpreter.handle.tree; + const tree = interpreter.getHandle().tree; const tags = tree.nodes.items(.tag); var psi = scope.parentScopeIterator(); @@ -728,7 +731,7 @@ pub fn interpret( scope: ?*InterpreterScope, options: InterpretOptions, ) InterpretError!InterpretResult { - const tree = interpreter.handle.tree; + const tree = interpreter.getHandle().tree; const tags = tree.nodes.items(.tag); const data = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -833,9 +836,11 @@ pub fn interpret( .name = name, }); - if (scope.?.scopeKind() != .container) { + // TODO: Am I a dumbo shrimp? (e.g. is this tree shaking correct? works on my machine so like...) + + // if (scope.?.scopeKind() != .container) { + if (scope.?.node_idx != 0) _ = try scope.?.declarations.getPtr(name).?.getValue(); - } return InterpretResult{ .nothing = {} }; }, @@ -969,8 +974,7 @@ pub fn interpret( var irv = try ir.getValue(); var sub_scope = irv.value_data.@"type".getTypeInfo().getScopeOfType() orelse return error.IdentifierNotFound; - // var scope_sub_decl = sub_scope.declarations.get(rhs_str) orelse return error.IdentifierNotFound; - var scope_sub_decl = irv.value_data.@"type".interpreter.huntItDown(sub_scope, rhs_str, options) catch |err| { + var scope_sub_decl = sub_scope.interpreter.huntItDown(sub_scope, rhs_str, options) catch |err| { if (err == error.IdentifierNotFound) try interpreter.recordError( node_idx, "undeclared_identifier", @@ -1131,8 +1135,19 @@ pub fn interpret( const import_str = tree.tokenSlice(main_tokens[import_param]); - log.info("Resolving {s} from {s}", .{ import_str[1 .. import_str.len - 1], interpreter.handle.uri }); - var import_uri = (try interpreter.document_store.uriFromImportStr(interpreter.allocator, interpreter.handle.*, import_str[1 .. import_str.len - 1])) orelse return error.ImportFailure; + log.info("Resolving {s} from {s}", .{ import_str[1 .. import_str.len - 1], interpreter.uri }); + + // TODO: Implement root support + if (std.mem.eql(u8, import_str[1 .. import_str.len - 1], "root")) { + return InterpretResult{ .value = Value{ + .interpreter = interpreter, + .node_idx = node_idx, + .@"type" = try interpreter.createType(node_idx, .{ .@"struct" = .{ .scope = try interpreter.newScope(null, 0) } }), + .value_data = try interpreter.createValueData(.{ .@"struct" = .{} }), + } }; + } + + var import_uri = (try interpreter.document_store.uriFromImportStr(interpreter.allocator, interpreter.getHandle().*, import_str[1 .. import_str.len - 1])) orelse return error.ImportFailure; defer interpreter.allocator.free(import_uri); var handle = interpreter.document_store.getOrLoadHandle(import_uri) orelse return error.ImportFailure; @@ -1403,7 +1418,7 @@ pub fn call( // TODO: type check args - const tree = interpreter.handle.tree; + const tree = interpreter.getHandle().tree; const tags = tree.nodes.items(.tag); std.debug.assert(tags[func_node_idx] == .fn_decl); diff --git a/src/DocumentStore.zig b/src/DocumentStore.zig index ccd01f1..2b82bfe 100644 --- a/src/DocumentStore.zig +++ b/src/DocumentStore.zig @@ -944,7 +944,7 @@ pub fn ensureInterpreterExists(self: *DocumentStore, uri: Uri) !void { int.* = ComptimeInterpreter{ .allocator = self.allocator, .document_store = self, - .handle = handle, + .uri = uri, }; handle.interpreter = int; _ = try int.interpret(0, null, .{}); diff --git a/src/Server.zig b/src/Server.zig index f4e3ac4..c759c7d 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -2776,7 +2776,35 @@ pub fn processJsonRpc(server: *Server, writer: anytype, json: []const u8) !void } } - const method_map = .{ .{ "initialized", void, initializedHandler }, .{"$/cancelRequest"}, .{"textDocument/willSave"}, .{ "initialize", requests.Initialize, initializeHandler }, .{ "shutdown", void, shutdownHandler }, .{ "exit", void, exitHandler }, .{ "textDocument/didOpen", requests.OpenDocument, openDocumentHandler }, .{ "textDocument/didChange", requests.ChangeDocument, changeDocumentHandler }, .{ "textDocument/didSave", requests.SaveDocument, saveDocumentHandler }, .{ "textDocument/didClose", requests.CloseDocument, closeDocumentHandler }, .{ "textDocument/semanticTokens/full", requests.SemanticTokensFull, semanticTokensFullHandler }, .{ "textDocument/inlayHint", requests.InlayHint, inlayHintHandler }, .{ "textDocument/completion", requests.Completion, completionHandler }, .{ "textDocument/signatureHelp", requests.SignatureHelp, signatureHelpHandler }, .{ "textDocument/definition", requests.GotoDefinition, gotoDefinitionHandler }, .{ "textDocument/typeDefinition", requests.GotoDefinition, gotoDefinitionHandler }, .{ "textDocument/implementation", requests.GotoDefinition, gotoDefinitionHandler }, .{ "textDocument/declaration", requests.GotoDeclaration, gotoDeclarationHandler }, .{ "textDocument/hover", requests.Hover, hoverHandler }, .{ "textDocument/documentSymbol", requests.DocumentSymbols, documentSymbolsHandler }, .{ "textDocument/formatting", requests.Formatting, formattingHandler }, .{ "textDocument/rename", requests.Rename, renameHandler }, .{ "textDocument/references", requests.References, referencesHandler }, .{ "textDocument/documentHighlight", requests.DocumentHighlight, documentHighlightHandler }, .{ "textDocument/codeAction", requests.CodeAction, codeActionHandler }, .{ "workspace/didChangeConfiguration", Config.DidChangeConfigurationParams, didChangeConfigurationHandler }, .{ "textDocument/foldingRange", requests.FoldingRange, foldingRangeHandler } }; + const method_map = .{ + .{ "initialized", void, initializedHandler }, + .{"$/cancelRequest"}, + .{"textDocument/willSave"}, + .{ "initialize", requests.Initialize, initializeHandler }, + .{ "shutdown", void, shutdownHandler }, + .{ "exit", void, exitHandler }, + .{ "textDocument/didOpen", requests.OpenDocument, openDocumentHandler }, + .{ "textDocument/didChange", requests.ChangeDocument, changeDocumentHandler }, + .{ "textDocument/didSave", requests.SaveDocument, saveDocumentHandler }, + .{ "textDocument/didClose", requests.CloseDocument, closeDocumentHandler }, + .{ "textDocument/semanticTokens/full", requests.SemanticTokensFull, semanticTokensFullHandler }, + .{ "textDocument/inlayHint", requests.InlayHint, inlayHintHandler }, + .{ "textDocument/completion", requests.Completion, completionHandler }, + .{ "textDocument/signatureHelp", requests.SignatureHelp, signatureHelpHandler }, + .{ "textDocument/definition", requests.GotoDefinition, gotoDefinitionHandler }, + .{ "textDocument/typeDefinition", requests.GotoDefinition, gotoDefinitionHandler }, + .{ "textDocument/implementation", requests.GotoDefinition, gotoDefinitionHandler }, + .{ "textDocument/declaration", requests.GotoDeclaration, gotoDeclarationHandler }, + .{ "textDocument/hover", requests.Hover, hoverHandler }, + .{ "textDocument/documentSymbol", requests.DocumentSymbols, documentSymbolsHandler }, + .{ "textDocument/formatting", requests.Formatting, formattingHandler }, + .{ "textDocument/rename", requests.Rename, renameHandler }, + .{ "textDocument/references", requests.References, referencesHandler }, + .{ "textDocument/documentHighlight", requests.DocumentHighlight, documentHighlightHandler }, + .{ "textDocument/codeAction", requests.CodeAction, codeActionHandler }, + .{ "workspace/didChangeConfiguration", Config.DidChangeConfigurationParams, didChangeConfigurationHandler }, + .{ "textDocument/foldingRange", requests.FoldingRange, foldingRangeHandler }, + }; if (zig_builtin.zig_backend == .stage1) { // Hack to avoid `return`ing in the inline for, which causes bugs. diff --git a/src/zls.zig b/src/zls.zig index 40920b2..34290c1 100644 --- a/src/zls.zig +++ b/src/zls.zig @@ -1,4 +1,6 @@ -// used by tests as a package +// Used by tests as a package, can be used by tools such as +// zigbot9001 to take advantage of zls' tools + pub const analysis = @import("analysis.zig"); pub const header = @import("header.zig"); pub const offsets = @import("offsets.zig"); @@ -8,4 +10,5 @@ pub const Server = @import("Server.zig"); pub const translate_c = @import("translate_c.zig"); pub const types = @import("types.zig"); pub const URI = @import("uri.zig"); +pub const DocumentStore = @import("DocumentStore.zig"); pub const ComptimeInterpreter = @import("ComptimeInterpreter.zig"); diff --git a/tests/language_features/comptime_interpreter.zig b/tests/language_features/comptime_interpreter.zig index 79e6743..ae9311e 100644 --- a/tests/language_features/comptime_interpreter.zig +++ b/tests/language_features/comptime_interpreter.zig @@ -8,35 +8,51 @@ const ComptimeInterpreter = zls.ComptimeInterpreter; const allocator: std.mem.Allocator = std.testing.allocator; test "ComptimeInterpreter - basic test" { - var tree = try std.zig.parse(allocator, + 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; \\} ); - defer tree.deinit(allocator); - var interpreter = ComptimeInterpreter{ .tree = tree, .allocator = allocator }; + var interpreter = ComptimeInterpreter{ + .allocator = allocator, + .document_store = &doc_store, + .uri = "file:///file.zig", + }; defer interpreter.deinit(); + _ = try interpreter.interpret(0, null, .{}); + var bool_type = try interpreter.createType(std.math.maxInt(std.zig.Ast.Node.Index), .{ .@"bool" = .{} }); var arg_false = ComptimeInterpreter.Value{ + .interpreter = &interpreter, .node_idx = std.math.maxInt(std.zig.Ast.Node.Index), .@"type" = bool_type, - .value_data = .{ .@"bool" = false }, + .value_data = try interpreter.createValueData(.{ .@"bool" = false }), }; var arg_true = ComptimeInterpreter.Value{ + .interpreter = &interpreter, .node_idx = std.math.maxInt(std.zig.Ast.Node.Index), .@"type" = bool_type, - .value_data = .{ .@"bool" = true }, + .value_data = try interpreter.createValueData(.{ .@"bool" = true }), }; - const call_with_false = try interpreter.call(tree.rootDecls()[0], &.{ + const rmt = interpreter.root_type.?.getTypeInfo().@"struct".scope.declarations.get("ReturnMyType").?; + + const call_with_false = try interpreter.call(null, rmt.node_idx, &.{ arg_false, }, .{}); defer call_with_false.scope.deinit(); - const call_with_true = try interpreter.call(tree.rootDecls()[0], &.{ + const call_with_true = try interpreter.call(null, rmt.node_idx, &.{ arg_true, }, .{}); defer call_with_true.scope.deinit(); @@ -46,7 +62,14 @@ test "ComptimeInterpreter - basic test" { } test "ComptimeInterpreter - struct" { - var tree = try std.zig.parse(allocator, + 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 { \\ return struct { \\ slay: bool, @@ -54,13 +77,20 @@ test "ComptimeInterpreter - struct" { \\ }; \\} ); - defer tree.deinit(allocator); - var interpreter = ComptimeInterpreter{ .tree = tree, .allocator = allocator }; + var interpreter = ComptimeInterpreter{ + .allocator = allocator, + .document_store = &doc_store, + .uri = "file:///file.zig", + }; defer interpreter.deinit(); - const z = try interpreter.call(tree.rootDecls()[0], &.{}, .{}); + _ = try interpreter.interpret(0, null, .{}); + + const rmt = interpreter.root_type.?.getTypeInfo().@"struct".scope.declarations.get("ReturnMyType").?; + + const z = try interpreter.call(null, rmt.node_idx, &.{}, .{}); defer z.scope.deinit(); - try std.testing.expectFmt("struct {slay: bool, const abc: comptime_int = TODO_PRINT_VALUES, }", "{any}", .{interpreter.formatTypeInfo(interpreter.typeToTypeInfo(z.result.value.value_data.@"type"))}); + try std.testing.expectFmt("struct {slay: bool, var abc: comptime_int = 123, }", "{any}", .{interpreter.formatTypeInfo(z.result.value.value_data.@"type".getTypeInfo())}); } diff --git a/tests/tests.zig b/tests/tests.zig index e1480d7..f6a97a9 100644 --- a/tests/tests.zig +++ b/tests/tests.zig @@ -17,5 +17,5 @@ comptime { // Language features _ = @import("language_features/cimport.zig"); - // _ = @import("language_features/comptime_interpreter.zig"); + _ = @import("language_features/comptime_interpreter.zig"); }