Skip to main content

oak_clojure/parser/
mod.rs

1/// Element type module for Clojure.
2pub mod element_type;
3pub use element_type::ClojureElementType;
4
5use crate::{language::ClojureLanguage, lexer::token_type::ClojureTokenType};
6use oak_core::{
7    OakError,
8    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
9    source::{Source, TextEdit},
10};
11
12pub(crate) type State<'a, S> = ParserState<'a, ClojureLanguage, S>;
13
14/// Clojure parser implementation.
15pub struct ClojureParser<'config> {
16    pub(crate) config: &'config ClojureLanguage,
17}
18
19impl<'config> ClojureParser<'config> {
20    /// Creates a new `ClojureParser`.
21    pub fn new(config: &'config ClojureLanguage) -> Self {
22        Self { config }
23    }
24
25    fn parse_form<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
26        match state.peek_kind() {
27            Some(ClojureTokenType::ListStart) => self.parse_list(state),
28            Some(ClojureTokenType::VectorStart) => self.parse_vector(state),
29            Some(ClojureTokenType::MapStart) => self.parse_map(state),
30            Some(ClojureTokenType::SetStart) => self.parse_set(state),
31            Some(ClojureTokenType::AnonFnStart) => self.parse_anon_fn(state),
32            Some(ClojureTokenType::Quote) => {
33                let cp = state.checkpoint();
34                state.bump();
35                self.parse_form(state)?;
36                state.finish_at(cp, ClojureElementType::Quotation);
37                Ok(())
38            }
39            Some(ClojureTokenType::Meta) => {
40                let cp = state.checkpoint();
41                state.bump();
42                self.parse_form(state)?;
43                state.finish_at(cp, ClojureElementType::Meta);
44                Ok(())
45            }
46            Some(_) => {
47                state.bump();
48                Ok(())
49            }
50            None => Ok(()),
51        }
52    }
53
54    fn parse_list<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
55        let cp = state.checkpoint();
56        state.expect(ClojureTokenType::ListStart).ok();
57        while state.not_at_end() && !state.at(ClojureTokenType::ListEnd) {
58            self.parse_form(state)?;
59        }
60        state.expect(ClojureTokenType::ListEnd).ok();
61        state.finish_at(cp, ClojureElementType::List);
62        Ok(())
63    }
64
65    fn parse_vector<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
66        let cp = state.checkpoint();
67        state.expect(ClojureTokenType::VectorStart).ok();
68        while state.not_at_end() && !state.at(ClojureTokenType::VectorEnd) {
69            self.parse_form(state)?;
70        }
71        state.expect(ClojureTokenType::VectorEnd).ok();
72        state.finish_at(cp, ClojureElementType::Vector);
73        Ok(())
74    }
75
76    fn parse_map<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
77        let cp = state.checkpoint();
78        state.expect(ClojureTokenType::MapStart).ok();
79        while state.not_at_end() && !state.at(ClojureTokenType::MapEnd) {
80            self.parse_form(state)?;
81        }
82        state.expect(ClojureTokenType::MapEnd).ok();
83        state.finish_at(cp, ClojureElementType::Map);
84        Ok(())
85    }
86
87    fn parse_set<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
88        let cp = state.checkpoint();
89        state.expect(ClojureTokenType::SetStart).ok();
90        while state.not_at_end() && !state.at(ClojureTokenType::MapEnd) {
91            self.parse_form(state)?;
92        }
93        state.expect(ClojureTokenType::MapEnd).ok();
94        state.finish_at(cp, ClojureElementType::Set);
95        Ok(())
96    }
97
98    fn parse_anon_fn<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
99        let cp = state.checkpoint();
100        state.expect(ClojureTokenType::AnonFnStart).ok();
101        while state.not_at_end() && !state.at(ClojureTokenType::ListEnd) {
102            self.parse_form(state)?;
103        }
104        state.expect(ClojureTokenType::ListEnd).ok();
105        state.finish_at(cp, ClojureElementType::AnonFn);
106        Ok(())
107    }
108}
109
110impl<'config> Parser<ClojureLanguage> for ClojureParser<'config> {
111    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ClojureLanguage>) -> ParseOutput<'a, ClojureLanguage> {
112        let lexer = crate::lexer::ClojureLexer::new(self.config);
113        parse_with_lexer(&lexer, text, edits, cache, |state| {
114            let checkpoint = state.checkpoint();
115
116            while state.not_at_end() {
117                self.parse_form(state)?
118            }
119
120            Ok(state.finish_at(checkpoint, ClojureElementType::SourceFile))
121        })
122    }
123}