1use std::{
36 collections::{hash_map, HashMap, HashSet},
37 hash::RandomState,
38 ops::{Deref, DerefMut},
39 sync::{Arc, Weak},
40};
41
42use crate::{
43 analysis::{
44 database::DocRecords,
45 AnalysisError,
46 AnalysisResult,
47 Analyzer,
48 Classifier,
49 Feature,
50 Grammar,
51 Initializer,
52 Invalidator,
53 Revision,
54 ScopeAttr,
55 TaskHandle,
56 },
57 arena::{Entry, Id, Identifiable},
58 lexis::ToSpan,
59 report::ld_unreachable,
60 sync::{Shared, SyncBuildHasher, TableReadGuard},
61 syntax::{ErrorRef, NodeRef, PolyRef, SyntaxTree},
62 units::{Document, Watcher},
63};
64
65pub type Event = u16;
70
71pub const DOC_ADDED_EVENT: Event = 1;
74
75pub const DOC_REMOVED_EVENT: Event = 2;
78
79pub const DOC_UPDATED_EVENT: Event = 3;
82
83pub const DOC_ERRORS_EVENT: Event = 4;
87
88pub const CUSTOM_EVENT_START_RANGE: Event = 0x100;
90
91#[repr(transparent)]
107pub struct DocumentReadGuard<'a, N: Grammar, S: SyncBuildHasher = RandomState> {
108 guard: TableReadGuard<'a, Id, DocEntry<N, S>, S>,
109}
110
111impl<'a, N: Grammar, S: SyncBuildHasher> Deref for DocumentReadGuard<'a, N, S> {
112 type Target = Document<N>;
113
114 #[inline(always)]
115 fn deref(&self) -> &Self::Target {
116 &self.guard.deref().doc
117 }
118}
119
120impl<'a, N: Grammar, S: SyncBuildHasher> From<TableReadGuard<'a, Id, DocEntry<N, S>, S>>
121 for DocumentReadGuard<'a, N, S>
122{
123 #[inline(always)]
124 fn from(guard: TableReadGuard<'a, Id, DocEntry<N, S>, S>) -> Self {
125 Self { guard }
126 }
127}
128
129pub(super) struct DocEntry<N: Grammar, S: SyncBuildHasher> {
130 pub(super) doc: Document<N>,
131 pub(super) classes_to_nodes: HashMap<<N::Classifier as Classifier>::Class, ClassToNodes<S>, S>,
132 pub(super) nodes_to_classes: HashMap<Entry, NodeToClasses<N, S>, S>,
133}
134
135pub(super) struct ClassToNodes<S> {
136 pub(super) nodes: Shared<HashSet<NodeRef, S>>,
137 pub(super) revision: Revision,
138}
139
140pub(super) struct NodeToClasses<N: Grammar, S> {
141 pub(super) classes: HashSet<<N::Classifier as Classifier>::Class, S>,
142}
143
144impl<N: Grammar, H: TaskHandle, S: SyncBuildHasher> Analyzer<N, H, S> {
145 pub(super) fn register_doc(&self, mut doc: Document<N>) -> Id {
146 let id = doc.id();
147
148 let node_refs = doc.node_refs().collect::<Vec<_>>();
149 let mut records = DocRecords::with_capacity(node_refs.len());
150 let mut classes_to_nodes =
151 HashMap::<<N::Classifier as Classifier>::Class, ClassToNodes<S>, S>::default();
152 let mut nodes_to_classes = HashMap::<Entry, NodeToClasses<N, S>, S>::default();
153
154 let revision = self.db.commit_revision();
155
156 if !node_refs.is_empty() {
157 let mut initializer = Initializer {
158 id,
159 database: Arc::downgrade(&self.db) as Weak<_>,
160 records: &mut records,
161 inserts: false,
162 };
163
164 for node_ref in &node_refs {
165 let Some(node) = node_ref.deref_mut(&mut doc) else {
166 continue;
167 };
168
169 node.init(&mut initializer);
170 }
171
172 for node_ref in node_refs {
173 let classes = <N::Classifier as Classifier>::classify(&doc, &node_ref);
174
175 if classes.is_empty() {
176 continue;
177 }
178
179 for class in &classes {
180 match classes_to_nodes.entry(class.clone()) {
181 hash_map::Entry::Occupied(mut entry) => {
182 let Some(nodes) = entry.get_mut().nodes.get_mut() else {
183 unsafe {
185 ld_unreachable!("Class nodes are shared during initialization")
186 }
187 };
188
189 let _ = nodes.insert(node_ref);
190 }
191
192 hash_map::Entry::Vacant(entry) => {
193 let mut nodes = HashSet::default();
194
195 let _ = nodes.insert(node_ref);
196
197 let _ = entry.insert(ClassToNodes {
198 nodes: Shared::new(nodes),
199 revision,
200 });
201 }
202 }
203 }
204
205 let _ = nodes_to_classes.insert(node_ref.entry, NodeToClasses { classes });
206 }
207 }
208
209 let _ = self.docs.insert(
210 id,
211 DocEntry {
212 doc,
213 classes_to_nodes,
214 nodes_to_classes,
215 },
216 );
217
218 let _ = self.db.records.insert(id, records);
219
220 self.trigger_event(id, DOC_ADDED_EVENT, revision);
221
222 id
223 }
224
225 pub(super) fn write_to_doc(
226 &self,
227 handle: &H,
228 id: Id,
229 span: impl ToSpan,
230 text: impl AsRef<str>,
231 ) -> AnalysisResult<()> {
232 #[derive(Default)]
233 struct DocWatcher<S> {
234 node_refs: HashSet<NodeRef, S>,
235 errors_signal: bool,
236 }
237
238 impl<S: SyncBuildHasher> Watcher for DocWatcher<S> {
239 #[inline(always)]
240 fn report_node(&mut self, node_ref: &NodeRef) {
241 let _ = self.node_refs.insert(*node_ref);
242 }
243
244 #[inline(always)]
245 fn report_error(&mut self, _error_ref: &ErrorRef) {
246 self.errors_signal = true
247 }
248 }
249 let Some(mut guard) = self.docs.get_mut(&id) else {
250 return Err(AnalysisError::MissingDocument);
251 };
252
253 let DocEntry {
254 doc,
255 classes_to_nodes,
256 nodes_to_classes,
257 } = guard.deref_mut();
258
259 let Document::Mutable(unit) = doc else {
260 return Err(AnalysisError::ImmutableDocument);
261 };
262
263 let Some(span) = span.to_site_span(unit) else {
264 return Err(AnalysisError::InvalidSpan);
265 };
266
267 let mut report = DocWatcher::<S>::default();
268
269 unit.write_and_watch(span, text, &mut report);
270
271 if report.node_refs.is_empty() && !report.errors_signal {
272 return Ok(());
273 }
274
275 let revision = self.db.commit_revision();
276
277 self.trigger_event(id, DOC_UPDATED_EVENT, revision);
278
279 if report.errors_signal {
280 self.trigger_event(id, DOC_ERRORS_EVENT, revision);
281 }
282
283 let Some(mut records) = self.db.records.get_mut(&id) else {
284 unsafe { ld_unreachable!("Missing database entry.") }
288 };
289
290 let mut initializer = Initializer {
291 id,
292 database: Arc::downgrade(&self.db) as Weak<_>,
293 records: records.deref_mut(),
294 inserts: false,
295 };
296
297 for node_ref in &report.node_refs {
298 let Some(node) = node_ref.deref_mut(doc) else {
299 let Some(node_to_classes) = nodes_to_classes.remove(&node_ref.entry) else {
300 continue;
301 };
302
303 for class in node_to_classes.classes {
304 let Some(class_to_nodes) = classes_to_nodes.get_mut(&class) else {
305 unsafe {
309 ld_unreachable!("Nodes and classes resynchronization.");
310 }
311 };
312
313 class_to_nodes.revision = class_to_nodes.revision.max(revision);
314
315 let nodes = class_to_nodes.nodes.make_mut();
316
317 if !nodes.remove(node_ref) {
318 unsafe {
322 ld_unreachable!("Nodes and classes resynchronization.");
323 }
324 }
325 }
326
327 continue;
328 };
329
330 node.init(&mut initializer);
331 }
332
333 let mut invalidator = Invalidator {
334 id,
335 records: &mut records.attrs,
336 };
337
338 for node_ref in &report.node_refs {
339 let Some(node) = node_ref.deref(doc) else {
340 continue;
341 };
342
343 let scope_attr = node.scope_attr()?;
344
345 scope_attr.invalidate(&mut invalidator);
346
347 if nodes_to_classes.contains_key(&node_ref.entry) {
348 continue;
349 }
350
351 let classes = <N as Grammar>::Classifier::classify(doc, node_ref);
352
353 for class in &classes {
354 let Some(class_to_nodes) = classes_to_nodes.get_mut(class) else {
355 let mut nodes = HashSet::default();
356
357 if !nodes.insert(*node_ref) {
358 unsafe {
360 ld_unreachable!("Duplicate entry.");
361 }
362 }
363
364 let previous = classes_to_nodes.insert(
365 class.clone(),
366 ClassToNodes {
367 nodes: Shared::new(nodes),
368 revision,
369 },
370 );
371
372 if previous.is_some() {
373 unsafe {
375 ld_unreachable!("Duplicate entry.");
376 }
377 }
378
379 continue;
380 };
381
382 let nodes = class_to_nodes.nodes.make_mut();
383
384 if !nodes.insert(*node_ref) {
385 unsafe {
389 ld_unreachable!("Nodes and classes resynchronization.");
390 }
391 }
392
393 class_to_nodes.revision = class_to_nodes.revision.max(revision);
394 }
395
396 if nodes_to_classes
397 .insert(node_ref.entry, NodeToClasses { classes })
398 .is_some()
399 {
400 unsafe {
402 ld_unreachable!("Duplicate entry.");
403 }
404 }
405 }
406
407 let mut scope_accumulator = HashSet::<NodeRef, S>::default();
408
409 for node_ref in &report.node_refs {
410 let Some(node) = node_ref.deref(doc) else {
411 continue;
412 };
413
414 let scope_attr = node.scope_attr()?;
415 let scope_attr_ref = scope_attr.as_ref();
416
417 let scope_ref = unsafe {
419 ScopeAttr::snapshot_manually(scope_attr_ref, handle, doc, &records.attrs, revision)?
420 };
421
422 if !scope_ref.is_nil() {
423 scope_accumulator.insert(scope_ref);
424 }
425 }
426
427 if !scope_accumulator.is_empty() {
428 let mut invalidator = Invalidator {
429 id,
430 records: &mut records.attrs,
431 };
432
433 for scope_ref in scope_accumulator {
434 let Some(node) = scope_ref.deref(doc) else {
435 continue;
436 };
437
438 node.invalidate(&mut invalidator);
439 }
440 }
441
442 Ok(())
443 }
444
445 pub(super) fn remove_doc(&self, id: Id) -> bool {
446 if self.docs.remove(&id).is_none() {
447 return false;
448 }
449
450 if self.db.records.remove(&id).is_none() {
451 unsafe { ld_unreachable!("Missing database entry.") }
453 }
454
455 let revision = self.db.commit_revision();
456
457 self.trigger_event(id, DOC_REMOVED_EVENT, revision);
458
459 true
460 }
461
462 pub(super) fn trigger_event(&self, id: Id, event: Event, revision: Revision) {
463 {
464 let mut guard = self.events.entry(Id::nil()).or_default();
465
466 let event_revision = guard.entry(event).or_default();
467
468 *event_revision = revision.max(*event_revision);
469 }
470
471 if !id.is_nil() {
472 let mut guard = self.events.entry(id).or_default();
473
474 let event_revision = guard.entry(event).or_default();
475
476 *event_revision = revision.max(*event_revision);
477 }
478 }
479}