wagon_parser/parser/
helpers.rs

1use wagon_lexer::productions::Productions;
2use wagon_utils::string_vec;
3use super::{Parse, LexerBridge, ParseResult, Tokens, Spannable, WagParseError, ResultNext, Peek, ResultPeek};
4
5impl Parse for String {
6    fn parse(lexer: &mut LexerBridge) -> ParseResult<Self> {
7        Ok(lexer.next_result()?.to_string())
8    }
9}
10
11/// A helper trait to quickly convert from any [`Tokens`] into an instance of something else.
12pub(super) trait TokenMapper {
13	fn token_to_enum(token: &Tokens) -> Option<Self> where Self: Sized;
14}
15
16/// A lambda which takes a lexerbridge and returns a [`ParseResult`]
17type ParseFunc<T> = Box<dyn FnOnce(&mut LexerBridge) -> ParseResult<T>>;
18
19fn __between_right<T>(lexer: &mut LexerBridge, right: &Tokens, fun: ParseFunc<T>) -> ParseResult<T> {
20	let resp = fun(lexer)?;
21	let span = lexer.span();
22	let token = lexer.peek_result()?;
23	if token == right {
24		lexer.next();
25		Ok(resp)
26	} else {
27		Err(WagParseError::Unexpected { span, offender: token.clone(), expected: string_vec!(right) })
28	}
29}
30
31fn __between<T>(lexer: &mut LexerBridge, left: &Tokens, right: &Tokens, fun: ParseFunc<T>) -> ParseResult<T> {
32	let span = lexer.span();
33	let token = lexer.peek_result()?;
34	if token == left {
35		lexer.next();
36		__between_right(lexer, right, fun)
37	} else {
38		Err(WagParseError::Unexpected { span, offender: token.clone(), expected: string_vec!(left) })
39	}
40}
41
42/// Parse a node, terminated by a final right [`Tokens`].
43pub(super) fn between_right<T: Parse>(lexer: &mut LexerBridge, right: &Tokens) -> ParseResult<T> {
44	__between_right(lexer, right, Box::new(|x| T::parse(x)))
45}
46
47/// Parse a node that is wrapped between a left [`Tokens`] and a right [`Tokens`].
48pub(super) fn between<T: Parse>(lexer: &mut LexerBridge, left: &Tokens, right: &Tokens) -> ParseResult<T> {
49	__between(lexer, left, right, Box::new(|x| T::parse(x)))
50}
51
52/// Parse multiple nodes wrapped between left and right [`Tokens`] and separated by (another) [`Tokens`].
53pub(super) fn between_sep<T: Parse>(lexer: &mut LexerBridge, left: &Tokens, right: &Tokens, sep: Tokens) -> ParseResult<Vec<T>> {
54	__between(lexer, left, right, Box::new(|x| T::parse_sep(x, sep)))
55}
56
57/// A macro that automatically expands to allow either a [`wagon_lexer::Tokens::ProductionToken`] or a [`wagon_lexer::Tokens::MathToken`] with the same name.
58#[macro_export] 
59macro_rules! either_token {
60    ($variant:ident($($arg:tt)*)) => {
61        wagon_lexer::Tokens::ProductionToken(wagon_lexer::productions::Productions::$variant($($arg)*)) 
62        | wagon_lexer::Tokens::MathToken(wagon_lexer::math::Math::$variant($($arg)*))
63    };
64    ($variant:ident) => {
65    	wagon_lexer::Tokens::ProductionToken(wagon_lexer::productions::Productions::$variant) 
66    	| wagon_lexer::Tokens::MathToken(wagon_lexer::math::Math::$variant)
67    };
68}
69
70/// The same as [`either_token!`] but as a reference.
71#[macro_export]
72macro_rules! either_token_ref {
73	($variant:ident($($arg:tt)*)) => {
74        &wagon_lexer::Tokens::ProductionToken(wagon_lexer::productions::Productions::$variant($($arg)*)) 
75        | &wagon_lexer::Tokens::MathToken(wagon_lexer::math::Math::$variant($($arg)*))
76    };
77    ($variant:ident) => {
78    	&wagon_lexer::Tokens::ProductionToken(wagon_lexer::productions::Productions::$variant) 
79    	| &wagon_lexer::Tokens::MathToken(wagon_lexer::math::Math::$variant)
80    };
81}
82
83/// A macro that automatically expands to allow either a [`wagon_lexer::Tokens::ProductionToken`], a [`wagon_lexer::Tokens::MathToken`] or a [`wagon_lexer::Tokens::MetadataToken`].
84#[macro_export] 
85macro_rules! any_token {
86    ($variant:ident($($arg:tt)*)) => {
87        either_token!($variant) 
88        | wagon_lexer::Tokens::MetadataToken(wagon_lexer::metadata::Metadata::$variant($($arg)*))
89    };
90    ($variant:ident) => {
91    	either_token!($variant) 
92    	| wagon_lexer::Tokens::MetadataToken(wagon_lexer::metadata::Metadata::$variant)
93    };
94}
95
96#[allow(clippy::unnested_or_patterns)]
97/// Check if there's a `;` token, return an error otherwise.
98pub(super) fn check_semi(lexer: &mut LexerBridge) -> Result<(), WagParseError> {
99	if lexer.next_if(|x| matches!(x, Ok(any_token!(Semi)))).is_none() {
100    	Err(WagParseError::Unexpected { span: lexer.span(), offender: lexer.next_result()?, expected: string_vec![Tokens::ProductionToken(Productions::Semi)] })
101    } else {
102    	Ok(())
103    }
104}
105
106#[allow(clippy::unnested_or_patterns)]
107/// Check if there's a `:` token, return an error otherwise.
108pub(super) fn check_colon(lexer: &mut LexerBridge) -> Result<(), WagParseError> {
109	if lexer.next_if(|x| matches!(x, Ok(any_token!(Colon)))).is_none() {
110    	Err(WagParseError::Unexpected { span: lexer.span(), offender: lexer.next_result()?, expected: string_vec![Tokens::ProductionToken(Productions::Colon)] })
111    } else {
112    	Ok(())
113    }
114}