phase_rs/raw_syntax/
pattern.rs

1//! Raw syntax patterns.
2
3use std::ops::Range;
4
5use pretty::RcDoc;
6use winnow::{
7    LocatingSlice, ModalResult, Parser,
8    ascii::multispace0,
9    combinator::{alt, delimited, separated},
10};
11
12use crate::{
13    ket::CompKetState,
14    raw_syntax::TermR,
15    text::{HasParser, Span, Spanned, ToDoc},
16    typecheck::{Env, TypeCheckError},
17    typed_syntax::PatternT,
18};
19
20/// Raw syntax pattern with text span.
21/// Represents a list of tensored patterns composed together.
22pub type PatternR<S> = Spanned<S, PatternRInner<S>>;
23
24/// Raw syntax pattern without text span.
25/// Represents a list of tensored patterns composed together.
26#[derive(Clone, Debug, PartialEq)]
27pub struct PatternRInner<S> {
28    pub(crate) patterns: Vec<PatTensorR<S>>,
29}
30
31impl<S> ToDoc for PatternRInner<S> {
32    fn to_doc(&self) -> RcDoc<'_> {
33        RcDoc::intersperse(
34            self.patterns.iter().map(PatTensorR::to_doc),
35            RcDoc::line().append(". "),
36        )
37        .group()
38    }
39}
40
41/// Raw syntax tensored pattern with text span.
42/// Represents a list of pattern atoms tensored together.
43pub type PatTensorR<S> = Spanned<S, PatTensorRInner<S>>;
44
45/// Raw syntax tensored pattern without text span.
46/// Represents a list of pattern atoms tensored together.
47#[derive(Clone, Debug, PartialEq)]
48pub struct PatTensorRInner<S> {
49    pub(crate) patterns: Vec<PatAtomR<S>>,
50}
51
52impl<S> ToDoc for PatTensorRInner<S> {
53    fn to_doc(&self) -> RcDoc<'_> {
54        RcDoc::intersperse(
55            self.patterns.iter().map(PatAtomR::to_doc),
56            RcDoc::line().append("x "),
57        )
58        .group()
59    }
60}
61
62/// Raw syntax pattern atom with text span.
63/// Represents a pattern other than a tensor or composition (or a composition/tensor in brackets)
64pub type PatAtomR<S> = Spanned<S, PatAtomRInner<S>>;
65
66/// Raw syntax pattern atom without text span.
67/// Represents a pattern other than a tensor or composition (or a composition/tensor in brackets)
68#[derive(Clone, Debug, PartialEq)]
69pub enum PatAtomRInner<S> {
70    /// A pattern enclosed in parentheses
71    Brackets(PatternR<S>),
72    /// A sequence of ket states "|xyz>", equivalent to "|x> x |y> x |z>"
73    Ket(CompKetState),
74    /// A unitary pattern
75    Unitary(Box<TermR<S>>),
76}
77
78impl<S> ToDoc for PatAtomRInner<S> {
79    fn to_doc(&self) -> RcDoc<'_> {
80        match self {
81            PatAtomRInner::Brackets(pattern) => RcDoc::text("(")
82                .append(RcDoc::line().append(pattern.to_doc()).nest(2))
83                .append(RcDoc::line())
84                .append(")")
85                .group(),
86            PatAtomRInner::Ket(states) => states.to_doc(),
87            PatAtomRInner::Unitary(inner) => inner.to_doc(),
88        }
89    }
90}
91
92impl<S: Span> PatternR<S> {
93    /// Typecheck a raw pattern in given environment
94    pub fn check(&self, env: &Env) -> Result<PatternT, TypeCheckError<S>> {
95        let mut pattern_iter = self.inner.patterns.iter();
96        let mut raw = pattern_iter.next().unwrap();
97        let p = raw.check(env)?;
98        let mut ty1 = p.get_type();
99        let mut v = vec![p];
100        for r in pattern_iter {
101            let pattern = r.check(env)?;
102            let ty2 = pattern.get_type();
103            if ty1.1 != ty2.0 {
104                return Err(TypeCheckError::PatternTypeMismatch {
105                    p1: raw.clone(),
106                    ty1,
107                    p2: r.clone(),
108                    ty2,
109                });
110            }
111            raw = r;
112            ty1 = ty2;
113            v.push(pattern);
114        }
115        Ok(PatternT::Comp(v))
116    }
117}
118
119impl<S: Span> PatTensorR<S> {
120    fn check(&self, env: &Env) -> Result<PatternT, TypeCheckError<S>> {
121        Ok(PatternT::Tensor(
122            self.inner
123                .patterns
124                .iter()
125                .map(|p| p.check(env))
126                .collect::<Result<_, _>>()?,
127        ))
128    }
129}
130
131impl<S: Span> PatAtomR<S> {
132    fn check(&self, env: &Env) -> Result<PatternT, TypeCheckError<S>> {
133        match &self.inner {
134            PatAtomRInner::Brackets(pattern) => pattern.check(env),
135            PatAtomRInner::Ket(states) => Ok(PatternT::Ket(states.clone())),
136            PatAtomRInner::Unitary(inner) => {
137                Ok(PatternT::Unitary(Box::new(inner.check(env, None)?)))
138            }
139        }
140    }
141}
142
143impl HasParser for PatternRInner<Range<usize>> {
144    fn parser(input: &mut LocatingSlice<&str>) -> ModalResult<Self> {
145        separated(1.., PatTensorR::parser, (multispace0, '.', multispace0))
146            .map(|patterns| PatternRInner { patterns })
147            .parse_next(input)
148    }
149}
150
151impl HasParser for PatTensorRInner<Range<usize>> {
152    fn parser(input: &mut LocatingSlice<&str>) -> ModalResult<Self> {
153        separated(1.., PatAtomR::parser, (multispace0, 'x', multispace0))
154            .map(|patterns| PatTensorRInner { patterns })
155            .parse_next(input)
156    }
157}
158
159impl HasParser for PatAtomRInner<Range<usize>> {
160    fn parser(input: &mut LocatingSlice<&str>) -> ModalResult<Self> {
161        alt((
162            delimited(("(", multispace0), PatternR::parser, (multispace0, ")"))
163                .map(PatAtomRInner::Brackets),
164            CompKetState::parser.map(PatAtomRInner::Ket),
165            TermR::parser.map(|x| PatAtomRInner::Unitary(Box::new(x))),
166        ))
167        .parse_next(input)
168    }
169}