loess_rust/expressions/
literals.rs

1use loess::{Error, ErrorPriority, Errors, Input, IntoTokens, PeekFrom, PopFrom, grammar};
2use proc_macro2::{Literal, TokenTree};
3
4grammar! {
5	/// [STRING_LITERAL](https://doc.rust-lang.org/stable/reference/tokens.html#r-lex.token.literal.str.syntax):
6	/// `"`[…]`"`
7	///
8	/// […]: https://doc.rust-lang.org/stable/reference/tokens.html#string-literals
9	#[derive(Clone)]
10	pub struct StringLiteral(pub Literal);
11
12	/// [RAW_STRING_LITERAL](https://doc.rust-lang.org/stable/reference/tokens.html#r-lex.token.literal.str-raw.syntax):
13	/// `r`​`#`<sup>n ≥ 0</sup>`"`[…]`"`​`#`<sup>n</sup>
14	///
15	/// […]: https://doc.rust-lang.org/stable/reference/tokens.html#raw-string-literals
16	#[derive(Clone)]
17	pub struct RawStringLiteral(pub Literal);
18
19	#[derive(Clone)]
20	pub enum AnyStringLiteral: doc, PeekFrom, PopFrom, IntoTokens {
21		/// `"…"`
22		Plain(StringLiteral),
23		/// `r#"…"#` and similar.
24		Raw(RawStringLiteral),
25	} else "Expected &str literal.";
26}
27
28impl PeekFrom for StringLiteral {
29	fn peek_from(input: &Input) -> bool {
30		matches!(input.front(), Some(TokenTree::Literal(literal)) if literal.to_string().starts_with('"'))
31	}
32}
33
34impl PopFrom for StringLiteral {
35	fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
36		input
37			.pop_or_replace(|t, _| match t {
38				[TokenTree::Literal(literal)] if literal.to_string().starts_with('"') => {
39					Ok(Self(literal))
40				}
41				other => Err(other),
42			})
43			.map_err(|spans| {
44				errors.push(Error::new(ErrorPriority::GRAMMAR, "Expected `\"`.", spans))
45			})
46	}
47}
48
49impl IntoTokens for StringLiteral {
50	fn into_tokens(
51		self,
52		root: &proc_macro2::TokenStream,
53		tokens: &mut impl Extend<proc_macro2::TokenTree>,
54	) {
55		self.0.into_tokens(root, tokens);
56	}
57}
58
59impl PeekFrom for RawStringLiteral {
60	fn peek_from(input: &Input) -> bool {
61		//TODO: This might not be entirely accurate.
62		matches!(input.front(), Some(TokenTree::Literal(literal)) if literal.to_string().starts_with('r'))
63	}
64}
65
66impl PopFrom for RawStringLiteral {
67	fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
68		input
69			.pop_or_replace(|t, _| match t {
70				[TokenTree::Literal(literal)] if literal.to_string().starts_with('r') => {
71					Ok(Self(literal))
72				}
73				other => Err(other),
74			})
75			.map_err(|spans| {
76				errors.push(Error::new(
77					ErrorPriority::GRAMMAR,
78					"Expected raw string literal.",
79					spans,
80				))
81			})
82	}
83}
84
85impl IntoTokens for RawStringLiteral {
86	fn into_tokens(
87		self,
88		root: &proc_macro2::TokenStream,
89		tokens: &mut impl Extend<proc_macro2::TokenTree>,
90	) {
91		self.0.into_tokens(root, tokens);
92	}
93}