Skip to main content

bluejay_parser/ast/
parse.rs

1use crate::ast::{depth_limiter::DEFAULT_MAX_DEPTH, DepthLimiter, FromTokens, LexerTokens, Tokens};
2use crate::lexer::LogosLexer;
3use crate::Error;
4
5#[non_exhaustive]
6#[derive(Debug, PartialEq)]
7pub struct ParseDetails<T> {
8    pub result: Result<T, Vec<Error>>,
9    pub token_count: usize,
10}
11
12impl<T> ParseDetails<T> {
13    pub fn new(result: Result<T, Vec<Error>>, token_count: usize) -> Self {
14        Self {
15            result,
16            token_count,
17        }
18    }
19}
20
21pub struct ParseOptions {
22    pub graphql_ruby_compatibility: bool,
23    pub max_depth: usize,
24    pub max_tokens: Option<usize>,
25}
26
27impl Default for ParseOptions {
28    fn default() -> Self {
29        Self {
30            graphql_ruby_compatibility: false,
31            max_depth: DEFAULT_MAX_DEPTH,
32            max_tokens: None,
33        }
34    }
35}
36
37pub trait Parse<'a>: Sized {
38    #[inline]
39    fn parse(s: &'a str) -> ParseDetails<Self> {
40        Self::parse_with_options(s, Default::default())
41    }
42
43    #[inline]
44    fn parse_with_options(s: &'a str, options: ParseOptions) -> ParseDetails<Self> {
45        let lexer = LogosLexer::new(s)
46            .with_graphql_ruby_compatibility(options.graphql_ruby_compatibility)
47            .with_max_tokens(options.max_tokens);
48        let tokens = LexerTokens::new(lexer);
49
50        Self::parse_from_tokens(tokens, options.max_depth)
51    }
52
53    fn parse_from_tokens(tokens: impl Tokens<'a>, max_depth: usize) -> ParseDetails<Self>;
54}
55
56impl<'a, T: FromTokens<'a>> Parse<'a> for T {
57    #[inline]
58    fn parse_from_tokens(mut tokens: impl Tokens<'a>, max_depth: usize) -> ParseDetails<Self> {
59        let result = T::from_tokens(&mut tokens, DepthLimiter::new(max_depth));
60        let token_count = tokens.token_count();
61        let errors = tokens.into_errors();
62
63        let result = if errors.is_empty() {
64            result.map_err(|err| vec![err.into()])
65        } else {
66            Err(errors.into_iter().map(Into::into).collect())
67        };
68
69        ParseDetails::new(result, token_count)
70    }
71}