quil_rs/parser/
token.rs

1use crate::instruction::QuotedString;
2use crate::parser::lexer::{Command, DataType, LexInput, LexResult, Modifier, Operator};
3use std::fmt;
4use std::fmt::Formatter;
5
6/// Wrapper for [`Token`] that includes file location information.
7#[derive(Debug, Clone, PartialEq)]
8pub struct TokenWithLocation<'a> {
9    token: Token,
10    original_input: LexInput<'a>,
11}
12
13impl PartialEq<Token> for TokenWithLocation<'_> {
14    fn eq(&self, other: &Token) -> bool {
15        &self.token == other
16    }
17}
18
19impl TokenWithLocation<'_> {
20    /// Returns a reference to the contained token.
21    pub fn as_token(&self) -> &Token {
22        &self.token
23    }
24
25    /// Converts this `TokenWithLocation` into the contained [`Token`].
26    pub fn into_token(self) -> Token {
27        self.token
28    }
29
30    /// The line that this token appears on.
31    pub fn line(&self) -> u32 {
32        self.original_input.location_line()
33    }
34
35    /// The column of the line this token appears on.
36    pub fn column(&self) -> usize {
37        self.original_input.get_utf8_column()
38    }
39}
40
41impl nom::InputLength for TokenWithLocation<'_> {
42    fn input_len(&self) -> usize {
43        // All tokens take up exactly one place in the input token stream
44        self.as_token().input_len()
45    }
46}
47
48/// Wraps a parser that returns a [`Token`] and combines it with file location information.
49pub(crate) fn token_with_location<'i, E, P>(
50    mut parser: P,
51) -> impl FnMut(LexInput<'i>) -> LexResult<'i, TokenWithLocation<'i>, E>
52where
53    P: nom::Parser<LexInput<'i>, Token, E>,
54    E: nom::error::ParseError<LexInput<'i>>,
55{
56    move |input| {
57        // Using this syntax because map(parser, || ...)(input) has lifetime issues for parser.
58        parser.parse(input).map(|(leftover, token)| {
59            (
60                leftover,
61                TokenWithLocation {
62                    token,
63                    original_input: input,
64                },
65            )
66        })
67    }
68}
69
70/// The subset of [`Token`]s which (a) do not have arguments and (b) are keywords.  Used to ensure
71/// that keyword-checking remains in sync with the definition of [`Token`].
72#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::Display, strum::EnumString)]
73#[strum(serialize_all = "SCREAMING-KEBAB-CASE")]
74pub enum KeywordToken {
75    As,
76    Matrix,
77    #[strum(serialize = "mut")]
78    Mutable,
79    #[strum(serialize = "NONBLOCKING")]
80    NonBlocking,
81    Offset,
82    PauliSum,
83    Permutation,
84    Sharing,
85}
86
87impl From<KeywordToken> for Token {
88    fn from(token: KeywordToken) -> Self {
89        match token {
90            KeywordToken::As => Token::As,
91            KeywordToken::Matrix => Token::Matrix,
92            KeywordToken::Mutable => Token::Mutable,
93            KeywordToken::NonBlocking => Token::NonBlocking,
94            KeywordToken::Offset => Token::Offset,
95            KeywordToken::PauliSum => Token::PauliSum,
96            KeywordToken::Permutation => Token::Permutation,
97            KeywordToken::Sharing => Token::Sharing,
98        }
99    }
100}
101
102impl TryFrom<Token> for KeywordToken {
103    type Error = ();
104
105    fn try_from(token: Token) -> Result<Self, Self::Error> {
106        // This match is explicit so that if you add a new [`Token`] constructor you have to decide
107        // if it's a keyword.
108        #[deny(clippy::wildcard_enum_match_arm, clippy::wildcard_in_or_patterns)]
109        match token {
110            Token::As => Ok(KeywordToken::As),
111            Token::Matrix => Ok(KeywordToken::Matrix),
112            Token::Mutable => Ok(KeywordToken::Mutable),
113            Token::Offset => Ok(KeywordToken::Offset),
114            Token::PauliSum => Ok(KeywordToken::PauliSum),
115            Token::Permutation => Ok(KeywordToken::Permutation),
116            Token::Sharing => Ok(KeywordToken::Sharing),
117
118            Token::Colon
119            | Token::Comma
120            | Token::Command(_)
121            | Token::Comment(_)
122            | Token::DataType(_)
123            | Token::Float(_)
124            | Token::Identifier(_)
125            | Token::Indentation
126            | Token::Integer(_)
127            | Token::Target(_)
128            | Token::LBracket
129            | Token::LParenthesis
130            | Token::NonBlocking
131            | Token::Modifier(_)
132            | Token::NewLine
133            | Token::Operator(_)
134            | Token::RBracket
135            | Token::RParenthesis
136            | Token::Semicolon
137            | Token::String(_)
138            | Token::Variable(_) => Err(()),
139        }
140    }
141}
142
143#[derive(Clone, PartialEq)]
144pub enum Token {
145    As,
146    Colon,
147    Comma,
148    Command(Command),
149    Comment(String),
150    DataType(DataType),
151    Float(f64),
152    Identifier(String),
153    Indentation,
154    Integer(u64),
155    Target(String),
156    LBracket,
157    LParenthesis,
158    NonBlocking,
159    Matrix,
160    Modifier(Modifier),
161    Mutable,
162    NewLine,
163    Operator(Operator),
164    Offset,
165    PauliSum,
166    Permutation,
167    RBracket,
168    RParenthesis,
169    Semicolon,
170    Sharing,
171    String(String),
172    Variable(String),
173}
174
175impl fmt::Display for Token {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        match self {
178            Token::As => write!(f, "{}", KeywordToken::As),
179            Token::Colon => write!(f, ":"),
180            Token::Comma => write!(f, ","),
181            Token::Command(cmd) => write!(f, "{cmd}"),
182            Token::Comment(comment) => write!(f, "# {comment}"),
183            Token::DataType(typ) => write!(f, "{typ}"),
184            Token::Float(float) => write!(f, "{float}"),
185            Token::Identifier(ident) => write!(f, "{ident}"),
186            Token::Indentation => write!(f, "    "),
187            Token::Integer(i) => write!(f, "{i}"),
188            Token::Target(label) => write!(f, "{label}"),
189            Token::LBracket => write!(f, "["),
190            Token::LParenthesis => write!(f, "("),
191            Token::NonBlocking => write!(f, "{}", KeywordToken::NonBlocking),
192            Token::Matrix => write!(f, "{}", KeywordToken::Matrix),
193            Token::Modifier(m) => write!(f, "{m}"),
194            Token::Mutable => write!(f, "{}", KeywordToken::Mutable),
195            Token::NewLine => write!(f, "NEWLINE"),
196            Token::Operator(op) => write!(f, "{op}"),
197            Token::Offset => write!(f, "{}", KeywordToken::Offset),
198            Token::PauliSum => write!(f, "{}", KeywordToken::PauliSum),
199            Token::Permutation => write!(f, "{}", KeywordToken::Permutation),
200            Token::RBracket => write!(f, "]"),
201            Token::RParenthesis => write!(f, ")"),
202            Token::Semicolon => write!(f, ";"),
203            Token::Sharing => write!(f, "{}", KeywordToken::Sharing),
204            Token::String(s) => write!(f, "{}", QuotedString(s)),
205            Token::Variable(v) => write!(f, "{v}"),
206        }
207    }
208}
209
210impl fmt::Debug for Token {
211    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
212        match self {
213            Token::As => write!(f, "{self}"),
214            Token::Colon => write!(f, "COLON"),
215            Token::Comma => write!(f, "COMMA"),
216            Token::Command(cmd) => write!(f, "COMMAND({cmd})"),
217            Token::Comment(comment) => write!(f, "COMMENT({comment:?})"),
218            Token::DataType(typ) => write!(f, "DATATYPE({typ})"),
219            Token::Float(float) => write!(f, "FLOAT({float})"),
220            Token::Identifier(id) => write!(f, "IDENTIFIER({id})"),
221            Token::Indentation => write!(f, "INDENT"),
222            Token::Integer(i) => write!(f, "INTEGER({i})"),
223            Token::Target(label) => write!(f, "@{label}"),
224            Token::LBracket => write!(f, "LBRACKET"),
225            Token::LParenthesis => write!(f, "LPAREN"),
226            Token::NonBlocking => write!(f, "{self}"),
227            Token::Matrix => write!(f, "{self}"),
228            Token::Modifier(m) => write!(f, "MODIFIER({m})"),
229            Token::Mutable => write!(f, "{self}"),
230            Token::NewLine => write!(f, "NEWLINE"),
231            Token::Operator(op) => write!(f, "OPERATOR({op})"),
232            Token::Offset => write!(f, "{self}"),
233            Token::PauliSum => write!(f, "{self}"),
234            Token::Permutation => write!(f, "{self}"),
235            Token::RBracket => write!(f, "RBRACKET"),
236            Token::RParenthesis => write!(f, "RPAREN"),
237            Token::Semicolon => write!(f, "SEMICOLON"),
238            Token::Sharing => write!(f, "{self}"),
239            Token::String(s) => write!(f, "STRING({s:?})"),
240            Token::Variable(v) => write!(f, "VARIABLE({v})"),
241        }
242    }
243}
244
245impl nom::InputLength for Token {
246    fn input_len(&self) -> usize {
247        // All tokens take up exactly one place in the input token stream
248        1
249    }
250}