Use a newtype for Line
[hiphop-php.git] / hphp / hack / src / hackc / assemble / token.rs
blob02c02478bdfe69070f228b4300b9004a50fe80fc
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use std::fmt;
8 use anyhow::anyhow;
9 use anyhow::bail;
10 use anyhow::Result;
11 use newtype::newtype_int;
13 // 1-based line number.
14 newtype_int!(Line, u32, LineMap, LineSet);
16 #[derive(Debug, PartialEq, Eq, Copy, Clone, strum_macros::IntoStaticStr)]
17 pub(crate) enum Token<'a> {
18     // See Lexer::from_slice for regex definitions
19     Global(&'a [u8], Line),
20     Variable(&'a [u8], Line),
21     TripleStrLiteral(&'a [u8], Line),
22     Decl(&'a [u8], Line),
23     StrLiteral(&'a [u8], Line),
24     Variadic(Line),
25     Semicolon(Line),
26     Dash(Line),
27     OpenCurly(Line),
28     OpenBracket(Line),
29     OpenParen(Line),
30     CloseParen(Line),
31     CloseBracket(Line),
32     CloseCurly(Line),
33     Equal(Line),
34     Number(&'a [u8], Line),
35     Comma(Line),
36     Lt(Line),
37     Gt(Line),
38     Colon(Line),
39     Identifier(&'a [u8], Line),
40     Newline(Line),
41     Error(&'a [u8], Line),
44 impl<'a> Token<'a> {
45     pub(crate) fn error(&self, err: impl std::fmt::Display) -> anyhow::Error {
46         anyhow!("Error [line {line}]: {err} ({self:?})", line = self.line())
47     }
49     pub(crate) fn line(&self) -> Line {
50         match self {
51             Token::CloseBracket(u)
52             | Token::CloseCurly(u)
53             | Token::CloseParen(u)
54             | Token::Colon(u)
55             | Token::Comma(u)
56             | Token::Dash(u)
57             | Token::Decl(_, u)
58             | Token::Equal(u)
59             | Token::Error(_, u)
60             | Token::Global(_, u)
61             | Token::Gt(u)
62             | Token::Identifier(_, u)
63             | Token::Lt(u)
64             | Token::Newline(u)
65             | Token::Number(_, u)
66             | Token::OpenBracket(u)
67             | Token::OpenCurly(u)
68             | Token::OpenParen(u)
69             | Token::Semicolon(u)
70             | Token::StrLiteral(_, u)
71             | Token::TripleStrLiteral(_, u)
72             | Token::Variable(_, u)
73             | Token::Variadic(u) => *u,
74         }
75     }
77     pub(crate) fn as_bytes(&self) -> &'a [u8] {
78         match self {
79             Token::Global(u, _)
80             | Token::Variable(u, _)
81             | Token::TripleStrLiteral(u, _)
82             | Token::Decl(u, _)
83             | Token::StrLiteral(u, _)
84             | Token::Number(u, _)
85             | Token::Identifier(u, _)
86             | Token::Error(u, _) => u,
87             Token::Semicolon(_) => b";",
88             Token::Dash(_) => b"-",
89             Token::OpenCurly(_) => b"{",
90             Token::OpenBracket(_) => b"[",
91             Token::OpenParen(_) => b"(",
92             Token::CloseParen(_) => b")",
93             Token::CloseBracket(_) => b"]",
94             Token::CloseCurly(_) => b"}",
95             Token::Equal(_) => b"=",
96             Token::Comma(_) => b",",
97             Token::Lt(_) => b"<",
98             Token::Gt(_) => b">",
99             Token::Colon(_) => b":",
100             Token::Variadic(_) => b"...",
101             Token::Newline(_) => b"\n",
102         }
103     }
105     /// Only str_literal and triple_str_literal can be parsed into a new tokenizer.
106     /// To create a new tokenizer that still has accurate error reporting, we want to pass the line
107     /// So `into_str_literal_and_line` and `into_triple_str_literal_and_line` return a Result of bytes rep and line # or bail
108     pub(crate) fn into_triple_str_literal_and_line(self) -> Result<(&'a [u8], Line)> {
109         match self {
110             Token::TripleStrLiteral(vec_u8, pos) => Ok((vec_u8, pos)),
111             _ => bail!("Expected a triple str literal, got: {}", self),
112         }
113     }
115     pub(crate) fn into_global(self) -> Result<&'a [u8]> {
116         match self {
117             Token::Global(vec_u8, _) => Ok(vec_u8),
118             _ => bail!("Expected a global, got: {}", self),
119         }
120     }
122     pub(crate) fn into_variable(self) -> Result<&'a [u8]> {
123         match self {
124             Token::Variable(vec_u8, _) => Ok(vec_u8),
125             _ => bail!("Expected a variable, got: {}", self),
126         }
127     }
129     pub(crate) fn into_triple_str_literal(self) -> Result<&'a [u8]> {
130         match self {
131             Token::TripleStrLiteral(vec_u8, _) => Ok(vec_u8),
132             _ => bail!("Expected a triple str literal, got: {}", self),
133         }
134     }
136     pub(crate) fn into_decl(self) -> Result<&'a [u8]> {
137         match self {
138             Token::Decl(vec_u8, _) => Ok(vec_u8),
139             _ => bail!("Expected a decl, got: {}", self),
140         }
141     }
143     pub(crate) fn into_str_literal(self) -> Result<&'a [u8]> {
144         match self {
145             Token::StrLiteral(vec_u8, _) => Ok(vec_u8),
146             _ => bail!("Expected a str literal, got: {}", self),
147         }
148     }
150     pub(crate) fn into_number(self) -> Result<&'a [u8]> {
151         match self {
152             Token::Number(vec_u8, _) => Ok(vec_u8),
153             _ => bail!("Expected a number, got: {}", self),
154         }
155     }
157     pub(crate) fn into_identifier(self) -> Result<&'a [u8]> {
158         match self {
159             Token::Identifier(vec_u8, _) => Ok(vec_u8),
160             _ => bail!("Expected an identifier, got: {}", self),
161         }
162     }
164     pub(crate) fn into_semicolon(self) -> Result<&'a [u8]> {
165         match self {
166             Token::Semicolon(_) => Ok(self.as_bytes()),
167             _ => bail!("Expected a semicolon, got: {}", self),
168         }
169     }
171     pub(crate) fn into_dash(self) -> Result<&'a [u8]> {
172         match self {
173             Token::Dash(_) => Ok(self.as_bytes()),
174             _ => bail!("Expected a dash, got: {}", self),
175         }
176     }
178     pub(crate) fn into_open_curly(self) -> Result<&'a [u8]> {
179         match self {
180             Token::OpenCurly(_) => Ok(self.as_bytes()),
181             _ => bail!("Expected an open curly, got: {}", self),
182         }
183     }
185     pub(crate) fn into_open_bracket(self) -> Result<&'a [u8]> {
186         match self {
187             Token::OpenBracket(_) => Ok(self.as_bytes()),
188             _ => bail!("Expected an open bracket, got: {}", self),
189         }
190     }
192     pub(crate) fn into_open_paren(self) -> Result<&'a [u8]> {
193         match self {
194             Token::OpenParen(_) => Ok(self.as_bytes()),
195             _ => bail!("Expected an open paren, got: {}", self),
196         }
197     }
199     pub(crate) fn into_close_paren(self) -> Result<&'a [u8]> {
200         match self {
201             Token::CloseParen(_) => Ok(self.as_bytes()),
202             _ => bail!("Expected a close paren, got: {}", self),
203         }
204     }
206     pub(crate) fn into_close_bracket(self) -> Result<&'a [u8]> {
207         match self {
208             Token::CloseBracket(_) => Ok(self.as_bytes()),
209             _ => bail!("Expected a close bracket, got: {}", self),
210         }
211     }
213     pub(crate) fn into_close_curly(self) -> Result<&'a [u8]> {
214         match self {
215             Token::CloseCurly(_) => Ok(self.as_bytes()),
216             _ => bail!("Expected a close curly, got: {}", self),
217         }
218     }
220     pub(crate) fn into_equal(self) -> Result<&'a [u8]> {
221         match self {
222             Token::Equal(_) => Ok(self.as_bytes()),
223             _ => bail!("Expected an equal, got: {}", self),
224         }
225     }
227     pub(crate) fn into_comma(self) -> Result<&'a [u8]> {
228         match self {
229             Token::Comma(_) => Ok(self.as_bytes()),
230             _ => bail!("Expected a comma, got: {}", self),
231         }
232     }
234     pub(crate) fn into_lt(self) -> Result<&'a [u8]> {
235         match self {
236             Token::Lt(_) => Ok(self.as_bytes()),
237             _ => bail!("Expected a lt (<), got: {}", self),
238         }
239     }
241     pub(crate) fn into_gt(self) -> Result<&'a [u8]> {
242         match self {
243             Token::Gt(_) => Ok(self.as_bytes()),
244             _ => bail!("Expected a gt (>), got: {}", self),
245         }
246     }
248     pub(crate) fn into_colon(self) -> Result<&'a [u8]> {
249         match self {
250             Token::Colon(_) => Ok(self.as_bytes()),
251             _ => bail!("Expected a colon, got: {}", self),
252         }
253     }
255     pub(crate) fn is_newline(&self) -> bool {
256         matches!(self, Token::Newline(..))
257     }
259     pub(crate) fn is_triple_str_literal(&self) -> bool {
260         matches!(self, Token::TripleStrLiteral(..))
261     }
263     pub(crate) fn is_decl(&self) -> bool {
264         matches!(self, Token::Decl(..))
265     }
267     pub(crate) fn is_str_literal(&self) -> bool {
268         matches!(self, Token::StrLiteral(..))
269     }
271     pub(crate) fn is_number(&self) -> bool {
272         matches!(self, Token::Number(..))
273     }
275     pub(crate) fn is_identifier(&self) -> bool {
276         matches!(self, Token::Identifier(..))
277     }
279     pub(crate) fn is_semicolon(&self) -> bool {
280         matches!(self, Token::Semicolon(_))
281     }
283     pub(crate) fn is_dash(&self) -> bool {
284         matches!(self, Token::Dash(_))
285     }
287     pub(crate) fn is_open_bracket(&self) -> bool {
288         matches!(self, Token::OpenBracket(_))
289     }
291     pub(crate) fn is_close_paren(&self) -> bool {
292         matches!(self, Token::CloseParen(_))
293     }
295     pub(crate) fn is_close_bracket(&self) -> bool {
296         matches!(self, Token::CloseBracket(_))
297     }
299     pub(crate) fn is_close_curly(&self) -> bool {
300         matches!(self, Token::CloseCurly(_))
301     }
303     pub(crate) fn is_equal(&self) -> bool {
304         matches!(self, Token::Equal(_))
305     }
307     pub(crate) fn is_lt(&self) -> bool {
308         matches!(self, Token::Lt(_))
309     }
311     pub(crate) fn is_gt(&self) -> bool {
312         matches!(self, Token::Gt(_))
313     }
315     pub(crate) fn is_variadic(&self) -> bool {
316         matches!(self, Token::Variadic(_))
317     }
320 impl fmt::Display for Token<'_> {
321     /// Purpose of this fmt: so that vec of u8 (internal str representation of each token) is printed as a string rather than bytes
322     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
323         let text = std::str::from_utf8(self.as_bytes()).map_err(|_| fmt::Error)?;
324         let variant: &str = (*self).into();
325         let line = self.line();
326         write!(f, r#"{variant}("{text}", line: {line})"#)
327     }