#![doc = include_str!("readme.md")]
pub mod cache;
pub mod pratt;
pub mod session;
pub mod state;
pub use self::{
cache::{CachingParseSession, ContentCache},
pratt::{Associativity, OperatorInfo, Pratt, PrattParser, binary, postfix, unary},
session::{ParseCache, ParseSession},
state::{ParserState, deep_clone_node},
};
pub use triomphe::Arc;
pub use crate::{
Language, Lexer,
errors::{OakDiagnostics, OakError},
source::{Source, TextEdit},
tree::GreenNode,
};
pub type ParseOutput<'a, L: Language> = OakDiagnostics<&'a GreenNode<'a, L>>;
pub trait Parser<L: Language + Send + Sync>
where
L::ElementType: From<L::TokenType>,
{
fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<L>) -> ParseOutput<'a, L>;
}
pub fn parse<'a, L, P, Lex, S>(parser: &P, _lexer: &Lex, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<L>) -> ParseOutput<'a, L>
where
L: Language + Send + Sync,
L::ElementType: From<L::TokenType>,
P: Parser<L>,
Lex: Lexer<L>,
S: Source + ?Sized,
{
parser.parse(text, edits, cache)
}
pub fn parse_one_pass<'a, L, P, S>(parser: &P, text: &'a S, cache: &'a mut impl ParseCache<L>) -> ParseOutput<'a, L>
where
L: Language + Send + Sync,
L::ElementType: From<L::TokenType>,
P: Parser<L>,
S: Source + ?Sized,
{
parser.parse(text, &[], cache)
}
#[cfg(feature = "parallel")]
pub fn parse_parallel<'a, L, P, S>(parser: &P, text: &'a S, cache: &'a mut impl ParseCache<L>) -> ParseOutput<'a, L>
where
L: Language + Send + Sync,
L::ElementType: From<L::TokenType>,
P: Parser<L> + Sync,
S: Source + ?Sized,
{
use rayon::prelude::*;
let length = text.length();
const CHUNK_SIZE: usize = 1024 * 1024;
if length <= CHUNK_SIZE {
return parse_one_pass(parser, text, cache);
}
let chunks: Vec<_> = (0..length)
.step_by(CHUNK_SIZE)
.map(|start| {
let end = std::cmp::min(start + CHUNK_SIZE, length);
(start, end)
})
.collect();
let results: Vec<_> = chunks
.par_iter()
.map(|&(start, end)| {
let mut chunk_cache = cache.clone();
parser.parse(text, &[], &mut chunk_cache)
})
.collect();
results.into_iter().next().unwrap_or_else(|| parse_one_pass(parser, text, cache))
}
pub fn parse_with_lexer<'a, L, S, Lex>(lexer: &Lex, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<L>, run: impl FnOnce(&mut ParserState<'a, L, S>) -> Result<&'a GreenNode<'a, L>, OakError>) -> ParseOutput<'a, L>
where
L: Language + Send + Sync,
L::ElementType: From<L::TokenType>,
S: Source + ?Sized,
Lex: Lexer<L>,
{
let lex_out = match cache.lex_output().cloned() {
Some(out) => out,
None => {
let out = lexer.lex(text, edits, cache);
cache.set_lex_output(out.clone());
out
}
};
let capacity_hint = cache.old_tree().map(|old| old.children.len().max(1024)).unwrap_or(1024);
let arena: &'a crate::memory::arena::SyntaxArena = unsafe { std::mem::transmute(cache.arena()) };
let mut st = ParserState::new(arena, lex_out, text, capacity_hint);
if let Some(old) = cache.old_tree() {
let old: &'a GreenNode<'a, L> = unsafe { std::mem::transmute(old) };
st.set_incremental(old, edits);
}
let result = run(&mut st);
let output = st.finish(result);
if let Ok(root) = output.result {
cache.commit_generation(root);
}
output
}