1use crate::pretty::{DbgDocBldr, DebugDocBuilder, PrettyDebugWithSource};
2use crate::text::Text;
3
4use derive_new::new;
5use getset::Getters;
6use serde::Deserialize;
7use serde::Serialize;
8use std::cmp::Ordering;
9use std::path::{Path, PathBuf};
10
11#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub enum AnchorLocation {
14    Url(String),
16    File(String),
18    Source(Text),
20}
21
22pub trait HasTag {
23    fn tag(&self) -> Tag;
25}
26
27#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
29pub struct Spanned<T> {
30    pub span: Span,
31    pub item: T,
32}
33
34impl<T> Spanned<T> {
35    pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Spanned<U> {
37        let span = self.span;
38
39        let mapped = input(self.item);
40        mapped.spanned(span)
41    }
42}
43
44impl Spanned<String> {
45    pub fn items<'a, U>(
47        items: impl Iterator<Item = &'a Spanned<String>>,
48    ) -> impl Iterator<Item = &'a str> {
49        items.map(|item| &item.item[..])
50    }
51
52    pub fn borrow_spanned(&self) -> Spanned<&str> {
54        let span = self.span;
55        self.item[..].spanned(span)
56    }
57
58    pub fn slice_spanned(&self, span: impl Into<Span>) -> Spanned<&str> {
59        let span = span.into();
60        let item = &self.item[span.start()..span.end()];
61        item.spanned(span)
62    }
63}
64
65pub trait SpannedItem: Sized {
66    fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
68        Spanned {
69            item: self,
70            span: span.into(),
71        }
72    }
73
74    fn spanned_unknown(self) -> Spanned<Self> {
76        Spanned {
77            item: self,
78            span: Span::unknown(),
79        }
80    }
81}
82impl<T> SpannedItem for T {}
83
84impl<T> std::ops::Deref for Spanned<T> {
85    type Target = T;
86
87    fn deref(&self) -> &T {
89        &self.item
90    }
91}
92
93#[derive(new, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
95pub struct Tagged<T> {
96    pub tag: Tag,
97    pub item: T,
98}
99
100impl Tagged<String> {
101    pub fn borrow_spanned(&self) -> Spanned<&str> {
103        let span = self.tag.span;
104        self.item[..].spanned(span)
105    }
106
107    pub fn borrow_tagged(&self) -> Tagged<&str> {
109        self.item[..].tagged(self.tag.clone())
110    }
111}
112
113impl<T> Tagged<Vec<T>> {
114    pub fn items(&self) -> impl Iterator<Item = &T> {
116        self.item.iter()
117    }
118}
119
120impl<T> HasTag for Tagged<T> {
121    fn tag(&self) -> Tag {
123        self.tag.clone()
124    }
125}
126
127impl AsRef<Path> for Tagged<PathBuf> {
128    fn as_ref(&self) -> &Path {
130        self.item.as_ref()
131    }
132}
133
134pub trait TaggedItem: Sized {
135    fn tagged(self, tag: impl Into<Tag>) -> Tagged<Self> {
136        Tagged {
137            item: self,
138            tag: tag.into(),
139        }
140    }
141
142    fn tagged_unknown(self) -> Tagged<Self> {
146        Tagged {
147            item: self,
148            tag: Tag {
149                span: Span::unknown(),
150                anchor: None,
151            },
152        }
153    }
154}
155
156impl<T> TaggedItem for T {}
157
158impl<T> std::ops::Deref for Tagged<T> {
159    type Target = T;
160
161    fn deref(&self) -> &T {
162        &self.item
163    }
164}
165
166impl<T> Tagged<T> {
167    pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Tagged<U> {
168        let tag = self.tag();
169
170        let mapped = input(self.item);
171        mapped.tagged(tag)
172    }
173
174    pub fn map_anchored(self, anchor: &Option<AnchorLocation>) -> Tagged<T> {
175        let mut tag = self.tag;
176
177        tag.anchor = anchor.clone();
178
179        Tagged {
180            item: self.item,
181            tag,
182        }
183    }
184
185    pub fn transpose(&self) -> Tagged<&T> {
186        Tagged {
187            item: &self.item,
188            tag: self.tag.clone(),
189        }
190    }
191
192    pub fn tag(&self) -> Tag {
194        self.tag.clone()
195    }
196
197    pub fn span(&self) -> Span {
199        self.tag.span
200    }
201
202    pub fn anchor(&self) -> Option<AnchorLocation> {
204        self.tag.anchor.clone()
205    }
206
207    pub fn anchor_name(&self) -> Option<String> {
209        match self.tag.anchor {
210            Some(AnchorLocation::File(ref file)) => Some(file.clone()),
211            Some(AnchorLocation::Url(ref url)) => Some(url.clone()),
212            _ => None,
213        }
214    }
215
216    pub fn item(&self) -> &T {
218        &self.item
219    }
220
221    pub fn into_parts(self) -> (T, Tag) {
223        (self.item, self.tag)
224    }
225}
226
227impl From<&Tag> for Tag {
228    fn from(input: &Tag) -> Tag {
229        input.clone()
230    }
231}
232
233impl From<(usize, usize)> for Span {
234    fn from(input: (usize, usize)) -> Span {
235        Span::new(input.0, input.1)
236    }
237}
238
239impl From<&std::ops::Range<usize>> for Span {
240    fn from(input: &std::ops::Range<usize>) -> Span {
241        Span::new(input.start, input.end)
242    }
243}
244
245#[derive(
247    Debug,
248    Default,
249    Clone,
250    PartialEq,
251    Eq,
252    Ord,
253    PartialOrd,
254    Serialize,
255    Deserialize,
256    Hash,
257    Getters,
258    new,
259)]
260pub struct Tag {
261    pub anchor: Option<AnchorLocation>,
263    pub span: Span,
265}
266
267impl From<Span> for Tag {
268    fn from(span: Span) -> Self {
269        Tag { anchor: None, span }
270    }
271}
272
273impl From<&Span> for Tag {
274    fn from(span: &Span) -> Self {
275        Tag {
276            anchor: None,
277            span: *span,
278        }
279    }
280}
281
282impl From<(usize, usize, AnchorLocation)> for Tag {
283    fn from((start, end, anchor): (usize, usize, AnchorLocation)) -> Self {
284        Tag {
285            anchor: Some(anchor),
286            span: Span::new(start, end),
287        }
288    }
289}
290
291impl From<(usize, usize, Option<AnchorLocation>)> for Tag {
292    fn from((start, end, anchor): (usize, usize, Option<AnchorLocation>)) -> Self {
293        Tag {
294            anchor,
295            span: Span::new(start, end),
296        }
297    }
298}
299
300impl From<Tag> for Span {
301    fn from(tag: Tag) -> Self {
302        tag.span
303    }
304}
305
306impl From<&Tag> for Span {
307    fn from(tag: &Tag) -> Self {
308        tag.span
309    }
310}
311
312impl Tag {
313    pub fn default() -> Self {
315        Tag {
316            anchor: None,
317            span: Span::unknown(),
318        }
319    }
320
321    pub fn anchored(self, anchor: Option<AnchorLocation>) -> Tag {
322        Tag {
323            anchor,
324            span: self.span,
325        }
326    }
327
328    pub fn unknown_anchor(span: Span) -> Tag {
330        Tag { anchor: None, span }
331    }
332
333    pub fn for_char(pos: usize, anchor: AnchorLocation) -> Tag {
335        Tag {
336            anchor: Some(anchor),
337            span: Span::new(pos, pos + 1),
338        }
339    }
340
341    pub fn unknown_span(anchor: AnchorLocation) -> Tag {
343        Tag {
344            anchor: Some(anchor),
345            span: Span::unknown(),
346        }
347    }
348
349    pub fn unknown() -> Tag {
351        Tag {
352            anchor: None,
353            span: Span::unknown(),
354        }
355    }
356
357    pub fn anchor(&self) -> Option<AnchorLocation> {
359        self.anchor.clone()
360    }
361
362    pub fn until(&self, other: impl Into<Tag>) -> Tag {
367        let other = other.into();
368        debug_assert!(
369            self.anchor == other.anchor,
370            "Can only merge two tags with the same anchor"
371        );
372
373        Tag {
374            span: Span::new(self.span.start, other.span.end),
375            anchor: self.anchor.clone(),
376        }
377    }
378
379    pub fn until_option(&self, other: Option<impl Into<Tag>>) -> Tag {
385        match other {
386            Some(other) => {
387                let other = other.into();
388                debug_assert!(
389                    self.anchor == other.anchor,
390                    "Can only merge two tags with the same anchor"
391                );
392
393                Tag {
394                    span: Span::new(self.span.start, other.span.end),
395                    anchor: self.anchor.clone(),
396                }
397            }
398            None => self.clone(),
399        }
400    }
401
402    pub fn slice<'a>(&self, source: &'a str) -> &'a str {
403        self.span.slice(source)
404    }
405
406    pub fn string(&self, source: &str) -> String {
407        self.span.slice(source).to_string()
408    }
409
410    pub fn tagged_slice<'a>(&self, source: &'a str) -> Tagged<&'a str> {
411        self.span.slice(source).tagged(self)
412    }
413
414    pub fn tagged_string(&self, source: &str) -> Tagged<String> {
415        self.span.slice(source).to_string().tagged(self)
416    }
417
418    pub fn anchor_name(&self) -> Option<String> {
419        match self.anchor {
420            Some(AnchorLocation::File(ref file)) => Some(file.clone()),
421            Some(AnchorLocation::Url(ref url)) => Some(url.clone()),
422            _ => None,
423        }
424    }
425}
426
427pub fn tag_for_tagged_list(mut iter: impl Iterator<Item = Tag>) -> Tag {
428    let first = iter.next();
429
430    let first = match first {
431        None => return Tag::unknown(),
432        Some(first) => first,
433    };
434
435    let last = iter.last();
436
437    match last {
438        None => first,
439        Some(last) => first.until(last),
440    }
441}
442
443pub fn span_for_spanned_list(mut iter: impl Iterator<Item = Span>) -> Span {
444    let first = iter.next();
445
446    let first = match first {
447        None => return Span::unknown(),
448        Some(first) => first,
449    };
450
451    let last = iter.last();
452
453    match last {
454        None => first,
455        Some(last) => first.until(last),
456    }
457}
458
459#[derive(
464    Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash,
465)]
466pub struct Span {
467    start: usize,
468    end: usize,
469}
470
471impl From<&Span> for Span {
472    fn from(span: &Span) -> Span {
473        *span
474    }
475}
476
477impl From<Option<Span>> for Span {
478    fn from(input: Option<Span>) -> Span {
479        input.unwrap_or_else(|| Span::new(0, 0))
480    }
481}
482
483impl From<Span> for std::ops::Range<usize> {
484    fn from(input: Span) -> std::ops::Range<usize> {
485        std::ops::Range {
486            start: input.start,
487            end: input.end,
488        }
489    }
490}
491
492impl Span {
493    pub fn default() -> Self {
495        Span::unknown()
496    }
497
498    pub fn unknown() -> Span {
500        Span::new(0, 0)
501    }
502
503    pub fn from_list(list: &[impl HasSpan]) -> Span {
504        let mut iterator = list.iter();
505
506        match iterator.next() {
507            None => Span::new(0, 0),
508            Some(first) => {
509                let last = iterator.last().unwrap_or(first);
510
511                Span::new(first.span().start, last.span().end)
512            }
513        }
514    }
515
516    pub fn new(start: usize, end: usize) -> Span {
518        assert!(
519            end >= start,
520            "Can't create a Span whose end < start, start={}, end={}",
521            start,
522            end
523        );
524
525        Span { start, end }
526    }
527
528    pub fn new_option(start: usize, end: usize) -> Option<Span> {
529        if end >= start {
530            None
531        } else {
532            Some(Span { start, end })
533        }
534    }
535
536    pub fn for_char(pos: usize) -> Span {
547        Span {
548            start: pos,
549            end: pos + 1,
550        }
551    }
552
553    pub fn contains(&self, pos: usize) -> bool {
565        self.start <= pos && pos < self.end
566    }
567
568    pub fn since(&self, other: impl Into<Span>) -> Span {
583        let other = other.into();
584
585        Span::new(other.start, self.end)
586    }
587
588    pub fn until(&self, other: impl Into<Span>) -> Span {
603        let other = other.into();
604
605        Span::new(self.start, other.end)
606    }
607
608    pub fn merge(&self, other: impl Into<Span>) -> Span {
609        let other = other.into();
610
611        if other.end < self.start {
612            other.until(self)
613        } else {
614            self.until(other)
615        }
616    }
617
618    pub fn until_option(&self, other: Option<impl Into<Span>>) -> Span {
623        match other {
624            Some(other) => {
625                let other = other.into();
626
627                Span::new(self.start, other.end)
628            }
629            None => *self,
630        }
631    }
632
633    pub fn string(&self, source: &str) -> String {
634        self.slice(source).to_string()
635    }
636
637    pub fn spanned_slice<'a>(&self, source: &'a str) -> Spanned<&'a str> {
638        self.slice(source).spanned(*self)
639    }
640
641    pub fn spanned_string(&self, source: &str) -> Spanned<String> {
642        self.slice(source).to_string().spanned(*self)
643    }
644
645    pub fn start(&self) -> usize {
647        self.start
648    }
649
650    pub fn end(&self) -> usize {
652        self.end
653    }
654
655    pub fn is_unknown(&self) -> bool {
667        self.start == 0 && self.end == 0
668    }
669
670    pub fn is_closed(&self) -> bool {
688        self.start == self.end
689    }
690
691    pub fn slice<'a>(&self, source: &'a str) -> &'a str {
693        &source[self.start..self.end]
694    }
695}
696
697impl PartialOrd<usize> for Span {
698    fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
699        (self.end - self.start).partial_cmp(other)
700    }
701}
702
703impl PartialEq<usize> for Span {
704    fn eq(&self, other: &usize) -> bool {
705        (self.end - self.start) == *other
706    }
707}
708
709pub trait IntoSpanned {
710    type Output: HasFallibleSpan;
711
712    fn into_spanned(self, span: impl Into<Span>) -> Self::Output;
713}
714
715impl<T: HasFallibleSpan> IntoSpanned for T {
716    type Output = T;
717    fn into_spanned(self, _span: impl Into<Span>) -> Self::Output {
718        self
719    }
720}
721
722pub trait HasSpan {
723    fn span(&self) -> Span;
724}
725
726impl<T, E> HasSpan for Result<T, E>
727where
728    T: HasSpan,
729{
730    fn span(&self) -> Span {
731        match self {
732            Result::Ok(val) => val.span(),
733            Result::Err(_) => Span::unknown(),
734        }
735    }
736}
737
738impl<T> HasSpan for Spanned<T> {
739    fn span(&self) -> Span {
740        self.span
741    }
742}
743
744pub trait HasFallibleSpan {
745    fn maybe_span(&self) -> Option<Span>;
746}
747
748impl HasFallibleSpan for bool {
749    fn maybe_span(&self) -> Option<Span> {
750        None
751    }
752}
753
754impl HasFallibleSpan for () {
755    fn maybe_span(&self) -> Option<Span> {
756        None
757    }
758}
759
760impl<T> HasFallibleSpan for T
761where
762    T: HasSpan,
763{
764    fn maybe_span(&self) -> Option<Span> {
765        Some(HasSpan::span(self))
766    }
767}
768
769impl PrettyDebugWithSource for Option<Span> {
770    fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
771        match self {
772            None => DbgDocBldr::description("no span"),
773            Some(span) => span.pretty_debug(source),
774        }
775    }
776}
777
778impl HasFallibleSpan for Option<Span> {
779    fn maybe_span(&self) -> Option<Span> {
780        *self
781    }
782}
783
784impl PrettyDebugWithSource for Span {
785    fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
786        DbgDocBldr::typed(
787            "span",
788            DbgDocBldr::keyword("for")
789                + DbgDocBldr::space()
790                + DbgDocBldr::description(format!("{:?}", self.slice(source))),
791        )
792    }
793}
794
795impl HasSpan for Span {
796    fn span(&self) -> Span {
797        *self
798    }
799}
800
801impl<T> PrettyDebugWithSource for Option<Spanned<T>>
802where
803    Spanned<T>: PrettyDebugWithSource,
804{
805    fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
806        match self {
807            None => DbgDocBldr::description("nothing"),
808            Some(v) => v.pretty_debug(v.span.slice(source)),
809        }
810    }
811}
812
813impl<T> HasFallibleSpan for Option<Spanned<T>> {
814    fn maybe_span(&self) -> Option<Span> {
815        self.as_ref().map(|value| value.span)
816    }
817}
818
819impl<T> PrettyDebugWithSource for Option<Tagged<T>>
820where
821    Tagged<T>: PrettyDebugWithSource,
822{
823    fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
824        match self {
825            None => DbgDocBldr::description("nothing"),
826            Some(d) => d.pretty_debug(source),
827        }
828    }
829}
830
831impl<T> HasFallibleSpan for Option<Tagged<T>> {
832    fn maybe_span(&self) -> Option<Span> {
833        self.as_ref().map(|value| value.tag.span)
834    }
835}
836
837impl<T> HasSpan for Tagged<T> {
838    fn span(&self) -> Span {
839        self.tag.span
840    }
841}