diff --git a/src/Config.zig b/src/Config.zig index 5b4df43..62380c3 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -90,10 +90,13 @@ pub fn loadFromFile(allocator: std.mem.Allocator, file_path: []const u8) ?Config const file_buf = file.readToEndAlloc(allocator, 0x1000000) catch return null; defer allocator.free(file_buf); - @setEvalBranchQuota(7000); + @setEvalBranchQuota(10000); + + var token_stream = std.json.TokenStream.init(file_buf); const parse_options = std.json.ParseOptions{ .allocator = allocator, .ignore_unknown_fields = true }; + // TODO: Better errors? Doesn't seem like std.json can provide us positions or context. - var config = std.json.parse(Config, &std.json.TokenStream.init(file_buf), parse_options) catch |err| { + var config = std.json.parse(Config, &token_stream, parse_options) catch |err| { logger.warn("Error while parsing configuration file: {}", .{err}); return null; }; diff --git a/src/DocumentStore.zig b/src/DocumentStore.zig index 6d94233..9f633c8 100644 --- a/src/DocumentStore.zig +++ b/src/DocumentStore.zig @@ -134,7 +134,9 @@ fn loadBuildAssociatedConfiguration(allocator: std.mem.Allocator, build_file: *B const file_buf = try config_file.readToEndAlloc(allocator, 0x1000000); defer allocator.free(file_buf); - break :blk try std.json.parse(BuildAssociatedConfig, &std.json.TokenStream.init(file_buf), options); + var token_stream = std.json.TokenStream.init(file_buf); + + break :blk try std.json.parse(BuildAssociatedConfig, &token_stream, options); }; defer std.json.parseFree(BuildAssociatedConfig, build_associated_config, options); @@ -234,9 +236,11 @@ fn loadBuildConfiguration(context: LoadBuildConfigContext) !void { build_file.config.deinit(allocator); + var token_stream = std.json.TokenStream.init(zig_run_result.stdout); + const config: BuildConfig = std.json.parse( BuildConfig, - &std.json.TokenStream.init(zig_run_result.stdout), + &token_stream, parse_options, ) catch return error.RunFailed; defer std.json.parseFree(BuildConfig, config, parse_options); diff --git a/src/Server.zig b/src/Server.zig index b1aea5f..3eb28ad 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -1627,32 +1627,45 @@ fn exitHandler(server: *Server, writer: anytype, id: types.RequestId) noreturn { } fn registerCapability(server: *Server, writer: anytype, method: []const u8) !void { - // NOTE: stage1 moment occurs if we dont do it like this :( - // long live stage2's not broken anon structs - + const id = try std.fmt.allocPrint(server.arena.allocator(), "register-{s}", .{method}); log.debug("Dynamically registering method '{s}'", .{method}); - const id = try std.fmt.allocPrint(server.arena.allocator(), "register-{s}", .{method}); - const reg = types.RegistrationParams.Registration{ - .id = id, - .method = method, - }; - const registrations = [1]types.RegistrationParams.Registration{reg}; - const params = types.RegistrationParams{ - .registrations = ®istrations, - }; + if (zig_builtin.zig_backend == .stage1) { + const reg = types.RegistrationParams.Registration{ + .id = id, + .method = method, + }; + const registrations = [1]types.RegistrationParams.Registration{reg}; + const params = types.RegistrationParams{ + .registrations = ®istrations, + }; - const respp = types.ResponseParams{ - .RegistrationParams = params, - }; + const respp = types.ResponseParams{ + .RegistrationParams = params, + }; + const req = types.Request{ + .id = .{ .String = id }, + .method = "client/registerCapability", + .params = respp, + }; - const req = types.Request{ - .id = .{ .String = id }, - .method = "client/registerCapability", - .params = respp, - }; - - try send(writer, server.arena.allocator(), req); + try send(writer, server.arena.allocator(), req); + } else { + try send(writer, server.arena.allocator(), types.Request{ + .id = .{ .String = id }, + .method = "client/registerCapability", + .params = types.ResponseParams{ + .RegistrationParams = types.RegistrationParams{ + .registrations = &.{ + .{ + .id = id, + .method = method, + }, + }, + }, + }, + }); + } } fn requestConfiguration(server: *Server, writer: anytype) !void { @@ -1670,7 +1683,7 @@ fn requestConfiguration(server: *Server, writer: anytype) !void { try send(writer, server.arena.allocator(), types.Request{ .id = .{ .String = "i_haz_configuration" }, .method = "workspace/configuration", - .params = .{ + .params = types.ResponseParams{ .ConfigurationParams = .{ .items = &configuration_items, }, @@ -1785,7 +1798,6 @@ fn semanticTokensFullHandler(server: *Server, writer: anytype, id: types.Request }; const token_array = try semantic_tokens.writeAllSemanticTokens(&server.arena, &server.document_store, handle, server.offset_encoding); - defer server.allocator.free(token_array); return try send(writer, server.arena.allocator(), types.Response{ .id = id, @@ -2429,38 +2441,58 @@ pub fn processJsonRpc(server: *Server, writer: anytype, json: []const u8) !void .{ "workspace/didChangeConfiguration", std.json.Value, didChangeConfigurationHandler }, }; - // Hack to avoid `return`ing in the inline for, which causes bugs. - // TODO: Change once stage2 is shipped and more stable? - var done: ?anyerror = null; - inline for (method_map) |method_info| { - if (done == null and std.mem.eql(u8, method, method_info[0])) { - if (method_info.len == 1) { - log.warn("method not mapped: {s}", .{method}); - done = error.HackDone; - } else if (method_info[1] != void) { - const ReqT = method_info[1]; - if (requests.fromDynamicTree(&server.arena, ReqT, tree.root)) |request_obj| { + if (zig_builtin.zig_backend == .stage1) { + // Hack to avoid `return`ing in the inline for, which causes bugs. + var done: ?anyerror = null; + inline for (method_map) |method_info| { + if (done == null and std.mem.eql(u8, method, method_info[0])) { + if (method_info.len == 1) { + log.warn("method not mapped: {s}", .{method}); done = error.HackDone; - done = extractErr(method_info[2](server, writer, id, request_obj)); - } else |err| { - if (err == error.MalformedJson) { - log.warn("Could not create request type {s} from JSON {s}", .{ @typeName(ReqT), json }); + } else if (method_info[1] != void) { + const ReqT = method_info[1]; + if (requests.fromDynamicTree(&server.arena, ReqT, tree.root)) |request_obj| { + done = error.HackDone; + done = extractErr(method_info[2](server, writer, id, request_obj)); + } else |err| { + if (err == error.MalformedJson) { + log.warn("Could not create request type {s} from JSON {s}", .{ @typeName(ReqT), json }); + } + done = err; } - done = err; + } else { + done = error.HackDone; + (method_info[2])(server, writer, id) catch |err| { + done = err; + }; } - } else { - done = error.HackDone; - (method_info[2])(server, writer, id) catch |err| { - done = err; - }; + } + } + if (done) |err| switch (err) { + error.MalformedJson => return try respondGeneric(writer, id, null_result_response), + error.HackDone => return, + else => return err, + }; + } else { + inline for (method_map) |method_info| { + if (std.mem.eql(u8, method, method_info[0])) { + if (method_info.len == 1) { + log.warn("method not mapped: {s}", .{method}); + } else if (method_info[1] != void) { + const ReqT = method_info[1]; + const request_obj = try requests.fromDynamicTree(&server.arena, ReqT, tree.root); + method_info[2](server, writer, id, request_obj) catch |err| { + log.err("failed to process request: {s}", .{@errorName(err)}); + }; + } else { + method_info[2](server, writer, id) catch |err| { + log.err("failed to process request: {s}", .{@errorName(err)}); + }; + } + return; } } } - if (done) |err| switch (err) { - error.MalformedJson => return try respondGeneric(writer, id, null_result_response), - error.HackDone => return, - else => return err, - }; // Boolean value is true if the method is a request (and thus the client // needs a response) or false if the method is a notification (in which diff --git a/src/inlay_hints.zig b/src/inlay_hints.zig index 0cba1d0..c4daccb 100644 --- a/src/inlay_hints.zig +++ b/src/inlay_hints.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const zig_builtin = @import("builtin"); const DocumentStore = @import("DocumentStore.zig"); const analysis = @import("analysis.zig"); const types = @import("types.zig"); @@ -242,6 +243,20 @@ fn writeCallNodeHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: } } +/// HACK self-hosted has not implemented async yet +fn callWriteNodeInlayHint(allocator: std.mem.Allocator, args: anytype) error{OutOfMemory}!void { + if (zig_builtin.zig_backend == .other or zig_builtin.zig_backend == .stage1) { + const FrameSize = @sizeOf(@Frame(writeNodeInlayHint)); + var child_frame = try allocator.alignedAlloc(u8, std.Target.stack_align, FrameSize); + defer allocator.free(child_frame); + + return await @asyncCall(child_frame, {}, writeNodeInlayHint, args); + } else { + // TODO find a non recursive solution + return @call(.{}, writeNodeInlayHint, args); + } +} + /// iterates over the ast and writes parameter hints into `builder.hints` for every function call and builtin call /// nodes outside the given range are excluded fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *DocumentStore, maybe_node: ?Ast.Node.Index, range: types.Range) error{OutOfMemory}!void { @@ -255,9 +270,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: if (node == 0 or node > node_data.len) return; - const FrameSize = @sizeOf(@Frame(writeNodeInlayHint)); - var child_frame = try arena.child_allocator.alignedAlloc(u8, std.Target.stack_align, FrameSize); - defer arena.child_allocator.free(child_frame); + var allocator = arena.allocator(); const tag = node_tags[node]; @@ -283,7 +296,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: if (!isNodeInRange(tree, param, range)) continue; } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, param, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, param, range }); } }, @@ -314,7 +327,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: if (!isNodeInRange(tree, param, range)) continue; } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, param, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, param, range }); } }, @@ -336,7 +349,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .array_type_sentinel => { const array_type = tree.arrayTypeSentinel(node); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, array_type.ast.sentinel, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, array_type.ast.sentinel, range }); }, .ptr_type_aligned, @@ -347,19 +360,19 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: const ptr_type: Ast.full.PtrType = ast.ptrType(tree, node).?; if (ptr_type.ast.sentinel != 0) { - return try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, ptr_type.ast.sentinel, range }); + return try callWriteNodeInlayHint(allocator, .{ builder, arena, store, ptr_type.ast.sentinel, range }); } if (ptr_type.ast.align_node != 0) { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, ptr_type.ast.align_node, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, ptr_type.ast.align_node, range }); if (ptr_type.ast.bit_range_start != 0) { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, ptr_type.ast.bit_range_start, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, ptr_type.ast.bit_range_end, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, ptr_type.ast.bit_range_start, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, ptr_type.ast.bit_range_end, range }); } } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, ptr_type.ast.child_type, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, ptr_type.ast.child_type, range }); }, .@"usingnamespace", @@ -379,7 +392,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .grouped_expression, .@"comptime", .@"nosuspend", - => try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].lhs, range }), + => try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].lhs, range }), .test_decl, .global_var_decl, @@ -389,7 +402,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .@"errdefer", .@"defer", .@"break", - => try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].rhs, range }), + => try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].rhs, range }), .@"catch", .equal_equal, @@ -444,8 +457,8 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .error_value, .error_union, => { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].lhs, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].rhs, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].lhs, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].rhs, range }); }, .slice_open, @@ -459,10 +472,10 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: else => unreachable, }; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, slice.ast.sliced, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, slice.ast.start, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, slice.ast.end, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, slice.ast.sentinel, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, slice.ast.sliced, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, slice.ast.start, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, slice.ast.end, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, slice.ast.sentinel, range }); }, .array_init_one, @@ -483,9 +496,9 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: else => unreachable, }; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, array_init.ast.type_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, array_init.ast.type_expr, range }); for (array_init.ast.elements) |elem| { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, elem, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, elem, range }); } }, @@ -507,21 +520,21 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: else => unreachable, }; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, struct_init.ast.type_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, struct_init.ast.type_expr, range }); for (struct_init.ast.fields) |field_init| { if (struct_init.ast.fields.len > inlay_hints_max_inline_children) { if (!isNodeInRange(tree, field_init, range)) continue; } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, field_init, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, field_init, range }); } }, .@"switch", .switch_comma, => { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].lhs, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].lhs, range }); const extra = tree.extraData(node_data[node].rhs, Ast.Node.SubRange); const cases = tree.extra_data[extra.start..extra.end]; @@ -531,7 +544,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: if (!isNodeInRange(tree, case_node, range)) continue; } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, case_node, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, case_node, range }); } }, @@ -540,7 +553,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: => { const switch_case = if (tag == .switch_case) tree.switchCase(node) else tree.switchCaseOne(node); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, switch_case.ast.target_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, switch_case.ast.target_expr, range }); }, .while_simple, @@ -551,12 +564,12 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: => { const while_node = ast.whileAst(tree, node).?; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, while_node.ast.cond_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, while_node.ast.cont_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, while_node.ast.then_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, while_node.ast.cond_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, while_node.ast.cont_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, while_node.ast.then_expr, range }); if (while_node.ast.else_expr != 0) { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, while_node.ast.else_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, while_node.ast.else_expr, range }); } }, @@ -564,9 +577,9 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .@"if", => { const if_node = ast.ifFull(tree, node); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, if_node.ast.cond_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, if_node.ast.then_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, if_node.ast.else_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, if_node.ast.cond_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, if_node.ast.then_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, if_node.ast.else_expr, range }); }, .fn_proto_simple, @@ -580,18 +593,18 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: var it = fn_proto.iterate(&tree); while (ast.nextFnParam(&it)) |param_decl| { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, param_decl.type_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, param_decl.type_expr, range }); } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, fn_proto.ast.align_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, fn_proto.ast.addrspace_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, fn_proto.ast.section_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, fn_proto.ast.callconv_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, fn_proto.ast.align_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, fn_proto.ast.addrspace_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, fn_proto.ast.section_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, fn_proto.ast.callconv_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, fn_proto.ast.return_type, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, fn_proto.ast.return_type, range }); if (tag == .fn_decl) { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].rhs, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].rhs, range }); } }, @@ -611,14 +624,14 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: var buffer: [2]Ast.Node.Index = undefined; const decl: Ast.full.ContainerDecl = ast.containerDecl(tree, node, &buffer).?; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, decl.ast.arg, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, decl.ast.arg, range }); for (decl.ast.members) |child| { if (decl.ast.members.len > inlay_hints_max_inline_children) { if (!isNodeInRange(tree, child, range)) continue; } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, child, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, child, range }); } }, @@ -628,15 +641,15 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: => { const container_field = ast.containerField(tree, node).?; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, container_field.ast.value_expr, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, container_field.ast.align_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, container_field.ast.value_expr, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, container_field.ast.align_expr, range }); }, .block_two, .block_two_semicolon, => { - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].lhs, range }); - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, node_data[node].rhs, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].lhs, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, node_data[node].rhs, range }); }, .block, @@ -649,7 +662,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: if (!isNodeInRange(tree, child, range)) continue; } - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, child, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, child, range }); } }, @@ -664,7 +677,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: else => return, }; - try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, asm_node.ast.template, range }); + try callWriteNodeInlayHint(allocator, .{ builder, arena, store, asm_node.ast.template, range }); }, } } diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index b57f810..ab0bf10 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const zig_builtin = @import("builtin"); const offsets = @import("offsets.zig"); const DocumentStore = @import("DocumentStore.zig"); const analysis = @import("analysis.zig"); @@ -50,16 +51,18 @@ pub const TokenModifiers = packed struct { }; const Builder = struct { - allocator: std.mem.Allocator, + arena: *std.heap.ArenaAllocator, + store: *DocumentStore, handle: *DocumentStore.Handle, previous_position: usize = 0, previous_token: ?Ast.TokenIndex = null, arr: std.ArrayListUnmanaged(u32), encoding: offsets.Encoding, - fn init(allocator: std.mem.Allocator, handle: *DocumentStore.Handle, encoding: offsets.Encoding) Builder { + fn init(arena: *std.heap.ArenaAllocator, store: *DocumentStore, handle: *DocumentStore.Handle, encoding: offsets.Encoding) Builder { return Builder{ - .allocator = allocator, + .arena = arena, + .store = store, .handle = handle, .arr = std.ArrayListUnmanaged(u32){}, .encoding = encoding, @@ -182,7 +185,7 @@ const Builder = struct { const text = self.handle.tree.source[self.previous_position..start]; const delta = offsets.indexToPosition(text, text.len, self.encoding); - try self.arr.appendSlice(self.allocator, &.{ + try self.arr.appendSlice(self.arena.allocator(), &.{ @truncate(u32, delta.line), @truncate(u32, delta.character), @truncate(u32, length), @@ -193,7 +196,7 @@ const Builder = struct { } fn toOwnedSlice(self: *Builder) []u32 { - return self.arr.toOwnedSlice(self.allocator); + return self.arr.toOwnedSlice(self.arena.allocator()); } }; @@ -260,16 +263,24 @@ fn colorIdentifierBasedOnType(builder: *Builder, type_node: analysis.TypeWithHan const WriteTokensError = error{ OutOfMemory, - Utf8InvalidStartByte, - CodepointTooLong, - Utf8ExpectedContinuation, - Utf8OverlongEncoding, - Utf8EncodesSurrogateHalf, - Utf8CodepointTooLarge, MovedBackwards, }; -fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *DocumentStore, maybe_node: ?Ast.Node.Index) WriteTokensError!void { +/// HACK self-hosted has not implemented async yet +fn callWriteNodeTokens(allocator: std.mem.Allocator, args: anytype) WriteTokensError!void { + if (zig_builtin.zig_backend == .other or zig_builtin.zig_backend == .stage1) { + const FrameSize = @sizeOf(@Frame(writeNodeTokens)); + var child_frame = try allocator.alignedAlloc(u8, std.Target.stack_align, FrameSize); + // defer allocator.free(child_frame); allocator is a arena allocator + + return await @asyncCall(child_frame, {}, writeNodeTokens, args); + } else { + // TODO find a non recursive solution + return @call(.{}, writeNodeTokens, args); + } +} + +fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) WriteTokensError!void { const node = maybe_node orelse return; const handle = builder.handle; @@ -280,9 +291,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D const main_tokens = tree.nodes.items(.main_token); if (node == 0 or node > node_data.len) return; - const FrameSize = @sizeOf(@Frame(writeNodeTokens)); - var child_frame = try arena.child_allocator.alignedAlloc(u8, std.Target.stack_align, FrameSize); - defer arena.child_allocator.free(child_frame); + var allocator = builder.arena.allocator(); const tag = node_tags[node]; const main_token = main_tokens[node]; @@ -292,7 +301,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .container_field, .container_field_align, .container_field_init, - => try writeContainerField(builder, arena, store, node, .field, child_frame), + => try writeContainerField(builder, node, .field), .@"errdefer" => { try writeToken(builder, main_token, .keyword); @@ -303,7 +312,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, payload_tok + 1, .operator); } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .block, .block_semicolon, @@ -319,9 +328,9 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D for (statements) |child| { if (node_tags[child].isContainerField()) { - try writeContainerField(builder, arena, store, child, .field, child_frame); + try writeContainerField(builder, child, .field); } else { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, child }); + try callWriteNodeTokens(allocator, .{ builder, child }); } } }, @@ -340,18 +349,18 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, var_decl.comptime_token, .keyword); try writeToken(builder, var_decl.ast.mut_token, .keyword); - if (try analysis.resolveTypeOfNode(store, arena, .{ .node = node, .handle = handle })) |decl_type| { + if (try analysis.resolveTypeOfNode(builder.store, builder.arena, .{ .node = node, .handle = handle })) |decl_type| { try colorIdentifierBasedOnType(builder, decl_type, var_decl.ast.mut_token + 1, .{ .declaration = true }); } else { try writeTokenMod(builder, var_decl.ast.mut_token + 1, .variable, .{ .declaration = true }); } try writeToken(builder, var_decl.ast.mut_token + 2, .operator); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, var_decl.ast.type_node }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, var_decl.ast.align_node }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, var_decl.ast.section_node }); + try callWriteNodeTokens(allocator, .{ builder, var_decl.ast.type_node }); + try callWriteNodeTokens(allocator, .{ builder, var_decl.ast.align_node }); + try callWriteNodeTokens(allocator, .{ builder, var_decl.ast.section_node }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, var_decl.ast.init_node }); + try callWriteNodeTokens(allocator, .{ builder, var_decl.ast.init_node }); }, .@"usingnamespace" => { const first_tok = tree.firstToken(node); @@ -359,7 +368,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeDocComments(builder, tree, first_tok - 1); try writeToken(builder, if (token_tags[first_tok] == .keyword_pub) first_tok else null, .keyword); try writeToken(builder, main_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); }, .container_decl, .container_decl_trailing, @@ -381,17 +390,17 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, decl.ast.main_token, .keyword); if (decl.ast.enum_token) |enum_token| { if (decl.ast.arg != 0) - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, decl.ast.arg }) + try callWriteNodeTokens(allocator, .{ builder, decl.ast.arg }) else try writeToken(builder, enum_token, .keyword); - } else try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, decl.ast.arg }); + } else try callWriteNodeTokens(allocator, .{ builder, decl.ast.arg }); const field_token_type = fieldTokenType(node, handle); for (decl.ast.members) |child| { if (node_tags[child].isContainerField()) { - try writeContainerField(builder, arena, store, child, field_token_type, child_frame); + try writeContainerField(builder, child, field_token_type); } else { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, child }); + try callWriteNodeTokens(allocator, .{ builder, child }); } } }, @@ -411,8 +420,8 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D } if (try analysis.lookupSymbolGlobal( - store, - arena, + builder.store, + builder.arena, handle, name, tree.tokens.items(.start)[main_token], @@ -421,7 +430,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D return try writeToken(builder, main_token, .parameter); } var bound_type_params = analysis.BoundTypeParams{}; - if (try child.resolveType(store, arena, &bound_type_params)) |decl_type| { + if (try child.resolveType(builder.store, builder.arena, &bound_type_params)) |decl_type| { try colorIdentifierBasedOnType(builder, decl_type, main_token, .{}); } else { try writeTokenMod(builder, main_token, .variable, .{}); @@ -464,28 +473,28 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeTokenMod(builder, param_decl.name_token, .parameter, .{ .declaration = true }); if (param_decl.anytype_ellipsis3) |any_token| { try writeToken(builder, any_token, .type); - } else try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, param_decl.type_expr }); + } else try callWriteNodeTokens(allocator, .{ builder, param_decl.type_expr }); } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, fn_proto.ast.align_expr }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, fn_proto.ast.section_expr }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, fn_proto.ast.callconv_expr }); + try callWriteNodeTokens(allocator, .{ builder, fn_proto.ast.align_expr }); + try callWriteNodeTokens(allocator, .{ builder, fn_proto.ast.section_expr }); + try callWriteNodeTokens(allocator, .{ builder, fn_proto.ast.callconv_expr }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, fn_proto.ast.return_type }); + try callWriteNodeTokens(allocator, .{ builder, fn_proto.ast.return_type }); if (tag == .fn_decl) - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .anyframe_type => { try writeToken(builder, main_token, .type); if (node_data[node].rhs != 0) { try writeToken(builder, node_data[node].lhs, .type); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); } }, .@"defer" => { try writeToken(builder, main_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .@"comptime", .@"nosuspend", @@ -493,25 +502,25 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D if (analysis.getDocCommentTokenIndex(token_tags, main_token)) |doc| try writeDocComments(builder, tree, doc); try writeToken(builder, main_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); }, .@"switch", .switch_comma, => { try writeToken(builder, main_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); const extra = tree.extraData(node_data[node].rhs, Ast.Node.SubRange); const cases = tree.extra_data[extra.start..extra.end]; for (cases) |case_node| { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, case_node }); + try callWriteNodeTokens(allocator, .{ builder, case_node }); } }, .switch_case_one, .switch_case, => { const switch_case = if (tag == .switch_case) tree.switchCase(node) else tree.switchCaseOne(node); - for (switch_case.ast.values) |item_node| try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, item_node }); + for (switch_case.ast.values) |item_node| try callWriteNodeTokens(allocator, .{ builder, item_node }); // check it it's 'else' if (switch_case.ast.values.len == 0) try writeToken(builder, switch_case.ast.arrow_token - 1, .keyword); try writeToken(builder, switch_case.ast.arrow_token, .operator); @@ -519,7 +528,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D const actual_payload = payload_token + @boolToInt(token_tags[payload_token] == .asterisk); try writeToken(builder, actual_payload, .variable); } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, switch_case.ast.target_expr }); + try callWriteNodeTokens(allocator, .{ builder, switch_case.ast.target_expr }); }, .@"while", .while_simple, @@ -531,7 +540,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, while_node.label_token, .label); try writeToken(builder, while_node.inline_token, .keyword); try writeToken(builder, while_node.ast.while_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.cond_expr }); + try callWriteNodeTokens(allocator, .{ builder, while_node.ast.cond_expr }); if (while_node.payload_token) |payload| { try writeToken(builder, payload - 1, .operator); try writeToken(builder, payload, .variable); @@ -543,9 +552,9 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D } try writeToken(builder, r_pipe, .operator); } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.cont_expr }); + try callWriteNodeTokens(allocator, .{ builder, while_node.ast.cont_expr }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.then_expr }); + try callWriteNodeTokens(allocator, .{ builder, while_node.ast.then_expr }); if (while_node.ast.else_expr != 0) { try writeToken(builder, while_node.else_token, .keyword); @@ -555,7 +564,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, err_token, .variable); try writeToken(builder, err_token + 1, .operator); } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.else_expr }); + try callWriteNodeTokens(allocator, .{ builder, while_node.ast.else_expr }); } }, .@"if", @@ -564,7 +573,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D const if_node = ast.ifFull(tree, node); try writeToken(builder, if_node.ast.if_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.cond_expr }); + try callWriteNodeTokens(allocator, .{ builder, if_node.ast.cond_expr }); if (if_node.payload_token) |payload| { // if (?x) |x| @@ -572,7 +581,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, payload, .variable); // x try writeToken(builder, payload + 1, .operator); // | } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.then_expr }); + try callWriteNodeTokens(allocator, .{ builder, if_node.ast.then_expr }); if (if_node.ast.else_expr != 0) { try writeToken(builder, if_node.else_token, .keyword); @@ -582,7 +591,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, err_token, .variable); // err try writeToken(builder, err_token + 1, .operator); // | } - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.else_expr }); + try callWriteNodeTokens(allocator, .{ builder, if_node.ast.else_expr }); } }, .array_init, @@ -603,8 +612,8 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D else => unreachable, }; - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, array_init.ast.type_expr }); - for (array_init.ast.elements) |elem| try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, elem }); + try callWriteNodeTokens(allocator, .{ builder, array_init.ast.type_expr }); + for (array_init.ast.elements) |elem| try callWriteNodeTokens(allocator, .{ builder, elem }); }, .struct_init, .struct_init_comma, @@ -627,12 +636,13 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D var field_token_type: ?TokenType = null; if (struct_init.ast.type_expr != 0) { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, struct_init.ast.type_expr }); + try callWriteNodeTokens(allocator, .{ builder, struct_init.ast.type_expr }); - field_token_type = if (try analysis.resolveTypeOfNode(store, arena, .{ - .node = struct_init.ast.type_expr, - .handle = handle, - })) |struct_type| switch (struct_type.type.data) { + field_token_type = if (try analysis.resolveTypeOfNode( + builder.store, + builder.arena, + .{ .node = struct_init.ast.type_expr, .handle = handle }, + )) |struct_type| switch (struct_type.type.data) { .other => |type_node| if (ast.isContainer(struct_type.handle.tree, type_node)) fieldTokenType(type_node, struct_type.handle) else @@ -646,7 +656,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, init_token - 3, field_token_type orelse .field); // '.' try writeToken(builder, init_token - 2, field_token_type orelse .field); // name try writeToken(builder, init_token - 1, .operator); // '=' - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, field_init }); + try callWriteNodeTokens(allocator, .{ builder, field_init }); } }, .call, @@ -662,14 +672,14 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D const call = ast.callFull(tree, node, ¶ms).?; try writeToken(builder, call.async_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, call.ast.fn_expr }); + try callWriteNodeTokens(allocator, .{ builder, call.ast.fn_expr }); if (builder.previous_token) |prev| { if (prev != ast.lastToken(tree, call.ast.fn_expr) and token_tags[ast.lastToken(tree, call.ast.fn_expr)] == .identifier) { try writeToken(builder, ast.lastToken(tree, call.ast.fn_expr), .function); } } - for (call.ast.params) |param| try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, param }); + for (call.ast.params) |param| try callWriteNodeTokens(allocator, .{ builder, param }); }, .slice, .slice_open, @@ -682,27 +692,27 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D else => unreachable, }; - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, slice.ast.sliced }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, slice.ast.start }); + try callWriteNodeTokens(allocator, .{ builder, slice.ast.sliced }); + try callWriteNodeTokens(allocator, .{ builder, slice.ast.start }); try writeToken(builder, ast.lastToken(tree, slice.ast.start) + 1, .operator); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, slice.ast.end }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, slice.ast.sentinel }); + try callWriteNodeTokens(allocator, .{ builder, slice.ast.end }); + try callWriteNodeTokens(allocator, .{ builder, slice.ast.sentinel }); }, .array_access => { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .deref => { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); try writeToken(builder, main_token, .operator); }, .unwrap_optional => { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); try writeToken(builder, main_token + 1, .operator); }, .grouped_expression => { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); }, .@"break", .@"continue", @@ -710,11 +720,11 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, main_token, .keyword); if (node_data[node].lhs != 0) try writeToken(builder, node_data[node].lhs, .label); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .@"suspend", .@"return" => { try writeToken(builder, main_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); }, .number_literal => { try writeToken(builder, main_token, .number); @@ -733,7 +743,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, main_token, .builtin); for (params) |param| - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, param }); + try callWriteNodeTokens(allocator, .{ builder, param }); }, .string_literal, .char_literal, @@ -765,7 +775,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, main_token, .keyword); try writeToken(builder, asm_node.volatile_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, asm_node.ast.template }); + try callWriteNodeTokens(allocator, .{ builder, asm_node.ast.template }); // TODO Inputs, outputs. }, .test_decl => { @@ -776,14 +786,14 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D if (token_tags[main_token + 1] == .string_literal) try writeToken(builder, main_token + 1, .string); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .@"catch" => { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); try writeToken(builder, main_token, .keyword); if (token_tags[main_token + 1] == .pipe) try writeToken(builder, main_token + 1, .variable); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .add, .add_wrap, @@ -835,43 +845,48 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .sub_sat, .@"orelse", => { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); const token_type: TokenType = switch (tag) { .bool_and, .bool_or, .@"orelse" => .keyword, else => .operator, }; try writeToken(builder, main_token, token_type); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].rhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].rhs }); }, .field_access => { const data = node_data[node]; if (data.rhs == 0) return; const rhs_str = ast.tokenSlice(tree, data.rhs) catch return; - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, data.lhs }); + try callWriteNodeTokens(allocator, .{ builder, data.lhs }); // TODO This is basically exactly the same as what is done in analysis.resolveTypeOfNode, with the added // writeToken code. // Maybe we can hook into it insead? Also applies to Identifier and VarDecl var bound_type_params = analysis.BoundTypeParams{}; const lhs_type = try analysis.resolveFieldAccessLhsType( - store, - arena, - (try analysis.resolveTypeOfNodeInternal(store, arena, .{ - .node = data.lhs, - .handle = handle, - }, &bound_type_params)) orelse return, + builder.store, + builder.arena, + (try analysis.resolveTypeOfNodeInternal( + builder.store, + builder.arena, + .{ .node = data.lhs, .handle = handle }, + &bound_type_params, + )) orelse return, &bound_type_params, ); const left_type_node = switch (lhs_type.type.data) { .other => |n| n, else => return, }; - if (try analysis.lookupSymbolContainer(store, arena, .{ - .node = left_type_node, - .handle = lhs_type.handle, - }, rhs_str, !lhs_type.type.is_type_val)) |decl_type| { + if (try analysis.lookupSymbolContainer( + builder.store, + builder.arena, + .{ .node = left_type_node, .handle = lhs_type.handle }, + rhs_str, + !lhs_type.type.is_type_val, + )) |decl_type| { switch (decl_type.decl.*) { .ast_node => |decl_node| { if (decl_type.handle.tree.nodes.items(.tag)[decl_node].isContainerField()) { @@ -891,7 +906,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D else => {}, } - if (try decl_type.resolveType(store, arena, &bound_type_params)) |resolved_type| { + if (try decl_type.resolveType(builder.store, builder.arena, &bound_type_params)) |resolved_type| { try colorIdentifierBasedOnType(builder, resolved_type, data.rhs, .{}); } } @@ -906,12 +921,12 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D if (ptr_type.size == .One and token_tags[main_token] == .asterisk_asterisk and main_token == main_tokens[ptr_type.ast.child_type]) { - return try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, ptr_type.ast.child_type }); + return try callWriteNodeTokens(allocator, .{ builder, ptr_type.ast.child_type }); } if (ptr_type.size == .One) try writeToken(builder, main_token, .operator); if (ptr_type.ast.sentinel != 0) { - return try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, ptr_type.ast.sentinel }); + return try callWriteNodeTokens(allocator, .{ builder, ptr_type.ast.sentinel }); } try writeToken(builder, ptr_type.allowzero_token, .keyword); @@ -919,19 +934,19 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D if (ptr_type.ast.align_node != 0) { const first_tok = tree.firstToken(ptr_type.ast.align_node); try writeToken(builder, first_tok - 2, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, ptr_type.ast.align_node }); + try callWriteNodeTokens(allocator, .{ builder, ptr_type.ast.align_node }); if (ptr_type.ast.bit_range_start != 0) { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, ptr_type.ast.bit_range_start }); + try callWriteNodeTokens(allocator, .{ builder, ptr_type.ast.bit_range_start }); try writeToken(builder, tree.firstToken(ptr_type.ast.bit_range_end - 1), .operator); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, ptr_type.ast.bit_range_end }); + try callWriteNodeTokens(allocator, .{ builder, ptr_type.ast.bit_range_end }); } } try writeToken(builder, ptr_type.const_token, .keyword); try writeToken(builder, ptr_type.volatile_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, ptr_type.ast.child_type }); + try callWriteNodeTokens(allocator, .{ builder, ptr_type.ast.child_type }); }, .array_type, .array_type_sentinel, @@ -941,10 +956,10 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D else tree.arrayTypeSentinel(node); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, array_type.ast.elem_count }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, array_type.ast.sentinel }); + try callWriteNodeTokens(allocator, .{ builder, array_type.ast.elem_count }); + try callWriteNodeTokens(allocator, .{ builder, array_type.ast.sentinel }); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, array_type.ast.elem_type }); + try callWriteNodeTokens(allocator, .{ builder, array_type.ast.elem_type }); }, .address_of, .bit_not, @@ -954,25 +969,27 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .negation_wrap, => { try writeToken(builder, main_token, .operator); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); }, .@"try", .@"resume", .@"await", => { try writeToken(builder, main_token, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, node_data[node].lhs }); + try callWriteNodeTokens(allocator, .{ builder, node_data[node].lhs }); }, .anyframe_literal => try writeToken(builder, main_token, .keyword), } } -fn writeContainerField(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *DocumentStore, node: Ast.Node.Index, field_token_type: ?TokenType, child_frame: anytype) !void { +fn writeContainerField(builder: *Builder, node: Ast.Node.Index, field_token_type: ?TokenType) !void { const tree = builder.handle.tree; const container_field = ast.containerField(tree, node).?; const base = tree.nodes.items(.main_token)[node]; const tokens = tree.tokens.items(.tag); + var allocator = builder.arena.allocator(); + if (analysis.getDocCommentTokenIndex(tokens, base)) |docs| try writeDocComments(builder, tree, docs); @@ -980,10 +997,10 @@ fn writeContainerField(builder: *Builder, arena: *std.heap.ArenaAllocator, store if (field_token_type) |tok_type| try writeToken(builder, container_field.ast.name_token, tok_type); if (container_field.ast.type_expr != 0) { - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, container_field.ast.type_expr }); + try callWriteNodeTokens(allocator, .{ builder, container_field.ast.type_expr }); if (container_field.ast.align_expr != 0) { try writeToken(builder, tree.firstToken(container_field.ast.align_expr) - 2, .keyword); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, container_field.ast.align_expr }); + try callWriteNodeTokens(allocator, .{ builder, container_field.ast.align_expr }); } } @@ -996,19 +1013,18 @@ fn writeContainerField(builder: *Builder, arena: *std.heap.ArenaAllocator, store break :block; try writeToken(builder, eq_tok, .operator); - try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, container_field.ast.value_expr }); + try callWriteNodeTokens(allocator, .{ builder, container_field.ast.value_expr }); } } // TODO Range version, edit version. pub fn writeAllSemanticTokens(arena: *std.heap.ArenaAllocator, store: *DocumentStore, handle: *DocumentStore.Handle, encoding: offsets.Encoding) ![]u32 { - var builder = Builder.init(arena.child_allocator, handle, encoding); - errdefer builder.arr.deinit(arena.child_allocator); + var builder = Builder.init(arena, store, handle, encoding); // reverse the ast from the root declarations var buf: [2]Ast.Node.Index = undefined; for (ast.declMembers(handle.tree, 0, &buf)) |child| { - writeNodeTokens(&builder, arena, store, child) catch |err| switch (err) { + writeNodeTokens(&builder, child) catch |err| switch (err) { error.MovedBackwards => break, else => |e| return e, }; diff --git a/src/translate_c.zig b/src/translate_c.zig index 3244686..32e1aa5 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const zig_builtin = @import("builtin"); const builtin = @import("builtin"); const Config = @import("Config.zig"); const ast = @import("ast.zig"); @@ -41,6 +42,20 @@ pub fn convertCInclude(allocator: std.mem.Allocator, tree: Ast, node: Ast.Node.I return output.toOwnedSlice(allocator); } +/// HACK self-hosted has not implemented async yet +fn callConvertCIncludeInternal(allocator: std.mem.Allocator, args: anytype) error{ OutOfMemory, Unsupported }!void { + if (zig_builtin.zig_backend == .other or zig_builtin.zig_backend == .stage1) { + const FrameSize = @sizeOf(@Frame(convertCIncludeInternal)); + var child_frame = try allocator.alignedAlloc(u8, std.Target.stack_align, FrameSize); + defer allocator.free(child_frame); + + return await @asyncCall(child_frame, {}, convertCIncludeInternal, args); + } else { + // TODO find a non recursive solution + return @call(.{}, convertCIncludeInternal, args); + } +} + fn convertCIncludeInternal( allocator: std.mem.Allocator, stack_allocator: std.mem.Allocator, @@ -55,12 +70,8 @@ fn convertCIncludeInternal( var buffer: [2]Ast.Node.Index = undefined; if (ast.isBlock(tree, node)) { - const FrameSize = @sizeOf(@Frame(convertCIncludeInternal)); - var child_frame = try stack_allocator.alignedAlloc(u8, std.Target.stack_align, FrameSize); - defer stack_allocator.free(child_frame); - for (ast.blockStatements(tree, node, &buffer).?) |statement| { - try await @asyncCall(child_frame, {}, convertCIncludeInternal, .{ allocator, stack_allocator, tree, statement, output }); + try callConvertCIncludeInternal(stack_allocator, .{ allocator, stack_allocator, tree, statement, output }); } } else if (ast.builtinCallParams(tree, node, &buffer)) |params| { if (params.len < 1) return; diff --git a/src/types.zig b/src/types.zig index f2d264b..497b64b 100644 --- a/src/types.zig +++ b/src/types.zig @@ -138,7 +138,7 @@ pub const Diagnostic = struct { code: ?string, source: ?string, message: string, - relatedInformation: ?[]const DiagnosticRelatedInformation = null, + relatedInformation: ?[]DiagnosticRelatedInformation = null, }; pub const TextDocument = struct { diff --git a/src/uri.zig b/src/uri.zig index 60a3cb1..2b65603 100644 --- a/src/uri.zig +++ b/src/uri.zig @@ -24,6 +24,8 @@ pub fn fromPath(allocator: std.mem.Allocator, path: []const u8) ![]const u8 { const prefix = if (builtin.os.tag == .windows) "file:///" else "file://"; var buf = std.ArrayListUnmanaged(u8){}; + errdefer buf.deinit(allocator); + try buf.appendSlice(allocator, prefix); for (path) |char| { diff --git a/tests/utility/position_context.zig b/tests/utility/position_context.zig index bdafa7c..0a867bc 100644 --- a/tests/utility/position_context.zig +++ b/tests/utility/position_context.zig @@ -249,10 +249,10 @@ fn freeDocument(doc: types.TextDocument) void { allocator.free(doc.text); } - -fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.PositionContext), comptime maybe_range: ?[]const u8) !void { - const cursor_idx = comptime std.mem.indexOf(u8, line, "").?; - const final_line = line[0..cursor_idx] ++ line[cursor_idx + "".len ..]; +fn testContext(line: []const u8, tag: std.meta.Tag(analysis.PositionContext), maybe_range: ?[]const u8) !void { + const cursor_idx = std.mem.indexOf(u8, line, "").?; + const final_line = try std.mem.concat(allocator, u8, &.{ line[0..cursor_idx], line[cursor_idx + "".len ..] }); + defer allocator.free(final_line); const doc = try makeDocument("", line); defer freeDocument(doc); @@ -264,7 +264,7 @@ fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.Po return error.DifferentTag; } - const actual_loc = ctx.loc() orelse if(maybe_range) |expected_range| { + const actual_loc = ctx.loc() orelse if (maybe_range) |expected_range| { std.debug.print("Expected `{s}`, got null range\n", .{ expected_range, }); @@ -277,14 +277,14 @@ fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.Po }); return error.DifferentRange; }; - - const expected_range_start = comptime std.mem.indexOf(u8, final_line, expected_range).?; + + const expected_range_start = std.mem.indexOf(u8, final_line, expected_range).?; const expected_range_end = expected_range_start + expected_range.len; if (expected_range_start != actual_loc.start or expected_range_end != actual_loc.end) { std.debug.print("Expected range `{s}` ({}..{}), got `{s}` ({}..{})\n", .{ doc.text[expected_range_start..expected_range_end], expected_range_start, expected_range_end, - doc.text[actual_loc.start..actual_loc.end], actual_loc.start, actual_loc.end, + doc.text[actual_loc.start..actual_loc.end], actual_loc.start, actual_loc.end, }); return error.DifferentRange; }