pub mod element_type;
use crate::{
language::RhombusLanguage,
lexer::{RhombusLexer, token_type::RhombusTokenType},
parser::element_type::RhombusElementType,
};
use oak_core::{
OakError,
parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
source::{Source, TextEdit},
};
pub(crate) type State<'a, S> = ParserState<'a, RhombusLanguage, S>;
pub struct RhombusParser<'config> {
pub(crate) config: &'config RhombusLanguage,
}
impl<'config> RhombusParser<'config> {
pub fn new(config: &'config RhombusLanguage) -> Self {
Self { config }
}
fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
let cp = state.checkpoint();
self.parse_expression(state)?;
state.finish_at(cp, RhombusElementType::Statement);
Ok(())
}
fn parse_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
match state.peek_kind() {
Some(RhombusTokenType::LeftParen) | Some(RhombusTokenType::LeftBracket) | Some(RhombusTokenType::LeftBrace) => self.parse_block(state),
Some(_) => {
state.bump();
Ok(())
}
None => Ok(()),
}
}
fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
let cp = state.checkpoint();
let open_kind = state.peek_kind();
let close_kind = match open_kind {
Some(RhombusTokenType::LeftParen) => Some(RhombusTokenType::RightParen),
Some(RhombusTokenType::LeftBracket) => Some(RhombusTokenType::RightBracket),
Some(RhombusTokenType::LeftBrace) => Some(RhombusTokenType::RightBrace),
_ => None,
};
state.bump();
while state.not_at_end() {
if let Some(ck) = close_kind {
if state.at(ck) {
break;
}
}
self.parse_statement(state)?;
}
if let Some(ck) = close_kind {
state.expect(ck).ok();
}
state.finish_at(cp, RhombusElementType::Block);
Ok(())
}
}
impl<'config> Parser<RhombusLanguage> for RhombusParser<'config> {
fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<RhombusLanguage>) -> ParseOutput<'a, RhombusLanguage> {
let lexer = RhombusLexer::new(&self.config);
parse_with_lexer(&lexer, text, edits, cache, |state| {
let checkpoint = state.checkpoint();
while state.not_at_end() {
self.parse_statement(state)?
}
Ok(state.finish_at(checkpoint, RhombusElementType::SourceFile))
})
}
}