Progress in makeScopeInternal

This commit is contained in:
Luuk de Gram 2021-02-27 21:55:39 +01:00
parent 72605c7549
commit 5f5d6ce4ea
No known key found for this signature in database
GPG Key ID: A002B174963DBB7D

View File

@ -1542,6 +1542,8 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: ast.Tree, nod
.container_field, .container_field,
.container_field_align, .container_field_align,
.container_field_init, .container_field_init,
.tagged_union_enum_tag,
.tagged_union_enum_tag_trailing,
=> .Field, => .Field,
else => .Variable, else => .Variable,
}, },
@ -1558,7 +1560,8 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: ast.Tree, nod
}; };
var index: usize = 0; var index: usize = 0;
try addOutlineNodes(allocator, tree, node, &child_context); if (true) @panic("FIX: addOutlineNodes");
// try addOutlineNodes(allocator, tree, node, &child_context);
// while (node.iterate(index)) |child| : (index += 1) { // while (node.iterate(index)) |child| : (index += 1) {
// try addOutlineNodes(allocator, tree, child, &child_context); // try addOutlineNodes(allocator, tree, child, &child_context);
@ -1590,8 +1593,8 @@ pub const Declaration = union(enum) {
/// Function parameter /// Function parameter
param_decl: ast.full.FnProto.Param, param_decl: ast.full.FnProto.Param,
pointer_payload: struct { pointer_payload: struct {
node: ast.full.PtrType, name: ast.TokenIndex,
condition: *ast.Node, condition: ast.Node.Index,
}, },
array_payload: struct { array_payload: struct {
identifier: *ast.Node, identifier: *ast.Node,
@ -1602,7 +1605,7 @@ pub const Declaration = union(enum) {
switch_expr: *ast.Node, switch_expr: *ast.Node,
items: []const *ast.Node, items: []const *ast.Node,
}, },
label_decl: *ast.Node, // .id is While, For or Block (firstToken will be the label) label_decl: ast.TokenIndex, // .id is While, For or Block (firstToken will be the label)
}; };
pub const DeclWithHandle = struct { pub const DeclWithHandle = struct {
@ -2145,7 +2148,7 @@ fn isContainer(tag: ast.Node.Tag) bool {
/// Returns the member indices of a given declaration container. /// Returns the member indices of a given declaration container.
/// Asserts given `tag` is a container node /// Asserts given `tag` is a container node
fn declMembers(tree: ast.Tree, tag: ast.Node.Tag) []ast.Node.index { fn declMembers(tree: ast.Tree, tag: ast.Node.Tag, node_idx: ast.Node.Index) []const ast.Node.Index {
std.debug.assert(isContainer(tag)); std.debug.assert(isContainer(tag));
return switch (tag) { return switch (tag) {
.container_decl, .container_decl_trailing => tree.containerDecl(node_idx).ast.members, .container_decl, .container_decl_trailing => tree.containerDecl(node_idx).ast.members,
@ -2167,6 +2170,18 @@ fn declMembers(tree: ast.Tree, tag: ast.Node.Tag) []ast.Node.index {
}; };
} }
/// Returns an `ast.full.VarDecl` for a given node index.
/// Returns null if the tag doesn't match
fn varDecl(tree: ast.Tree, node_idx: ast.Node.Index) ?ast.full.VarDecl {
return switch (tree.nodes.items(.tag)[node_idx]) {
.global_var_decl => tree.globalVarDecl(node_idx),
.local_var_decl => tree.localVarDecl(node_idx),
.aligned_var_decl => tree.alignedVarDecl(node_idx),
.simple_var_decl => tree.simpleVarDecl(node_idx),
else => null,
};
}
// TODO Possibly collect all imports to diff them on changes // TODO Possibly collect all imports to diff them on changes
// as well // as well
fn makeScopeInternal( fn makeScopeInternal(
@ -2179,16 +2194,18 @@ fn makeScopeInternal(
) error{OutOfMemory}!void { ) error{OutOfMemory}!void {
const tags = tree.nodes.items(.tag); const tags = tree.nodes.items(.tag);
const token_tags = tree.tokens.items(.tag); const token_tags = tree.tokens.items(.tag);
const data = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const node = tags[node_idx]; const node = tags[node_idx];
if (isContainer(node)) { if (isContainer(node)) {
const ast_decls = declMembers(tree, node); const ast_decls = declMembers(tree, node, node_idx);
(try scopes.addOne(allocator)).* = .{ (try scopes.addOne(allocator)).* = .{
.range = nodeSourceRange(tree, node_idx), .range = nodeSourceRange(tree, node_idx),
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .{ .container = node_idx }, .data = .{ .container = node_idx },
}; };
const scope_idx = scopes.items.len - 1; const scope_idx = scopes.items.len - 1;
@ -2227,7 +2244,7 @@ fn makeScopeInternal(
}; };
} }
const container_field: ?ast.full.ContainerField = switch (decl) { const container_field: ?ast.full.ContainerField = switch (tags[decl]) {
.container_field => tree.containerField(decl), .container_field => tree.containerField(decl),
.container_field_align => tree.containerFieldAlign(decl), .container_field_align => tree.containerFieldAlign(decl),
.container_field_init => tree.containerFieldInit(decl), .container_field_init => tree.containerFieldInit(decl),
@ -2235,7 +2252,7 @@ fn makeScopeInternal(
}; };
if (container_field) |field| { if (container_field) |field| {
const empty_field = field.type_expr == 0 and field.value_expr == 0; const empty_field = field.ast.type_expr == 0 and field.ast.value_expr == 0;
if (empty_field and node == .root) { if (empty_field and node == .root) {
continue; continue;
} }
@ -2250,7 +2267,7 @@ fn makeScopeInternal(
}, },
.tagged_union, .tagged_union_trailing => tree.taggedUnion(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_enum_tag, .tagged_union_enum_tag_trailing => tree.taggedUnionEnumTag(node_idx),
.tagged_union_enum_tag, .tagged_union_enum_tag_trailing => blk: { .tagged_union_two, .tagged_union_two_trailing => blk: {
var buffer: [2]ast.Node.Index = undefined; var buffer: [2]ast.Node.Index = undefined;
break :blk tree.taggedUnionTwo(&buffer, node_idx); break :blk tree.taggedUnionTwo(&buffer, node_idx);
}, },
@ -2287,44 +2304,56 @@ fn makeScopeInternal(
} }
switch (node) { switch (node) {
.FnProto => { .fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => {
const func = node.castTag(.FnProto).?; var buf: [1]ast.Node.Index = undefined;
const func: ast.full.FnProto = switch (node) {
.fn_proto => tree.fnProto(node_idx),
.fn_proto_one => tree.fnProtoOne(&buf, node_idx),
.fn_proto_simple => tree.fnProtoSimple(&buf, node_idx),
.fn_proto_multi => tree.fnProtoMulti(node_idx),
.fn_decl => tree.fnProto(data[node_idx].lhs),
else => unreachable,
};
(try scopes.addOne(allocator)).* = .{ (try scopes.addOne(allocator)).* = .{
.range = nodeSourceRange(tree, node), .range = nodeSourceRange(tree, node_idx),
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .{ .function = node }, .data = .{ .function = node },
}; };
var scope_idx = scopes.items.len - 1; var scope_idx = scopes.items.len - 1;
errdefer scopes.items[scope_idx].decls.deinit(); errdefer scopes.items[scope_idx].decls.deinit();
for (func.params()) |*param| { var it = func.iterate(tree);
if (param.name_token) |name_tok| { while (it.next()) |param| {
if (try scopes.items[scope_idx].decls.fetchPut(tree.tokenSlice(name_tok), .{ .param_decl = param })) |existing| { if (param.name_token) |name_token| {
// TODO Record a redefinition error if (try scopes.items[scope_idx].decls.fetchPut(tree.tokenSlice(name_token), .{ .param_decl = param })) |existing| {
// TODO record a redefinition error
} }
} }
} }
if (func.getBodyNode()) |body| { if (node == .fn_decl) {
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, body); try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs);
} }
return; return;
}, },
.TestDecl => { .test_decl => {
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.castTag(.TestDecl).?.body_node); return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs);
}, },
.LabeledBlock => { .block, .block_semicolon, .block_two, .block_two_semicolon => {
const block = node.castTag(.LabeledBlock).?; const first_token = tree.firstToken(node_idx);
std.debug.assert(tree.token_ids[block.label] == .Identifier); const last_token = tree.lastToken(node_idx);
var scope = try scopes.addOne(allocator);
// if labeled block
if (token_tags[first_token] == .identifier) {
const scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{
.start = tree.token_locs[block.lbrace].start, .start = tree.tokenLocation(main_tokens[node_idx]).line_start,
.end = tree.token_locs[block.rbrace].end, .end = tree.tokenLocation(@truncate(u32, start), last_token).line_start,
}, },
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
@ -2332,17 +2361,15 @@ fn makeScopeInternal(
.data = .other, .data = .other,
}; };
errdefer scope.decls.deinit(); errdefer scope.decls.deinit();
try scopes.items[scope_idx].decls.putNoClobber(tree.tokenSlice(first_token), .{ .label_decl = first_token });
try scope.decls.putNoClobber(tree.tokenSlice(block.label), .{ }
.label_decl = node,
});
(try scopes.addOne(allocator)).* = .{ (try scopes.addOne(allocator)).* = .{
.range = nodeSourceRange(tree, node), .range = nodeSourceRange(tree, node_idx),
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .{ .block = node }, .data = .{ .block = node_idx },
}; };
var scope_idx = scopes.items.len - 1; var scope_idx = scopes.items.len - 1;
// var uses = std.ArrayList(*ast.Node.Use).init(allocator); // var uses = std.ArrayList(*ast.Node.Use).init(allocator);
@ -2352,18 +2379,23 @@ fn makeScopeInternal(
// uses.deinit(); // uses.deinit();
} }
var child_idx: usize = 0; const statements: []const ast.Node.Index = switch (node) {
while (node.iterate(child_idx)) |child_node| : (child_idx += 1) { .block, .block_semicolon => tree.extra_data[data[node_idx].lhs..data[node_idx].rhs],
// if (child_node.castTag(.Use)) |use| { .block_two, .block_two_semicolon => blk: {
// try uses.append(use); const statements = [2]ast.Node.Index{ data[node_idx].lhs, data[node_idx].rhs };
// continue; const len: usize = if (data[node_idx].lhs == 0) 0 else if (data[node_idx].rhs == 0) 1 else 2;
// } break :blk statements[0..len];
},
else => unreachable,
};
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node); for (statements[0..len]) |idx| {
if (child_node.castTag(.VarDecl)) |var_decl| { try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, idx);
const name = tree.tokenSlice(var_decl.name_token); // if (tags[
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| { if (varDecl(idx)) |var_decl| {
// TODO Record a redefinition error. const name = tree.tokenSlice(var_decl.ast.mut_token + 1);
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = idx })) |existing| {
// TODO record a redefinition error.
} }
} }
} }
@ -2371,171 +2403,139 @@ fn makeScopeInternal(
// scopes.items[scope_idx].uses = uses.toOwnedSlice(); // scopes.items[scope_idx].uses = uses.toOwnedSlice();
return; return;
}, },
.Block => { .@"comptime", .@"nosuspend" => {
const block = node.castTag(.Block).?; return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].lhs);
(try scopes.addOne(allocator)).* = .{
.range = nodeSourceRange(tree, node),
.decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{},
.data = .{ .block = node },
};
var scope_idx = scopes.items.len - 1;
// var uses = std.ArrayList(*ast.Node.Use).init(allocator);
errdefer {
scopes.items[scope_idx].decls.deinit();
// uses.deinit();
}
var child_idx: usize = 0;
while (node.iterate(child_idx)) |child_node| : (child_idx += 1) {
// if (child_node.castTag(.Use)) |use| {
// try uses.append(use);
// continue;
// }
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node);
if (child_node.castTag(.VarDecl)) |var_decl| {
const name = tree.tokenSlice(var_decl.name_token);
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| {
// TODO Record a redefinition error.
}
}
}
// scopes.items[scope_idx].uses = uses.toOwnedSlice();
return;
}, },
.Comptime => { .@"if", .if_simple => {
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.castTag(.Comptime).?.expr); const if_node: ast.full.If = if (node == .@"if")
}, tree.ifFull(node_idx)
.If => { else
const if_node = node.castTag(.If).?; tree.ifSimple(node_idx);
if (if_node.payload) |payload| { if (if_node.payload_token) |payload| {
std.debug.assert(payload.tag == .PointerPayload);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{
.start = tree.token_locs[payload.firstToken()].start, .start = tree.tokenLocation(0, payload).line_start,
.end = tree.token_locs[if_node.body.lastToken()].end, .end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(if_node.ast.then_expr)).line_end,
}, },
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .other, .data = .other,
}; };
errdefer scope.decls.deinit(); errdefer scope.decls.deinit();
const ptr_payload = payload.castTag(.PointerPayload).?; const name_token = payload + @boolToInt(token_tags[payload] == .asterisk);
std.debug.assert(ptr_payload.value_symbol.tag == .Identifier); std.debug.assert(token_tags[name_token] == .identifier);
const name = tree.tokenSlice(ptr_payload.value_symbol.firstToken());
const name = tree.tokenSlice(name_token);
try scope.decls.putNoClobber(name, .{ try scope.decls.putNoClobber(name, .{
.pointer_payload = .{ .pointer_payload = .{
.node = ptr_payload, .name = name_token,
.condition = if_node.condition, .condition = if_node.ast.cond_expr,
}, },
}); });
} }
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.body);
if (if_node.@"else") |else_node| { try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.ast.then_expr);
if (else_node.payload) |payload| {
std.debug.assert(payload.tag == .Payload); if (if_node.ast.else_expr != 0) {
if (if_node.error_token) |err_token| {
std.debug.assert(token_tags[err_token] == .identifier);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{
.start = tree.token_locs[payload.firstToken()].start, .start = tree.tokenLocation(0, err_token).line_start,
.end = tree.token_locs[else_node.body.lastToken()].end, .end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(if_node.ast.else_expr)).line_end,
}, },
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .other, .data = .other,
}; };
errdefer scope.decls.deinit(); errdefer scope.decls.deinit();
const err_payload = payload.castTag(.Payload).?; const name = tree.tokenSlice(err_token);
std.debug.assert(err_payload.error_symbol.tag == .Identifier); try scope.decls.putNoClobber(name, .{ .ast_node = if_node.ast.else_expr });
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
} }
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body); try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.ast.else_expr);
} }
}, },
.While => { .@"while", .while_simple, .while_cont, .@"for", .for_simple => {
const while_node = node.castTag(.While).?; const while_node: ast.full.While = switch (node) {
if (while_node.label) |label| { .@"while" => tree.whileFull(node_idx),
std.debug.assert(tree.token_ids[label] == .Identifier); .while_simple => tree.whileSimple(node_idx),
.while_cont => tree.whileCont(node_idx),
.@"for" => tree.forFull(node_idx),
.for_simple => tree.forSimple(node_idx),
else => unreachable,
};
if (while_node.label_token) |label| {
std.debug.assert(tags[label] == .identifier);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{
.start = tree.token_locs[while_node.while_token].start, .start = tree.tokenLocation(0, main_tokens[node_idx]).line_start,
.end = tree.token_locs[while_node.lastToken()].end, .end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(while_node.ast.then_expr)).line_end,
}, },
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .other, .data = .other,
}; };
errdefer scope.decls.deinit(); errdefer scope.decls.deinit();
try scope.decls.putNoClobber(tree.tokenSlice(label), .{ try scope.decls.putNoClobber(tree.tokenSlice(label), .{ .label_decl = label });
.label_decl = node,
});
} }
if (while_node.payload) |payload| { if (while_node.payload_token) |payload| {
std.debug.assert(payload.tag == .PointerPayload);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{
.start = tree.token_locs[payload.firstToken()].start, .start = tree.tokenLocation(0, payload).line_start,
.end = tree.token_locs[while_node.body.lastToken()].end, .end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(while_node.ast.then_exp)).line_end,
}, },
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .other, .data = .other,
}; };
errdefer scope.decls.deinit(); errdefer scope.decls.deinit();
const ptr_payload = payload.castTag(.PointerPayload).?; const name_token = payload + @boolToInt(token_tags[payload] == .asterisk);
std.debug.assert(ptr_payload.value_symbol.tag == .Identifier); std.debug.assert(token_tags[name_token] == .identifier);
const name = tree.tokenSlice(ptr_payload.value_symbol.firstToken());
const name = tree.tokenSlice(name_token);
try scope.decls.putNoClobber(name, .{ try scope.decls.putNoClobber(name, .{
.pointer_payload = .{ .pointer_payload = .{
.node = ptr_payload, .name = name_token,
.condition = while_node.condition, .condition = while_node.ast.cond_expr,
}, },
}); });
} }
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.body); try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.ast.then_expr);
if (while_node.@"else") |else_node| { if (while_node.ast.else_expr != 0) {
if (else_node.payload) |payload| { if (while_node.error_token) |err_token| {
std.debug.assert(payload.tag == .Payload); std.debug.assert(token_tags[err_token] == .identifier);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{
.start = tree.token_locs[payload.firstToken()].start, .start = tree.tokenLocation(0, err_token).line_start,
.end = tree.token_locs[else_node.body.lastToken()].end, .end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(if_node.ast.else_expr)).line_end,
}, },
.decls = std.StringHashMap(Declaration).init(allocator), .decls = std.StringHashMap(Declaration).init(allocator),
// .uses = &[0]*ast.Node.Use{}, // .uses = &[0]*ast.Node.Use{},
.tests = &[0]*ast.Node{}, .tests = &.{},
.data = .other, .data = .other,
}; };
errdefer scope.decls.deinit(); errdefer scope.decls.deinit();
const err_payload = payload.castTag(.Payload).?; const name = tree.tokenSlice(err_token);
std.debug.assert(err_payload.error_symbol.tag == .Identifier); try scope.decls.putNoClobber(name, .{ .ast_node = if_node.ast.else_expr });
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
} }
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body); try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.ast.else_expr);
} }
}, },
.For => { .For => {