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
18pub struct SchemeParser<'config> {
20 pub(crate) config: &'config SchemeLanguage,
21}
22
23impl<'config> SchemeParser<'config> {
24 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}