1use std::collections::{BTreeMap, BTreeSet};
2use std::fmt;
3use std::sync::Arc;
4
5use crate::configuration::{ParseConfiguration, TriviaAttachmentPolicy};
6use crate::embedded_region_parser;
7use crate::language_parser::{BuiltInLanguageParser, LanguageParser};
8use crate::language_profile::LanguageProfile;
9use crate::link_flags::LinkFlags;
10use crate::mixed_regions::EmbeddedRegion;
11use crate::natural_language::annotate_natural_language;
12use crate::query::{LinkQuery, QueryMatch, QueryPredicateHost, RejectPredicateHost};
13use crate::self_description::{definition_expression, SELF_DESCRIPTION_ROOTS};
14use crate::source::{ByteRange, Point, SourceSpan};
15use crate::substitution::{
16 SubstitutionBindings, SubstitutionReport, SubstitutionRule, VariableSubstitutionRule,
17};
18use crate::verification::{VerificationIssue, VerificationIssueKind, VerificationReport};
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct LinkId(pub(crate) u64);
23
24impl LinkId {
25 #[must_use]
27 pub const fn from_u64(value: u64) -> Self {
28 Self(value)
29 }
30
31 #[must_use]
33 pub const fn as_u64(self) -> u64 {
34 self.0
35 }
36}
37
38impl fmt::Display for LinkId {
39 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(formatter, "{}", self.0)
41 }
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
46pub enum LinkType {
47 Link,
48 Reference,
49 Relation,
50 Language,
51 Grammar,
52 Type,
53 Concept,
54 Syntax,
55 Field,
56 Trivia,
57 Token,
58 Document,
59 Semantic,
60 Region,
61 Object,
62}
63
64#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66pub enum NetworkProjection {
67 Lossless,
69 ConcreteSyntax,
71 AbstractSyntax,
73 Semantic,
75}
76
77impl NetworkProjection {
78 #[must_use]
80 pub const fn label(self) -> &'static str {
81 match self {
82 Self::Lossless => "lossless",
83 Self::ConcreteSyntax => "concrete syntax",
84 Self::AbstractSyntax => "abstract syntax",
85 Self::Semantic => "semantic",
86 }
87 }
88
89 fn includes(self, link: &Link) -> bool {
90 match self {
91 Self::Lossless => true,
92 Self::ConcreteSyntax => link.metadata().link_type() != Some(LinkType::Semantic),
93 Self::AbstractSyntax => !matches!(
94 link.metadata().link_type(),
95 Some(LinkType::Token | LinkType::Trivia)
96 ),
97 Self::Semantic => matches!(
98 link.metadata().link_type(),
99 Some(LinkType::Semantic | LinkType::Concept | LinkType::Type | LinkType::Language)
100 ),
101 }
102 }
103}
104
105impl fmt::Display for LinkType {
106 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
107 let name = match self {
108 Self::Link => "link",
109 Self::Reference => "reference",
110 Self::Relation => "relation",
111 Self::Language => "language",
112 Self::Grammar => "grammar",
113 Self::Type => "type",
114 Self::Concept => "concept",
115 Self::Syntax => "syntax",
116 Self::Field => "field",
117 Self::Trivia => "trivia",
118 Self::Token => "token",
119 Self::Document => "document",
120 Self::Semantic => "semantic",
121 Self::Region => "region",
122 Self::Object => "object",
123 };
124 formatter.write_str(name)
125 }
126}
127
128#[derive(Clone, Debug, Default, PartialEq, Eq)]
130pub struct LinkMetadata {
131 link_type: Option<LinkType>,
132 named: bool,
133 term: Option<Arc<str>>,
134 definition: Option<Arc<str>>,
135 language: Option<Arc<str>>,
136 span: Option<SourceSpan>,
137 flags: LinkFlags,
138}
139
140impl LinkMetadata {
141 #[must_use]
143 pub fn new() -> Self {
144 Self::default()
145 }
146
147 #[must_use]
149 pub const fn with_link_type(mut self, link_type: LinkType) -> Self {
150 self.link_type = Some(link_type);
151 self
152 }
153
154 #[must_use]
156 pub const fn with_named(mut self, named: bool) -> Self {
157 self.named = named;
158 self
159 }
160
161 #[must_use]
163 pub fn with_term(mut self, term: impl Into<String>) -> Self {
164 self.term = Some(Arc::from(term.into()));
165 self
166 }
167
168 #[must_use]
170 pub fn with_definition(mut self, definition: impl Into<String>) -> Self {
171 self.definition = Some(Arc::from(definition.into()));
172 self
173 }
174
175 #[must_use]
177 pub fn with_language(mut self, language: impl Into<String>) -> Self {
178 self.language = Some(Arc::from(language.into()));
179 self
180 }
181
182 #[must_use]
184 pub const fn with_span(mut self, span: SourceSpan) -> Self {
185 self.span = Some(span);
186 self
187 }
188
189 #[must_use]
191 pub const fn with_flags(mut self, flags: LinkFlags) -> Self {
192 self.flags = flags;
193 self
194 }
195
196 #[must_use]
198 pub const fn link_type(&self) -> Option<LinkType> {
199 self.link_type
200 }
201
202 #[must_use]
204 pub const fn is_named(&self) -> bool {
205 self.named
206 }
207
208 #[must_use]
210 pub fn term(&self) -> Option<&str> {
211 self.term.as_deref()
212 }
213
214 #[must_use]
216 pub fn definition(&self) -> Option<&str> {
217 self.definition.as_deref()
218 }
219
220 #[must_use]
222 pub fn language(&self) -> Option<&str> {
223 self.language.as_deref()
224 }
225
226 #[must_use]
228 pub const fn span(&self) -> Option<SourceSpan> {
229 self.span
230 }
231
232 #[must_use]
234 pub const fn flags(&self) -> LinkFlags {
235 self.flags
236 }
237}
238
239#[derive(Clone, Debug, PartialEq, Eq)]
241pub struct Link {
242 pub(crate) id: LinkId,
243 pub(crate) references: Arc<[LinkId]>,
244 pub(crate) metadata: LinkMetadata,
245}
246
247impl Link {
248 #[must_use]
250 pub const fn id(&self) -> LinkId {
251 self.id
252 }
253
254 #[must_use]
256 pub fn references(&self) -> &[LinkId] {
257 &self.references
258 }
259
260 #[must_use]
262 pub const fn metadata(&self) -> &LinkMetadata {
263 &self.metadata
264 }
265
266 const fn metadata_mut(&mut self) -> &mut LinkMetadata {
267 &mut self.metadata
268 }
269}
270
271#[derive(Clone, Debug, Default, PartialEq, Eq)]
273pub struct LinkNetwork {
274 pub(crate) next_id: u64,
275 pub(crate) links: BTreeMap<LinkId, Arc<Link>>,
276 pub(crate) terms: BTreeMap<Arc<str>, LinkId>,
277 pub(crate) concept_syntax: BTreeMap<(Arc<str>, Arc<str>), Arc<str>>,
278 pub(crate) strings: BTreeSet<Arc<str>>,
279}
280
281impl LinkNetwork {
282 #[must_use]
284 pub const fn new() -> Self {
285 Self {
286 next_id: 1,
287 links: BTreeMap::new(),
288 terms: BTreeMap::new(),
289 concept_syntax: BTreeMap::new(),
290 strings: BTreeSet::new(),
291 }
292 }
293
294 #[must_use]
296 pub fn self_describing() -> Self {
297 let mut network = Self::new();
298 for root in SELF_DESCRIPTION_ROOTS {
299 let definition = definition_expression(root.term, root.references);
300 network.insert_typed_point(root.term, root.link_type, Some(&definition));
301 }
302
303 for root in SELF_DESCRIPTION_ROOTS {
304 let mut references = Vec::with_capacity(root.references.len() + 1);
305 references.push(
306 network
307 .find_term(root.term)
308 .expect("seeded self-description root exists"),
309 );
310 for reference in root.references {
311 references.push(
312 network
313 .find_term(reference)
314 .expect("seeded self-description reference exists"),
315 );
316 }
317
318 network.insert_dynamic_link(
319 &references,
320 LinkMetadata::new().with_link_type(LinkType::Relation),
321 );
322 }
323
324 network
325 }
326
327 #[must_use]
329 pub fn self_description_text(&self) -> String {
330 let mut output = String::new();
331 for root in SELF_DESCRIPTION_ROOTS {
332 let Some(id) = self.find_term(root.term) else {
333 continue;
334 };
335 let Some(definition) = self.definition_for(id) else {
336 continue;
337 };
338 output.push_str(definition);
339 output.push('\n');
340 }
341 output
342 }
343
344 #[must_use]
350 pub fn parse(text: &str, language: &str, configuration: ParseConfiguration) -> Self {
351 let mut network = BuiltInLanguageParser.parse_source(text, language, configuration);
352 if let Some(profile) = configuration.profile().and_then(LanguageProfile::builtin) {
353 profile.declare_in(&mut network);
354 }
355 network
356 }
357
358 #[must_use]
364 pub fn parse_lossless_text(
365 text: &str,
366 language: &str,
367 configuration: ParseConfiguration,
368 ) -> Self {
369 let (mut network, document) = Self::new_parse_document(text, language);
370
371 let mut row = 0;
372 let mut column = 0;
373 let mut open_parentheses = Vec::new();
374 for (start, character) in text.char_indices() {
375 let start_point = Point::new(row, column);
376 let end = start + character.len_utf8();
377 if character == '\n' {
378 row += 1;
379 column = 0;
380 } else {
381 column += 1;
382 }
383 let end_point = Point::new(row, column);
384 let span = SourceSpan::new(ByteRange::new(start, end), start_point, end_point);
385 let mut metadata = LinkMetadata::new()
386 .with_link_type(LinkType::Token)
387 .with_named(!character.is_whitespace())
388 .with_term(character.to_string())
389 .with_language(language)
390 .with_span(span);
391
392 if character.is_whitespace() {
393 metadata = metadata.with_flags(LinkFlags::extra());
394 }
395
396 let token = network.insert_link([document], metadata);
397 match character {
398 '(' => open_parentheses.push(token),
399 ')' if open_parentheses.pop().is_none() => {
400 network.set_flags(token, LinkFlags::error());
401 }
402 _ => {}
403 }
404 if character.is_whitespace() {
405 network.attach_trivia(
406 document,
407 token,
408 span,
409 configuration.trivia_attachment_policy(),
410 );
411 }
412 }
413
414 let missing_span = SourceSpan::new(
415 ByteRange::new(text.len(), text.len()),
416 end_point_for_text(text),
417 end_point_for_text(text),
418 );
419 for open_parenthesis in open_parentheses {
420 network.set_flags(open_parenthesis, LinkFlags::containing_error());
421 network.insert_link(
422 [document],
423 LinkMetadata::new()
424 .with_link_type(LinkType::Token)
425 .with_named(false)
426 .with_term(")")
427 .with_language(language)
428 .with_span(missing_span)
429 .with_flags(LinkFlags::missing()),
430 );
431 }
432
433 network.attach_embedded_regions(document, text, language, configuration);
434 annotate_natural_language(&mut network, document, text, language, configuration);
435
436 network
437 }
438
439 pub(crate) fn new_parse_document(text: &str, language: &str) -> (Self, LinkId) {
440 let mut network = Self::self_describing();
441 let language_link = network.insert_typed_point(language, LinkType::Language, None);
442 let document_span = SourceSpan::new(
443 ByteRange::new(0, text.len()),
444 Point::new(0, 0),
445 end_point_for_text(text),
446 );
447 let document = network.insert_link(
448 [language_link],
449 LinkMetadata::new()
450 .with_link_type(LinkType::Document)
451 .with_named(true)
452 .with_term(format!("{language} document"))
453 .with_language(language)
454 .with_span(document_span),
455 );
456 (network, document)
457 }
458
459 #[must_use]
461 pub fn len(&self) -> usize {
462 self.links.len()
463 }
464
465 #[must_use]
467 pub fn is_empty(&self) -> bool {
468 self.links.is_empty()
469 }
470
471 #[must_use]
473 pub fn shared_link_count(&self, id: LinkId) -> Option<usize> {
474 self.links.get(&id).map(Arc::strong_count)
475 }
476
477 #[must_use]
479 pub fn interned_string_count(&self, value: &str) -> Option<usize> {
480 self.strings.get(value).map(Arc::strong_count)
481 }
482
483 pub fn links(&self) -> impl Iterator<Item = &Link> {
485 self.links.values().map(Arc::as_ref)
486 }
487
488 pub fn projected_links(&self, projection: NetworkProjection) -> impl Iterator<Item = &Link> {
490 self.links().filter(move |link| projection.includes(link))
491 }
492
493 #[must_use]
495 pub fn reconstruct_text(&self) -> String {
496 let mut tokens = self
497 .links()
498 .filter(|link| link.metadata().link_type() == Some(LinkType::Token))
499 .filter(|link| !link.metadata().flags().is_missing())
500 .filter_map(|link| {
501 Some((
502 link.metadata().span()?.byte_range(),
503 link.id().as_u64(),
504 link.metadata().term()?.to_string(),
505 ))
506 })
507 .collect::<Vec<_>>();
508
509 tokens.sort_by_key(|(range, id, _term)| (range.start(), *id));
510 let mut reconstructed = String::new();
511 let mut covered_until = 0;
512 for (range, _id, term) in tokens {
513 if range.start() < covered_until {
514 continue;
515 }
516 reconstructed.push_str(&term);
517 covered_until = range.end();
518 }
519 reconstructed
520 }
521
522 #[must_use]
524 pub fn embedded_regions(&self) -> Vec<EmbeddedRegion> {
525 self.links()
526 .filter(|link| link.metadata().link_type() == Some(LinkType::Region))
527 .filter_map(|link| {
528 Some(EmbeddedRegion::new(
529 link.metadata().language()?.to_string(),
530 link.metadata().span()?,
531 ))
532 })
533 .collect()
534 }
535
536 #[must_use]
538 pub fn query_links(&self, query: &LinkQuery) -> Vec<&Link> {
539 self.query_matches(query)
540 .into_iter()
541 .filter_map(|query_match| self.link(query_match.link_id()))
542 .collect()
543 }
544
545 #[must_use]
547 pub fn query_matches(&self, query: &LinkQuery) -> Vec<QueryMatch> {
548 self.query_matches_with(query, &RejectPredicateHost)
549 }
550
551 #[must_use]
553 pub fn query_matches_with(
554 &self,
555 query: &LinkQuery,
556 predicate_host: &impl QueryPredicateHost,
557 ) -> Vec<QueryMatch> {
558 self.links()
559 .flat_map(|link| query.matches_in_network(self, link, predicate_host))
560 .collect()
561 }
562
563 pub fn insert_point(&mut self, term: &str) -> LinkId {
565 self.insert_typed_point(term, LinkType::Concept, None)
566 }
567
568 pub fn insert_object(&mut self, term: &str) -> LinkId {
570 self.insert_typed_point(term, LinkType::Object, None)
571 }
572
573 pub fn insert_relation<const N: usize>(
575 &mut self,
576 references: [LinkId; N],
577 link_type: LinkType,
578 span: SourceSpan,
579 ) -> LinkId {
580 self.insert_link(
581 references,
582 LinkMetadata::new()
583 .with_link_type(link_type)
584 .with_span(span),
585 )
586 }
587
588 pub fn insert_field(&mut self, parent: LinkId, label: &str, child: LinkId) -> LinkId {
590 let label_link = self.insert_typed_point(
591 label,
592 LinkType::Field,
593 Some("A field label names a relation between links."),
594 );
595 self.insert_link(
596 [parent, label_link, child],
597 LinkMetadata::new().with_link_type(LinkType::Field),
598 )
599 }
600
601 pub fn insert_link<const N: usize>(
603 &mut self,
604 references: [LinkId; N],
605 metadata: LinkMetadata,
606 ) -> LinkId {
607 let id = self.allocate_id();
608 let metadata = self.intern_metadata(metadata);
609 self.links.insert(
610 id,
611 Arc::new(Link {
612 id,
613 references: Arc::from(references.to_vec()),
614 metadata,
615 }),
616 );
617 id
618 }
619
620 #[must_use]
622 pub fn reconstruct_concept(&self, concept: &str, language: &str) -> Option<&str> {
623 let key = (Arc::<str>::from(concept), Arc::<str>::from(language));
624 self.concept_syntax.get(&key).map(Arc::as_ref)
625 }
626
627 pub fn apply_substitution(&mut self, rule: &SubstitutionRule) -> SubstitutionReport {
629 let mut report = SubstitutionReport::default();
630
631 if rule.pattern().is_empty() {
632 if !rule.replacement().is_empty() {
633 let created = self.insert_dynamic_link(
634 rule.replacement(),
635 LinkMetadata::new().with_link_type(LinkType::Relation),
636 );
637 report.created.push(created);
638 }
639 return report;
640 }
641
642 let matched = self
643 .links()
644 .filter(|link| link.references() == rule.pattern())
645 .map(Link::id)
646 .collect::<Vec<_>>();
647
648 if rule.replacement().is_empty() {
649 for id in matched {
650 if self.links.remove(&id).is_some() {
651 report.deleted.push(id);
652 }
653 }
654 return report;
655 }
656
657 for id in matched {
658 if let Some(link) = self.links.get_mut(&id) {
659 Arc::make_mut(link).references = Arc::from(rule.replacement().to_vec());
660 report.updated.push(id);
661 }
662 }
663
664 report
665 }
666
667 pub fn apply_variable_substitution(
669 &mut self,
670 rule: &VariableSubstitutionRule,
671 ) -> SubstitutionReport {
672 let mut report = SubstitutionReport::default();
673
674 if rule.pattern().is_empty() {
675 let bindings = SubstitutionBindings::default();
676 if let Some(references) = bindings.resolve_values(rule.replacement()) {
677 if !references.is_empty() {
678 let created = self.insert_dynamic_link(
679 &references,
680 LinkMetadata::new().with_link_type(LinkType::Relation),
681 );
682 report.created.push(created);
683 report.bindings.push(bindings);
684 }
685 }
686 return report;
687 }
688
689 let matched = self
690 .links()
691 .filter_map(|link| rule.match_link(link).map(|bindings| (link.id(), bindings)))
692 .collect::<Vec<_>>();
693
694 if rule.replacement().is_empty() {
695 for (id, bindings) in matched {
696 if self.links.remove(&id).is_some() {
697 report.deleted.push(id);
698 report.bindings.push(bindings);
699 }
700 }
701 return report;
702 }
703
704 for (id, bindings) in matched {
705 let Some(references) = bindings.resolve_values(rule.replacement()) else {
706 continue;
707 };
708 if let Some(link) = self.links.get_mut(&id) {
709 Arc::make_mut(link).references = Arc::from(references);
710 report.updated.push(id);
711 report.bindings.push(bindings);
712 }
713 }
714
715 report
716 }
717
718 #[must_use]
720 pub fn link(&self, id: LinkId) -> Option<&Link> {
721 self.links.get(&id).map(Arc::as_ref)
722 }
723
724 #[must_use]
726 pub fn find_term(&self, term: &str) -> Option<LinkId> {
727 self.terms.get(term).copied()
728 }
729
730 #[must_use]
732 pub fn definition_for(&self, id: LinkId) -> Option<&str> {
733 self.link(id).and_then(|link| link.metadata().definition())
734 }
735
736 pub fn set_span(&mut self, id: LinkId, span: SourceSpan) -> bool {
738 let Some(link) = self.links.get_mut(&id) else {
739 return false;
740 };
741 Arc::make_mut(link).metadata_mut().span = Some(span);
742 true
743 }
744
745 pub fn set_flags(&mut self, id: LinkId, flags: LinkFlags) -> bool {
747 let Some(link) = self.links.get_mut(&id) else {
748 return false;
749 };
750 Arc::make_mut(link).metadata_mut().flags = flags;
751 true
752 }
753
754 pub(crate) fn set_term(&mut self, id: LinkId, term: impl Into<String>) -> bool {
755 let term = self.intern_arc(Arc::from(term.into()));
756 let Some(link) = self.links.get_mut(&id) else {
757 return false;
758 };
759 Arc::make_mut(link).metadata_mut().term = Some(term);
760 true
761 }
762
763 #[must_use]
765 pub fn verify_full_match(&self, region: Option<ByteRange>) -> VerificationReport {
766 let issues = self
767 .links()
768 .filter(|link| link_is_in_region(link, region))
769 .filter_map(|link| {
770 let flags = link.metadata().flags();
771 let kind = if flags.is_error() {
772 VerificationIssueKind::ErrorLink
773 } else if flags.is_missing() {
774 VerificationIssueKind::MissingLink
775 } else if flags.has_error() {
776 VerificationIssueKind::HasErrorLink
777 } else {
778 return None;
779 };
780
781 Some(VerificationIssue::new(
782 link.id(),
783 kind,
784 link.metadata().span(),
785 ))
786 })
787 .collect();
788 VerificationReport::new(issues)
789 }
790
791 pub(crate) fn insert_typed_point(
792 &mut self,
793 term: &str,
794 link_type: LinkType,
795 definition: Option<&str>,
796 ) -> LinkId {
797 let definition = definition.map(|definition| self.intern_arc(Arc::from(definition)));
798 if let Some(id) = self.terms.get(term).copied() {
799 if let Some(definition) = definition {
800 if let Some(link) = self.links.get_mut(&id) {
801 Arc::make_mut(link).metadata_mut().definition = Some(definition);
802 }
803 }
804 return id;
805 }
806
807 let id = self.allocate_id();
808 let term = self.intern_arc(Arc::from(term));
809 let mut metadata = LinkMetadata::new()
810 .with_link_type(link_type)
811 .with_named(true);
812 metadata.term = Some(Arc::clone(&term));
813 if let Some(definition) = definition {
814 metadata.definition = Some(definition);
815 }
816 self.links.insert(
817 id,
818 Arc::new(Link {
819 id,
820 references: Arc::from(vec![id]),
821 metadata,
822 }),
823 );
824 self.terms.insert(term, id);
825 id
826 }
827
828 pub(crate) fn cache_concept_syntax(
829 &mut self,
830 concept: &str,
831 language: &str,
832 syntax: &str,
833 update_reconstruction: bool,
834 ) {
835 let concept = self.intern_arc(Arc::from(concept));
836 let language = self.intern_arc(Arc::from(language));
837 let syntax = self.intern_arc(Arc::from(syntax));
838
839 if update_reconstruction
840 || !self
841 .concept_syntax
842 .contains_key(&(Arc::clone(&concept), Arc::clone(&language)))
843 {
844 self.concept_syntax.insert((concept, language), syntax);
845 }
846 }
847
848 pub(crate) fn attach_trivia(
849 &mut self,
850 document: LinkId,
851 token: LinkId,
852 span: SourceSpan,
853 policy: TriviaAttachmentPolicy,
854 ) {
855 match policy {
856 TriviaAttachmentPolicy::ContainmentLink => {
857 self.insert_containment_trivia(document, token, span);
858 }
859 TriviaAttachmentPolicy::TokenLink => {
860 self.insert_token_trivia(token, span);
861 }
862 TriviaAttachmentPolicy::Both => {
863 self.insert_containment_trivia(document, token, span);
864 self.insert_token_trivia(token, span);
865 }
866 }
867 }
868
869 fn insert_containment_trivia(&mut self, document: LinkId, token: LinkId, span: SourceSpan) {
870 self.insert_link(
871 [document, token],
872 LinkMetadata::new()
873 .with_link_type(LinkType::Trivia)
874 .with_term("containment trivia")
875 .with_span(span)
876 .with_flags(LinkFlags::extra()),
877 );
878 }
879
880 fn insert_token_trivia(&mut self, token: LinkId, span: SourceSpan) {
881 self.insert_link(
882 [token],
883 LinkMetadata::new()
884 .with_link_type(LinkType::Trivia)
885 .with_term("token trivia")
886 .with_span(span)
887 .with_flags(LinkFlags::extra()),
888 );
889 }
890
891 pub(crate) fn insert_dynamic_link(
892 &mut self,
893 references: &[LinkId],
894 metadata: LinkMetadata,
895 ) -> LinkId {
896 let id = self.allocate_id();
897 let metadata = self.intern_metadata(metadata);
898 let term = metadata.term.clone();
899 self.links.insert(
900 id,
901 Arc::new(Link {
902 id,
903 references: Arc::from(references.to_vec()),
904 metadata,
905 }),
906 );
907 if let Some(term) = term {
908 self.terms.insert(term, id);
909 }
910 id
911 }
912
913 pub(crate) fn set_references(&mut self, id: LinkId, references: &[LinkId]) -> bool {
914 let Some(link) = self.links.get_mut(&id) else {
915 return false;
916 };
917 Arc::make_mut(link).references = Arc::from(references.to_vec());
918 true
919 }
920
921 pub(crate) fn attach_embedded_regions(
922 &mut self,
923 document: LinkId,
924 text: &str,
925 language: &str,
926 configuration: ParseConfiguration,
927 ) {
928 embedded_region_parser::attach_embedded_regions(
929 self,
930 document,
931 text,
932 language,
933 configuration,
934 );
935 }
936
937 fn intern_metadata(&mut self, mut metadata: LinkMetadata) -> LinkMetadata {
938 metadata.term = metadata.term.map(|value| self.intern_arc(value));
939 metadata.definition = metadata.definition.map(|value| self.intern_arc(value));
940 metadata.language = metadata.language.map(|value| self.intern_arc(value));
941 metadata
942 }
943
944 fn intern_arc(&mut self, value: Arc<str>) -> Arc<str> {
945 if let Some(interned) = self.strings.get(value.as_ref()) {
946 return Arc::clone(interned);
947 }
948
949 self.strings.insert(Arc::clone(&value));
950 value
951 }
952
953 const fn allocate_id(&mut self) -> LinkId {
954 let id = LinkId(self.next_id);
955 self.next_id += 1;
956 id
957 }
958}
959
960fn link_is_in_region(link: &Link, region: Option<ByteRange>) -> bool {
961 let Some(region) = region else {
962 return true;
963 };
964 link.metadata()
965 .span()
966 .is_some_and(|span| span.byte_range().intersects(region))
967}
968
969fn end_point_for_text(text: &str) -> Point {
970 let mut row = 0;
971 let mut column = 0;
972 for character in text.chars() {
973 if character == '\n' {
974 row += 1;
975 column = 0;
976 } else {
977 column += 1;
978 }
979 }
980 Point::new(row, column)
981}