luau_parser/
parser.rs

1//! The main item of this crate, the actual [`parser`](Parser).
2
3use luau_lexer::lexer::Lexer;
4#[cfg(feature = "cache")]
5use std::collections::HashMap;
6
7use crate::types::{Cst, Pointer};
8
9/// The cache used in [`Parser`] when `cache` feature is enabled.
10#[cfg(feature = "cache")]
11pub type ParserCache = HashMap<String, Pointer<Cst>>;
12
13/// A Luau parser.
14#[derive(Clone, Debug, Default, PartialEq, Eq)]
15#[cfg_attr(not(feature = "cache"), derive(Copy, Hash, PartialOrd, Ord))]
16#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
17pub struct Parser {
18    /// Cache, only works with the `cache` feature, this is useful when you need
19    /// to use the [`CST`](Cst) more than once in 2 different places without
20    /// re-parsing.
21    #[cfg(feature = "cache")]
22    cache: ParserCache,
23
24    /// The lexer.
25    lexer: Lexer,
26}
27
28impl Parser {
29    /// Create a new [`parser`](Parser).
30    #[inline]
31    pub fn new(input: &str) -> Self {
32        Self {
33            #[cfg(feature = "cache")]
34            cache: HashMap::new(),
35            lexer: Lexer::new(input),
36        }
37    }
38
39    /// Set the parser's input. Meant to be chained.
40    pub fn with_input(mut self, input: &str) -> Self {
41        self.lexer = self.lexer.with_input(input);
42        self
43    }
44
45    /// Set the parser's input.
46    pub fn set_input(&mut self, input: &str) {
47        self.lexer.set_input(input);
48    }
49
50    /// Parse Luau code into an [`CST`](Cst).
51    pub fn parse(&mut self, uri: &str) -> Pointer<Cst> {
52        let cst = Pointer::new(Cst::parse(self.lexer.next_token(), &mut self.lexer, uri));
53
54        #[cfg(feature = "cache")]
55        {
56            self.cache.insert(uri.to_string(), cst);
57
58            self.cache.get(uri).unwrap().to_owned()
59        }
60
61        #[cfg(not(feature = "cache"))]
62        cst
63    }
64
65    /// Get a specific [`CST`](Cst) from the cache, this function assumes the
66    /// cst does exist. If it may or may not exist, use
67    /// [`maybe_get_ast`](Self::maybe_get_ast).
68    #[cfg(feature = "cache")]
69    #[inline]
70    pub fn get_ast(&self, uri: &str) -> &Cst {
71        self.cache.get(uri).unwrap()
72    }
73
74    /// Get a specific [`CST`](Cst) from the cache (if `cache` feature is enabled),
75    /// or parse `code` and return the produced [`CST`](Cst)
76    #[inline]
77    pub fn get_or_create(&mut self, uri: &str, code: &str) -> Pointer<Cst> {
78        #[cfg(feature = "cache")]
79        if let Some(cst) = self.maybe_get_ast(uri) {
80            return cst;
81        }
82
83        self.set_input(code);
84        self.parse(uri)
85    }
86
87    /// Get a specific [`CST`](Cst) from the cache, this function, unlike
88    /// [`get_ast`](Self::get_ast), doesn't error when the [`CST`](Cst) isn't
89    /// there.
90    #[cfg(feature = "cache")]
91    #[inline]
92    pub fn maybe_get_ast(&self, uri: &str) -> Option<Pointer<Cst>> {
93        self.cache.get(uri).cloned()
94    }
95
96    /// Get all cached [`CST`](Cst)s.
97    #[cfg(feature = "cache")]
98    #[inline]
99    pub fn get_all_asts(&self) -> &ParserCache {
100        &self.cache
101    }
102
103    /// Clear the cache.
104    #[cfg(feature = "cache")]
105    #[inline]
106    pub fn clear_cache(&mut self) {
107        self.cache.clear();
108    }
109}