Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

another intern pool rewrite #1594

Merged
merged 30 commits into from
Dec 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
06e785c
ErrorBuilder improvements
Techatrix Nov 10, 2023
ecb2f2e
another intern pool rewrite
Techatrix Nov 10, 2023
f70cedb
stop comptime interpreter from always crashing
Techatrix Nov 10, 2023
7cff6bf
remove some unnecessary calls to `@as` builtin
Techatrix Nov 11, 2023
a73ca3a
simplify `InternPool.isUnknown`
Techatrix Nov 11, 2023
8a852a1
avoid calls to `extraData` in `InternPool.typeOf`
Techatrix Nov 12, 2023
be3321b
fix typo in `InternPool.deepHash`
Techatrix Nov 11, 2023
83c54e6
move `InternPool.Key` sub-types into `InternPool.Key`
Techatrix Nov 12, 2023
6129aa2
add TODO for representing arrays and vectors with unknown length
Techatrix Nov 13, 2023
201fc03
update some documentation in InternPool
Techatrix Nov 13, 2023
e6815d0
include comptime_float in `InternPool.isFloat`
Techatrix Nov 13, 2023
7c917b7
return null when integer doesn't fit in `InternPool.toInt`
Techatrix Nov 13, 2023
caf4e05
detect wrong value for `extra_count` in `InternPool.init`
Techatrix Nov 13, 2023
08c7895
add assertions to `InternPool.errorSetMerge`
Techatrix Nov 13, 2023
59282d1
fix looking up `len` on a single pointer to array
Techatrix Nov 22, 2023
03ea949
pack pointer type struct
Techatrix Nov 22, 2023
556f95c
add test for `StringPool.getOrPut` on existing string without allocation
Techatrix Nov 22, 2023
8720d14
pack function type struct
Techatrix Nov 23, 2023
c9de3a0
remove `InternPool.deepEql` and `InternPool.deepHash`
Techatrix Nov 23, 2023
ddcd106
add `InternPool.Index.Slice` and `InternPool.StringSlice`
Techatrix Nov 23, 2023
dfd511a
add a degibberish function for Zig types
Techatrix Dec 3, 2023
50d20be
remove usage of inline else from InternPool.get
Techatrix Dec 17, 2023
dab5cb7
encode large floats as u32 integers
Techatrix Dec 17, 2023
9a42f5d
improve StringPool API, safety and documentation
Techatrix Dec 18, 2023
be396db
rework storage of BigInt limbs
Techatrix Dec 20, 2023
d592eaa
replace `encoding.zig` with simpler u32 based encoding
Techatrix Dec 20, 2023
8391e8f
add thread safety to InternPool
Techatrix Dec 20, 2023
140db63
add tests for intern pool completions + fixes
Techatrix Dec 20, 2023
320cc30
fix compile errors on unused InternPool functions
Techatrix Dec 21, 2023
7162c33
don't use `std.Thread.RwLock.PthreadRwLock`
Techatrix Dec 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
456 changes: 232 additions & 224 deletions src/ComptimeInterpreter.zig

Large diffs are not rendered by default.

4,669 changes: 3,018 additions & 1,651 deletions src/analyser/InternPool.zig

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/analyser/analyser.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
pub const completions = @import("completions.zig");
pub const InternPool = @import("InternPool.zig");
pub const encoding = @import("encoding.zig");
pub const StringPool = @import("string_pool.zig").StringPool;
pub const degibberish = @import("degibberish.zig");

comptime {
const std = @import("std");
std.testing.refAllDecls(@This());
std.testing.refAllDeclsRecursive(@This());
}
283 changes: 217 additions & 66 deletions src/analyser/completions.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,48 @@
completions: *std.ArrayListUnmanaged(types.CompletionItem),
ip: *InternPool,
index: InternPool.Index,
is_type_val: bool,
node: ?Ast.Node.Index,
) error{OutOfMemory}!void {
std.debug.assert(index != .none);
_ = node;

const index_key = ip.indexToKey(index);
const val: InternPool.Key = if (is_type_val) index_key else .{ .unknown_value = .{ .ty = index } };
const ty: InternPool.Key = if (is_type_val) ip.indexToKey(index_key.typeOf()) else index_key;
const val: InternPool.Index = index;
const ty: InternPool.Index = ip.typeOf(index);

const inner_ty = switch (ty) {
.pointer_type => |info| if (info.size == .One) ip.indexToKey(info.elem_type) else ty,
const inner_ty = switch (ip.indexToKey(ty)) {
.pointer_type => |pointer_info| if (pointer_info.flags.size == .One) pointer_info.elem_type else ty,
else => ty,
};

switch (inner_ty) {
switch (ip.indexToKey(inner_ty)) {
.simple_type => |simple| switch (simple) {
.type => {
const namespace = val.getNamespace(ip.*);
if (val == .none) return;

const namespace = ip.getNamespace(val);
if (namespace != .none) {
// TODO lookup in namespace
}
switch (val) {

switch (ip.indexToKey(val)) {
.error_set_type => |error_set_info| {
for (error_set_info.names) |name| {
const error_name = ip.indexToKey(name).bytes;
try completions.append(arena, .{
.label = error_name,
const names = try error_set_info.names.dupe(arena, ip);
try completions.ensureUnusedCapacity(arena, names.len);
for (names) |name| {
completions.appendAssumeCapacity(.{
.label = try std.fmt.allocPrint(arena, "{}", .{name.fmt(&ip.string_pool)}),

Check warning on line 43 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L39-L43

Added lines #L39 - L43 were not covered by tests
.kind = .Constant,
.detail = try std.fmt.allocPrint(arena, "error.{s}", .{std.zig.fmtId(error_name)}),
.detail = try std.fmt.allocPrint(arena, "error.{}", .{ip.fmtId(name)}),

Check warning on line 45 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L45

Added line #L45 was not covered by tests
});
}
},
.union_type => {}, // TODO
.enum_type => |enum_index| {
const enum_info = ip.getEnum(enum_index);
var field_it = enum_info.fields.iterator();
while (field_it.next()) |entry| {
try completions.append(arena, .{
.label = entry.key_ptr.*,
try completions.ensureUnusedCapacity(arena, enum_info.fields.count());
for (enum_info.fields.keys()) |name| {
completions.appendAssumeCapacity(.{
.label = try std.fmt.allocPrint(arena, "{}", .{name.fmt(&ip.string_pool)}),

Check warning on line 55 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L52-L55

Added lines #L52 - L55 were not covered by tests
.kind = .EnumMember,
// include field.val?
});
Expand All @@ -62,48 +64,41 @@
else => {},
},
.pointer_type => |pointer_info| {
if (pointer_info.size == .Slice) {
var many_ptr_info = InternPool.Key{ .pointer_type = pointer_info };
many_ptr_info.pointer_type.size = .Many;
if (pointer_info.flags.size != .Slice) return;

try completions.append(arena, .{
const formatted = try std.fmt.allocPrint(arena, "{}", .{inner_ty.fmt(ip)});
std.debug.assert(std.mem.startsWith(u8, formatted, "[]"));

try completions.appendSlice(arena, &.{
.{
.label = "ptr",
.kind = .Field,
.detail = try std.fmt.allocPrint(arena, "ptr: {}", .{many_ptr_info.fmt(ip.*)}),
});
try completions.append(arena, .{
.label = "len",
.kind = .Field,
.detail = "len: usize",
});
} else if (ip.indexToKey(pointer_info.elem_type) == .array_type) {
try completions.append(arena, .{
.detail = try std.fmt.allocPrint(arena, "ptr: [*]{s}", .{formatted["[]".len..]}),
},
.{
.label = "len",
.kind = .Field,
.detail = "len: usize",
});
}
},
});
},
.array_type => |array_info| {
try completions.append(arena, .{
.label = "len",
.kind = .Field,
.detail = try std.fmt.allocPrint(arena, "const len: usize ({d})", .{array_info.len}), // TODO how should this be displayed
.detail = try std.fmt.allocPrint(arena, "const len: usize = {d}", .{array_info.len}),
});
},
.struct_type => |struct_index| {
const struct_info = ip.getStruct(struct_index);
try completions.ensureUnusedCapacity(arena, struct_info.fields.count());
var field_it = struct_info.fields.iterator();
while (field_it.next()) |entry| {
const label = entry.key_ptr.*;
const field = entry.value_ptr.*;
for (struct_info.fields.keys(), struct_info.fields.values()) |name, field| {

Check warning on line 95 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L95

Added line #L95 was not covered by tests
completions.appendAssumeCapacity(.{
.label = label,
.label = try std.fmt.allocPrint(arena, "{}", .{ip.fmtId(name)}),

Check warning on line 97 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L97

Added line #L97 was not covered by tests
.kind = .Field,
.detail = try std.fmt.allocPrint(arena, "{s}: {}", .{
label,
fmtFieldDetail(field, ip),
.detail = try std.fmt.allocPrint(arena, "{}: {}", .{
name.fmt(&ip.string_pool),
fmtFieldDetail(ip, field),

Check warning on line 101 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L99-L101

Added lines #L99 - L101 were not covered by tests
}),
});
}
Expand All @@ -112,41 +107,44 @@
try completions.append(arena, .{
.label = "?",
.kind = .Operator,
.detail = try std.fmt.allocPrint(arena, "{}", .{optional_info.payload_type.fmt(ip.*)}),
.detail = try std.fmt.allocPrint(arena, "{}", .{optional_info.payload_type.fmt(ip)}),
});
},
.enum_type => |enum_index| {
const enum_info = ip.getEnum(enum_index);
for (enum_info.fields.keys(), enum_info.values.keys()) |field_name, field_value| {
try completions.append(arena, .{
.label = field_name,
try completions.ensureUnusedCapacity(arena, enum_info.fields.count());
for (enum_info.fields.keys(), enum_info.values.keys()) |name, field_value| {
completions.appendAssumeCapacity(.{
.label = try std.fmt.allocPrint(arena, "{}", .{ip.fmtId(name)}),

Check warning on line 118 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L115-L118

Added lines #L115 - L118 were not covered by tests
.kind = .Field,
.detail = try std.fmt.allocPrint(arena, "{}", .{field_value.fmt(ip.*)}),
.detail = try std.fmt.allocPrint(arena, "{}", .{field_value.fmt(ip)}),

Check warning on line 120 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L120

Added line #L120 was not covered by tests
});
}
},
.union_type => |union_index| {
const union_info = ip.getUnion(union_index);
var field_it = union_info.fields.iterator();
while (field_it.next()) |entry| {
const label = entry.key_ptr.*;
const field = entry.value_ptr.*;
try completions.append(arena, .{
.label = label,
try completions.ensureUnusedCapacity(arena, union_info.fields.count());
for (union_info.fields.keys(), union_info.fields.values()) |name, field| {
completions.appendAssumeCapacity(.{
.label = try std.fmt.allocPrint(arena, "{}", .{ip.fmtId(name)}),

Check warning on line 129 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L126-L129

Added lines #L126 - L129 were not covered by tests
.kind = .Field,
.detail = if (field.alignment != 0)
try std.fmt.allocPrint(arena, "{s}: align({d}) {}", .{ label, field.alignment, field.ty.fmt(ip.*) })
try std.fmt.allocPrint(arena, "{}: align({d}) {}", .{ ip.fmtId(name), field.alignment, field.ty.fmt(ip) })

Check warning on line 132 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L132

Added line #L132 was not covered by tests
else
try std.fmt.allocPrint(arena, "{s}: {}", .{ label, field.ty.fmt(ip.*) }),
try std.fmt.allocPrint(arena, "{}: {}", .{ ip.fmtId(name), field.ty.fmt(ip) }),

Check warning on line 134 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L134

Added line #L134 was not covered by tests
});
}
},
.tuple_type => |tuple_info| {
for (tuple_info.types, 0..) |tuple_ty, i| {
try completions.append(arena, .{
std.debug.assert(tuple_info.types.len == tuple_info.values.len);
const tuple_types = try tuple_info.types.dupe(arena, ip);

Check warning on line 140 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L139-L140

Added lines #L139 - L140 were not covered by tests

try completions.ensureUnusedCapacity(arena, tuple_info.types.len);
for (tuple_types, 0..) |tuple_ty, i| {
completions.appendAssumeCapacity(.{

Check warning on line 144 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L142-L144

Added lines #L142 - L144 were not covered by tests
.label = try std.fmt.allocPrint(arena, "{d}", .{i}),
.kind = .Field,
.detail = try std.fmt.allocPrint(arena, "{d}: {}", .{ i, tuple_ty.fmt(ip.*) }),
.detail = try std.fmt.allocPrint(arena, "{d}: {}", .{ i, tuple_ty.fmt(ip) }),

Check warning on line 147 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L147

Added line #L147 was not covered by tests
});
}
},
Expand All @@ -170,11 +168,11 @@
.float_comptime_value,
=> {},

.bytes,
.optional_value,
.slice,
.aggregate,
.union_value,
.error_value,
.null_value,
.undefined_value,
.unknown_value,
Expand Down Expand Up @@ -205,15 +203,168 @@
if (field.alignment != 0) {
try writer.print("align({d}) ", .{field.alignment});
}
try writer.print("{}", .{field.ty.fmt(ctx.ip.*)});
try writer.print("{}", .{field.ty.fmt(ctx.ip)});

Check warning on line 206 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L206

Added line #L206 was not covered by tests
if (field.default_value != .none) {
try writer.print(" = {},", .{field.default_value.fmt(ctx.ip.*)});
try writer.print(" = {},", .{field.default_value.fmt(ctx.ip)});

Check warning on line 208 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L208

Added line #L208 was not covered by tests
}
}

pub fn fmtFieldDetail(field: InternPool.Struct.Field, ip: *InternPool) std.fmt.Formatter(formatFieldDetail) {
return .{ .data = .{
.ip = ip,
.item = field,
} };
pub fn fmtFieldDetail(ip: *InternPool, field: InternPool.Struct.Field) std.fmt.Formatter(formatFieldDetail) {
return .{ .data = .{ .ip = ip, .item = field } };

Check warning on line 213 in src/analyser/completions.zig

View check run for this annotation

Codecov / codecov/patch

src/analyser/completions.zig#L212-L213

Added lines #L212 - L213 were not covered by tests
}

test "dotCompletions - primitives" {
const gpa = std.testing.allocator;
var ip = try InternPool.init(gpa);
defer ip.deinit(gpa);

try testCompletion(&ip, .bool_type, &.{});
try testCompletion(&ip, .bool_true, &.{});
try testCompletion(&ip, .zero_comptime_int, &.{});
try testCompletion(&ip, .unknown_type, &.{});
try testCompletion(&ip, .unknown_unknown, &.{});
}

test "dotCompletions - optional types" {
const gpa = std.testing.allocator;
var ip = try InternPool.init(gpa);
defer ip.deinit(gpa);

const @"?u32" = try ip.get(gpa, .{ .optional_type = .{ .payload_type = .u32_type } });
try testCompletion(&ip, try ip.getUnknown(gpa, @"?u32"), &.{
.{
.label = "?",
.kind = .Operator,
.detail = "u32",
},
});
}

test "dotCompletions - array types" {
const gpa = std.testing.allocator;
var ip = try InternPool.init(gpa);
defer ip.deinit(gpa);

const @"[3]u32" = try ip.get(gpa, .{ .array_type = .{ .child = .u32_type, .len = 3 } });
const @"[1]u8" = try ip.get(gpa, .{ .array_type = .{ .child = .u8_type, .len = 1 } });

try testCompletion(&ip, try ip.getUnknown(gpa, @"[3]u32"), &.{
.{
.label = "len",
.kind = .Field,
.detail = "const len: usize = 3",
},
});
try testCompletion(&ip, try ip.getUnknown(gpa, @"[1]u8"), &.{
.{
.label = "len",
.kind = .Field,
.detail = "const len: usize = 1",
},
});
}

test "dotCompletions - pointer types" {
const gpa = std.testing.allocator;
var ip = try InternPool.init(gpa);
defer ip.deinit(gpa);

const @"*u32" = try ip.get(gpa, .{ .pointer_type = .{
.elem_type = .u32_type,
.flags = .{
.size = .One,
},
} });
const @"[]u32" = try ip.get(gpa, .{ .pointer_type = .{
.elem_type = .u32_type,
.flags = .{
.size = .Slice,
},
} });
const @"[]const u32" = try ip.get(gpa, .{ .pointer_type = .{
.elem_type = .u32_type,
.flags = .{
.size = .Slice,
.is_const = true,
},
} });

try testCompletion(&ip, try ip.getUnknown(gpa, @"*u32"), &.{});
try testCompletion(&ip, try ip.getUnknown(gpa, @"[]u32"), &.{
.{
.label = "ptr",
.kind = .Field,
.detail = "ptr: [*]u32",
},
.{
.label = "len",
.kind = .Field,
.detail = "len: usize",
},
});
try testCompletion(&ip, try ip.getUnknown(gpa, @"[]const u32"), &.{
.{
.label = "ptr",
.kind = .Field,
.detail = "ptr: [*]const u32",
},
.{
.label = "len",
.kind = .Field,
.detail = "len: usize",
},
});
}

test "dotCompletions - single pointer indirection" {
const gpa = std.testing.allocator;
var ip = try InternPool.init(gpa);
defer ip.deinit(gpa);

const @"[1]u32" = try ip.get(gpa, .{ .array_type = .{ .child = .u32_type, .len = 1 } });
const @"*[1]u32" = try ip.get(gpa, .{ .pointer_type = .{
.elem_type = @"[1]u32",
.flags = .{
.size = .One,
},
} });
const @"**[1]u32" = try ip.get(gpa, .{ .pointer_type = .{
.elem_type = @"*[1]u32",
.flags = .{
.size = .One,
},
} });
const @"[*][1]u32" = try ip.get(gpa, .{ .pointer_type = .{
.elem_type = @"[1]u32",
.flags = .{
.size = .Many,
},
} });

try testCompletion(&ip, try ip.getUnknown(gpa, @"*[1]u32"), &.{
.{
.label = "len",
.kind = .Field,
.detail = "const len: usize = 1",
},
});
try testCompletion(&ip, try ip.getUnknown(gpa, @"**[1]u32"), &.{});
try testCompletion(&ip, try ip.getUnknown(gpa, @"[*][1]u32"), &.{});
}

fn testCompletion(
ip: *InternPool,
index: InternPool.Index,
expected: []const types.CompletionItem,
) !void {
const gpa = std.testing.allocator;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();

const arena = arena_allocator.allocator();
var completions = std.ArrayListUnmanaged(types.CompletionItem){};

try dotCompletions(arena, &completions, ip, index, null);

try std.testing.expectEqualDeep(expected, completions.items);
}
Loading