1use std::{
4 fmt::{Debug, Display},
5 ops::Range,
6};
7
8use miette::SourceSpan;
9use pretty::RcDoc;
10use winnow::{
11 LocatingSlice, ModalResult, Parser,
12 ascii::{alphanumeric1, multispace0},
13 combinator::repeat,
14 error::{StrContext, StrContextValue},
15 token::take_until,
16};
17
18pub trait ToDoc {
20 fn to_doc(&self) -> RcDoc<'_>;
22}
23
24pub trait HasParser: Sized {
26 fn parser(input: &mut LocatingSlice<&str>) -> ModalResult<Self>;
28}
29
30pub trait Span: Clone + Debug + Into<SourceSpan> {}
31
32impl Span for Range<usize> {}
33
34#[derive(Clone, Debug)]
35pub struct NoSpan;
36
37impl From<NoSpan> for SourceSpan {
38 fn from(_: NoSpan) -> Self {
39 0.into()
40 }
41}
42
43impl Span for NoSpan {}
44
45#[derive(Clone, Debug, PartialEq)]
48pub struct Spanned<S, T> {
49 pub inner: T,
51 pub span: S,
53}
54
55impl<S, T: ToDoc> ToDoc for Spanned<S, T> {
56 fn to_doc(&self) -> RcDoc<'_> {
57 self.inner.to_doc()
58 }
59}
60
61impl<T> From<T> for Spanned<(), T> {
62 fn from(value: T) -> Self {
63 Spanned {
64 inner: value,
65 span: (),
66 }
67 }
68}
69
70impl<S: Span, T> From<Spanned<S, T>> for SourceSpan {
71 fn from(value: Spanned<S, T>) -> Self {
72 value.span.into()
73 }
74}
75impl<S: Span, T: Clone + Debug> Span for Spanned<S, T> {}
76
77impl<T: HasParser> HasParser for Spanned<Range<usize>, T> {
78 fn parser(input: &mut LocatingSlice<&str>) -> ModalResult<Self> {
79 T::parser
80 .with_span()
81 .map(|(inner, span)| Spanned { inner, span })
82 .parse_next(input)
83 }
84}
85
86pub fn comment_parser(input: &mut LocatingSlice<&str>) -> ModalResult<()> {
88 (
89 multispace0,
90 repeat::<_, _, (), _, _>(0.., ("//", take_until(0.., "\n"), multispace0).value(())),
91 )
92 .parse_next(input)?;
93 Ok(())
94}
95
96#[derive(Clone, Debug, PartialEq, Eq, Hash)]
97pub struct Name(String);
99
100impl Display for Name {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 std::fmt::Display::fmt(&self.0, f)
103 }
104}
105
106impl ToDoc for Name {
107 fn to_doc(&self) -> RcDoc<'_> {
108 RcDoc::text(&self.0)
109 }
110}
111
112impl HasParser for Name {
113 fn parser(input: &mut LocatingSlice<&str>) -> ModalResult<Self> {
114 alphanumeric1
115 .map(|s: &str| Name(s.to_owned()))
116 .context(StrContext::Label("identifier"))
117 .context(StrContext::Expected(StrContextValue::Description(
118 "alphanumeric string",
119 )))
120 .parse_next(input)
121 }
122}