use crate::{
ast::{Expr, Module, Script},
*,
};
use rslint_errors::Severity;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Parse<T> {
green: GreenNode,
errors: Vec<ParserError>,
_ty: PhantomData<fn() -> T>,
}
impl<T> Clone for Parse<T> {
fn clone(&self) -> Parse<T> {
Parse {
green: self.green.clone(),
errors: self.errors.clone(),
_ty: PhantomData,
}
}
}
impl<T> Parse<T> {
pub fn new(green: GreenNode, errors: Vec<ParserError>) -> Parse<T> {
Parse {
green,
errors,
_ty: PhantomData,
}
}
pub fn green(self) -> GreenNode {
self.green
}
pub fn syntax(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green.clone())
}
pub fn errors(&self) -> &[ParserError] {
&*self.errors
}
}
impl<T: AstNode> Parse<T> {
#[allow(clippy::wrong_self_convention)]
pub fn to_syntax(self) -> Parse<SyntaxNode> {
Parse {
green: self.green,
errors: self.errors,
_ty: PhantomData,
}
}
pub fn tree(&self) -> T {
T::cast(self.syntax()).unwrap()
}
pub fn try_tree(&self) -> Option<T> {
T::cast(self.syntax())
}
pub fn ok(self) -> Result<T, Vec<ParserError>> {
if !self.errors.iter().any(|d| d.severity == Severity::Error) {
Ok(self.tree())
} else {
Err(self.errors)
}
}
}
pub fn tokenize(text: &str, file_id: usize) -> (Vec<rslint_lexer::Token>, Vec<ParserError>) {
let mut tokens = Vec::new();
let mut errors = Vec::new();
for (tok, error) in rslint_lexer::Lexer::from_str(text, file_id) {
tokens.push(tok);
if let Some(err) = error {
errors.push(err)
}
}
(tokens, errors)
}
fn parse_common(
text: &str,
file_id: usize,
syntax: Syntax,
) -> (Vec<Event>, Vec<ParserError>, Vec<rslint_lexer::Token>) {
let (tokens, mut errors) = tokenize(text, file_id);
let tok_source = TokenSource::new(text, &tokens);
let mut parser = crate::Parser::new(tok_source, file_id, syntax);
crate::syntax::program::parse(&mut parser);
let (events, p_errs) = parser.finish();
errors.extend(p_errs);
(events, errors, tokens)
}
pub fn parse_text(text: &str, file_id: usize) -> Parse<Script> {
let (events, errors, tokens) = parse_common(text, file_id, Syntax::default());
let mut tree_sink = LosslessTreeSink::new(text, &tokens);
crate::process(&mut tree_sink, events, errors);
let (green, parse_errors) = tree_sink.finish();
Parse::new(green, parse_errors)
}
pub fn parse_text_lossy(text: &str, file_id: usize) -> Parse<Script> {
let (events, errors, tokens) = parse_common(text, file_id, Syntax::default());
let mut tree_sink = LossyTreeSink::new(text, &tokens);
crate::process(&mut tree_sink, events, errors);
let (green, parse_errors) = tree_sink.finish();
Parse::new(green, parse_errors)
}
pub fn parse_module_lossy(text: &str, file_id: usize) -> Parse<Module> {
let (events, errors, tokens) = parse_common(text, file_id, Syntax::default().module());
let mut tree_sink = LossyTreeSink::new(text, &tokens);
crate::process(&mut tree_sink, events, errors);
let (green, parse_errors) = tree_sink.finish();
Parse::new(green, parse_errors)
}
pub fn parse_module(text: &str, file_id: usize) -> Parse<Module> {
let (events, errors, tokens) = parse_common(text, file_id, Syntax::default().module());
let mut tree_sink = LosslessTreeSink::new(text, &tokens);
crate::process(&mut tree_sink, events, errors);
let (green, parse_errors) = tree_sink.finish();
Parse::new(green, parse_errors)
}
pub fn parse_expr(text: &str, file_id: usize) -> Parse<Expr> {
let (tokens, mut errors) = tokenize(text, file_id);
let tok_source = TokenSource::new(text, &tokens);
let mut parser = crate::Parser::new(tok_source, file_id, Syntax::default());
crate::syntax::expr::expr(&mut parser);
let (events, p_diags) = parser.finish();
errors.extend(p_diags);
let mut tree_sink = LosslessTreeSink::new(text, &tokens);
crate::process(&mut tree_sink, events, errors);
let (green, parse_errors) = tree_sink.finish();
Parse::new(green, parse_errors)
}
pub fn parse_with_syntax(text: &str, file_id: usize, syntax: Syntax) -> Parse<()> {
let (events, errors, tokens) = parse_common(text, file_id, syntax);
let mut tree_sink = LosslessTreeSink::new(text, &tokens);
crate::process(&mut tree_sink, events, errors);
let (green, parse_errors) = tree_sink.finish();
Parse::new(green, parse_errors)
}