diff --git a/src/Server.zig b/src/Server.zig index 7825cd8..cb7df43 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -299,17 +299,8 @@ fn publishDiagnostics(server: *Server, writer: anytype, handle: DocumentStore.Ha if (!std.mem.eql(u8, call_name, "@import")) continue; - const node_data = tree.nodes.items(.data)[node]; - const params = switch (tree.nodes.items(.tag)[node]) { - .builtin_call, .builtin_call_comma => tree.extra_data[node_data.lhs..node_data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (node_data.lhs == 0) - &[_]Ast.Node.Index{} - else if (node_data.rhs == 0) - &[_]Ast.Node.Index{node_data.lhs} - else - &[_]Ast.Node.Index{ node_data.lhs, node_data.rhs }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const params = ast.builtinCallParams(tree, node, &buffer).?; if (params.len != 1) continue; diff --git a/src/analysis.zig b/src/analysis.zig index 235604c..c9c99f6 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -203,7 +203,7 @@ pub fn hasSelfParam(arena: *std.heap.ArenaAllocator, document_store: *DocumentSt return true; } - if (isPtrType(tree, param.type_expr)) { + if (ast.isPtrType(tree, param.type_expr)) { if (try resolveTypeOfNode(document_store, arena, .{ .node = token_data[param.type_expr].rhs, .handle = handle, @@ -311,13 +311,6 @@ fn getDeclName(tree: Ast, node: Ast.Node.Index) ?[]const u8 { }; } -fn isContainerDecl(decl_handle: DeclWithHandle) bool { - return switch (decl_handle.decl.*) { - .ast_node => |inner_node| ast.isContainer(decl_handle.handle.tree.nodes.items(.tag)[inner_node]), - else => false, - }; -} - fn resolveVarDeclAliasInternal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle, root: bool) error{OutOfMemory}!?DeclWithHandle { _ = root; const handle = node_handle.handle; @@ -394,39 +387,14 @@ pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocato return null; } -fn isBlock(tree: Ast, node: Ast.Node.Index) bool { - return switch (tree.nodes.items(.tag)[node]) { - .block, - .block_semicolon, - .block_two, - .block_two_semicolon, - => true, - else => false, - }; -} - fn findReturnStatementInternal(tree: Ast, fn_decl: Ast.full.FnProto, body: Ast.Node.Index, already_found: *bool) ?Ast.Node.Index { var result: ?Ast.Node.Index = null; const node_tags = tree.nodes.items(.tag); const datas = tree.nodes.items(.data); - if (!isBlock(tree, body)) return null; - - const statements: []const Ast.Node.Index = switch (node_tags[body]) { - .block, .block_semicolon => tree.extra_data[datas[body].lhs..datas[body].rhs], - .block_two, .block_two_semicolon => blk: { - const statements = &[_]Ast.Node.Index{ datas[body].lhs, datas[body].rhs }; - const len: usize = if (datas[body].lhs == 0) - @as(usize, 0) - else if (datas[body].rhs == 0) - @as(usize, 1) - else - @as(usize, 2); - break :blk statements[0..len]; - }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const statements = ast.blockStatements(tree, body, &buffer) orelse return null; for (statements) |child_idx| { if (node_tags[child_idx] == .@"return") { @@ -532,17 +500,6 @@ fn resolveUnwrapErrorType(store: *DocumentStore, arena: *std.heap.ArenaAllocator return null; } -pub fn isPtrType(tree: Ast, node: Ast.Node.Index) bool { - return switch (tree.nodes.items(.tag)[node]) { - .ptr_type, - .ptr_type_aligned, - .ptr_type_bit_range, - .ptr_type_sentinel, - => true, - else => false, - }; -} - /// Resolves the child type of a deref type fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, deref: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { const deref_node = switch (deref.type.data) { @@ -560,7 +517,7 @@ fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, dere const main_token = tree.nodes.items(.main_token)[deref_node]; const token_tag = tree.tokens.items(.tag)[main_token]; - if (isPtrType(tree, deref_node)) { + if (ast.isPtrType(tree, deref_node)) { const ptr_type = ast.ptrType(tree, deref_node).?; switch (token_tag) { .asterisk => { @@ -900,17 +857,8 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl .builtin_call_two, .builtin_call_two_comma, => { - const data = datas[node]; - const params = switch (node_tags[node]) { - .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) - &[_]Ast.Node.Index{} - else if (data.rhs == 0) - &[_]Ast.Node.Index{data.lhs} - else - &[_]Ast.Node.Index{ data.lhs, data.rhs }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const params = ast.builtinCallParams(tree, node, &buffer).?; const call_name = tree.tokenSlice(main_tokens[node]); if (std.mem.eql(u8, call_name, "@This")) { @@ -1399,17 +1347,9 @@ pub fn getImportStr(tree: Ast, node: Ast.Node.Index, source_index: usize) ?[]con const call_name = tree.tokenSlice(builtin_token); if (!std.mem.eql(u8, call_name, "@import")) return null; - const data = tree.nodes.items(.data)[node]; - const params = switch (node_tags[node]) { - .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) - &[_]Ast.Node.Index{} - else if (data.rhs == 0) - &[_]Ast.Node.Index{data.lhs} - else - &[_]Ast.Node.Index{ data.lhs, data.rhs }, - else => unreachable, - }; + + var buffer: [2]Ast.Node.Index = undefined; + const params = ast.builtinCallParams(tree, node, &buffer).?; if (params.len != 1) return null; @@ -2522,21 +2462,8 @@ fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx: } } - const container_decl = switch (node_tag) { - .container_decl, .container_decl_trailing => tree.containerDecl(node_idx), - .container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node_idx), - .container_decl_two, .container_decl_two_trailing => blk: { - var buffer: [2]Ast.Node.Index = undefined; - break :blk tree.containerDeclTwo(&buffer, node_idx); - }, - .tagged_union, .tagged_union_trailing => tree.taggedUnion(node_idx), - .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => tree.taggedUnionEnumTag(node_idx), - .tagged_union_two, .tagged_union_two_trailing => blk: { - var buffer: [2]Ast.Node.Index = undefined; - break :blk tree.taggedUnionTwo(&buffer, node_idx); - }, - else => null, - }; + var buffer: [2]Ast.Node.Index = undefined; + const container_decl = ast.containerDecl(tree, node_idx, &buffer); // Only tagged unions and enums should pass this const can_have_enum_completions = if (container_decl) |container| blk: { @@ -2717,20 +2644,8 @@ fn makeScopeInternal(allocator: std.mem.Allocator, context: ScopeContext, node_i uses.deinit(); } - const statements: []const Ast.Node.Index = switch (node_tag) { - .block, .block_semicolon => tree.extra_data[data[node_idx].lhs..data[node_idx].rhs], - .block_two, .block_two_semicolon => blk: { - const statements = &[_]Ast.Node.Index{ data[node_idx].lhs, data[node_idx].rhs }; - const len: usize = if (data[node_idx].lhs == 0) - @as(usize, 0) - else if (data[node_idx].rhs == 0) - @as(usize, 1) - else - @as(usize, 2); - break :blk statements[0..len]; - }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const statements = ast.blockStatements(tree, node_idx, &buffer).?; for (statements) |idx| { if (tags[idx] == .@"usingnamespace") { @@ -3058,17 +2973,8 @@ fn makeScopeInternal(allocator: std.mem.Allocator, context: ScopeContext, node_i .builtin_call_two, .builtin_call_two_comma, => { - const b_data = data[node_idx]; - const params = switch (node_tag) { - .builtin_call, .builtin_call_comma => tree.extra_data[b_data.lhs..b_data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (b_data.lhs == 0) - &[_]Ast.Node.Index{} - else if (b_data.rhs == 0) - &[_]Ast.Node.Index{b_data.lhs} - else - &[_]Ast.Node.Index{ b_data.lhs, b_data.rhs }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const params = ast.builtinCallParams(tree, node_idx, &buffer).?; for (params) |param| { try makeScopeInternal(allocator, context, param); diff --git a/src/ast.zig b/src/ast.zig index 727a289..b5b66ce 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -948,6 +948,18 @@ pub fn isContainer(tree: Ast, node: Ast.Node.Index) bool { }; } +pub fn containerDecl(tree: Ast, node_idx: Ast.Node.Index, buffer: *[2]Ast.Node.Index) ?full.ContainerDecl { + return switch (tree.nodes.items(.tag)[node_idx]) { + .container_decl, .container_decl_trailing => tree.containerDecl(node_idx), + .container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node_idx), + .container_decl_two, .container_decl_two_trailing => tree.containerDeclTwo(buffer, node_idx), + .tagged_union, .tagged_union_trailing => tree.taggedUnion(node_idx), + .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => tree.taggedUnionEnumTag(node_idx), + .tagged_union_two, .tagged_union_two_trailing => tree.taggedUnionTwo(buffer, node_idx), + else => null, + }; +} + /// Returns the member indices of a given declaration container. /// Asserts given `tag` is a container node pub fn declMembers(tree: Ast, node_idx: Ast.Node.Index, buffer: *[2]Ast.Node.Index) []const Ast.Node.Index { @@ -977,6 +989,17 @@ pub fn varDecl(tree: Ast, node_idx: Ast.Node.Index) ?Ast.full.VarDecl { }; } +pub fn isPtrType(tree: Ast, node: Ast.Node.Index) bool { + return switch (tree.nodes.items(.tag)[node]) { + .ptr_type, + .ptr_type_aligned, + .ptr_type_bit_range, + .ptr_type_sentinel, + => true, + else => false, + }; +} + pub fn isBuiltinCall(tree: Ast, node: Ast.Node.Index) bool { return switch (tree.nodes.items(.tag)[node]) { .builtin_call, @@ -1003,6 +1026,17 @@ pub fn isCall(tree: Ast, node: Ast.Node.Index) bool { }; } +pub fn isBlock(tree: Ast, node: Ast.Node.Index) bool { + return switch (tree.nodes.items(.tag)[node]) { + .block_two, + .block_two_semicolon, + .block, + .block_semicolon, + => true, + else => false, + }; +} + pub fn fnProto(tree: Ast, node: Ast.Node.Index, buf: *[1]Ast.Node.Index) ?Ast.full.FnProto { return switch (tree.nodes.items(.tag)[node]) { .fn_proto => tree.fnProto(node), @@ -1029,3 +1063,47 @@ pub fn callFull(tree: Ast, node: Ast.Node.Index, buf: *[1]Ast.Node.Index) ?Ast.f else => null, }; } + +/// returns a list of parameters +pub fn builtinCallParams(tree: Ast, node: Ast.Node.Index, buf: *[2]Ast.Node.Index) ?[]const Node.Index { + const node_data = tree.nodes.items(.data); + return switch (tree.nodes.items(.tag)[node]) { + .builtin_call_two, .builtin_call_two_comma => { + buf[0] = node_data[node].lhs; + buf[1] = node_data[node].rhs; + if (node_data[node].lhs == 0) { + return buf[0..0]; + } else if (node_data[node].rhs == 0) { + return buf[0..1]; + } else { + return buf[0..2]; + } + }, + .builtin_call, + .builtin_call_comma, + => tree.extra_data[node_data[node].lhs..node_data[node].rhs], + else => return null, + }; +} + +/// returns a list of statements +pub fn blockStatements(tree: Ast, node: Ast.Node.Index, buf: *[2]Ast.Node.Index) ?[]const Node.Index { + const node_data = tree.nodes.items(.data); + return switch (tree.nodes.items(.tag)[node]) { + .block_two, .block_two_semicolon => { + buf[0] = node_data[node].lhs; + buf[1] = node_data[node].rhs; + if (node_data[node].lhs == 0) { + return buf[0..0]; + } else if (node_data[node].rhs == 0) { + return buf[0..1]; + } else { + return buf[0..2]; + } + }, + .block, + .block_semicolon, + => tree.extra_data[node_data[node].lhs..node_data[node].rhs], + else => return null, + }; +} diff --git a/src/inlay_hints.zig b/src/inlay_hints.zig index 9ba7965..8215e26 100644 --- a/src/inlay_hints.zig +++ b/src/inlay_hints.zig @@ -133,7 +133,7 @@ fn writeCallHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *Doc } /// takes parameter nodes from the ast and function parameter names from `Builtin.arguments` and writes parameter hints into `builder.hints` -fn writeBuiltinHint(builder: *Builder, parameters: []Ast.Node.Index, arguments: []const []const u8) !void { +fn writeBuiltinHint(builder: *Builder, parameters: []const Ast.Node.Index, arguments: []const []const u8) !void { if (parameters.len == 0) return; const handle = builder.handle; @@ -290,25 +290,9 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .builtin_call_comma, => { var buffer: [2]Ast.Node.Index = undefined; - const parameters: []Ast.Node.Index = switch (tag) { - .builtin_call_two, .builtin_call_two_comma => blk: { - buffer[0] = node_data[node].lhs; - buffer[1] = node_data[node].rhs; + const params = ast.builtinCallParams(tree, node, &buffer).?; - var size: usize = 0; - - if (node_data[node].rhs != 0) { - size = 2; - } else if (node_data[node].lhs != 0) { - size = 1; - } - break :blk buffer[0..size]; - }, - .builtin_call, .builtin_call_comma => tree.extra_data[node_data[node].lhs..node_data[node].rhs], - else => unreachable, - }; - - if (builder.config.inlay_hints_show_builtin and parameters.len > 1) { + if (builder.config.inlay_hints_show_builtin and params.len > 1) { const name = tree.tokenSlice(main_tokens[node]); outer: for (data.builtins) |builtin| { @@ -318,12 +302,12 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: if (std.mem.eql(u8, builtin_name, name)) break :outer; } - try writeBuiltinHint(builder, parameters, builtin.arguments); + try writeBuiltinHint(builder, params, builtin.arguments); } } - for (parameters) |param| { - if (parameters.len > inlay_hints_max_inline_children) { + for (params) |param| { + if (params.len > inlay_hints_max_inline_children) { if (!isNodeInRange(tree, param, range)) continue; } @@ -623,15 +607,7 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .tagged_union_enum_tag_trailing, => { var buffer: [2]Ast.Node.Index = undefined; - const decl: Ast.full.ContainerDecl = switch (tag) { - .container_decl, .container_decl_trailing => tree.containerDecl(node), - .container_decl_two, .container_decl_two_trailing => tree.containerDeclTwo(&buffer, node), - .container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node), - .tagged_union, .tagged_union_trailing => tree.taggedUnion(node), - .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => tree.taggedUnionEnumTag(node), - .tagged_union_two, .tagged_union_two_trailing => tree.taggedUnionTwo(&buffer, node), - else => unreachable, - }; + const decl: Ast.full.ContainerDecl = ast.containerDecl(tree, node, &buffer).?; try await @asyncCall(child_frame, {}, writeNodeInlayHint, .{ builder, arena, store, decl.ast.arg, range }); diff --git a/src/references.zig b/src/references.zig index fbd290f..52507c2 100644 --- a/src/references.zig +++ b/src/references.zig @@ -67,20 +67,9 @@ fn symbolReferencesInternal(arena: *std.heap.ArenaAllocator, store: *DocumentSto switch (node_tags[node]) { .block, .block_semicolon, .block_two, .block_two_semicolon => { - const statements: []const Ast.Node.Index = switch (node_tags[node]) { - .block, .block_semicolon => tree.extra_data[datas[node].lhs..datas[node].rhs], - .block_two, .block_two_semicolon => blk: { - const statements = &[_]Ast.Node.Index{ datas[node].lhs, datas[node].rhs }; - const len: usize = if (datas[node].lhs == 0) - @as(usize, 0) - else if (datas[node].rhs == 0) - @as(usize, 1) - else - @as(usize, 2); - break :blk statements[0..len]; - }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const statements = ast.blockStatements(tree, node, &buffer).?; + for (statements) |stmt| try symbolReferencesInternal(arena, store, .{ .node = stmt, .handle = handle }, decl, encoding, context, handler); }, @@ -319,13 +308,10 @@ fn symbolReferencesInternal(arena: *std.heap.ArenaAllocator, store: *DocumentSto .async_call_comma, .async_call_one, .async_call_one_comma, - => |c| { + => { var buf: [1]Ast.Node.Index = undefined; - const call: Ast.full.Call = switch (c) { - .call, .call_comma, .async_call, .async_call_comma => tree.callFull(node), - .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => tree.callOne(&buf, node), - else => unreachable, - }; + const call = ast.callFull(tree, node, &buf).?; + if (call.ast.fn_expr != 0) try symbolReferencesInternal(arena, store, .{ .node = call.ast.fn_expr, .handle = handle }, decl, encoding, context, handler); @@ -380,18 +366,9 @@ fn symbolReferencesInternal(arena: *std.heap.ArenaAllocator, store: *DocumentSto .builtin_call_comma, .builtin_call_two, .builtin_call_two_comma, - => |builtin_tag| { - const data = datas[node]; - const params = switch (builtin_tag) { - .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) - &[_]Ast.Node.Index{} - else if (data.rhs == 0) - &[_]Ast.Node.Index{data.lhs} - else - &[_]Ast.Node.Index{ data.lhs, data.rhs }, - else => unreachable, - }; + => { + var buffer: [2]Ast.Node.Index = undefined; + const params = ast.builtinCallParams(tree, node, &buffer).?; for (params) |param| try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler); diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index 301458e..384beaa 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -317,20 +317,8 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D try writeToken(builder, main_token - 2, .label); } - const statements: []const Ast.Node.Index = switch (tag) { - .block, .block_semicolon => tree.extra_data[node_data[node].lhs..node_data[node].rhs], - .block_two, .block_two_semicolon => blk: { - const statements = &[_]Ast.Node.Index{ node_data[node].lhs, node_data[node].rhs }; - const len: usize = if (node_data[node].lhs == 0) - @as(usize, 0) - else if (node_data[node].rhs == 0) - @as(usize, 1) - else - @as(usize, 2); - break :blk statements[0..len]; - }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const statements = ast.blockStatements(tree, node, &buffer).?; for (statements) |child| { if (node_tags[child].isContainerField()) { @@ -390,15 +378,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .tagged_union_two_trailing, => { var buf: [2]Ast.Node.Index = undefined; - const decl: Ast.full.ContainerDecl = switch (tag) { - .container_decl, .container_decl_trailing => tree.containerDecl(node), - .container_decl_two, .container_decl_two_trailing => tree.containerDeclTwo(&buf, node), - .container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node), - .tagged_union, .tagged_union_trailing => tree.taggedUnion(node), - .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => tree.taggedUnionEnumTag(node), - .tagged_union_two, .tagged_union_two_trailing => tree.taggedUnionTwo(&buf, node), - else => unreachable, - }; + const decl: Ast.full.ContainerDecl = ast.containerDecl(tree, node, &buf).?; try writeToken(builder, decl.layout_token, .keyword); try writeToken(builder, decl.ast.main_token, .keyword); @@ -427,7 +407,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .identifier => { const name = tree.getNodeSource(node); - if(std.mem.eql(u8,name, "undefined")) { + if (std.mem.eql(u8, name, "undefined")) { return try writeToken(builder, main_token, .keywordLiteral); } else if (analysis.isTypeIdent(name)) { return try writeToken(builder, main_token, .type); @@ -682,11 +662,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .async_call_one_comma, => { var params: [1]Ast.Node.Index = undefined; - const call: Ast.full.Call = switch (tag) { - .call, .call_comma, .async_call, .async_call_comma => tree.callFull(node), - .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => tree.callOne(¶ms, node), - else => unreachable, - }; + 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 }); @@ -757,17 +733,8 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .builtin_call_two, .builtin_call_two_comma, => { - const data = node_data[node]; - const params = switch (tag) { - .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) - &[_]Ast.Node.Index{} - else if (data.rhs == 0) - &[_]Ast.Node.Index{data.lhs} - else - &[_]Ast.Node.Index{ data.lhs, data.rhs }, - else => unreachable, - }; + var buffer: [2]Ast.Node.Index = undefined; + const params = ast.builtinCallParams(tree, node, &buffer).?; try writeToken(builder, main_token, .builtin); for (params) |param|