luau_parser/
parser.rs

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