Better alias support, fix another build file refcount issue

This commit is contained in:
Alexandros Naskos 2020-06-15 03:59:49 +03:00
parent 819b367360
commit 02de547ce9
2 changed files with 56 additions and 12 deletions

View File

@ -207,7 +207,55 @@ fn getDeclName(tree: *ast.Tree, node: *ast.Node) ?[]const u8 {
}; };
} }
/// Resolves variable declarationms like `const decl = @import("decl-file.zig").decl;` to the module's node fn isContainerDecl(decl_handle: DeclWithHandle) bool {
return switch (decl_handle.decl.*) {
.ast_node => |inner_node| inner_node.id == .ContainerDecl or inner_node.id == .Root,
else => false,
};
}
fn resolveVarDeclAliasInternal(
store: *DocumentStore,
arena: *std.heap.ArenaAllocator,
node_handle: NodeWithHandle,
root: bool,
) error{OutOfMemory}!?DeclWithHandle {
const handle = node_handle.handle;
if (node_handle.node.cast(ast.Node.Identifier)) |ident| {
return try lookupSymbolGlobal(store, arena, handle, handle.tree.tokenSlice(ident.token), handle.tree.token_locs[ident.token].start);
}
if (node_handle.node.cast(ast.Node.InfixOp)) |infix_op| {
if (infix_op.op != .Period) return null;
const container_node = if (infix_op.lhs.cast(ast.Node.BuiltinCall)) |builtin_call| block: {
if (!std.mem.eql(u8, handle.tree.tokenSlice(builtin_call.builtin_token), "@import"))
return null;
const inner_node = (try resolveTypeOfNode(store, arena, .{ .node = infix_op.lhs, .handle = handle })) orelse return null;
std.debug.assert(inner_node.node.id == .Root);
break :block inner_node;
} else if (try resolveVarDeclAliasInternal(store, arena, .{ .node = infix_op.lhs, .handle = handle }, false)) |decl_handle| block: {
if (!isContainerDecl(decl_handle)) return null;
break :block NodeWithHandle{
.node = decl_handle.decl.ast_node,
.handle = decl_handle.handle,
};
} else return null;
if (try lookupSymbolContainer(store, arena, container_node, handle.tree.tokenSlice(infix_op.rhs.firstToken()), false)) |inner_decl| {
if (!root and !isContainerDecl(inner_decl)) return null;
return inner_decl;
}
}
return null;
}
/// Resolves variable declarations consisting of chains of imports and field accesses of containers, ending with the same name as the variable decl's name
/// Examples:
///```zig
/// const decl = @import("decl-file.zig").decl;
/// const other = decl.middle.other;
///```
pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocator, decl_handle: NodeWithHandle) !?DeclWithHandle { pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocator, decl_handle: NodeWithHandle) !?DeclWithHandle {
const decl = decl_handle.node; const decl = decl_handle.node;
const handle = decl_handle.handle; const handle = decl_handle.handle;
@ -218,18 +266,11 @@ pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocato
const base_expr = var_decl.init_node.?; const base_expr = var_decl.init_node.?;
if (base_expr.cast(ast.Node.InfixOp)) |infix_op| { if (base_expr.cast(ast.Node.InfixOp)) |infix_op| {
if (infix_op.op != .Period) return null; if (infix_op.op != .Period) return null;
if (infix_op.lhs.cast(ast.Node.BuiltinCall)) |builtin_call| { const name = handle.tree.tokenSlice(infix_op.rhs.firstToken());
const name = handle.tree.tokenSlice(infix_op.rhs.firstToken()); if (!std.mem.eql(u8, handle.tree.tokenSlice(var_decl.name_token), name))
return null;
if (!std.mem.eql(u8, handle.tree.tokenSlice(builtin_call.builtin_token), "@import")) return try resolveVarDeclAliasInternal(store, arena, .{ .node = base_expr, .handle = handle }, true);
return null;
if (!std.mem.eql(u8, handle.tree.tokenSlice(var_decl.name_token), name))
return null;
const container_node = (try resolveTypeOfNode(store, arena, .{ .node = infix_op.lhs, .handle = handle })) orelse return null;
return lookupSymbolContainer(store, arena, container_node, name, false);
}
} }
} }

View File

@ -277,6 +277,9 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
const build_file_handle = try self.newDocument(build_file_uri, build_file_text); const build_file_handle = try self.newDocument(build_file_uri, build_file_text);
if (build_file_handle.is_build_file) |build_file| {
build_file.refs += 1;
}
handle.associated_build_file = build_file_handle.is_build_file; handle.associated_build_file = build_file_handle.is_build_file;
break; break;
} else break :associate_build_file; } else break :associate_build_file;