1use crate::parser::error::TokenAffinity;
2use crate::parser::token_list::TokenList;
3use crate::parser::token_list_ext::TokenListExt;
4use crate::parser::ParseResult;
5use crate::{ContextType, ParseError, ParseErrorType};
6use std::ops::Range;
7
8pub trait ParseResultExt<'s, T>: Sized {
9 fn into_parse_result(self) -> ParseResult<'s, T>;
10
11 fn maybe(self, tokens: TokenList<'s>) -> ParseResult<'s, Option<T>> {
12 match self.into_parse_result() {
13 Ok((tokens, val)) => Ok((tokens, Some(val))),
14 Err(err) if err.is_fatal => Err(err),
15 Err(_) => Ok((tokens, None)),
16 }
17 }
18
19 fn not_definite(self) -> ParseResult<'s, T> {
20 self.into_parse_result().map_err(|err| err.into_non_fatal())
21 }
22
23 fn definite(self) -> ParseResult<'s, T> {
24 self.into_parse_result().map_err(|err| err.into_fatal())
25 }
26
27 fn not_line_ending(self) -> ParseResult<'s, T> {
28 let (tokens, val) = self.into_parse_result()?;
29 if tokens.is_newline() {
30 Err(tokens.error(ParseErrorType::IllegalLineBreak))
31 } else {
32 Ok((tokens, val))
33 }
34 }
35
36 fn map_val<B, F: FnOnce(T) -> B>(self, map: F) -> ParseResult<'s, B> {
37 self.into_parse_result().map(|(tokens, a)| (tokens, map(a)))
38 }
39
40 fn or_try<F: FnOnce() -> ParseResult<'s, T>>(self, f: F) -> ParseResult<'s, T> {
41 match self.into_parse_result() {
42 Ok((tokens, val)) => Ok((tokens, val)),
43 Err(err) if err.is_fatal => Err(err),
44 Err(_) => f(),
45 }
46 }
47
48 fn or_error<F: FnOnce() -> ParseError>(self, f: F) -> ParseResult<'s, T> {
49 self.or_try(|| Err(f()))
50 }
51
52 fn with_context(self, ty: ContextType, range: Range<usize>) -> ParseResult<'s, T> {
53 self.replace_context(ContextType::Span, ty, range)
54 }
55
56 fn with_context_from(self, ty: ContextType, tokens: TokenList) -> ParseResult<'s, T> {
57 self.replace_context_from(ContextType::Span, ty, tokens)
58 }
59
60 fn replace_context(
61 self,
62 from_ty: ContextType,
63 to_ty: ContextType,
64 range: Range<usize>,
65 ) -> ParseResult<'s, T> {
66 self.into_parse_result()
67 .map_err(|err| err.replace_context(from_ty, to_ty, range, TokenAffinity::Inline))
68 }
69
70 fn replace_context_from(
71 self,
72 from_ty: ContextType,
73 to_ty: ContextType,
74 tokens: TokenList,
75 ) -> ParseResult<'s, T> {
76 let start_index = tokens.start_index();
77 self.into_parse_result().map_err(|err| {
78 let range = start_index..err.token_index;
79 err.replace_context(from_ty, to_ty, range, TokenAffinity::Before)
80 })
81 }
82
83 fn determines<B, F: FnOnce(TokenList<'s>, T) -> ParseResult<'s, B>>(
84 self,
85 f: F,
86 ) -> ParseResult<'s, B> {
87 let (tokens, a) = self.into_parse_result().not_definite()?;
88 f(tokens, a).definite()
89 }
90
91 fn opens<
92 Close,
93 Out,
94 FClose: Fn(TokenList<'s>) -> ParseResult<'s, Close>,
95 FInner: FnOnce(TokenList<'s>, T, Close) -> ParseResult<'s, Out>,
96 >(
97 self,
98 context: ContextType,
99 close: FClose,
100 inner: FInner,
101 ) -> ParseResult<'s, Out> {
102 let (tokens, open_val) = self.into_parse_result()?;
103 let close_index = tokens.previous().unwrap().close_index.unwrap();
104 let span_range = (tokens.start_index() - 1)..(close_index + 1);
105
106 let (inner_tokens, outer_tokens) = tokens.split_at(close_index);
107 let (outer_tokens, close_val) =
108 close(outer_tokens).with_context(context, span_range.clone())?;
109 let (inner_tokens, value) =
110 inner(inner_tokens, open_val, close_val).with_context(context, span_range.clone())?;
111
112 if !inner_tokens.is_ended() {
113 let mut remaining_tokens = inner_tokens;
114
115 loop {
118 let (new_tokens, _) =
119 close(remaining_tokens).with_context(context, span_range.clone())?;
120
121 assert!(!remaining_tokens.is_ended());
124
125 remaining_tokens = new_tokens;
126 }
127 }
128
129 Ok((outer_tokens, value))
130 }
131
132 fn determines_and_opens<
133 Close,
134 Out,
135 FClose: Fn(TokenList<'s>) -> ParseResult<'s, Close>,
136 FInner: FnOnce(TokenList<'s>, T, Close) -> ParseResult<'s, Out>,
137 >(
138 self,
139 context: ContextType,
140 close: FClose,
141 inner: FInner,
142 ) -> ParseResult<'s, Out> {
143 let (tokens, open_val) = self.into_parse_result().not_definite()?;
144 Ok((tokens, open_val))
145 .opens(context, close, inner)
146 .definite()
147 }
148}
149
150impl<'s, T> ParseResultExt<'s, T> for ParseResult<'s, T> {
151 #[inline]
152 fn into_parse_result(self) -> ParseResult<'s, T> {
153 self
154 }
155}