Skip to main content

oak_scheme/parser/
mod.rs

1#![doc = include_str!("readme.md")]
2
3pub mod element_type;
4
5use crate::{
6    language::SchemeLanguage,
7    lexer::{SchemeLexer, token_type::SchemeTokenType},
8    parser::element_type::SchemeElementType,
9};
10use oak_core::{
11    OakError,
12    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
13    source::{Source, TextEdit},
14};
15
16pub(crate) type State<'a, S> = ParserState<'a, SchemeLanguage, S>;
17
18/// Parser for the Scheme language.
19pub struct SchemeParser<'config> {
20    pub(crate) config: &'config SchemeLanguage,
21}
22
23impl<'config> SchemeParser<'config> {
24    /// Creates a new `SchemeParser` with the given configuration.
25    pub fn new(config: &'config SchemeLanguage) -> Self {
26        Self { config }
27    }
28
29    fn parse_form<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
30        match state.peek_kind() {
31            Some(SchemeTokenType::LeftParen) => self.parse_list(state),
32            Some(SchemeTokenType::Quote_) | Some(SchemeTokenType::Quasiquote_) | Some(SchemeTokenType::Unquote_) | Some(SchemeTokenType::UnquoteSplicing_) => {
33                let cp = state.checkpoint();
34                state.bump();
35                self.parse_form(state)?;
36                state.finish_at(cp, SchemeElementType::Quotation);
37                Ok(())
38            }
39            Some(_) => {
40                state.bump();
41                Ok(())
42            }
43            None => Ok(()),
44        }
45    }
46
47    fn parse_list<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
48        let cp = state.checkpoint();
49        state.expect(SchemeTokenType::LeftParen).ok();
50        while state.not_at_end() && !state.at(SchemeTokenType::RightParen) {
51            self.parse_form(state)?;
52        }
53        state.expect(SchemeTokenType::RightParen).ok();
54        state.finish_at(cp, SchemeElementType::List);
55        Ok(())
56    }
57}
58
59impl<'config> Parser<SchemeLanguage> for SchemeParser<'config> {
60    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<SchemeLanguage>) -> ParseOutput<'a, SchemeLanguage> {
61        let lexer = SchemeLexer::new(&self.config);
62        parse_with_lexer(&lexer, text, edits, cache, |state| {
63            let checkpoint = state.checkpoint();
64
65            while state.not_at_end() {
66                self.parse_form(state)?
67            }
68
69            Ok(state.finish_at(checkpoint, SchemeElementType::SourceFile))
70        })
71    }
72}