pub mod element_type;
use crate::{
language::JuliaLanguage,
lexer::{JuliaLexer, token_type::JuliaTokenType},
parser::element_type::JuliaElementType,
};
use oak_core::{
OakError,
parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
source::{Source, TextEdit},
};
pub(crate) type State<'a, S> = ParserState<'a, JuliaLanguage, S>;
pub struct JuliaParser<'config> {
pub(crate) config: &'config JuliaLanguage,
}
impl<'config> JuliaParser<'config> {
pub fn new(config: &'config JuliaLanguage) -> Self {
Self { config }
}
fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
while state.not_at_end() {
if let Some(kind) = state.peek_kind() {
if kind.is_trivia() {
state.bump();
continue;
}
}
break;
}
}
fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
self.skip_trivia(state);
if state.at(JuliaTokenType::Function) {
self.parse_function(state)?;
}
else if state.at(JuliaTokenType::If) {
self.parse_if(state)?;
}
else if state.at(JuliaTokenType::For) {
self.parse_for(state)?;
}
else if state.at(JuliaTokenType::End) {
state.bump();
}
else {
self.parse_expression(state)?;
}
Ok(())
}
fn parse_if<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
let cp = state.checkpoint();
state.bump(); self.skip_trivia(state);
self.parse_expression(state)?;
self.skip_trivia(state);
while state.not_at_end() && !state.at(JuliaTokenType::Else) && !state.at(JuliaTokenType::ElseIf) && !state.at(JuliaTokenType::End) {
self.parse_statement(state)?;
self.skip_trivia(state);
}
if state.at(JuliaTokenType::Else) || state.at(JuliaTokenType::ElseIf) {
state.bump();
self.skip_trivia(state);
while state.not_at_end() && !state.at(JuliaTokenType::End) {
self.parse_statement(state)?;
self.skip_trivia(state);
}
}
if state.at(JuliaTokenType::End) {
state.bump();
}
state.finish_at(cp, JuliaElementType::If);
Ok(())
}
fn parse_for<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
let cp = state.checkpoint();
state.bump(); self.skip_trivia(state);
if state.at(JuliaTokenType::Identifier) {
state.bump();
}
self.skip_trivia(state);
if state.at(JuliaTokenType::Equal) || state.at(JuliaTokenType::In) {
state.bump();
}
self.skip_trivia(state);
self.parse_expression(state)?;
self.skip_trivia(state);
while state.not_at_end() && !state.at(JuliaTokenType::End) {
self.parse_statement(state)?;
self.skip_trivia(state);
}
if state.at(JuliaTokenType::End) {
state.bump();
}
state.finish_at(cp, JuliaElementType::For);
Ok(())
}
fn parse_function<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
let cp = state.checkpoint();
state.bump(); self.skip_trivia(state);
if state.at(JuliaTokenType::Identifier) {
let name_cp = state.checkpoint();
state.bump(); state.finish_at(name_cp, JuliaElementType::Identifier);
}
if state.at(JuliaTokenType::LeftParen) {
state.bump();
self.skip_trivia(state);
while state.not_at_end() && !state.at(JuliaTokenType::RightParen) {
state.bump();
}
if state.at(JuliaTokenType::RightParen) {
state.bump();
}
}
self.skip_trivia(state);
while state.not_at_end() && !state.at(JuliaTokenType::End) {
self.parse_statement(state)?;
self.skip_trivia(state);
}
if state.at(JuliaTokenType::End) {
state.bump();
}
state.finish_at(cp, JuliaElementType::Function);
Ok(())
}
fn parse_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
self.skip_trivia(state);
let cp = state.checkpoint();
if state.at(JuliaTokenType::Identifier) {
state.bump();
let id_node = state.finish_at(cp, JuliaElementType::Identifier);
self.skip_trivia(state);
if state.at(JuliaTokenType::LeftParen) {
let call_cp = state.checkpoint_before(id_node);
state.bump(); self.skip_trivia(state);
let arg_cp = state.checkpoint();
while state.not_at_end() && !state.at(JuliaTokenType::RightParen) {
self.parse_expression(state)?;
self.skip_trivia(state);
if state.at(JuliaTokenType::Comma) {
state.bump();
self.skip_trivia(state);
}
}
state.finish_at(arg_cp, JuliaElementType::ArgumentList);
if state.at(JuliaTokenType::RightParen) {
state.bump();
}
state.finish_at(call_cp, JuliaElementType::Call);
}
}
else if state.at(JuliaTokenType::StringLiteral) {
state.bump();
state.finish_at(cp, JuliaElementType::StringLiteral);
}
else if state.not_at_end() {
state.bump();
}
Ok(())
}
}
impl<'config> Parser<JuliaLanguage> for JuliaParser<'config> {
fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<JuliaLanguage>) -> ParseOutput<'a, JuliaLanguage> {
let lexer = JuliaLexer::new(&self.config);
parse_with_lexer(&lexer, text, edits, cache, |state| {
let checkpoint = state.checkpoint();
while state.not_at_end() {
self.skip_trivia(state);
if !state.not_at_end() {
break;
}
self.parse_statement(state)?;
}
Ok(state.finish_at(checkpoint, JuliaElementType::Root))
})
}
}