Skip to main content

unsynn/
literal.rs

1//! This module provides a set of literal types that can be used to parse and tokenize
2//! literals.  The literals are parsed from the token stream and can be used to represent the
3//! parsed value. unsynn defines only simplified literals, such as integers, characters and
4//! strings. The literals here are not full rust syntax, which will be defined in the
5//! `unsynn-rust` crate. There are `Literal*` for `Integer, Character, String` to parse simple
6//! literals and `ConstInteger<V>` and `ConstCharacter<V>` who must match an exact character.
7//! The later two also implement `Default`, thus they can be used to create constant tokens.
8//! There is no `ConstString`; constant literal strings can be constructed with
9//! `IntoLiteralString<T>`.
10
11#![allow(clippy::module_name_repetitions)]
12
13#[cfg(doc)]
14use crate::*;
15
16use crate::{
17    Error, Literal, Parse, Parser, RefineErr, Result, ToTokens, TokenIter, TokenStream, TokenTree,
18};
19
20/// A simple unsigned 128 bit integer. This is the most simple form to parse integers. Note
21/// that only decimal integers without any other characters, signs or suffixes are supported,
22/// this is *not* full rust syntax.
23#[derive(Debug, Clone)]
24pub struct LiteralInteger {
25    /// Literal representing an integer
26    literal: Literal,
27    /// Value of the integer
28    value: u128,
29}
30
31impl LiteralInteger {
32    /// Create a new `LiteralInteger` from a `u128` value.
33    #[must_use]
34    pub fn new(value: u128) -> Self {
35        let literal = Literal::u128_unsuffixed(value);
36        Self { literal, value }
37    }
38
39    /// Get the value.
40    #[must_use]
41    pub const fn value(&self) -> u128 {
42        self.value
43    }
44
45    /// Set to a new the value.
46    pub fn set(&mut self, value: u128) {
47        *self = Self {
48            literal: Literal::u128_unsuffixed(value),
49            value,
50        };
51    }
52
53    /// Deconstructs `self` and gets the `Literal`
54    #[must_use]
55    pub fn into_inner(self) -> Literal {
56        self.literal
57    }
58}
59
60impl Parser for LiteralInteger {
61    fn parser(tokens: &mut TokenIter) -> Result<Self> {
62        let at = tokens.clone().next();
63        let literal = Literal::parser(tokens).refine_err::<Self>()?;
64        let value: u128 = match literal.to_string().parse() {
65            Ok(v) => v,
66            Err(e) => return Error::dynamic::<Self>(at, tokens, e),
67        };
68        Ok(Self { literal, value })
69    }
70}
71
72impl ToTokens for LiteralInteger {
73    fn to_tokens(&self, tokens: &mut TokenStream) {
74        self.literal.to_tokens(tokens);
75    }
76}
77
78impl PartialEq<u128> for LiteralInteger {
79    fn eq(&self, other: &u128) -> bool {
80        &self.value == other
81    }
82}
83
84impl From<LiteralInteger> for TokenTree {
85    fn from(lit: LiteralInteger) -> Self {
86        TokenTree::Literal(lit.into_inner())
87    }
88}
89
90#[test]
91fn test_literalinteger_into_tt() {
92    let lit = LiteralInteger::new(42);
93    let _: TokenTree = lit.into();
94}
95
96/// A constant `u128` integer of value `V`. Must match V and also has `Default` implemented to create
97/// a `LiteralInteger` with value `V`.
98///
99/// ```
100/// # use unsynn::*;
101/// let mut token_iter = "foo".to_token_iter();
102///
103/// let parsed = <OrDefault<u32, ConstInteger<1234>>>::parser(&mut token_iter).unwrap();
104/// assert_tokens_eq!(parsed, "1234");
105/// ```
106#[derive(Debug, Clone)]
107pub struct ConstInteger<const V: u128>(LiteralInteger);
108
109impl<const V: u128> ConstInteger<V> {
110    /// Get the value.
111    #[must_use]
112    pub const fn value(&self) -> u128 {
113        self.0.value
114    }
115
116    /// Deconstructs `self` and gets the `LiteralInteger`
117    #[must_use]
118    pub fn into_inner(self) -> LiteralInteger {
119        self.0
120    }
121}
122
123impl<const V: u128> Parser for ConstInteger<V> {
124    fn parser(tokens: &mut TokenIter) -> Result<Self> {
125        let at = tokens.clone().next();
126        Parse::parse_with(tokens, |this: LiteralInteger, e| {
127            if this.value == V {
128                Ok(Self(this))
129            } else {
130                Error::unexpected_token(at, e)
131            }
132        })
133        .refine_err::<Self>()
134    }
135}
136
137impl<const V: u128> ToTokens for ConstInteger<V> {
138    fn to_tokens(&self, tokens: &mut TokenStream) {
139        self.0.to_tokens(tokens);
140    }
141}
142
143impl<const V: u128> Default for ConstInteger<V> {
144    fn default() -> Self {
145        Self(LiteralInteger::new(V))
146    }
147}
148
149/// A single quoted character literal (`'x'`).
150#[derive(Debug, Clone)]
151pub struct LiteralCharacter {
152    /// Literal representing a single quoted character
153    literal: Literal,
154    /// The character value
155    value: char,
156}
157
158impl LiteralCharacter {
159    /// Create a new `LiteralCharacter` from a `char` value.
160    #[must_use]
161    pub fn new(value: char) -> Self {
162        let literal = Literal::character(value);
163        Self { literal, value }
164    }
165
166    /// Get the value.
167    #[must_use]
168    pub const fn value(&self) -> char {
169        self.value
170    }
171
172    /// Set to a new value.
173    pub fn set(&mut self, value: char) {
174        *self = Self {
175            literal: Literal::character(value),
176            value,
177        };
178    }
179
180    /// Deconstructs `self` and gets the `Literal`
181    #[must_use]
182    pub fn into_inner(self) -> Literal {
183        self.literal
184    }
185}
186
187impl Parser for LiteralCharacter {
188    fn parser(tokens: &mut TokenIter) -> Result<Self> {
189        let at = tokens.clone().next();
190        let literal = Literal::parser(tokens).refine_err::<Self>()?;
191        let string = literal.to_string();
192        let mut chars = string.chars();
193        // We only need to to check for first single quote, since the lexer already checked
194        // for proper literals
195        if let (Some('\''), Some(value)) = (chars.next(), chars.next()) {
196            Ok(Self { literal, value })
197        } else {
198            Error::unexpected_token(at, tokens)
199        }
200    }
201}
202
203impl ToTokens for LiteralCharacter {
204    fn to_tokens(&self, tokens: &mut TokenStream) {
205        self.literal.to_tokens(tokens);
206    }
207}
208
209impl PartialEq<char> for LiteralCharacter {
210    fn eq(&self, other: &char) -> bool {
211        &self.value == other
212    }
213}
214
215impl From<LiteralCharacter> for TokenTree {
216    fn from(lit: LiteralCharacter) -> Self {
217        TokenTree::Literal(lit.into_inner())
218    }
219}
220
221#[test]
222fn test_literalcharacter_into_tt() {
223    let lit = LiteralCharacter::new('c');
224    let _: TokenTree = lit.into();
225}
226
227/// A constant `char` of value `V`. Must match V and also has `Default` implemented to create
228/// a `LiteralCharacter` with value `V`.
229///
230/// ```
231/// # use unsynn::*;
232/// let mut token_iter = "'f'".to_token_iter();
233///
234/// let parsed = <OrDefault<u32, ConstCharacter<'f'>>>::parser(&mut token_iter).unwrap();
235/// assert_tokens_eq!(parsed, "'f'");
236/// ```
237#[derive(Debug, Clone)]
238pub struct ConstCharacter<const V: char>(LiteralCharacter);
239
240impl<const V: char> ConstCharacter<V> {
241    /// Get the value.
242    #[must_use]
243    pub const fn value(&self) -> char {
244        self.0.value
245    }
246
247    /// Deconstructs `self` and gets the `Literal`
248    #[must_use]
249    pub fn into_inner(self) -> LiteralCharacter {
250        self.0
251    }
252}
253
254impl<const V: char> Parser for ConstCharacter<V> {
255    fn parser(tokens: &mut TokenIter) -> Result<Self> {
256        let at = tokens.clone().next();
257        Parse::parse_with(tokens, |this: LiteralCharacter, e| {
258            if this.value == V {
259                Ok(Self(this))
260            } else {
261                Error::unexpected_token(at, e)
262            }
263        })
264        .refine_err::<Self>()
265    }
266}
267
268impl<const V: char> ToTokens for ConstCharacter<V> {
269    fn to_tokens(&self, tokens: &mut TokenStream) {
270        self.0.to_tokens(tokens);
271    }
272}
273
274impl<const V: char> Default for ConstCharacter<V> {
275    fn default() -> Self {
276        Self(LiteralCharacter::new(V))
277    }
278}
279
280/// A double quoted string literal (`"hello"`). The quotes are included in the value.  Note
281/// that this is a simplified string literal, and only double quoted strings are supported,
282/// this is *not* full rust syntax, eg. byte and C string literals are not supported.
283#[derive(Debug, Clone)]
284pub struct LiteralString {
285    /// Literal representing a double quoted string
286    literal: Literal,
287    /// The string value
288    value: String,
289}
290
291impl LiteralString {
292    /// Create a new `LiteralString` from a `String` value. The supplied `String` must start
293    /// and end with a double quote.
294    ///
295    /// # Panics
296    ///
297    /// Panics if the string does not start and end with a double quote.
298    #[must_use]
299    pub fn new(value: String) -> Self {
300        assert!(value.starts_with('"') && value.ends_with('"'));
301        let literal = Literal::string(&value);
302        Self { literal, value }
303    }
304
305    /// Create a new `LiteralString` from any `AsRef<str>` slice. Adds double quotes around
306    /// the supplied string.
307    #[must_use]
308    #[allow(clippy::should_implement_trait)]
309    pub fn from_str(string: impl AsRef<str>) -> Self {
310        let string = string.as_ref();
311        let value = format!(r#""{string}""#);
312        let literal = Literal::string(string);
313        Self { literal, value }
314    }
315
316    /// Get the `&str` including the surrounding quotes.
317    #[must_use]
318    #[allow(clippy::missing_const_for_fn)] // bug in clippy
319    pub fn value(&self) -> &str {
320        &self.value
321    }
322
323    /// Get the `&str` with the surrounding quotes removed.
324    #[must_use]
325    pub fn as_str(&self) -> &str {
326        &self.value[1..self.value.len() - 1]
327    }
328
329    /// Set the value to a new `String`.
330    pub fn set(&mut self, value: String) {
331        *self = Self {
332            literal: Literal::string(&value),
333            value,
334        };
335    }
336
337    /// Deconstructs `self` and gets the `Literal`
338    #[must_use]
339    pub fn into_inner(self) -> Literal {
340        self.literal
341    }
342}
343
344impl Parser for LiteralString {
345    fn parser(tokens: &mut TokenIter) -> Result<Self> {
346        let at = tokens.clone().next();
347        let literal = Literal::parser(tokens).refine_err::<Self>()?;
348        let string = literal.to_string();
349        // The lexer did its job here as well
350        if &string[0..1] == "\"" {
351            Ok(Self {
352                literal,
353                value: string,
354            })
355        } else {
356            Error::unexpected_token(at, tokens)
357        }
358    }
359}
360
361impl ToTokens for LiteralString {
362    fn to_tokens(&self, tokens: &mut TokenStream) {
363        self.literal.to_tokens(tokens);
364    }
365}
366
367/// Compares without the surrounding quotes.
368impl PartialEq<&str> for LiteralString {
369    fn eq(&self, other: &&str) -> bool {
370        self.as_str() == *other
371    }
372}
373
374impl From<LiteralString> for TokenTree {
375    fn from(lit: LiteralString) -> Self {
376        TokenTree::Literal(lit.into_inner())
377    }
378}
379
380#[test]
381fn test_literalstring_into_tt() {
382    let lit = LiteralString::from_str("foobar");
383    let _: TokenTree = lit.into();
384}