This repository has been archived by the owner on Dec 5, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
store.zig
143 lines (127 loc) · 5.71 KB
/
store.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
const imp = @import("../../imp.zig");
usingnamespace imp.common;
const meta = imp.meta;
const syntax = imp.lang.repr.syntax;
const core = imp.lang.repr.core;
const type_ = imp.lang.repr.type_;
pub const SyntaxMeta = struct {
start: usize,
end: usize,
};
pub const CoreMeta = struct {
from: *const syntax.Expr,
// this is just useful as a stable id for tests
id: usize,
};
pub const Store = struct {
arena: *ArenaAllocator,
next_expr_id: usize,
core_exprs: ArrayList(*const core.Expr),
specializations: DeepHashMap(type_.LazySetType, ArrayList(Specialization)),
pub fn init(arena: *ArenaAllocator) Store {
return Store{
.arena = arena,
.next_expr_id = 0,
.core_exprs = ArrayList(*const core.Expr).init(&arena.allocator),
.specializations = DeepHashMap(type_.LazySetType, ArrayList(Specialization)).init(&arena.allocator),
};
}
pub fn putSyntax(self: *Store, expr: syntax.Expr, start: usize, end: usize) !*const syntax.Expr {
var expr_and_meta = try self.arena.allocator.create(ExprAndMeta(syntax.Expr, SyntaxMeta));
expr_and_meta.* = .{
.expr = expr,
.meta = SyntaxMeta{
.start = start,
.end = end,
},
};
return &expr_and_meta.expr;
}
pub fn putCore(self: *Store, expr: core.Expr, from: *const syntax.Expr) !*const core.Expr {
var expr_and_meta = try self.arena.allocator.create(ExprAndMeta(core.Expr, CoreMeta));
const id = self.next_expr_id;
self.next_expr_id += 1;
expr_and_meta.* = .{
.expr = expr,
.meta = CoreMeta{
.from = from,
.id = id,
},
};
try self.core_exprs.append(&expr_and_meta.expr);
return &expr_and_meta.expr;
}
// TODO using @fieldParentPtr is unnecessarily dangerous
pub fn getSyntaxMeta(expr: *const syntax.Expr) *const SyntaxMeta {
return &@fieldParentPtr(ExprAndMeta(syntax.Expr, SyntaxMeta), "expr", expr).meta;
}
pub fn getCoreMeta(expr: *const core.Expr) *const CoreMeta {
return &@fieldParentPtr(ExprAndMeta(core.Expr, CoreMeta), "expr", expr).meta;
}
fn betterMatchForPosition(position: usize, a: *const core.Expr, b: *const core.Expr) bool {
const a_core_meta = Store.getCoreMeta(a);
const a_syntax_meta = Store.getSyntaxMeta(a_core_meta.from);
const b_core_meta = Store.getCoreMeta(b);
const b_syntax_meta = Store.getSyntaxMeta(b_core_meta.from);
// anything past position is not a match
if (a_syntax_meta.end > position) return false;
if (b_syntax_meta.end > position) return true;
// the expr that ends closest to position is the best match
if (a_syntax_meta.end > b_syntax_meta.end) return true;
if (a_syntax_meta.end < b_syntax_meta.end) return false;
// if both end at the same point, the expr that is longest is the best match
if (a_syntax_meta.start < b_syntax_meta.start) return true;
if (a_syntax_meta.start > b_syntax_meta.start) return false;
// if both have same length, return the outermost expr in the tree
return a_core_meta.id > b_core_meta.id;
}
pub fn findCoreExprAt(self: Store, position: usize) ?*const core.Expr {
if (std.sort.min(*const core.Expr, self.core_exprs.items, position, betterMatchForPosition)) |best_match| {
const match_meta = Store.getSyntaxMeta(Store.getCoreMeta(best_match).from);
if (match_meta.end <= position) return best_match;
}
return null;
}
pub fn putSpecialization(self: *Store, lazy: type_.LazySetType, hint: []const type_.ScalarType, set_type: type_.SetType) !void {
const used_hint = switch (set_type) {
// always empty so can't say how much of the hint was used
.None => hint,
// didn't specialize so all we know is this hint isn't enough
.Lazy => hint,
// specialized, so cannot have used >concrete.columns.len of the hint
.Concrete => |concrete| hint[0..min(hint.len, concrete.columns.len)],
};
// analyze shouldn't redo previous work
assert(self.getSpecialization(lazy, used_hint) == null);
var slot = try self.specializations.getOrPut(lazy);
if (!slot.found_existing) slot.value_ptr.* = ArrayList(Specialization).init(&self.arena.allocator);
try slot.value_ptr.append(.{
.hint = used_hint,
.set_type = set_type,
});
}
pub fn getSpecialization(self: *Store, lazy: type_.LazySetType, hint: []const type_.ScalarType) ?type_.SetType {
const entry = self.specializations.getEntry(lazy) orelse return null;
for (entry.value_ptr.items) |specialization| {
const is_match = switch (specialization.set_type) {
// if couldn't specialize with a longer hint, can't specialize with this one
.Lazy => specialization.hint.len >= hint.len and meta.deepEqual(specialization.hint[0..hint.len], hint),
// if could specialize with a shorter hint, can specialize with this one
.None, .Concrete => specialization.hint.len <= hint.len and meta.deepEqual(specialization.hint, hint[0..specialization.hint.len]),
};
if (is_match) return specialization.set_type;
}
return null;
}
};
// --------------------------------------------------------------------------------
fn ExprAndMeta(comptime Expr: type, comptime Meta: type) type {
return struct {
expr: Expr,
meta: Meta,
};
}
const Specialization = struct {
hint: []const type_.ScalarType,
set_type: type_.SetType,
};