Skip to content

Commit e95ad89

Browse files
committed
Implement initial query engine
1 parent 138f1b4 commit e95ad89

File tree

3 files changed

+214
-2
lines changed

3 files changed

+214
-2
lines changed

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/building/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ edition = "2021"
66
[dependencies]
77
dashmap = "6.1.0"
88
id = { version = "0.1.0", path = "../id" }
9+
indexing = { version = "0.1.0", path = "../indexing" }
910
indexmap = "2.7.1"
11+
lexing = { version = "0.1.0", path = "../lexing" }
1012
parking_lot = "0.12.3"
13+
parsing = { version = "0.1.0", path = "../parsing" }
1114
petgraph = "0.7.1"
1215
rayon = "1.10.0"
16+
rowan = "0.16.1"
1317
rustc-hash = "2.1.0"
18+
syntax = { version = "0.1.0", path = "../syntax" }

crates/building/src/base.rs

Lines changed: 204 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,207 @@
1+
use std::{mem, sync::Arc};
2+
3+
use indexing::IndexingResult;
4+
use rowan::ast::AstNode;
5+
use rustc_hash::{FxHashMap, FxHashSet};
6+
use syntax::cst;
7+
8+
use crate::files::FileId;
9+
110
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
211
pub enum QueryKey {
3-
Index(usize),
4-
Resolve(usize),
12+
Content(FileId),
13+
Parse(FileId),
14+
Index(FileId),
15+
}
16+
17+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18+
pub struct Trace {
19+
built: usize,
20+
changed: usize,
21+
dependencies: Arc<[QueryKey]>,
22+
}
23+
24+
impl Trace {
25+
pub fn create_input(revision: usize) -> Trace {
26+
Trace { built: revision, changed: revision, dependencies: [].into() }
27+
}
28+
29+
pub fn create_fresh(revision: usize, dependencies: Arc<[QueryKey]>) -> Trace {
30+
Trace { built: revision, changed: revision, dependencies }
31+
}
32+
}
33+
34+
#[derive(Default)]
35+
pub struct Runtime {
36+
revision: usize,
37+
traces: FxHashMap<QueryKey, Trace>,
38+
39+
content: FxHashMap<FileId, Arc<str>>,
40+
parse: FxHashMap<FileId, cst::Module>,
41+
index: FxHashMap<FileId, Arc<IndexingResult>>,
42+
43+
parent: Option<QueryKey>,
44+
dependencies: FxHashMap<QueryKey, FxHashSet<QueryKey>>,
45+
}
46+
47+
impl Runtime {
48+
pub fn compute<T>(&mut self, k: QueryKey, compute: impl Fn(&mut Runtime) -> T) -> T {
49+
let parent = mem::replace(&mut self.parent, Some(k));
50+
let result = compute(self);
51+
52+
self.revision += 1;
53+
let revision = self.revision;
54+
55+
let dependencies = self
56+
.dependencies
57+
.get(&k)
58+
.map(|dependencies| dependencies.iter().copied())
59+
.unwrap_or_default()
60+
.collect();
61+
62+
let v = Trace::create_fresh(revision, dependencies);
63+
self.traces.insert(k, v);
64+
65+
self.parent = parent;
66+
result
67+
}
68+
69+
pub fn query<T: Clone>(
70+
&mut self,
71+
k: QueryKey,
72+
compute: impl Fn(&mut Runtime) -> T,
73+
get_storage: impl Fn(&mut Runtime) -> Option<(T, &mut Trace)>,
74+
set_storage: impl Fn(&mut Runtime, T),
75+
) -> T {
76+
if let Some(parent) = self.parent {
77+
self.dependencies.entry(parent).or_default().insert(k);
78+
}
79+
80+
let revision = self.revision;
81+
if let Some((value, trace)) = get_storage(self) {
82+
if trace.built == revision {
83+
value
84+
} else {
85+
let built = trace.built;
86+
let dependencies = Arc::clone(&trace.dependencies);
87+
88+
let mut latest = 0;
89+
for dependency in dependencies.iter() {
90+
match dependency {
91+
QueryKey::Content(_) => (),
92+
QueryKey::Parse(id) => {
93+
self.parse(*id);
94+
}
95+
QueryKey::Index(_) => (),
96+
}
97+
if let Some(dependency) = self.traces.get(dependency) {
98+
latest = latest.max(dependency.changed);
99+
}
100+
}
101+
102+
if built >= latest {
103+
if let Some(trace) = self.traces.get_mut(&k) {
104+
trace.built = revision;
105+
}
106+
value
107+
} else {
108+
let fresh = self.compute(k, compute);
109+
set_storage(self, T::clone(&fresh));
110+
fresh
111+
}
112+
}
113+
} else {
114+
let fresh = self.compute(k, compute);
115+
set_storage(self, T::clone(&fresh));
116+
fresh
117+
}
118+
}
119+
120+
pub fn set_content(&mut self, id: FileId, content: Arc<str>) {
121+
self.revision += 1;
122+
let revision = self.revision;
123+
124+
self.content.insert(id, content);
125+
126+
let k = QueryKey::Content(id);
127+
let v = Trace::create_input(revision);
128+
self.traces.insert(k, v);
129+
}
130+
131+
pub fn content(&mut self, id: FileId) -> Arc<str> {
132+
let k = QueryKey::Content(id);
133+
if let Some(parent) = self.parent {
134+
self.dependencies.entry(parent).or_default().insert(k);
135+
}
136+
let v = self.content.get(&id).expect("invalid violated: invalid query key");
137+
Arc::clone(v)
138+
}
139+
140+
pub fn parse(&mut self, id: FileId) -> cst::Module {
141+
let k = QueryKey::Parse(id);
142+
self.query(
143+
k,
144+
|this| {
145+
let content = this.content(id);
146+
147+
let lexed = lexing::lex(&content);
148+
let tokens = lexing::layout(&lexed);
149+
150+
let (node, _) = parsing::parse(&lexed, &tokens);
151+
cst::Module::cast(node).expect("invariant violated: cannot cast parse result")
152+
},
153+
|this| {
154+
let value = this.parse.get(&id).cloned()?;
155+
let trace = this.traces.get_mut(&k)?;
156+
Some((value, trace))
157+
},
158+
|this, value| {
159+
this.parse.insert(id, value);
160+
},
161+
)
162+
}
163+
164+
pub fn index(&mut self, id: FileId) -> Arc<IndexingResult> {
165+
let k = QueryKey::Index(id);
166+
self.query(
167+
k,
168+
|this| {
169+
let module = this.parse(id);
170+
let (result, _) = indexing::index(&module);
171+
Arc::new(result)
172+
},
173+
|this| {
174+
let value = this.index.get(&id).cloned()?;
175+
let trace = this.traces.get_mut(&k)?;
176+
Some((value, trace))
177+
},
178+
|this, value| {
179+
this.index.insert(id, value);
180+
},
181+
)
182+
}
183+
}
184+
185+
#[cfg(test)]
186+
mod tests {
187+
use crate::files::Files;
188+
189+
use super::Runtime;
190+
191+
#[test]
192+
fn test_basic() {
193+
let mut runtime = Runtime::default();
194+
let mut files = Files::default();
195+
196+
let id = files.insert("./src/Main.purs", "module Main where\n\nlife = 42");
197+
let content = files.content(id);
198+
199+
runtime.set_content(id, content);
200+
dbg!(runtime.index(id));
201+
dbg!(runtime.index(id));
202+
203+
runtime.set_content(id, "module Main where\n\n\n\nlife = 42".into());
204+
dbg!(runtime.index(id));
205+
dbg!(runtime.index(id));
206+
}
5207
}

0 commit comments

Comments
 (0)